diff options
292 files changed, 8221 insertions, 9719 deletions
@@ -1,4 +1,8 @@ *.a +*.gcda +*.gcno +*.gcno.gcov.json.gz +*.gcov *.la *.lo *.so @@ -16,6 +20,7 @@ Makefile.in /build-aux/ /config.* /configure +/configure~ /libtool /stamp-h1 /iptables/iptables-apply.8 @@ -25,3 +30,14 @@ Makefile.in # vim/nano swap file *.swp + +/tags + +# make check results +/test-suite.log +/iptables-test.py.log +/iptables-test.py.trs +/xlate-test.py.log +/xlate-test.py.trs +iptables/tests/shell/run-tests.sh.log +iptables/tests/shell/run-tests.sh.trs diff --git a/INCOMPATIBILITIES b/INCOMPATIBILITIES deleted file mode 100644 index ddb24087..00000000 --- a/INCOMPATIBILITIES +++ /dev/null @@ -1,14 +0,0 @@ -INCOMPATIBILITIES: - -- The REJECT target has an '--reject-with admin-prohib' option which used - with kernels that do not support it, will result in a plain DROP instead - of REJECT. Use with caution. - Kernels that do support it: - 2.4 - since 2.4.22-pre9 - 2.6 - all - -- There are some issues related to upgrading from 1.2.x to 1.3.x on a system - with dynamic ruleset changes during runtime. (Please see - https://bugzilla.netfilter.org/bugzilla/show_bug.cgi?id=334). - After upgrading from 1.2 to 1.3, it suggest go do an iptables-save, then - iptables-restore to ensure your dynamic rule changes continue to work. diff --git a/Makefile.am b/Makefile.am index 799bf8b8..299ab46d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,7 +1,7 @@ # -*- Makefile -*- ACLOCAL_AMFLAGS = -I m4 -AUTOMAKE_OPTIONS = foreign subdir-objects +AUTOMAKE_OPTIONS = foreign subdir-objects dist-xz no-dist-gzip SUBDIRS = libiptc libxtables if ENABLE_DEVEL @@ -16,6 +16,8 @@ SUBDIRS += extensions # Depends on extensions/libext.a: SUBDIRS += iptables +EXTRA_DIST = autogen.sh iptables-test.py xlate-test.py + if ENABLE_NFTABLES confdir = $(sysconfdir) dist_conf_DATA = etc/ethertypes @@ -26,8 +28,10 @@ tarball: rm -Rf /tmp/${PACKAGE_TARNAME}-${PACKAGE_VERSION}; pushd ${top_srcdir} && git archive --prefix=${PACKAGE_TARNAME}-${PACKAGE_VERSION}/ HEAD | tar -C /tmp -x && popd; pushd /tmp/${PACKAGE_TARNAME}-${PACKAGE_VERSION} && ./autogen.sh && popd; - tar -C /tmp -cjf ${PACKAGE_TARNAME}-${PACKAGE_VERSION}.tar.bz2 --owner=root --group=root ${PACKAGE_TARNAME}-${PACKAGE_VERSION}/; + tar -C /tmp -cJf ${PACKAGE_TARNAME}-${PACKAGE_VERSION}.tar.xz --owner=root --group=root ${PACKAGE_TARNAME}-${PACKAGE_VERSION}/; rm -Rf /tmp/${PACKAGE_TARNAME}-${PACKAGE_VERSION}; config.status: extensions/GNUmakefile.in \ include/xtables-version.h.in + +TESTS = xlate-test.py iptables-test.py iptables/tests/shell/run-tests.sh diff --git a/configure.ac b/configure.ac index 00ae60c5..bc2ed47b 100644 --- a/configure.ac +++ b/configure.ac @@ -1,9 +1,9 @@ -AC_INIT([iptables], [1.8.7]) +AC_INIT([iptables], [1.8.9]) # See libtool.info "Libtool's versioning system" -libxtables_vcurrent=17 -libxtables_vage=5 +libxtables_vcurrent=19 +libxtables_vage=7 AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_HEADERS([config.h]) @@ -12,9 +12,8 @@ AC_PROG_INSTALL AM_INIT_AUTOMAKE([-Wall]) AC_PROG_CC AM_PROG_CC_C_O -AC_DISABLE_STATIC m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) -AM_PROG_LIBTOOL +LT_INIT([disable-static]) AC_ARG_WITH([kernel], AS_HELP_STRING([--with-kernel=PATH], @@ -72,6 +71,9 @@ AC_ARG_WITH([xt-lock-name], AS_HELP_STRING([--with-xt-lock-name=PATH], [Path to the xtables lock [[/run/xtables.lock]]]), [xt_lock_name="$withval"], [xt_lock_name="/run/xtables.lock"]) +AC_ARG_ENABLE([profiling], + AS_HELP_STRING([--enable-profiling], [build for use of gcov/gprof]), + [enable_profiling="$enableval"], [enable_profiling="no"]) AC_MSG_CHECKING([whether $LD knows -Wl,--no-undefined]) saved_LDFLAGS="$LDFLAGS"; @@ -189,6 +191,11 @@ if [[ -n "$ksourcedir" ]]; then fi; pkgdatadir='${datadir}/xtables'; +if test "x$enable_profiling" = "xyes"; then + regular_CFLAGS+=" -fprofile-arcs -ftest-coverage" + regular_LDFLAGS+=" -lgcov --coverage" +fi + define([EXPAND_VARIABLE], [$2=[$]$1 if test $prefix = 'NONE'; then @@ -206,6 +213,7 @@ eval "$2=[$]$2" AC_SUBST([regular_CFLAGS]) AC_SUBST([regular_CPPFLAGS]) AC_SUBST([noundef_LDFLAGS]) +AC_SUBST([regular_LDFLAGS]) AC_SUBST([kinclude_CPPFLAGS]) AC_SUBST([kbuilddir]) AC_SUBST([ksourcedir]) @@ -251,6 +259,7 @@ Iptables Configuration: nfsynproxy util support: ${enable_nfsynproxy} nftables support: ${enable_nftables} connlabel support: ${enable_connlabel} + profiling support: ${enable_profiling} Build parameters: Put plugins into executable (static): ${enable_static} diff --git a/etc/xtables.conf b/etc/xtables.conf deleted file mode 100644 index 3c54ced0..00000000 --- a/etc/xtables.conf +++ /dev/null @@ -1,74 +0,0 @@ -family ipv4 { - table raw { - chain PREROUTING hook NF_INET_PRE_ROUTING prio -300 - chain OUTPUT hook NF_INET_LOCAL_OUT prio -300 - } - - table mangle { - chain PREROUTING hook NF_INET_PRE_ROUTING prio -150 - chain INPUT hook NF_INET_LOCAL_IN prio -150 - chain FORWARD hook NF_INET_FORWARD prio -150 - chain OUTPUT hook NF_INET_LOCAL_OUT prio -150 - chain POSTROUTING hook NF_INET_POST_ROUTING prio -150 - } - - table filter { - chain INPUT hook NF_INET_LOCAL_IN prio 0 - chain FORWARD hook NF_INET_FORWARD prio 0 - chain OUTPUT hook NF_INET_LOCAL_OUT prio 0 - } - - table nat { - chain PREROUTING hook NF_INET_PRE_ROUTING prio -100 - chain INPUT hook NF_INET_LOCAL_IN prio 100 - chain OUTPUT hook NF_INET_LOCAL_OUT prio -100 - chain POSTROUTING hook NF_INET_POST_ROUTING prio 100 - } - - table security { - chain INPUT hook NF_INET_LOCAL_IN prio 50 - chain FORWARD hook NF_INET_FORWARD prio 50 - chain OUTPUT hook NF_INET_LOCAL_OUT prio 50 - } -} - -family ipv6 { - table raw { - chain PREROUTING hook NF_INET_PRE_ROUTING prio -300 - chain OUTPUT hook NF_INET_LOCAL_OUT prio -300 - } - - table mangle { - chain PREROUTING hook NF_INET_PRE_ROUTING prio -150 - chain INPUT hook NF_INET_LOCAL_IN prio -150 - chain FORWARD hook NF_INET_FORWARD prio -150 - chain OUTPUT hook NF_INET_LOCAL_OUT prio -150 - chain POSTROUTING hook NF_INET_POST_ROUTING prio -150 - } - - table filter { - chain INPUT hook NF_INET_LOCAL_IN prio 0 - chain FORWARD hook NF_INET_FORWARD prio 0 - chain OUTPUT hook NF_INET_LOCAL_OUT prio 0 - } - - table nat { - chain PREROUTING hook NF_INET_PRE_ROUTING prio -100 - chain INPUT hook NF_INET_LOCAL_IN prio 100 - chain OUTPUT hook NF_INET_LOCAL_OUT prio -100 - chain POSTROUTING hook NF_INET_POST_ROUTING prio 100 - } - - table security { - chain INPUT hook NF_INET_LOCAL_IN prio 50 - chain FORWARD hook NF_INET_FORWARD prio 50 - chain OUTPUT hook NF_INET_LOCAL_OUT prio 50 - } -} - -family arp { - table filter { - chain INPUT hook NF_ARP_IN prio 0 - chain OUTPUT hook NF_ARP_OUT prio 0 - } -} diff --git a/extensions/GNUmakefile.in b/extensions/GNUmakefile.in index 956ccb38..e289adf0 100644 --- a/extensions/GNUmakefile.in +++ b/extensions/GNUmakefile.in @@ -24,7 +24,7 @@ kinclude_CPPFLAGS = @kinclude_CPPFLAGS@ AM_CFLAGS = ${regular_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@ +AM_LDFLAGS = @noundef_LDFLAGS@ @regular_LDFLAGS@ ifeq (${V},) AM_LIBTOOL_SILENT = --silent @@ -42,7 +42,7 @@ endif pfx_build_mod := $(patsubst ${srcdir}/libxt_%.c,%,$(sort $(wildcard ${srcdir}/libxt_*.c))) @ENABLE_NFTABLES_TRUE@ pfb_build_mod := $(patsubst ${srcdir}/libebt_%.c,%,$(sort $(wildcard ${srcdir}/libebt_*.c))) @ENABLE_NFTABLES_TRUE@ pfa_build_mod := $(patsubst ${srcdir}/libarpt_%.c,%,$(sort $(wildcard ${srcdir}/libarpt_*.c))) -pfx_symlinks := NOTRACK state +pfx_symlinks := NOTRACK state REDIRECT MASQUERADE SNAT DNAT @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@ @blacklist_x_modules@,${pfx_build_mod}) @@ -79,7 +79,7 @@ targets_install := .SECONDARY: -.PHONY: all install uninstall clean distclean FORCE +.PHONY: all install uninstall clean distclean FORCE dvi check installcheck all: ${targets} @@ -106,7 +106,8 @@ uninstall: } clean: - rm -f *.o *.oo *.so *.a {matches,targets}.man initext.c initext4.c initext6.c initextb.c initexta.c; + rm -f *.o *.oo *.so *.a matches.man targets.man + rm -f initext.c initext4.c initext6.c initextb.c initexta.c rm -f .*.d .*.dd; distclean: clean @@ -130,6 +131,14 @@ libxt_NOTRACK.so: libxt_CT.so ln -fs $< $@ libxt_state.so: libxt_conntrack.so ln -fs $< $@ +libxt_REDIRECT.so: libxt_NAT.so + ln -fs $< $@ +libxt_MASQUERADE.so: libxt_NAT.so + ln -fs $< $@ +libxt_SNAT.so: libxt_NAT.so + ln -fs $< $@ +libxt_DNAT.so: libxt_NAT.so + ln -fs $< $@ # Need the LIBADDs in iptables/Makefile.am too for libxtables_la_LIBADD xt_RATEEST_LIBADD = -lm @@ -167,111 +176,33 @@ initexta_func := $(addprefix arpt_,${pfa_build_mod}) initext4_func := $(addprefix ipt_,${pf4_build_mod}) initext6_func := $(addprefix ip6t_,${pf6_build_mod}) -.initext.dd: FORCE - @echo "${initext_func}" >$@.tmp; \ - 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 $@; \ - rm -f $@.tmp; +initexts := ext exta extb ext4 ext6 +initext_depfiles = $(patsubst %,.init%.dd,${initexts}) +initext_sources = $(patsubst %,init%.c,${initexts}) -.initext6.dd: FORCE - @echo "${initext6_func}" >$@.tmp; \ +${initext_depfiles}: FORCE + @echo "$(value $(patsubst .%.dd,%,$@)_func)" >$@.tmp; \ cmp -s $@ $@.tmp || mv $@.tmp $@; \ rm -f $@.tmp; -initext.c: .initext.dd +${initext_sources}: %.c: .%.dd ${AM_VERBOSE_GEN} @( \ + initext_func="$(value $(basename $@)_func)"; \ + funcname="init_extensions$(patsubst initext%.c,%,$@)"; \ echo "" >$@; \ - for i in ${initext_func}; do \ + for i in $${initext_func}; do \ echo "extern void lib$${i}_init(void);" >>$@; \ done; \ - echo "void init_extensions(void);" >>$@; \ - echo "void init_extensions(void)" >>$@; \ + echo "void $${funcname}(void);" >>$@; \ + echo "void $${funcname}(void)" >>$@; \ echo "{" >>$@; \ - for i in ${initext_func}; do \ + for i in $${initext_func}; do \ echo " ""lib$${i}_init();" >>$@; \ done; \ 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} - @( \ - echo "" >$@; \ - for i in ${initext4_func}; do \ - echo "extern void lib$${i}_init(void);" >>$@; \ - done; \ - echo "void init_extensions4(void);" >>$@; \ - echo "void init_extensions4(void)" >>$@; \ - echo "{" >>$@; \ - for i in ${initext4_func}; do \ - echo " ""lib$${i}_init();" >>$@; \ - done; \ - echo "}" >>$@; \ - ); - -initext6.c: .initext6.dd - ${AM_VERBOSE_GEN} - @( \ - echo "" >$@; \ - for i in ${initext6_func}; do \ - echo "extern void lib$${i}_init(void);" >>$@; \ - done; \ - echo "void init_extensions6(void);" >>$@; \ - echo "void init_extensions6(void)" >>$@; \ - echo "{" >>$@; \ - for i in ${initext6_func}; do \ - echo " ""lib$${i}_init();" >>$@; \ - done; \ - echo "}" >>$@; \ - ); - # # Manual pages # @@ -300,8 +231,21 @@ man_run = \ fi; \ done >$@; -matches.man: .initext.dd .initextb.dd .initexta.dd .initext4.dd .initext6.dd $(wildcard ${srcdir}/lib*.man) +matches.man: ${initext_depfiles} $(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 .initextb.dd .initexta.dd .initext4.dd .initext6.dd $(wildcard ${srcdir}/lib*.man) +targets.man: ${initext_depfiles} $(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})) + +dist_initext_src = $(addprefix $(srcdir)/,${initext_sources}) +dist_sources = $(filter-out ${dist_initext_src},$(wildcard $(srcdir)/*.[ch])) + +distdir: + mkdir -p $(distdir) + cp -p ${dist_sources} $(distdir)/ + cp -p $(wildcard ${srcdir}/lib*.man) $(distdir)/ + cp -p $(wildcard ${srcdir}/*.t ${srcdir}/*.txlate) $(distdir)/ + +dvi: +check: all +installcheck: diff --git a/extensions/dscp_helper.c b/extensions/dscp_helper.c index 75b1fece..1f20b2a5 100644 --- a/extensions/dscp_helper.c +++ b/extensions/dscp_helper.c @@ -58,7 +58,7 @@ class_to_dscp(const char *name) } xtables_error(PARAMETER_PROBLEM, - "Invalid DSCP value `%s'\n", name); + "Invalid DSCP value `%s'", name); } @@ -73,7 +73,7 @@ dscp_to_name(unsigned int dscp) return ds_classes[i].name; xtables_error(PARAMETER_PROBLEM, - "Invalid DSCP value `%d'\n", dscp); + "Invalid DSCP value `%d'", dscp); } #endif diff --git a/extensions/generic.txlate b/extensions/generic.txlate index 9ae9a5b5..c24ed156 100644 --- a/extensions/generic.txlate +++ b/extensions/generic.txlate @@ -1,84 +1,90 @@ iptables-translate -I OUTPUT -p udp -d 8.8.8.8 -j ACCEPT -nft insert rule ip filter OUTPUT ip protocol udp ip daddr 8.8.8.8 counter accept +nft 'insert rule ip filter OUTPUT ip protocol udp ip daddr 8.8.8.8 counter accept' iptables-translate -F -t nat nft flush table ip nat iptables-translate -I INPUT -i iifname -s 10.0.0.0/8 -nft insert rule ip filter INPUT iifname "iifname" ip saddr 10.0.0.0/8 counter +nft 'insert rule ip filter INPUT iifname "iifname" ip saddr 10.0.0.0/8 counter' iptables-translate -A INPUT -i iif+ ! -d 10.0.0.0/8 -nft add rule ip filter INPUT iifname "iif*" ip daddr != 10.0.0.0/8 counter +nft 'add rule ip filter INPUT iifname "iif*" ip daddr != 10.0.0.0/8 counter' iptables-translate -I INPUT -s 10.11.12.13/255.255.0.0 -nft insert rule ip filter INPUT ip saddr 10.11.0.0/16 counter +nft 'insert rule ip filter INPUT ip saddr 10.11.0.0/16 counter' iptables-translate -I INPUT -s 10.11.12.13/255.0.255.0 -nft insert rule ip filter INPUT ip saddr & 255.0.255.0 == 10.0.12.0 counter +nft 'insert rule ip filter INPUT ip saddr & 255.0.255.0 == 10.0.12.0 counter' iptables-translate -I INPUT -s 10.11.12.13/0.255.0.255 -nft insert rule ip filter INPUT ip saddr & 0.255.0.255 == 0.11.0.13 counter +nft 'insert rule ip filter INPUT ip saddr & 0.255.0.255 == 0.11.0.13 counter' iptables-translate -I INPUT ! -s 10.11.12.13/0.255.0.255 -nft insert rule ip filter INPUT ip saddr & 0.255.0.255 != 0.11.0.13 counter +nft 'insert rule ip filter INPUT ip saddr & 0.255.0.255 != 0.11.0.13 counter' iptables-translate -I INPUT -s 0.0.0.0/16 -nft insert rule ip filter INPUT ip saddr 0.0.0.0/16 counter +nft 'insert rule ip filter INPUT ip saddr 0.0.0.0/16 counter' iptables-translate -I INPUT -s 0.0.0.0/0 -nft insert rule ip filter INPUT counter +nft 'insert rule ip filter INPUT counter' iptables-translate -I INPUT ! -s 0.0.0.0/0 -nft insert rule ip filter INPUT ip saddr != 0.0.0.0/0 counter +nft 'insert rule ip filter INPUT ip saddr != 0.0.0.0/0 counter' ip6tables-translate -I INPUT -i iifname -s feed::/16 -nft insert rule ip6 filter INPUT iifname "iifname" ip6 saddr feed::/16 counter +nft 'insert rule ip6 filter INPUT iifname "iifname" ip6 saddr feed::/16 counter' ip6tables-translate -A INPUT -i iif+ ! -d feed::/16 -nft add rule ip6 filter INPUT iifname "iif*" ip6 daddr != feed::/16 counter +nft 'add rule ip6 filter INPUT iifname "iif*" ip6 daddr != feed::/16 counter' ip6tables-translate -I INPUT -s feed:babe::1/ffff:ff00:: -nft insert rule ip6 filter INPUT ip6 saddr feed:ba00::/24 counter +nft 'insert rule ip6 filter INPUT ip6 saddr feed:ba00::/24 counter' ip6tables-translate -I INPUT -s feed:babe:c0ff:ee00:c0be:1234:5678:90ab/ffff:0:ffff:0:ffff:0:ffff:0 -nft insert rule ip6 filter INPUT ip6 saddr & ffff:0:ffff:0:ffff:0:ffff:0 == feed:0:c0ff:0:c0be:0:5678:0 counter +nft 'insert rule ip6 filter INPUT ip6 saddr & ffff:0:ffff:0:ffff:0:ffff:0 == feed:0:c0ff:0:c0be:0:5678:0 counter' ip6tables-translate -I INPUT -s feed:babe:c0ff:ee00:c0be:1234:5678:90ab/0:ffff:0:ffff:0:ffff:0:ffff -nft insert rule ip6 filter INPUT ip6 saddr & 0:ffff:0:ffff:0:ffff:0:ffff == 0:babe:0:ee00:0:1234:0:90ab counter +nft 'insert rule ip6 filter INPUT ip6 saddr & 0:ffff:0:ffff:0:ffff:0:ffff == 0:babe:0:ee00:0:1234:0:90ab counter' ip6tables-translate -I INPUT ! -s feed:babe:c0ff:ee00:c0be:1234:5678:90ab/0:ffff:0:ffff:0:ffff:0:ffff -nft insert rule ip6 filter INPUT ip6 saddr & 0:ffff:0:ffff:0:ffff:0:ffff != 0:babe:0:ee00:0:1234:0:90ab counter +nft 'insert rule ip6 filter INPUT ip6 saddr & 0:ffff:0:ffff:0:ffff:0:ffff != 0:babe:0:ee00:0:1234:0:90ab counter' ip6tables-translate -I INPUT -s ::/16 -nft insert rule ip6 filter INPUT ip6 saddr ::/16 counter +nft 'insert rule ip6 filter INPUT ip6 saddr ::/16 counter' ip6tables-translate -I INPUT -s ::/0 -nft insert rule ip6 filter INPUT counter +nft 'insert rule ip6 filter INPUT counter' ip6tables-translate -I INPUT ! -s ::/0 -nft insert rule ip6 filter INPUT ip6 saddr != ::/0 counter +nft 'insert rule ip6 filter INPUT ip6 saddr != ::/0 counter' ebtables-translate -I INPUT -i iname --logical-in ilogname -s 0:0:0:0:0:0 -nft insert rule bridge filter INPUT iifname "iname" meta ibrname "ilogname" ether saddr 00:00:00:00:00:00 counter +nft 'insert rule bridge filter INPUT iifname "iname" meta ibrname "ilogname" ether saddr 00:00:00:00:00:00 counter' ebtables-translate -A FORWARD ! -i iname --logical-in ilogname -o out+ --logical-out lout+ -d 1:2:3:4:de:af -nft add rule bridge filter FORWARD iifname != "iname" meta ibrname "ilogname" oifname "out*" meta obrname "lout*" ether daddr 01:02:03:04:de:af counter +nft 'add rule bridge filter FORWARD iifname != "iname" meta ibrname "ilogname" oifname "out*" meta obrname "lout*" ether daddr 01:02:03:04:de:af counter' ebtables-translate -I INPUT -p ip -d 1:2:3:4:5:6/ff:ff:ff:ff:00:00 -nft insert rule bridge filter INPUT ether type 0x800 ether daddr 01:02:03:04:00:00 and ff:ff:ff:ff:00:00 == 01:02:03:04:00:00 counter +nft 'insert rule bridge filter INPUT ether type 0x800 ether daddr and ff:ff:ff:ff:00:00 == 01:02:03:04:00:00 counter' + +ebtables-translate -I INPUT -p Length +nft 'insert rule bridge filter INPUT ether type < 0x0600 counter' + +ebtables-translate -I INPUT -p ! Length +nft 'insert rule bridge filter INPUT ether type >= 0x0600 counter' # asterisk is not special in iptables and it is even a valid interface name -iptables-translate -A FORWARD -i '*' -o 'eth*foo' -nft add rule ip filter FORWARD iifname "\*" oifname "eth\*foo" counter +iptables-translate -A FORWARD -i * -o eth*foo +nft 'add rule ip filter FORWARD iifname "\*" oifname "eth*foo" counter' -# escape all asterisks but translate only the first plus character -iptables-translate -A FORWARD -i 'eth*foo*+' -o 'eth++' -nft add rule ip filter FORWARD iifname "eth\*foo\**" oifname "eth+*" counter +# escape only suffix asterisk and translate only the last plus character +iptables-translate -A FORWARD -i eth*foo*+ -o eth++ +nft 'add rule ip filter FORWARD iifname "eth*foo**" oifname "eth+*" counter' # skip for always matching interface names -iptables-translate -A FORWARD -i '+' -nft add rule ip filter FORWARD counter +iptables-translate -A FORWARD -i + +nft 'add rule ip filter FORWARD counter' # match against invalid interface name to simulate never matching rule -iptables-translate -A FORWARD ! -i '+' -nft add rule ip filter FORWARD iifname "INVAL/D" counter +iptables-translate -A FORWARD ! -i + +nft 'add rule ip filter FORWARD iifname "INVAL/D" counter' diff --git a/extensions/libarpt_mangle.c b/extensions/libarpt_mangle.c index a2378a8b..765edf34 100644 --- a/extensions/libarpt_mangle.c +++ b/extensions/libarpt_mangle.c @@ -13,7 +13,6 @@ #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) { diff --git a/extensions/libebt_802_3.t b/extensions/libebt_802_3.t index ddfb2f0a..a138f35d 100644 --- a/extensions/libebt_802_3.t +++ b/extensions/libebt_802_3.t @@ -1,3 +1,5 @@ :INPUT,FORWARD,OUTPUT ---802_3-sap ! 0x0a -j CONTINUE;=;OK ---802_3-type 0x000a -j RETURN;=;OK +--802_3-sap ! 0x0a -j CONTINUE;=;FAIL +--802_3-type 0x000a -j RETURN;=;FAIL +-p Length --802_3-sap ! 0x0a -j CONTINUE;=;OK +-p Length --802_3-type 0x000a -j RETURN;=;OK diff --git a/extensions/libebt_among.c b/extensions/libebt_among.c index 7eb898f9..a80fb804 100644 --- a/extensions/libebt_among.c +++ b/extensions/libebt_among.c @@ -68,12 +68,12 @@ parse_nft_among_pair(char *buf, struct nft_among_pair *pair, bool have_ip) if (!inet_pton(AF_INET, sep + 1, &pair->in)) xtables_error(PARAMETER_PROBLEM, - "Invalid IP address '%s'\n", sep + 1); + "Invalid IP address '%s'", sep + 1); } ether = ether_aton(buf); if (!ether) xtables_error(PARAMETER_PROBLEM, - "Invalid MAC address '%s'\n", buf); + "Invalid MAC address '%s'", buf); memcpy(&pair->ether, ether, sizeof(*ether)); } @@ -119,7 +119,6 @@ static int bramong_parse(int c, char **argv, int invert, struct xt_entry_match **match) { struct nft_among_data *data = (struct nft_among_data *)(*match)->data; - struct xt_entry_match *new_match; bool have_ip, dst = false; size_t new_size, cnt; struct stat stats; @@ -152,10 +151,9 @@ static int bramong_parse(int c, char **argv, int invert, xtables_error(PARAMETER_PROBLEM, "File should only contain one line"); optarg[flen-1] = '\0'; - /* fall through */ + break; case AMONG_DST: - if (c == AMONG_DST) - dst = true; + dst = true; /* fall through */ case AMONG_SRC: break; @@ -171,18 +169,17 @@ static int bramong_parse(int c, char **argv, int invert, new_size *= sizeof(struct nft_among_pair); new_size += XT_ALIGN(sizeof(struct xt_entry_match)) + sizeof(struct nft_among_data); - new_match = xtables_calloc(1, new_size); - memcpy(new_match, *match, (*match)->u.match_size); - new_match->u.match_size = new_size; - data = (struct nft_among_data *)new_match->data; + if (new_size > (*match)->u.match_size) { + *match = xtables_realloc(*match, new_size); + (*match)->u.match_size = new_size; + data = (struct nft_among_data *)(*match)->data; + } + have_ip = nft_among_pairs_have_ip(optarg); poff = nft_among_prepare_data(data, dst, cnt, invert, have_ip); parse_nft_among_pairs(data->pairs + poff, optarg, cnt, have_ip); - free(*match); - *match = new_match; - if (c == AMONG_DST_F || c == AMONG_SRC_F) { munmap(argv, flen); close(fd); diff --git a/extensions/libebt_arp.c b/extensions/libebt_arp.c index d5035b95..63a953d4 100644 --- a/extensions/libebt_arp.c +++ b/extensions/libebt_arp.c @@ -87,91 +87,17 @@ static void brarp_print_help(void) #define OPT_MAC_D 0x40 #define OPT_GRAT 0x80 -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 brarp_parse(int c, char **argv, int invert, unsigned int *flags, const void *entry, struct xt_entry_match **match) { struct ebt_arp_info *arpinfo = (struct ebt_arp_info *)(*match)->data; + struct in_addr *ipaddr, ipmask; long int i; char *end; - uint32_t *addr; - uint32_t *mask; unsigned char *maddr; unsigned char *mmask; + unsigned int ipnr; switch (c) { case ARP_OPCODE: @@ -231,24 +157,25 @@ brarp_parse(int c, char **argv, int invert, unsigned int *flags, case ARP_IP_S: case ARP_IP_D: + xtables_ipparse_any(optarg, &ipaddr, &ipmask, &ipnr); if (c == ARP_IP_S) { EBT_CHECK_OPTION(flags, OPT_IP_S); - addr = &arpinfo->saddr; - mask = &arpinfo->smsk; + arpinfo->saddr = ipaddr->s_addr; + arpinfo->smsk = ipmask.s_addr; arpinfo->bitmask |= EBT_ARP_SRC_IP; } else { EBT_CHECK_OPTION(flags, OPT_IP_D); - addr = &arpinfo->daddr; - mask = &arpinfo->dmsk; + arpinfo->daddr = ipaddr->s_addr; + arpinfo->dmsk = ipmask.s_addr; arpinfo->bitmask |= EBT_ARP_DST_IP; } + free(ipaddr); if (invert) { if (c == ARP_IP_S) arpinfo->invflags |= EBT_ARP_SRC_IP; else arpinfo->invflags |= EBT_ARP_DST_IP; } - ebt_parse_ip_address(optarg, addr, mask); break; case ARP_MAC_S: case ARP_MAC_D: diff --git a/extensions/libebt_arp.t b/extensions/libebt_arp.t index 14ff0f09..96fbce90 100644 --- a/extensions/libebt_arp.t +++ b/extensions/libebt_arp.t @@ -6,6 +6,9 @@ -p ARP ! --arp-ip-dst 1.2.3.4;-p ARP --arp-ip-dst ! 1.2.3.4 -j CONTINUE;OK -p ARP --arp-ip-src ! 0.0.0.0;=;OK -p ARP --arp-ip-dst ! 0.0.0.0/8;=;OK +-p ARP --arp-ip-src ! 1.2.3.4/32;-p ARP --arp-ip-src ! 1.2.3.4;OK +-p ARP --arp-ip-src ! 1.2.3.4/255.255.255.0;-p ARP --arp-ip-src ! 1.2.3.0/24;OK +-p ARP --arp-ip-src ! 1.2.3.4/255.0.255.255;-p ARP --arp-ip-src ! 1.0.3.4/255.0.255.255;OK -p ARP --arp-mac-src 00:de:ad:be:ef:00;=;OK -p ARP --arp-mac-dst de:ad:be:ef:00:00/ff:ff:ff:ff:00:00;=;OK -p ARP --arp-gratuitous;=;OK diff --git a/extensions/libebt_dnat.txlate b/extensions/libebt_dnat.txlate index 2652dd55..531a22aa 100644 --- a/extensions/libebt_dnat.txlate +++ b/extensions/libebt_dnat.txlate @@ -1,8 +1,8 @@ -ebtables-translate -t nat -A PREROUTING -i someport --to-dst de:ad:00:be:ee:ff -nft add rule bridge nat PREROUTING iifname "someport" ether daddr set de:ad:0:be:ee:ff accept counter +ebtables-translate -t nat -A PREROUTING -i someport -j dnat --to-dst de:ad:00:be:ee:ff +nft 'add rule bridge nat PREROUTING iifname "someport" counter ether daddr set de:ad:0:be:ee:ff accept' -ebtables-translate -t nat -A PREROUTING -i someport --to-dst de:ad:00:be:ee:ff --dnat-target ACCEPT -nft add rule bridge nat PREROUTING iifname "someport" ether daddr set de:ad:0:be:ee:ff accept counter +ebtables-translate -t nat -A PREROUTING -i someport -j dnat --to-dst de:ad:00:be:ee:ff --dnat-target ACCEPT +nft 'add rule bridge nat PREROUTING iifname "someport" counter ether daddr set de:ad:0:be:ee:ff accept' -ebtables-translate -t nat -A PREROUTING -i someport --to-dst de:ad:00:be:ee:ff --dnat-target CONTINUE -nft add rule bridge nat PREROUTING iifname "someport" ether daddr set de:ad:0:be:ee:ff continue counter +ebtables-translate -t nat -A PREROUTING -i someport -j dnat --to-dst de:ad:00:be:ee:ff --dnat-target CONTINUE +nft 'add rule bridge nat PREROUTING iifname "someport" counter ether daddr set de:ad:0:be:ee:ff continue' diff --git a/extensions/libebt_ip.c b/extensions/libebt_ip.c index 51649ffb..fd87dae7 100644 --- a/extensions/libebt_ip.c +++ b/extensions/libebt_ip.c @@ -20,40 +20,10 @@ #include <netdb.h> #include <inttypes.h> #include <xtables.h> +#include <linux/netfilter_bridge/ebt_ip.h> #include "libxt_icmp.h" -#define EBT_IP_SOURCE 0x01 -#define EBT_IP_DEST 0x02 -#define EBT_IP_TOS 0x04 -#define EBT_IP_PROTO 0x08 -#define EBT_IP_SPORT 0x10 -#define EBT_IP_DPORT 0x20 -#define EBT_IP_ICMP 0x40 -#define EBT_IP_IGMP 0x80 -#define EBT_IP_MASK (EBT_IP_SOURCE | EBT_IP_DEST | EBT_IP_TOS | EBT_IP_PROTO |\ - EBT_IP_SPORT | EBT_IP_DPORT | EBT_IP_ICMP | EBT_IP_IGMP) - -struct ebt_ip_info { - __be32 saddr; - __be32 daddr; - __be32 smsk; - __be32 dmsk; - __u8 tos; - __u8 protocol; - __u8 bitmask; - __u8 invflags; - union { - __u16 sport[2]; - __u8 icmp_type[2]; - __u8 igmp_type[2]; - }; - union { - __u16 dport[2]; - __u8 icmp_code[2]; - }; -}; - #define IP_SOURCE '1' #define IP_DEST '2' #define IP_EBT_TOS '3' /* include/bits/in.h seems to already define IP_TOS */ @@ -80,68 +50,6 @@ static const struct option brip_opts[] = { XT_GETOPT_TABLEEND, }; -static const struct xt_icmp_names icmp_codes[] = { - { "echo-reply", 0, 0, 0xFF }, - /* Alias */ { "pong", 0, 0, 0xFF }, - - { "destination-unreachable", 3, 0, 0xFF }, - { "network-unreachable", 3, 0, 0 }, - { "host-unreachable", 3, 1, 1 }, - { "protocol-unreachable", 3, 2, 2 }, - { "port-unreachable", 3, 3, 3 }, - { "fragmentation-needed", 3, 4, 4 }, - { "source-route-failed", 3, 5, 5 }, - { "network-unknown", 3, 6, 6 }, - { "host-unknown", 3, 7, 7 }, - { "network-prohibited", 3, 9, 9 }, - { "host-prohibited", 3, 10, 10 }, - { "TOS-network-unreachable", 3, 11, 11 }, - { "TOS-host-unreachable", 3, 12, 12 }, - { "communication-prohibited", 3, 13, 13 }, - { "host-precedence-violation", 3, 14, 14 }, - { "precedence-cutoff", 3, 15, 15 }, - - { "source-quench", 4, 0, 0xFF }, - - { "redirect", 5, 0, 0xFF }, - { "network-redirect", 5, 0, 0 }, - { "host-redirect", 5, 1, 1 }, - { "TOS-network-redirect", 5, 2, 2 }, - { "TOS-host-redirect", 5, 3, 3 }, - - { "echo-request", 8, 0, 0xFF }, - /* Alias */ { "ping", 8, 0, 0xFF }, - - { "router-advertisement", 9, 0, 0xFF }, - - { "router-solicitation", 10, 0, 0xFF }, - - { "time-exceeded", 11, 0, 0xFF }, - /* Alias */ { "ttl-exceeded", 11, 0, 0xFF }, - { "ttl-zero-during-transit", 11, 0, 0 }, - { "ttl-zero-during-reassembly", 11, 1, 1 }, - - { "parameter-problem", 12, 0, 0xFF }, - { "ip-header-bad", 12, 0, 0 }, - { "required-option-missing", 12, 1, 1 }, - - { "timestamp-request", 13, 0, 0xFF }, - - { "timestamp-reply", 14, 0, 0xFF }, - - { "address-mask-request", 17, 0, 0xFF }, - - { "address-mask-reply", 18, 0, 0xFF } -}; - -static const struct xt_icmp_names igmp_types[] = { - { "membership-query", 0x11 }, - { "membership-report-v1", 0x12 }, - { "membership-report-v2", 0x16 }, - { "leave-group", 0x17 }, - { "membership-report-v3", 0x22 }, -}; - static void brip_print_help(void) { printf( @@ -194,156 +102,6 @@ parse_port_range(const char *protocol, const char *portstring, uint16_t *ports) } /* 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 char *parse_range(const char *str, unsigned int res[]) -{ - char *next; - - if (!xtables_strtoui(str, &next, &res[0], 0, 255)) - return NULL; - - res[1] = res[0]; - if (*next == ':') { - str = next + 1; - if (!xtables_strtoui(str, &next, &res[1], 0, 255)) - return NULL; - } - - return next; -} - -static int ebt_parse_icmp(const struct xt_icmp_names *codes, size_t n_codes, - const char *icmptype, uint8_t type[], uint8_t code[]) -{ - unsigned int match = n_codes; - unsigned int i, number[2]; - - for (i = 0; i < n_codes; i++) { - if (strncasecmp(codes[i].name, icmptype, strlen(icmptype))) - continue; - if (match != n_codes) - xtables_error(PARAMETER_PROBLEM, "Ambiguous ICMP type `%s':" - " `%s' or `%s'?", - icmptype, codes[match].name, - codes[i].name); - match = i; - } - - if (match < n_codes) { - type[0] = type[1] = codes[match].type; - if (code) { - code[0] = codes[match].code_min; - code[1] = codes[match].code_max; - } - } else { - char *next = parse_range(icmptype, number); - if (!next) { - xtables_error(PARAMETER_PROBLEM, "Unknown ICMP type `%s'", - icmptype); - return -1; - } - - type[0] = (uint8_t) number[0]; - type[1] = (uint8_t) number[1]; - switch (*next) { - case 0: - if (code) { - code[0] = 0; - code[1] = 255; - } - return 0; - case '/': - if (code) { - next = parse_range(next+1, number); - code[0] = (uint8_t) number[0]; - code[1] = (uint8_t) number[1]; - if (next == NULL) - return -1; - if (next && *next == 0) - return 0; - } - /* fallthrough */ - default: - xtables_error(PARAMETER_PROBLEM, "unknown character %c", *next); - return -1; - } - } - return 0; -} - static void print_icmp_code(uint8_t *code) { if (!code) @@ -385,18 +143,26 @@ 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; + struct in_addr *ipaddr, ipmask; + unsigned int ipnr; switch (c) { case IP_SOURCE: if (invert) info->invflags |= EBT_IP_SOURCE; - ebt_parse_ip_address(optarg, &info->saddr, &info->smsk); + xtables_ipparse_any(optarg, &ipaddr, &ipmask, &ipnr); + info->saddr = ipaddr->s_addr; + info->smsk = ipmask.s_addr; + free(ipaddr); 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); + xtables_ipparse_any(optarg, &ipaddr, &ipmask, &ipnr); + info->daddr = ipaddr->s_addr; + info->dmsk = ipmask.s_addr; + free(ipaddr); info->bitmask |= EBT_IP_DEST; break; case IP_SPORT: @@ -414,15 +180,13 @@ brip_parse(int c, char **argv, int invert, unsigned int *flags, case IP_EBT_ICMP: if (invert) info->invflags |= EBT_IP_ICMP; - ebt_parse_icmp(icmp_codes, ARRAY_SIZE(icmp_codes), optarg, - info->icmp_type, info->icmp_code); + ebt_parse_icmp(optarg, info->icmp_type, info->icmp_code); info->bitmask |= EBT_IP_ICMP; break; case IP_EBT_IGMP: if (invert) info->invflags |= EBT_IP_IGMP; - ebt_parse_icmp(igmp_types, ARRAY_SIZE(igmp_types), optarg, - info->igmp_type, NULL); + ebt_parse_igmp(optarg, info->igmp_type); info->bitmask |= EBT_IP_IGMP; break; case IP_EBT_TOS: { diff --git a/extensions/libebt_ip.txlate b/extensions/libebt_ip.txlate index b5882c34..75c1db24 100644 --- a/extensions/libebt_ip.txlate +++ b/extensions/libebt_ip.txlate @@ -1,26 +1,26 @@ ebtables-translate -A FORWARD -p ip --ip-src ! 192.168.0.0/24 -j ACCEPT -nft add rule bridge filter FORWARD ip saddr != 192.168.0.0/24 counter accept +nft 'add rule bridge filter FORWARD ip saddr != 192.168.0.0/24 counter accept' ebtables-translate -I FORWARD -p ip --ip-dst 10.0.0.1 -nft insert rule bridge filter FORWARD ip daddr 10.0.0.1 counter +nft 'insert rule bridge filter FORWARD ip daddr 10.0.0.1 counter' ebtables-translate -I OUTPUT 3 -p ip -o eth0 --ip-tos 0xff -nft insert rule bridge filter OUTPUT oifname "eth0" ip dscp 0x3f counter +nft 'insert rule bridge filter OUTPUT oifname "eth0" ip dscp 0x3f counter' ebtables-translate -A FORWARD -p ip --ip-proto tcp --ip-dport 22 -nft add rule bridge filter FORWARD tcp dport 22 counter +nft 'add rule bridge filter FORWARD tcp dport 22 counter' ebtables-translate -A FORWARD -p ip --ip-proto udp --ip-sport 1024:65535 -nft add rule bridge filter FORWARD udp sport 1024-65535 counter +nft 'add rule bridge filter FORWARD udp sport 1024-65535 counter' ebtables-translate -A FORWARD -p ip --ip-proto 253 -nft add rule bridge filter FORWARD ip protocol 253 counter +nft 'add rule bridge filter FORWARD ip protocol 253 counter' ebtables-translate -A FORWARD -p ip --ip-protocol icmp --ip-icmp-type "echo-request" -nft add rule bridge filter FORWARD icmp type 8 counter +nft 'add rule bridge filter FORWARD icmp type 8 counter' ebtables-translate -A FORWARD -p ip --ip-proto icmp --ip-icmp-type 1/1 -nft add rule bridge filter FORWARD icmp type 1 icmp code 1 counter +nft 'add rule bridge filter FORWARD icmp type 1 icmp code 1 counter' ebtables-translate -A FORWARD -p ip --ip-protocol icmp --ip-icmp-type ! 1:10 -nft add rule bridge filter FORWARD icmp type != 1-10 counter +nft 'add rule bridge filter FORWARD icmp type != 1-10 counter' diff --git a/extensions/libebt_ip6.c b/extensions/libebt_ip6.c index a686a285..18bb2720 100644 --- a/extensions/libebt_ip6.c +++ b/extensions/libebt_ip6.c @@ -49,44 +49,6 @@ static const struct option brip6_opts[] = { XT_GETOPT_TABLEEND, }; -static const struct xt_icmp_names icmpv6_codes[] = { - { "destination-unreachable", 1, 0, 0xFF }, - { "no-route", 1, 0, 0 }, - { "communication-prohibited", 1, 1, 1 }, - { "address-unreachable", 1, 3, 3 }, - { "port-unreachable", 1, 4, 4 }, - - { "packet-too-big", 2, 0, 0xFF }, - - { "time-exceeded", 3, 0, 0xFF }, - /* Alias */ { "ttl-exceeded", 3, 0, 0xFF }, - { "ttl-zero-during-transit", 3, 0, 0 }, - { "ttl-zero-during-reassembly", 3, 1, 1 }, - - { "parameter-problem", 4, 0, 0xFF }, - { "bad-header", 4, 0, 0 }, - { "unknown-header-type", 4, 1, 1 }, - { "unknown-option", 4, 2, 2 }, - - { "echo-request", 128, 0, 0xFF }, - /* Alias */ { "ping", 128, 0, 0xFF }, - - { "echo-reply", 129, 0, 0xFF }, - /* Alias */ { "pong", 129, 0, 0xFF }, - - { "router-solicitation", 133, 0, 0xFF }, - - { "router-advertisement", 134, 0, 0xFF }, - - { "neighbour-solicitation", 135, 0, 0xFF }, - /* Alias */ { "neighbor-solicitation", 135, 0, 0xFF }, - - { "neighbour-advertisement", 136, 0, 0xFF }, - /* Alias */ { "neighbor-advertisement", 136, 0, 0xFF }, - - { "redirect", 137, 0, 0xFF }, -}; - static void parse_port_range(const char *protocol, const char *portstring, uint16_t *ports) { @@ -110,76 +72,6 @@ parse_port_range(const char *protocol, const char *portstring, uint16_t *ports) free(buffer); } -static char *parse_range(const char *str, unsigned int res[]) -{ - char *next; - - if (!xtables_strtoui(str, &next, &res[0], 0, 255)) - return NULL; - - res[1] = res[0]; - if (*next == ':') { - str = next + 1; - if (!xtables_strtoui(str, &next, &res[1], 0, 255)) - return NULL; - } - - return next; -} - -static int -parse_icmpv6(const char *icmpv6type, uint8_t type[], uint8_t code[]) -{ - static const unsigned int limit = ARRAY_SIZE(icmpv6_codes); - unsigned int match = limit; - unsigned int i, number[2]; - - for (i = 0; i < limit; i++) { - if (strncasecmp(icmpv6_codes[i].name, icmpv6type, strlen(icmpv6type))) - continue; - if (match != limit) - xtables_error(PARAMETER_PROBLEM, "Ambiguous ICMPv6 type `%s':" - " `%s' or `%s'?", - icmpv6type, icmpv6_codes[match].name, - icmpv6_codes[i].name); - match = i; - } - - if (match < limit) { - type[0] = type[1] = icmpv6_codes[match].type; - code[0] = icmpv6_codes[match].code_min; - code[1] = icmpv6_codes[match].code_max; - } else { - char *next = parse_range(icmpv6type, number); - if (!next) { - xtables_error(PARAMETER_PROBLEM, "Unknown ICMPv6 type `%s'", - icmpv6type); - return -1; - } - type[0] = (uint8_t) number[0]; - type[1] = (uint8_t) number[1]; - switch (*next) { - case 0: - code[0] = 0; - code[1] = 255; - return 0; - case '/': - next = parse_range(next+1, number); - code[0] = (uint8_t) number[0]; - code[1] = (uint8_t) number[1]; - if (next == NULL) - return -1; - if (next && *next == 0) - return 0; - /* fallthrough */ - default: - xtables_error(PARAMETER_PROBLEM, "unknown character %c", *next); - return -1; - } - } - return 0; -} - static void print_port_range(uint16_t *ports) { if (ports[0] == ports[1]) @@ -304,8 +196,7 @@ brip6_parse(int c, char **argv, int invert, unsigned int *flags, case IP_ICMP6: if (invert) info->invflags |= EBT_IP6_ICMP6; - if (parse_icmpv6(optarg, info->icmpv6_type, info->icmpv6_code)) - return 0; + ebt_parse_icmpv6(optarg, info->icmpv6_type, info->icmpv6_code); info->bitmask |= EBT_IP6_ICMP6; break; case IP_TCLASS: diff --git a/extensions/libebt_ip6.txlate b/extensions/libebt_ip6.txlate index 0271734c..0debbe12 100644 --- a/extensions/libebt_ip6.txlate +++ b/extensions/libebt_ip6.txlate @@ -1,29 +1,29 @@ ebtables-translate -A FORWARD -p ip6 --ip6-src ! dead::beef/64 -j ACCEPT -nft add rule bridge filter FORWARD ip6 saddr != dead::/64 counter accept +nft 'add rule bridge filter FORWARD ip6 saddr != dead::/64 counter accept' ebtables-translate -A FORWARD -p ip6 ! --ip6-dst dead:beef::/64 -j ACCEPT -nft add rule bridge filter FORWARD ip6 daddr != dead:beef::/64 counter accept +nft 'add rule bridge filter FORWARD ip6 daddr != dead:beef::/64 counter accept' ebtables-translate -I FORWARD -p ip6 --ip6-dst f00:ba:: -nft insert rule bridge filter FORWARD ip6 daddr f00:ba:: counter +nft 'insert rule bridge filter FORWARD ip6 daddr f00:ba:: counter' ebtables-translate -I OUTPUT -o eth0 -p ip6 --ip6-tclass 0xff -nft insert rule bridge filter OUTPUT oifname "eth0" ip6 dscp 0x3f counter +nft 'insert rule bridge filter OUTPUT oifname "eth0" ip6 dscp 0x3f counter' ebtables-translate -A FORWARD -p ip6 --ip6-proto tcp --ip6-dport 22 -nft add rule bridge filter FORWARD ether type ip6 tcp dport 22 counter +nft 'add rule bridge filter FORWARD ether type ip6 tcp dport 22 counter' ebtables-translate -A FORWARD -p ip6 --ip6-proto udp --ip6-sport 1024:65535 -nft add rule bridge filter FORWARD ether type ip6 udp sport 1024-65535 counter +nft 'add rule bridge filter FORWARD ether type ip6 udp sport 1024-65535 counter' ebtables-translate -A FORWARD -p ip6 --ip6-proto 253 -nft add rule bridge filter FORWARD ether type ip6 meta l4proto 253 counter +nft 'add rule bridge filter FORWARD ether type ip6 meta l4proto 253 counter' ebtables-translate -A FORWARD -p ip6 --ip6-protocol icmpv6 --ip6-icmp-type "echo-request" -nft add rule bridge filter FORWARD icmpv6 type 128 counter +nft 'add rule bridge filter FORWARD icmpv6 type 128 counter' ebtables-translate -A FORWARD -p ip6 --ip6-protocol icmpv6 --ip6-icmp-type 1/1 -nft add rule bridge filter FORWARD icmpv6 type 1 icmpv6 code 1 counter +nft 'add rule bridge filter FORWARD icmpv6 type 1 icmpv6 code 1 counter' ebtables-translate -A FORWARD -p ip6 --ip6-protocol icmpv6 --ip6-icmp-type ! 1:10 -nft add rule bridge filter FORWARD icmpv6 type != 1-10 counter +nft 'add rule bridge filter FORWARD icmpv6 type != 1-10 counter' diff --git a/extensions/libebt_limit.txlate b/extensions/libebt_limit.txlate index b6af15d5..adcce3ed 100644 --- a/extensions/libebt_limit.txlate +++ b/extensions/libebt_limit.txlate @@ -1,8 +1,8 @@ ebtables-translate -A INPUT --limit 3/m --limit-burst 3 -nft add rule bridge filter INPUT limit rate 3/minute burst 3 packets counter +nft 'add rule bridge filter INPUT limit rate 3/minute burst 3 packets counter' ebtables-translate -A INPUT --limit 10/s --limit-burst 5 -nft add rule bridge filter INPUT limit rate 10/second burst 5 packets counter +nft 'add rule bridge filter INPUT limit rate 10/second burst 5 packets counter' ebtables-translate -A INPUT --limit 10/s --limit-burst 0 -nft add rule bridge filter INPUT limit rate 10/second counter +nft 'add rule bridge filter INPUT limit rate 10/second counter' diff --git a/extensions/libebt_log.c b/extensions/libebt_log.c index 8858cf0e..9f8d1589 100644 --- a/extensions/libebt_log.c +++ b/extensions/libebt_log.c @@ -161,9 +161,10 @@ static void brlog_print(const void *ip, const struct xt_entry_target *target, { 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); + printf("--log-level %s", eight_priority[loginfo->loglevel].c_name); + + if (loginfo->prefix[0]) + printf(" --log-prefix \"%s\"", loginfo->prefix); if (loginfo->bitmask & EBT_LOG_IP) printf(" --log-ip"); @@ -180,16 +181,14 @@ static int brlog_xlate(struct xt_xlate *xl, const struct ebt_log_info *loginfo = (const void *)params->target->data; xt_xlate_add(xl, "log"); - if (loginfo->prefix[0]) { - if (params->escape_quotes) - xt_xlate_add(xl, " prefix \\\"%s\\\"", loginfo->prefix); - else - xt_xlate_add(xl, " prefix \"%s\"", loginfo->prefix); - } + if (loginfo->prefix[0]) + xt_xlate_add(xl, " prefix \"%s\"", loginfo->prefix); if (loginfo->loglevel != LOG_DEFAULT_LEVEL) xt_xlate_add(xl, " level %s", eight_priority[loginfo->loglevel].c_name); + /* ebt_log always decodes MAC header, nft_log always decodes upper header - + * so set flags ether and ignore EBT_LOG_IP, EBT_LOG_ARP and EBT_LOG_IP6 */ xt_xlate_add(xl, " flags ether "); return 1; @@ -198,6 +197,7 @@ static int brlog_xlate(struct xt_xlate *xl, static struct xtables_target brlog_target = { .name = "log", .revision = 0, + .ext_flags = XTABLES_EXT_WATCHER, .version = XTABLES_VERSION, .family = NFPROTO_BRIDGE, .size = XT_ALIGN(sizeof(struct ebt_log_info)), diff --git a/extensions/libebt_log.t b/extensions/libebt_log.t index a0df6169..e6adbd3b 100644 --- a/extensions/libebt_log.t +++ b/extensions/libebt_log.t @@ -1,6 +1,6 @@ :INPUT,FORWARD,OUTPUT ---log;=;OK +--log;--log-level notice;OK --log-level crit;=;OK ---log-level 1;--log-level alert --log-prefix "";OK ---log-level emerg --log-ip --log-arp --log-ip6;--log-level emerg --log-prefix "" --log-ip --log-arp --log-ip6 -j CONTINUE;OK +--log-level 1;--log-level alert;OK +--log-level emerg --log-ip --log-arp --log-ip6;=;OK --log-level crit --log-ip --log-arp --log-ip6 --log-prefix foo;--log-level crit --log-prefix "foo" --log-ip --log-arp --log-ip6 -j CONTINUE;OK diff --git a/extensions/libebt_log.txlate b/extensions/libebt_log.txlate index 7ef8d5e1..9847e4c1 100644 --- a/extensions/libebt_log.txlate +++ b/extensions/libebt_log.txlate @@ -1,15 +1,15 @@ ebtables-translate -A INPUT --log -nft add rule bridge filter INPUT log level notice flags ether counter +nft 'add rule bridge filter INPUT log level notice flags ether counter' ebtables-translate -A INPUT --log-level 1 -nft add rule bridge filter INPUT log level alert flags ether counter +nft 'add rule bridge filter INPUT log level alert flags ether counter' ebtables-translate -A INPUT --log-level crit -nft add rule bridge filter INPUT log level crit flags ether counter +nft 'add rule bridge filter INPUT log level crit flags ether counter' ebtables-translate -A INPUT --log-level emerg --log-ip --log-arp --log-ip6 -nft add rule bridge filter INPUT log level emerg flags ether counter +nft 'add rule bridge filter INPUT log level emerg flags ether counter' ebtables-translate -A INPUT --log-level crit --log-ip --log-arp --log-ip6 --log-prefix foo -nft add rule bridge filter INPUT log prefix "foo" level crit flags ether counter +nft 'add rule bridge filter INPUT log prefix "foo" level crit flags ether counter' diff --git a/extensions/libebt_mark.c b/extensions/libebt_mark.c index 423c5c91..40e49618 100644 --- a/extensions/libebt_mark.c +++ b/extensions/libebt_mark.c @@ -201,7 +201,7 @@ static int brmark_xlate(struct xt_xlate *xl, return 0; } - tmp = info->target & EBT_VERDICT_BITS; + tmp = info->target | ~EBT_VERDICT_BITS; xt_xlate_add(xl, "0x%lx %s ", info->mark, brmark_verdict(tmp)); return 1; } diff --git a/extensions/libebt_mark.txlate b/extensions/libebt_mark.txlate new file mode 100644 index 00000000..4ace1a1f --- /dev/null +++ b/extensions/libebt_mark.txlate @@ -0,0 +1,11 @@ +ebtables-translate -A INPUT -j mark --mark-set 42 +nft 'add rule bridge filter INPUT counter meta mark set 0x2a accept' + +ebtables-translate -A INPUT -j mark --mark-or 42 --mark-target RETURN +nft 'add rule bridge filter INPUT counter meta mark set meta mark or 0x2a return' + +ebtables-translate -A INPUT -j mark --mark-and 42 --mark-target ACCEPT +nft 'add rule bridge filter INPUT counter meta mark set meta mark and 0x2a accept' + +ebtables-translate -A INPUT -j mark --mark-xor 42 --mark-target DROP +nft 'add rule bridge filter INPUT counter meta mark set meta mark xor 0x2a drop' diff --git a/extensions/libebt_mark.xlate b/extensions/libebt_mark.xlate deleted file mode 100644 index e0982a1e..00000000 --- a/extensions/libebt_mark.xlate +++ /dev/null @@ -1,11 +0,0 @@ -ebtables-translate -A INPUT --mark-set 42 -nft add rule bridge filter INPUT mark set 0x2a counter - -ebtables-translate -A INPUT --mark-or 42 --mark-target RETURN -nft add rule bridge filter INPUT mark set mark or 0x2a counter return - -ebtables-translate -A INPUT --mark-and 42 --mark-target ACCEPT -nft add rule bridge filter INPUT mark set mark and 0x2a counter accept - -ebtables-translate -A INPUT --mark-xor 42 --mark-target DROP -nft add rule bridge filter INPUT mark set mark xor 0x2a counter drop diff --git a/extensions/libebt_mark_m.txlate b/extensions/libebt_mark_m.txlate index 7b44425b..2981a564 100644 --- a/extensions/libebt_mark_m.txlate +++ b/extensions/libebt_mark_m.txlate @@ -1,14 +1,14 @@ ebtables-translate -A INPUT --mark 42 -nft add rule bridge filter INPUT meta mark 0x2a counter +nft 'add rule bridge filter INPUT meta mark 0x2a counter' ebtables-translate -A INPUT ! --mark 42 -nft add rule bridge filter INPUT meta mark != 0x2a counter +nft 'add rule bridge filter INPUT meta mark != 0x2a counter' ebtables-translate -A INPUT --mark ! 42 -nft add rule bridge filter INPUT meta mark != 0x2a counter +nft 'add rule bridge filter INPUT meta mark != 0x2a counter' ebtables-translate -A INPUT --mark ! 0x1/0xff -nft add rule bridge filter INPUT meta mark and 0xff != 0x1 counter +nft 'add rule bridge filter INPUT meta mark and 0xff != 0x1 counter' ebtables-translate -A INPUT --mark /0x02 -nft add rule bridge filter INPUT meta mark and 0x2 != 0 counter +nft 'add rule bridge filter INPUT meta mark and 0x2 != 0 counter' diff --git a/extensions/libebt_nflog.c b/extensions/libebt_nflog.c index 9801f358..762d6d5d 100644 --- a/extensions/libebt_nflog.c +++ b/extensions/libebt_nflog.c @@ -130,12 +130,8 @@ static int brnflog_xlate(struct xt_xlate *xl, const struct ebt_nflog_info *info = (void *)params->target->data; xt_xlate_add(xl, "log "); - if (info->prefix[0] != '\0') { - if (params->escape_quotes) - xt_xlate_add(xl, "prefix \\\"%s\\\" ", info->prefix); - else - xt_xlate_add(xl, "prefix \"%s\" ", info->prefix); - } + if (info->prefix[0] != '\0') + xt_xlate_add(xl, "prefix \"%s\" ", info->prefix); xt_xlate_add(xl, "group %u ", info->group); @@ -150,6 +146,7 @@ static int brnflog_xlate(struct xt_xlate *xl, static struct xtables_target brnflog_watcher = { .name = "nflog", .revision = 0, + .ext_flags = XTABLES_EXT_WATCHER, .version = XTABLES_VERSION, .family = NFPROTO_BRIDGE, .size = XT_ALIGN(sizeof(struct ebt_nflog_info)), diff --git a/extensions/libebt_nflog.t b/extensions/libebt_nflog.t index f867df30..e98d8f5f 100644 --- a/extensions/libebt_nflog.t +++ b/extensions/libebt_nflog.t @@ -1,5 +1,5 @@ :INPUT,FORWARD,OUTPUT ---nflog;=;OK +--nflog;--nflog-group 1;OK --nflog-group 42;=;OK --nflog-range 42;--nflog-group 1 --nflog-range 42 -j CONTINUE;OK --nflog-threshold 100 --nflog-prefix foo;--nflog-prefix "foo" --nflog-group 1 --nflog-threshold 100 -j CONTINUE;OK diff --git a/extensions/libebt_nflog.txlate b/extensions/libebt_nflog.txlate index bc3f5364..6f292fd2 100644 --- a/extensions/libebt_nflog.txlate +++ b/extensions/libebt_nflog.txlate @@ -1,11 +1,11 @@ ebtables-translate -A INPUT --nflog -nft add rule bridge filter INPUT log group 1 counter +nft 'add rule bridge filter INPUT log group 1 counter' ebtables-translate -A INPUT --nflog-group 42 -nft add rule bridge filter INPUT log group 42 counter +nft 'add rule bridge filter INPUT log group 42 counter' ebtables-translate -A INPUT --nflog-range 42 -nft add rule bridge filter INPUT log group 1 snaplen 42 counter +nft 'add rule bridge filter INPUT log group 1 snaplen 42 counter' ebtables-translate -A INPUT --nflog-threshold 100 --nflog-prefix foo -nft add rule bridge filter INPUT log prefix "foo" group 1 queue-threshold 100 counter +nft 'add rule bridge filter INPUT log prefix "foo" group 1 queue-threshold 100 counter' diff --git a/extensions/libebt_pkttype.txlate b/extensions/libebt_pkttype.txlate index 94d016d9..6a828a98 100644 --- a/extensions/libebt_pkttype.txlate +++ b/extensions/libebt_pkttype.txlate @@ -1,20 +1,20 @@ ebtables-translate -A INPUT --pkttype-type host -nft add rule bridge filter INPUT meta pkttype host counter +nft 'add rule bridge filter INPUT meta pkttype host counter' ebtables-translate -A INPUT ! --pkttype-type broadcast -nft add rule bridge filter INPUT meta pkttype != broadcast counter +nft 'add rule bridge filter INPUT meta pkttype != broadcast counter' ebtables-translate -A INPUT --pkttype-type ! multicast -nft add rule bridge filter INPUT meta pkttype != multicast counter +nft 'add rule bridge filter INPUT meta pkttype != multicast counter' ebtables-translate -A INPUT --pkttype-type otherhost -nft add rule bridge filter INPUT meta pkttype other counter +nft 'add rule bridge filter INPUT meta pkttype other counter' ebtables-translate -A INPUT --pkttype-type outgoing -nft add rule bridge filter INPUT meta pkttype 4 counter +nft 'add rule bridge filter INPUT meta pkttype 4 counter' ebtables-translate -A INPUT --pkttype-type loopback -nft add rule bridge filter INPUT meta pkttype 5 counter +nft 'add rule bridge filter INPUT meta pkttype 5 counter' ebtables-translate -A INPUT --pkttype-type fastroute -nft add rule bridge filter INPUT meta pkttype 6 counter +nft 'add rule bridge filter INPUT meta pkttype 6 counter' diff --git a/extensions/libebt_redirect.c b/extensions/libebt_redirect.c index 6e653997..4d4c7a02 100644 --- a/extensions/libebt_redirect.c +++ b/extensions/libebt_redirect.c @@ -86,7 +86,7 @@ static int brredir_xlate(struct xt_xlate *xl, xt_xlate_add(xl, "meta set pkttype host"); if (red->target != EBT_ACCEPT) xt_xlate_add(xl, " %s ", brredir_verdict(red->target)); - return 0; + return 1; } static struct xtables_target brredirect_target = { diff --git a/extensions/libebt_redirect.t b/extensions/libebt_redirect.t index 23858afa..58492b79 100644 --- a/extensions/libebt_redirect.t +++ b/extensions/libebt_redirect.t @@ -1,4 +1,4 @@ :PREROUTING *nat --j redirect;=;OK +-j redirect ;=;OK -j redirect --redirect-target RETURN;=;OK diff --git a/extensions/libebt_snat.txlate b/extensions/libebt_snat.txlate index 0d846024..37343d3a 100644 --- a/extensions/libebt_snat.txlate +++ b/extensions/libebt_snat.txlate @@ -1,5 +1,5 @@ -ebtables-translate -t nat -A POSTROUTING -s 0:0:0:0:0:0 -o someport+ --to-source de:ad:00:be:ee:ff -nft add rule bridge nat POSTROUTING oifname "someport*" ether saddr 00:00:00:00:00:00 ether saddr set de:ad:0:be:ee:ff accept counter +ebtables-translate -t nat -A POSTROUTING -s 0:0:0:0:0:0 -o someport+ -j snat --to-source de:ad:00:be:ee:ff +nft 'add rule bridge nat POSTROUTING oifname "someport*" ether saddr 00:00:00:00:00:00 counter ether saddr set de:ad:0:be:ee:ff accept' -ebtables-translate -t nat -A POSTROUTING -o someport --to-src de:ad:00:be:ee:ff --snat-target CONTINUE -nft add rule bridge nat POSTROUTING oifname "someport" ether saddr set de:ad:0:be:ee:ff continue counter +ebtables-translate -t nat -A POSTROUTING -o someport -j snat --to-src de:ad:00:be:ee:ff --snat-target CONTINUE +nft 'add rule bridge nat POSTROUTING oifname "someport" counter ether saddr set de:ad:0:be:ee:ff continue' diff --git a/extensions/libebt_standard.t b/extensions/libebt_standard.t index c6c31727..97cb3baa 100644 --- a/extensions/libebt_standard.t +++ b/extensions/libebt_standard.t @@ -12,12 +12,17 @@ :INPUT -i foobar;=;OK -o foobar;=;FAIL +--logical-in br0;=;OK +--logical-out br1;=;FAIL :FORWARD -i foobar;=;OK -o foobar;=;OK +--logical-in br0 --logical-out br1;=;OK :OUTPUT -i foobar;=;FAIL -o foobar;=;OK +--logical-in br0;=;FAIL +--logical-out br1;=;OK :PREROUTING *nat -i foobar;=;OK diff --git a/extensions/libebt_stp.c b/extensions/libebt_stp.c index 3e9e2447..41059baa 100644 --- a/extensions/libebt_stp.c +++ b/extensions/libebt_stp.c @@ -146,9 +146,9 @@ out: static void print_range(unsigned int l, unsigned int u) { if (l == u) - printf("%u ", l); + printf("%u", l); else - printf("%u:%u ", l, u); + printf("%u:%u", l, u); } static int diff --git a/extensions/libebt_stp.t b/extensions/libebt_stp.t index 0c6b77b9..17d6c1c0 100644 --- a/extensions/libebt_stp.t +++ b/extensions/libebt_stp.t @@ -1,7 +1,7 @@ :INPUT,FORWARD,OUTPUT --stp-type 1;=;OK --stp-flags 0x1;--stp-flags topology-change -j CONTINUE;OK ---stp-root-prio 1 -j ACCEPT;=;OK +--stp-root-prio 1 -j ACCEPT;=;OK --stp-root-addr 0d:ea:d0:0b:ee:f0;=;OK --stp-root-cost 1;=;OK --stp-sender-prio 1;=;OK diff --git a/extensions/libebt_vlan.t b/extensions/libebt_vlan.t index 81c79585..3ec05599 100644 --- a/extensions/libebt_vlan.t +++ b/extensions/libebt_vlan.t @@ -4,8 +4,8 @@ -p 802_1Q --vlan-prio 1;=;OK -p 802_1Q --vlan-prio ! 1;=;OK -p 802_1Q --vlan-encap ip;-p 802_1Q --vlan-encap 0800 -j CONTINUE;OK --p 802_1Q --vlan-encap 0800 ;=;OK --p 802_1Q --vlan-encap ! 0800 ;=;OK +-p 802_1Q --vlan-encap 0800;=;OK +-p 802_1Q --vlan-encap ! 0800;=;OK -p 802_1Q --vlan-encap IPv6 ! --vlan-id 1;-p 802_1Q --vlan-id ! 1 --vlan-encap 86DD -j CONTINUE;OK -p 802_1Q --vlan-id ! 1 --vlan-encap 86DD;=;OK --vlan-encap ip;=;FAIL diff --git a/extensions/libebt_vlan.txlate b/extensions/libebt_vlan.txlate index 2ab62d53..5d21e3eb 100644 --- a/extensions/libebt_vlan.txlate +++ b/extensions/libebt_vlan.txlate @@ -1,11 +1,11 @@ ebtables-translate -A INPUT -p 802_1Q --vlan-id 42 -nft add rule bridge filter INPUT vlan id 42 counter +nft 'add rule bridge filter INPUT vlan id 42 counter' ebtables-translate -A INPUT -p 802_1Q --vlan-prio ! 1 -nft add rule bridge filter INPUT vlan pcp != 1 counter +nft 'add rule bridge filter INPUT vlan pcp != 1 counter' ebtables-translate -A INPUT -p 802_1Q --vlan-encap ip -nft add rule bridge filter INPUT vlan type 0x0800 counter +nft 'add rule bridge filter INPUT vlan type 0x0800 counter' ebtables-translate -A INPUT -p 802_1Q --vlan-encap ipv6 ! --vlan-id 1 -nft add rule bridge filter INPUT vlan id != 1 vlan type 0x86dd counter +nft 'add rule bridge filter INPUT vlan id != 1 vlan type 0x86dd counter' diff --git a/extensions/libip6t_DNAT.c b/extensions/libip6t_DNAT.c deleted file mode 100644 index f1ad8143..00000000 --- a/extensions/libip6t_DNAT.c +++ /dev/null @@ -1,409 +0,0 @@ -/* - * Copyright (c) 2011 Patrick McHardy <kaber@trash.net> - * - * Based on Rusty Russell's IPv4 DNAT target. Development of IPv6 NAT - * funded by Astaro. - */ - -#include <stdio.h> -#include <netdb.h> -#include <string.h> -#include <stdlib.h> -#include <xtables.h> -#include <iptables.h> -#include <limits.h> /* INT_MAX in ip_tables.h */ -#include <linux/netfilter_ipv6/ip6_tables.h> -#include <linux/netfilter/nf_nat.h> - -enum { - O_TO_DEST = 0, - O_RANDOM, - O_PERSISTENT, - O_X_TO_DEST, - F_TO_DEST = 1 << O_TO_DEST, - F_RANDOM = 1 << O_RANDOM, - F_X_TO_DEST = 1 << O_X_TO_DEST, -}; - -static void DNAT_help(void) -{ - printf( -"DNAT target options:\n" -" --to-destination [<ipaddr>[-<ipaddr>]][:port[-port]]\n" -" Address to map destination to.\n" -"[--random] [--persistent]\n"); -} - -static void DNAT_help_v2(void) -{ - printf( -"DNAT target options:\n" -" --to-destination [<ipaddr>[-<ipaddr>]][:port[-port[/port]]]\n" -" Address to map destination to.\n" -"[--random] [--persistent]\n"); -} - -static const struct xt_option_entry DNAT_opts[] = { - {.name = "to-destination", .id = O_TO_DEST, .type = XTTYPE_STRING, - .flags = XTOPT_MAND | XTOPT_MULTI}, - {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE}, - {.name = "persistent", .id = O_PERSISTENT, .type = XTTYPE_NONE}, - XTOPT_TABLEEND, -}; - -/* Ranges expected in network order. */ -static void -parse_to(const char *orig_arg, int portok, struct nf_nat_range2 *range, int rev) -{ - char *arg, *start, *end = NULL, *colon = NULL, *dash, *error; - const struct in6_addr *ip; - - arg = xtables_strdup(orig_arg); - - start = strchr(arg, '['); - if (start == NULL) { - start = arg; - /* Lets assume one colon is port information. Otherwise its an IPv6 address */ - colon = strchr(arg, ':'); - if (colon && strchr(colon+1, ':')) - colon = NULL; - } - else { - start++; - end = strchr(start, ']'); - if (end == NULL) - xtables_error(PARAMETER_PROBLEM, - "Invalid address format"); - - *end = '\0'; - colon = strchr(end + 1, ':'); - } - - if (colon) { - int port; - - if (!portok) - xtables_error(PARAMETER_PROBLEM, - "Need TCP, UDP, SCTP or DCCP with port specification"); - - range->flags |= NF_NAT_RANGE_PROTO_SPECIFIED; - - port = atoi(colon+1); - if (port <= 0 || port > 65535) - xtables_error(PARAMETER_PROBLEM, - "Port `%s' not valid\n", colon+1); - - error = strchr(colon+1, ':'); - if (error) - xtables_error(PARAMETER_PROBLEM, - "Invalid port:port syntax - use dash\n"); - - dash = strchr(colon, '-'); - if (!dash) { - range->min_proto.tcp.port - = range->max_proto.tcp.port - = htons(port); - } else { - int maxport; - - maxport = atoi(dash + 1); - if (maxport <= 0 || maxport > 65535) - xtables_error(PARAMETER_PROBLEM, - "Port `%s' not valid\n", dash+1); - if (maxport < port) - /* People are stupid. */ - xtables_error(PARAMETER_PROBLEM, - "Port range `%s' funky\n", colon+1); - range->min_proto.tcp.port = htons(port); - range->max_proto.tcp.port = htons(maxport); - - if (rev >= 2) { - char *slash = strchr(dash, '/'); - if (slash) { - int baseport; - - baseport = atoi(slash + 1); - if (baseport <= 0 || baseport > 65535) - xtables_error(PARAMETER_PROBLEM, - "Port `%s' not valid\n", slash+1); - range->flags |= NF_NAT_RANGE_PROTO_OFFSET; - range->base_proto.tcp.port = htons(baseport); - } - } - } - /* Starts with colon or [] colon? No IP info...*/ - if (colon == arg || colon == arg+2) { - free(arg); - return; - } - *colon = '\0'; - } - - range->flags |= NF_NAT_RANGE_MAP_IPS; - dash = strchr(start, '-'); - if (colon && dash && dash > colon) - dash = NULL; - - if (dash) - *dash = '\0'; - - ip = xtables_numeric_to_ip6addr(start); - if (!ip) - xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n", - start); - range->min_addr.in6 = *ip; - if (dash) { - ip = xtables_numeric_to_ip6addr(dash + 1); - if (!ip) - xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n", - dash+1); - range->max_addr.in6 = *ip; - } else - range->max_addr = range->min_addr; - - free(arg); - return; -} - -static void _DNAT_parse(struct xt_option_call *cb, - struct nf_nat_range2 *range, int rev) -{ - const struct ip6t_entry *entry = cb->xt_entry; - int portok; - - if (entry->ipv6.proto == IPPROTO_TCP || - entry->ipv6.proto == IPPROTO_UDP || - entry->ipv6.proto == IPPROTO_SCTP || - entry->ipv6.proto == IPPROTO_DCCP || - entry->ipv6.proto == IPPROTO_ICMP) - portok = 1; - else - portok = 0; - - xtables_option_parse(cb); - switch (cb->entry->id) { - case O_TO_DEST: - if (cb->xflags & F_X_TO_DEST) { - xtables_error(PARAMETER_PROBLEM, - "DNAT: Multiple --to-destination not supported"); - } - parse_to(cb->arg, portok, range, rev); - cb->xflags |= F_X_TO_DEST; - break; - case O_PERSISTENT: - range->flags |= NF_NAT_RANGE_PERSISTENT; - break; - } -} - -static void DNAT_parse(struct xt_option_call *cb) -{ - struct nf_nat_range *range_v1 = (void *)cb->data; - struct nf_nat_range2 range = {}; - - memcpy(&range, range_v1, sizeof(*range_v1)); - _DNAT_parse(cb, &range, 1); - memcpy(range_v1, &range, sizeof(*range_v1)); -} - -static void DNAT_parse_v2(struct xt_option_call *cb) -{ - _DNAT_parse(cb, (struct nf_nat_range2 *)cb->data, 2); -} - -static void _DNAT_fcheck(struct xt_fcheck_call *cb, unsigned int *flags) -{ - static const unsigned int f = F_TO_DEST | F_RANDOM; - - if ((cb->xflags & f) == f) - *flags |= NF_NAT_RANGE_PROTO_RANDOM; -} - -static void DNAT_fcheck(struct xt_fcheck_call *cb) -{ - _DNAT_fcheck(cb, &((struct nf_nat_range *)cb->data)->flags); -} - -static void DNAT_fcheck_v2(struct xt_fcheck_call *cb) -{ - _DNAT_fcheck(cb, &((struct nf_nat_range2 *)cb->data)->flags); -} - -static void print_range(const struct nf_nat_range2 *range, int rev) -{ - if (range->flags & NF_NAT_RANGE_MAP_IPS) { - if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) - printf("["); - printf("%s", xtables_ip6addr_to_numeric(&range->min_addr.in6)); - if (memcmp(&range->min_addr, &range->max_addr, - sizeof(range->min_addr))) - printf("-%s", xtables_ip6addr_to_numeric(&range->max_addr.in6)); - if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) - printf("]"); - } - if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { - printf(":"); - printf("%hu", ntohs(range->min_proto.tcp.port)); - if (range->max_proto.tcp.port != range->min_proto.tcp.port) - printf("-%hu", ntohs(range->max_proto.tcp.port)); - if (rev >= 2 && (range->flags & NF_NAT_RANGE_PROTO_OFFSET)) - printf("/%hu", ntohs(range->base_proto.tcp.port)); - } -} - -static void _DNAT_print(const struct nf_nat_range2 *range, int rev) -{ - printf(" to:"); - print_range(range, rev); - if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) - printf(" random"); - if (range->flags & NF_NAT_RANGE_PERSISTENT) - printf(" persistent"); -} - -static void DNAT_print(const void *ip, const struct xt_entry_target *target, - int numeric) -{ - const struct nf_nat_range *range_v1 = (const void *)target->data; - struct nf_nat_range2 range = {}; - - memcpy(&range, range_v1, sizeof(*range_v1)); - _DNAT_print(&range, 1); -} - -static void DNAT_print_v2(const void *ip, const struct xt_entry_target *target, - int numeric) -{ - _DNAT_print((const struct nf_nat_range2 *)target->data, 2); -} - -static void _DNAT_save(const struct nf_nat_range2 *range, int rev) -{ - printf(" --to-destination "); - print_range(range, rev); - if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) - printf(" --random"); - if (range->flags & NF_NAT_RANGE_PERSISTENT) - printf(" --persistent"); -} - -static void DNAT_save(const void *ip, const struct xt_entry_target *target) -{ - const struct nf_nat_range *range_v1 = (const void *)target->data; - struct nf_nat_range2 range = {}; - - memcpy(&range, range_v1, sizeof(*range_v1)); - _DNAT_save(&range, 1); -} - -static void DNAT_save_v2(const void *ip, const struct xt_entry_target *target) -{ - _DNAT_save((const struct nf_nat_range2 *)target->data, 2); -} - -static void print_range_xlate(const struct nf_nat_range2 *range, - struct xt_xlate *xl, int rev) -{ - 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 nf_nat_range2 *range, int rev) -{ - bool sep_need = false; - const char *sep = " "; - - xt_xlate_add(xl, "dnat to "); - print_range_xlate(range, xl, rev); - 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 int DNAT_xlate(struct xt_xlate *xl, - const struct xt_xlate_tg_params *params) -{ - const struct nf_nat_range *range_v1 = (const void *)params->target->data; - struct nf_nat_range2 range = {}; - - memcpy(&range, range_v1, sizeof(*range_v1)); - _DNAT_xlate(xl, &range, 1); - - return 1; -} - -static int DNAT_xlate_v2(struct xt_xlate *xl, - const struct xt_xlate_tg_params *params) -{ - _DNAT_xlate(xl, (const struct nf_nat_range2 *)params->target->data, 2); - - return 1; -} - -static struct xtables_target dnat_tg_reg[] = { - { - .name = "DNAT", - .version = XTABLES_VERSION, - .family = NFPROTO_IPV6, - .revision = 1, - .size = XT_ALIGN(sizeof(struct nf_nat_range)), - .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)), - .help = DNAT_help, - .print = DNAT_print, - .save = DNAT_save, - .x6_parse = DNAT_parse, - .x6_fcheck = DNAT_fcheck, - .x6_options = DNAT_opts, - .xlate = DNAT_xlate, - }, - { - .name = "DNAT", - .version = XTABLES_VERSION, - .family = NFPROTO_IPV6, - .revision = 2, - .size = XT_ALIGN(sizeof(struct nf_nat_range2)), - .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range2)), - .help = DNAT_help_v2, - .print = DNAT_print_v2, - .save = DNAT_save_v2, - .x6_parse = DNAT_parse_v2, - .x6_fcheck = DNAT_fcheck_v2, - .x6_options = DNAT_opts, - .xlate = DNAT_xlate_v2, - }, -}; - -void _init(void) -{ - xtables_register_targets(dnat_tg_reg, ARRAY_SIZE(dnat_tg_reg)); -} diff --git a/extensions/libip6t_DNAT.t b/extensions/libip6t_DNAT.t index ec7d61f4..e53dfa16 100644 --- a/extensions/libip6t_DNAT.t +++ b/extensions/libip6t_DNAT.t @@ -13,4 +13,8 @@ -p tcp -j DNAT --to-destination [dead::beef-dead::fee7]:1000-2000/65535;=;OK -p tcp -j DNAT --to-destination [dead::beef-dead::fee7]:1000-2000/0;;FAIL -p tcp -j DNAT --to-destination [dead::beef-dead::fee7]:1000-2000/65536;;FAIL +-p tcp -j DNAT --to-destination [dead::beef]:ssh;-p tcp -j DNAT --to-destination [dead::beef]:22;OK +-p tcp -j DNAT --to-destination [dead::beef]:ftp-data;-p tcp -j DNAT --to-destination [dead::beef]:20;OK +-p tcp -j DNAT --to-destination [dead::beef]:echo-ssh;;FAIL +-p tcp -j DNAT --to-destination [dead::beef]:10-20/ftp;-p tcp -j DNAT --to-destination [dead::beef]:10-20/21;OK -j DNAT;;FAIL diff --git a/extensions/libip6t_DNAT.txlate b/extensions/libip6t_DNAT.txlate deleted file mode 100644 index 03c4caf7..00000000 --- a/extensions/libip6t_DNAT.txlate +++ /dev/null @@ -1,11 +0,0 @@ -ip6tables-translate -t nat -A prerouting -i eth1 -p tcp --dport 8080 -j DNAT --to-destination [fec0::1234]:80 -nft add rule ip6 nat prerouting iifname "eth1" tcp dport 8080 counter dnat to [fec0::1234]:80 - -ip6tables-translate -t nat -A prerouting -p tcp -j DNAT --to-destination [fec0::1234]:1-20 -nft add rule ip6 nat prerouting meta l4proto tcp counter dnat to [fec0::1234]:1-20 - -ip6tables-translate -t nat -A prerouting -p tcp -j DNAT --to-destination [fec0::1234]:80 --persistent -nft add rule ip6 nat prerouting meta l4proto tcp counter dnat to [fec0::1234]:80 persistent - -ip6tables-translate -t nat -A prerouting -p tcp -j DNAT --to-destination [fec0::1234]:80 --random --persistent -nft add rule ip6 nat prerouting meta l4proto tcp counter dnat to [fec0::1234]:80 random,persistent diff --git a/extensions/libip6t_LOG.c b/extensions/libip6t_LOG.c deleted file mode 100644 index 40adc69d..00000000 --- a/extensions/libip6t_LOG.c +++ /dev/null @@ -1,250 +0,0 @@ -#include <stdio.h> -#include <string.h> -#include <syslog.h> -#include <xtables.h> -#include <linux/netfilter_ipv6/ip6t_LOG.h> - -#ifndef IP6T_LOG_UID /* Old kernel */ -#define IP6T_LOG_UID 0x08 -#undef IP6T_LOG_MASK -#define IP6T_LOG_MASK 0x0f -#endif - -#define LOG_DEFAULT_LEVEL LOG_WARNING - -enum { - O_LOG_LEVEL = 0, - O_LOG_PREFIX, - O_LOG_TCPSEQ, - O_LOG_TCPOPTS, - O_LOG_IPOPTS, - O_LOG_UID, - O_LOG_MAC, -}; - -static void LOG_help(void) -{ - printf( -"LOG target options:\n" -" --log-level level Level of logging (numeric or see syslog.conf)\n" -" --log-prefix prefix Prefix log messages with this prefix.\n" -" --log-tcp-sequence Log TCP sequence numbers.\n" -" --log-tcp-options Log TCP options.\n" -" --log-ip-options Log IP options.\n" -" --log-uid Log UID owning the local socket.\n" -" --log-macdecode Decode MAC addresses and protocol.\n"); -} - -#define s struct ip6t_log_info -static const struct xt_option_entry LOG_opts[] = { - {.name = "log-level", .id = O_LOG_LEVEL, .type = XTTYPE_SYSLOGLEVEL, - .flags = XTOPT_PUT, XTOPT_POINTER(s, level)}, - {.name = "log-prefix", .id = O_LOG_PREFIX, .type = XTTYPE_STRING, - .flags = XTOPT_PUT, XTOPT_POINTER(s, prefix), .min = 1}, - {.name = "log-tcp-sequence", .id = O_LOG_TCPSEQ, .type = XTTYPE_NONE}, - {.name = "log-tcp-options", .id = O_LOG_TCPOPTS, .type = XTTYPE_NONE}, - {.name = "log-ip-options", .id = O_LOG_IPOPTS, .type = XTTYPE_NONE}, - {.name = "log-uid", .id = O_LOG_UID, .type = XTTYPE_NONE}, - {.name = "log-macdecode", .id = O_LOG_MAC, .type = XTTYPE_NONE}, - XTOPT_TABLEEND, -}; -#undef s - -static void LOG_init(struct xt_entry_target *t) -{ - struct ip6t_log_info *loginfo = (struct ip6t_log_info *)t->data; - - loginfo->level = LOG_DEFAULT_LEVEL; - -} - -struct ip6t_log_names { - const char *name; - unsigned int level; -}; - -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 }, - { .name = "debug", .level = LOG_DEBUG }, - { .name = "emerg", .level = LOG_EMERG }, - { .name = "error", .level = LOG_ERR }, /* DEPRECATED */ - { .name = "info", .level = LOG_INFO }, - { .name = "notice", .level = LOG_NOTICE }, - { .name = "panic", .level = LOG_EMERG }, /* DEPRECATED */ - { .name = "warning", .level = LOG_WARNING } -}; - -static void LOG_parse(struct xt_option_call *cb) -{ - struct ip6t_log_info *info = cb->data; - - xtables_option_parse(cb); - switch (cb->entry->id) { - case O_LOG_PREFIX: - if (strchr(cb->arg, '\n') != NULL) - xtables_error(PARAMETER_PROBLEM, - "Newlines not allowed in --log-prefix"); - break; - case O_LOG_TCPSEQ: - info->logflags |= IP6T_LOG_TCPSEQ; - break; - case O_LOG_TCPOPTS: - info->logflags |= IP6T_LOG_TCPOPT; - break; - case O_LOG_IPOPTS: - info->logflags |= IP6T_LOG_IPOPT; - break; - case O_LOG_UID: - info->logflags |= IP6T_LOG_UID; - break; - case O_LOG_MAC: - info->logflags |= IP6T_LOG_MACDECODE; - break; - } -} - -static void LOG_print(const void *ip, const struct xt_entry_target *target, - int numeric) -{ - const struct ip6t_log_info *loginfo - = (const struct ip6t_log_info *)target->data; - unsigned int i = 0; - - printf(" LOG"); - if (numeric) - printf(" flags %u level %u", - loginfo->logflags, loginfo->level); - else { - for (i = 0; i < ARRAY_SIZE(ip6t_log_names); ++i) - if (loginfo->level == ip6t_log_names[i].level) { - printf(" level %s", ip6t_log_names[i].name); - break; - } - if (i == ARRAY_SIZE(ip6t_log_names)) - printf(" UNKNOWN level %u", loginfo->level); - if (loginfo->logflags & IP6T_LOG_TCPSEQ) - printf(" tcp-sequence"); - if (loginfo->logflags & IP6T_LOG_TCPOPT) - printf(" tcp-options"); - if (loginfo->logflags & IP6T_LOG_IPOPT) - printf(" ip-options"); - if (loginfo->logflags & IP6T_LOG_UID) - printf(" uid"); - if (loginfo->logflags & IP6T_LOG_MACDECODE) - printf(" macdecode"); - if (loginfo->logflags & ~(IP6T_LOG_MASK)) - printf(" unknown-flags"); - } - - if (strcmp(loginfo->prefix, "") != 0) - printf(" prefix \"%s\"", loginfo->prefix); -} - -static void LOG_save(const void *ip, const struct xt_entry_target *target) -{ - const struct ip6t_log_info *loginfo - = (const struct ip6t_log_info *)target->data; - - if (strcmp(loginfo->prefix, "") != 0) { - printf(" --log-prefix"); - xtables_save_string(loginfo->prefix); - } - - if (loginfo->level != LOG_DEFAULT_LEVEL) - printf(" --log-level %d", loginfo->level); - - if (loginfo->logflags & IP6T_LOG_TCPSEQ) - printf(" --log-tcp-sequence"); - if (loginfo->logflags & IP6T_LOG_TCPOPT) - printf(" --log-tcp-options"); - if (loginfo->logflags & IP6T_LOG_IPOPT) - printf(" --log-ip-options"); - if (loginfo->logflags & IP6T_LOG_UID) - printf(" --log-uid"); - if (loginfo->logflags & IP6T_LOG_MACDECODE) - 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, - .family = NFPROTO_IPV6, - .size = XT_ALIGN(sizeof(struct ip6t_log_info)), - .userspacesize = XT_ALIGN(sizeof(struct ip6t_log_info)), - .help = LOG_help, - .init = LOG_init, - .print = LOG_print, - .save = LOG_save, - .x6_parse = LOG_parse, - .x6_options = LOG_opts, - .xlate = LOG_xlate, -}; - -void _init(void) -{ - xtables_register_target(&log_tg6_reg); -} diff --git a/extensions/libip6t_LOG.txlate b/extensions/libip6t_LOG.txlate index 2820a82c..29ffce72 100644 --- a/extensions/libip6t_LOG.txlate +++ b/extensions/libip6t_LOG.txlate @@ -1,8 +1,8 @@ iptables-translate -I INPUT -j LOG -nft insert rule ip filter INPUT counter log +nft 'insert rule ip filter INPUT counter log' ip6tables-translate -A FORWARD -p tcp -j LOG --log-level debug -nft add rule ip6 filter FORWARD meta l4proto tcp counter log level debug +nft 'add rule ip6 filter FORWARD meta l4proto tcp counter log level debug' ip6tables-translate -A FORWARD -p tcp -j LOG --log-prefix "Checking log" -nft add rule ip6 filter FORWARD meta l4proto tcp counter log prefix \"Checking log\" +nft 'add rule ip6 filter FORWARD meta l4proto tcp counter log prefix "Checking log"' diff --git a/extensions/libip6t_MASQUERADE.c b/extensions/libip6t_MASQUERADE.c deleted file mode 100644 index f28f071b..00000000 --- a/extensions/libip6t_MASQUERADE.c +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright (c) 2011 Patrick McHardy <kaber@trash.net> - * - * Based on Rusty Russell's IPv4 MASQUERADE target. Development of IPv6 NAT - * funded by Astaro. - */ - -#include <stdio.h> -#include <netdb.h> -#include <string.h> -#include <stdlib.h> -#include <getopt.h> -#include <xtables.h> -#include <limits.h> /* INT_MAX in ip_tables.h */ -#include <linux/netfilter_ipv6/ip6_tables.h> -#include <linux/netfilter/nf_nat.h> - -enum { - O_TO_PORTS = 0, - O_RANDOM, - O_RANDOM_FULLY, -}; - -static void MASQUERADE_help(void) -{ - printf( -"MASQUERADE target options:\n" -" --to-ports <port>[-<port>]\n" -" Port (range) to map to.\n" -" --random\n" -" Randomize source port.\n" -" --random-fully\n" -" Fully randomize source port.\n"); -} - -static const struct xt_option_entry MASQUERADE_opts[] = { - {.name = "to-ports", .id = O_TO_PORTS, .type = XTTYPE_STRING}, - {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE}, - {.name = "random-fully", .id = O_RANDOM_FULLY, .type = XTTYPE_NONE}, - XTOPT_TABLEEND, -}; - -/* Parses ports */ -static void -parse_ports(const char *arg, struct nf_nat_range *r) -{ - char *end; - unsigned int port, maxport; - - r->flags |= NF_NAT_RANGE_PROTO_SPECIFIED; - - if (!xtables_strtoui(arg, &end, &port, 0, UINT16_MAX)) - xtables_param_act(XTF_BAD_VALUE, "MASQUERADE", "--to-ports", arg); - - switch (*end) { - case '\0': - r->min_proto.tcp.port - = r->max_proto.tcp.port - = htons(port); - return; - case '-': - if (!xtables_strtoui(end + 1, NULL, &maxport, 0, UINT16_MAX)) - break; - - if (maxport < port) - break; - - r->min_proto.tcp.port = htons(port); - r->max_proto.tcp.port = htons(maxport); - return; - default: - break; - } - xtables_param_act(XTF_BAD_VALUE, "MASQUERADE", "--to-ports", arg); -} - -static void MASQUERADE_parse(struct xt_option_call *cb) -{ - const struct ip6t_entry *entry = cb->xt_entry; - struct nf_nat_range *r = cb->data; - int portok; - - if (entry->ipv6.proto == IPPROTO_TCP || - entry->ipv6.proto == IPPROTO_UDP || - entry->ipv6.proto == IPPROTO_SCTP || - entry->ipv6.proto == IPPROTO_DCCP || - entry->ipv6.proto == IPPROTO_ICMP) - portok = 1; - else - portok = 0; - - xtables_option_parse(cb); - switch (cb->entry->id) { - case O_TO_PORTS: - if (!portok) - xtables_error(PARAMETER_PROBLEM, - "Need TCP, UDP, SCTP or DCCP with port specification"); - parse_ports(cb->arg, r); - break; - case O_RANDOM: - r->flags |= NF_NAT_RANGE_PROTO_RANDOM; - break; - case O_RANDOM_FULLY: - r->flags |= NF_NAT_RANGE_PROTO_RANDOM_FULLY; - break; - } -} - -static void -MASQUERADE_print(const void *ip, const struct xt_entry_target *target, - int numeric) -{ - const struct nf_nat_range *r = (const void *)target->data; - - if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { - printf(" masq ports: "); - printf("%hu", ntohs(r->min_proto.tcp.port)); - if (r->max_proto.tcp.port != r->min_proto.tcp.port) - printf("-%hu", ntohs(r->max_proto.tcp.port)); - } - - if (r->flags & NF_NAT_RANGE_PROTO_RANDOM) - printf(" random"); - - if (r->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) - printf(" random-fully"); -} - -static void -MASQUERADE_save(const void *ip, const struct xt_entry_target *target) -{ - const struct nf_nat_range *r = (const void *)target->data; - - if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { - printf(" --to-ports %hu", ntohs(r->min_proto.tcp.port)); - if (r->max_proto.tcp.port != r->min_proto.tcp.port) - printf("-%hu", ntohs(r->max_proto.tcp.port)); - } - - if (r->flags & NF_NAT_RANGE_PROTO_RANDOM) - printf(" --random"); - - if (r->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) - printf(" --random-fully"); -} - -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 "); - - xt_xlate_add(xl, " "); - if (r->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) - xt_xlate_add(xl, "fully-random "); - - return 1; -} - -static struct xtables_target masquerade_tg_reg = { - .name = "MASQUERADE", - .version = XTABLES_VERSION, - .family = NFPROTO_IPV6, - .size = XT_ALIGN(sizeof(struct nf_nat_range)), - .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)), - .help = MASQUERADE_help, - .x6_parse = MASQUERADE_parse, - .print = MASQUERADE_print, - .save = MASQUERADE_save, - .x6_options = MASQUERADE_opts, - .xlate = MASQUERADE_xlate, -}; - -void _init(void) -{ - xtables_register_target(&masquerade_tg_reg); -} diff --git a/extensions/libip6t_MASQUERADE.txlate b/extensions/libip6t_MASQUERADE.txlate index 6c289c2b..3f003477 100644 --- a/extensions/libip6t_MASQUERADE.txlate +++ b/extensions/libip6t_MASQUERADE.txlate @@ -1,8 +1,17 @@ ip6tables-translate -t nat -A POSTROUTING -j MASQUERADE -nft add rule ip6 nat POSTROUTING counter masquerade +nft 'add rule ip6 nat POSTROUTING counter masquerade' ip6tables-translate -t nat -A POSTROUTING -p tcp -j MASQUERADE --to-ports 10 -nft add rule ip6 nat POSTROUTING meta l4proto tcp counter masquerade to :10 +nft 'add rule ip6 nat POSTROUTING meta l4proto tcp counter masquerade to :10' ip6tables-translate -t nat -A POSTROUTING -p tcp -j MASQUERADE --to-ports 10-20 --random -nft add rule ip6 nat POSTROUTING meta l4proto tcp counter masquerade to :10-20 random +nft 'add rule ip6 nat POSTROUTING meta l4proto tcp counter masquerade to :10-20 random' + +ip6tables-translate -t nat -A POSTROUTING -p tcp -j MASQUERADE --random +nft 'add rule ip6 nat POSTROUTING meta l4proto tcp counter masquerade random' + +ip6tables-translate -t nat -A POSTROUTING -p tcp -j MASQUERADE --random-fully +nft 'add rule ip6 nat POSTROUTING meta l4proto tcp counter masquerade fully-random' + +ip6tables-translate -t nat -A POSTROUTING -p tcp -j MASQUERADE --random --random-fully +nft 'add rule ip6 nat POSTROUTING meta l4proto tcp counter masquerade random,fully-random' diff --git a/extensions/libip6t_NETMAP.t b/extensions/libip6t_NETMAP.t index 043562d2..79d47bf6 100644 --- a/extensions/libip6t_NETMAP.t +++ b/extensions/libip6t_NETMAP.t @@ -1,4 +1,4 @@ :PREROUTING,INPUT,OUTPUT,POSTROUTING *nat -j NETMAP --to dead::/64;=;OK --j NETMAP --to dead::beef;=;OK +-j NETMAP --to dead::beef;-j NETMAP --to dead::beef/128;OK diff --git a/extensions/libip6t_REDIRECT.c b/extensions/libip6t_REDIRECT.c deleted file mode 100644 index 8e04d2cd..00000000 --- a/extensions/libip6t_REDIRECT.c +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright (c) 2011 Patrick McHardy <kaber@trash.net> - * - * Based on Rusty Russell's IPv4 REDIRECT target. Development of IPv6 NAT - * funded by Astaro. - */ - -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <xtables.h> -#include <limits.h> /* INT_MAX in ip_tables.h */ -#include <linux/netfilter_ipv6/ip6_tables.h> -#include <linux/netfilter/nf_nat.h> - -enum { - O_TO_PORTS = 0, - O_RANDOM, - F_TO_PORTS = 1 << O_TO_PORTS, - F_RANDOM = 1 << O_RANDOM, -}; - -static void REDIRECT_help(void) -{ - printf( -"REDIRECT target options:\n" -" --to-ports <port>[-<port>]\n" -" Port (range) to map to.\n" -" [--random]\n"); -} - -static const struct xt_option_entry REDIRECT_opts[] = { - {.name = "to-ports", .id = O_TO_PORTS, .type = XTTYPE_STRING}, - {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE}, - XTOPT_TABLEEND, -}; - -/* Parses ports */ -static void -parse_ports(const char *arg, struct nf_nat_range *range) -{ - char *end = ""; - unsigned int port, maxport; - - range->flags |= NF_NAT_RANGE_PROTO_SPECIFIED; - - if (!xtables_strtoui(arg, &end, &port, 0, UINT16_MAX) && - (port = xtables_service_to_port(arg, NULL)) == (unsigned)-1) - xtables_param_act(XTF_BAD_VALUE, "REDIRECT", "--to-ports", arg); - - switch (*end) { - case '\0': - range->min_proto.tcp.port - = range->max_proto.tcp.port - = htons(port); - return; - case '-': - if (!xtables_strtoui(end + 1, NULL, &maxport, 0, UINT16_MAX) && - (maxport = xtables_service_to_port(end + 1, NULL)) == (unsigned)-1) - break; - - if (maxport < port) - break; - - range->min_proto.tcp.port = htons(port); - range->max_proto.tcp.port = htons(maxport); - return; - default: - break; - } - xtables_param_act(XTF_BAD_VALUE, "REDIRECT", "--to-ports", arg); -} - -static void REDIRECT_parse(struct xt_option_call *cb) -{ - const struct ip6t_entry *entry = cb->xt_entry; - struct nf_nat_range *range = (void *)(*cb->target)->data; - int portok; - - if (entry->ipv6.proto == IPPROTO_TCP - || entry->ipv6.proto == IPPROTO_UDP - || entry->ipv6.proto == IPPROTO_SCTP - || entry->ipv6.proto == IPPROTO_DCCP - || entry->ipv6.proto == IPPROTO_ICMP) - portok = 1; - else - portok = 0; - - xtables_option_parse(cb); - switch (cb->entry->id) { - case O_TO_PORTS: - if (!portok) - xtables_error(PARAMETER_PROBLEM, - "Need TCP, UDP, SCTP or DCCP with port specification"); - parse_ports(cb->arg, range); - if (cb->xflags & F_RANDOM) - range->flags |= NF_NAT_RANGE_PROTO_RANDOM; - break; - case O_RANDOM: - if (cb->xflags & F_TO_PORTS) - range->flags |= NF_NAT_RANGE_PROTO_RANDOM; - break; - } -} - -static void REDIRECT_print(const void *ip, const struct xt_entry_target *target, - int numeric) -{ - const struct nf_nat_range *range = (const void *)target->data; - - if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { - printf(" redir ports "); - printf("%hu", ntohs(range->min_proto.tcp.port)); - if (range->max_proto.tcp.port != range->min_proto.tcp.port) - printf("-%hu", ntohs(range->max_proto.tcp.port)); - if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) - printf(" random"); - } -} - -static void REDIRECT_save(const void *ip, const struct xt_entry_target *target) -{ - const struct nf_nat_range *range = (const void *)target->data; - - if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { - printf(" --to-ports "); - printf("%hu", ntohs(range->min_proto.tcp.port)); - if (range->max_proto.tcp.port != range->min_proto.tcp.port) - printf("-%hu", ntohs(range->max_proto.tcp.port)); - if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) - printf(" --random"); - } -} - -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, - .family = NFPROTO_IPV6, - .size = XT_ALIGN(sizeof(struct nf_nat_range)), - .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)), - .help = REDIRECT_help, - .x6_parse = REDIRECT_parse, - .print = REDIRECT_print, - .save = REDIRECT_save, - .x6_options = REDIRECT_opts, - .xlate = REDIRECT_xlate, -}; - -void _init(void) -{ - xtables_register_target(&redirect_tg_reg); -} diff --git a/extensions/libip6t_REDIRECT.t b/extensions/libip6t_REDIRECT.t deleted file mode 100644 index a0fb0ed1..00000000 --- a/extensions/libip6t_REDIRECT.t +++ /dev/null @@ -1,6 +0,0 @@ -: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_REDIRECT.txlate b/extensions/libip6t_REDIRECT.txlate deleted file mode 100644 index 209f67a4..00000000 --- a/extensions/libip6t_REDIRECT.txlate +++ /dev/null @@ -1,5 +0,0 @@ -ip6tables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 8080 -nft add rule ip6 nat prerouting tcp dport 80 counter redirect to :8080 - -ip6tables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 8080 --random -nft add rule ip6 nat prerouting tcp dport 80 counter redirect to :8080 random diff --git a/extensions/libip6t_REJECT.t b/extensions/libip6t_REJECT.t index d2b337d7..8294f0bb 100644 --- a/extensions/libip6t_REJECT.t +++ b/extensions/libip6t_REJECT.t @@ -1,5 +1,5 @@ :INPUT,FORWARD,OUTPUT --j REJECT;=;OK +-j REJECT;-j REJECT --reject-with icmp6-port-unreachable;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 diff --git a/extensions/libip6t_REJECT.txlate b/extensions/libip6t_REJECT.txlate index cfa35ebf..184713d1 100644 --- a/extensions/libip6t_REJECT.txlate +++ b/extensions/libip6t_REJECT.txlate @@ -1,8 +1,8 @@ ip6tables-translate -A FORWARD -p TCP --dport 22 -j REJECT -nft add rule ip6 filter FORWARD tcp dport 22 counter reject +nft 'add rule ip6 filter FORWARD tcp dport 22 counter reject' ip6tables-translate -A FORWARD -p TCP --dport 22 -j REJECT --reject-with icmp6-reject-route -nft add rule ip6 filter FORWARD tcp dport 22 counter reject with icmpv6 type reject-route +nft 'add rule ip6 filter FORWARD tcp dport 22 counter reject with icmpv6 type reject-route' ip6tables-translate -A FORWARD -p TCP --dport 22 -j REJECT --reject-with tcp-reset -nft add rule ip6 filter FORWARD tcp dport 22 counter reject with tcp reset +nft 'add rule ip6 filter FORWARD tcp dport 22 counter reject with tcp reset' diff --git a/extensions/libip6t_SNAT.c b/extensions/libip6t_SNAT.c deleted file mode 100644 index 6d19614c..00000000 --- a/extensions/libip6t_SNAT.c +++ /dev/null @@ -1,315 +0,0 @@ -/* - * Copyright (c) 2011 Patrick McHardy <kaber@trash.net> - * - * Based on Rusty Russell's IPv4 SNAT target. Development of IPv6 NAT - * funded by Astaro. - */ - -#include <stdio.h> -#include <netdb.h> -#include <string.h> -#include <stdlib.h> -#include <xtables.h> -#include <iptables.h> -#include <limits.h> /* INT_MAX in ip_tables.h */ -#include <linux/netfilter_ipv6/ip6_tables.h> -#include <linux/netfilter/nf_nat.h> - -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_RANDOM_FULLY = 1 << O_RANDOM_FULLY, - F_X_TO_SRC = 1 << O_X_TO_SRC, -}; - -static void SNAT_help(void) -{ - printf( -"SNAT target options:\n" -" --to-source [<ipaddr>[-<ipaddr>]][:port[-port]]\n" -" Address to map source to.\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, -}; - -/* Ranges expected in network order. */ -static void -parse_to(const char *orig_arg, int portok, struct nf_nat_range *range) -{ - char *arg, *start, *end = NULL, *colon = NULL, *dash, *error; - const struct in6_addr *ip; - - arg = xtables_strdup(orig_arg); - - start = strchr(arg, '['); - if (start == NULL) { - start = arg; - /* Lets assume one colon is port information. Otherwise its an IPv6 address */ - colon = strchr(arg, ':'); - if (colon && strchr(colon+1, ':')) - colon = NULL; - } - else { - start++; - end = strchr(start, ']'); - if (end == NULL) - xtables_error(PARAMETER_PROBLEM, - "Invalid address format"); - - *end = '\0'; - colon = strchr(end + 1, ':'); - } - - if (colon) { - int port; - - if (!portok) - xtables_error(PARAMETER_PROBLEM, - "Need TCP, UDP, SCTP or DCCP with port specification"); - - range->flags |= NF_NAT_RANGE_PROTO_SPECIFIED; - - port = atoi(colon+1); - if (port <= 0 || port > 65535) - xtables_error(PARAMETER_PROBLEM, - "Port `%s' not valid\n", colon+1); - - error = strchr(colon+1, ':'); - if (error) - xtables_error(PARAMETER_PROBLEM, - "Invalid port:port syntax - use dash\n"); - - dash = strchr(colon, '-'); - if (!dash) { - range->min_proto.tcp.port - = range->max_proto.tcp.port - = htons(port); - } else { - int maxport; - - maxport = atoi(dash + 1); - if (maxport <= 0 || maxport > 65535) - xtables_error(PARAMETER_PROBLEM, - "Port `%s' not valid\n", dash+1); - if (maxport < port) - /* People are stupid. */ - xtables_error(PARAMETER_PROBLEM, - "Port range `%s' funky\n", colon+1); - range->min_proto.tcp.port = htons(port); - range->max_proto.tcp.port = htons(maxport); - } - /* Starts with colon or [] colon? No IP info...*/ - if (colon == arg || colon == arg+2) { - free(arg); - return; - } - *colon = '\0'; - } - - range->flags |= NF_NAT_RANGE_MAP_IPS; - dash = strchr(start, '-'); - if (colon && dash && dash > colon) - dash = NULL; - - if (dash) - *dash = '\0'; - - ip = xtables_numeric_to_ip6addr(start); - if (!ip) - xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n", - start); - range->min_addr.in6 = *ip; - if (dash) { - ip = xtables_numeric_to_ip6addr(dash + 1); - if (!ip) - xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n", - dash+1); - range->max_addr.in6 = *ip; - } else - range->max_addr = range->min_addr; - - free(arg); - return; -} - -static void SNAT_parse(struct xt_option_call *cb) -{ - const struct ip6t_entry *entry = cb->xt_entry; - struct nf_nat_range *range = cb->data; - int portok; - - if (entry->ipv6.proto == IPPROTO_TCP || - entry->ipv6.proto == IPPROTO_UDP || - entry->ipv6.proto == IPPROTO_SCTP || - entry->ipv6.proto == IPPROTO_DCCP || - entry->ipv6.proto == IPPROTO_ICMP) - portok = 1; - else - portok = 0; - - xtables_option_parse(cb); - switch (cb->entry->id) { - case O_TO_SRC: - if (cb->xflags & F_X_TO_SRC) { - xtables_error(PARAMETER_PROBLEM, - "SNAT: Multiple --to-source not supported"); - } - parse_to(cb->arg, portok, range); - cb->xflags |= F_X_TO_SRC; - break; - case O_PERSISTENT: - range->flags |= NF_NAT_RANGE_PERSISTENT; - break; - } -} - -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) -{ - if (range->flags & NF_NAT_RANGE_MAP_IPS) { - if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) - printf("["); - printf("%s", xtables_ip6addr_to_numeric(&range->min_addr.in6)); - if (memcmp(&range->min_addr, &range->max_addr, - sizeof(range->min_addr))) - printf("-%s", xtables_ip6addr_to_numeric(&range->max_addr.in6)); - if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) - printf("]"); - } - if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { - printf(":"); - printf("%hu", ntohs(range->min_proto.tcp.port)); - if (range->max_proto.tcp.port != range->min_proto.tcp.port) - printf("-%hu", ntohs(range->max_proto.tcp.port)); - } -} - -static void SNAT_print(const void *ip, const struct xt_entry_target *target, - int numeric) -{ - const struct nf_nat_range *range = (const void *)target->data; - - printf(" to:"); - 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 SNAT_save(const void *ip, const struct xt_entry_target *target) -{ - const struct nf_nat_range *range = (const void *)target->data; - - printf(" --to-source "); - 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, - .family = NFPROTO_IPV6, - .revision = 1, - .size = XT_ALIGN(sizeof(struct nf_nat_range)), - .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)), - .help = SNAT_help, - .x6_parse = SNAT_parse, - .x6_fcheck = SNAT_fcheck, - .print = SNAT_print, - .save = SNAT_save, - .x6_options = SNAT_opts, - .xlate = SNAT_xlate, -}; - -void _init(void) -{ - xtables_register_target(&snat_tg_reg); -} diff --git a/extensions/libip6t_SNAT.t b/extensions/libip6t_SNAT.t index d188a6bb..98aa7602 100644 --- a/extensions/libip6t_SNAT.t +++ b/extensions/libip6t_SNAT.t @@ -4,6 +4,12 @@ -j SNAT --to-source dead::beef-dead::fee7;=;OK -j SNAT --to-source [dead::beef]:1025-65535;;FAIL -j SNAT --to-source [dead::beef] --to-source [dead::fee7];;FAIL +-j SNAT --to-source dead::beef --random;=;OK +-j SNAT --to-source dead::beef --random-fully;=;OK +-j SNAT --to-source dead::beef --persistent;=;OK +-j SNAT --to-source dead::beef --random --persistent;=;OK +-j SNAT --to-source dead::beef --random --random-fully;=;OK +-j SNAT --to-source dead::beef --random --random-fully --persistent;=;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 diff --git a/extensions/libip6t_SNAT.txlate b/extensions/libip6t_SNAT.txlate index 44f2fcea..e5f6f735 100644 --- a/extensions/libip6t_SNAT.txlate +++ b/extensions/libip6t_SNAT.txlate @@ -1,11 +1,11 @@ ip6tables-translate -t nat -A postrouting -o eth0 -p tcp -j SNAT --to [fec0::1234]:80 -nft add rule ip6 nat postrouting oifname "eth0" meta l4proto tcp counter snat to [fec0::1234]:80 +nft 'add rule ip6 nat postrouting oifname "eth0" meta l4proto tcp counter snat to [fec0::1234]:80' ip6tables-translate -t nat -A postrouting -o eth0 -p tcp -j SNAT --to [fec0::1234]:1-20 -nft add rule ip6 nat postrouting oifname "eth0" meta l4proto tcp counter snat to [fec0::1234]:1-20 +nft 'add rule ip6 nat postrouting oifname "eth0" meta l4proto tcp counter snat to [fec0::1234]:1-20' ip6tables-translate -t nat -A postrouting -o eth0 -p tcp -j SNAT --to [fec0::1234]:123 --random -nft add rule ip6 nat postrouting oifname "eth0" meta l4proto tcp counter snat to [fec0::1234]:123 random +nft 'add rule ip6 nat postrouting oifname "eth0" meta l4proto tcp counter snat to [fec0::1234]:123 random' ip6tables-translate -t nat -A postrouting -o eth0 -p tcp -j SNAT --to [fec0::1234]:123 --random-fully --persistent -nft add rule ip6 nat postrouting oifname "eth0" meta l4proto tcp counter snat to [fec0::1234]:123 fully-random,persistent +nft 'add rule ip6 nat postrouting oifname "eth0" meta l4proto tcp counter snat to [fec0::1234]:123 fully-random,persistent' diff --git a/extensions/libip6t_ah.txlate b/extensions/libip6t_ah.txlate index c6b09a2e..cc33ac27 100644 --- a/extensions/libip6t_ah.txlate +++ b/extensions/libip6t_ah.txlate @@ -1,17 +1,17 @@ ip6tables-translate -A INPUT -m ah --ahspi 500 -j DROP -nft add rule ip6 filter INPUT ah spi 500 counter drop +nft 'add rule ip6 filter INPUT ah spi 500 counter drop' ip6tables-translate -A INPUT -m ah --ahspi 500:550 -j DROP -nft add rule ip6 filter INPUT ah spi 500-550 counter drop +nft 'add rule ip6 filter INPUT ah spi 500-550 counter drop' ip6tables-translate -A INPUT -m ah ! --ahlen 120 -nft add rule ip6 filter INPUT ah hdrlength != 120 counter +nft 'add rule ip6 filter INPUT ah hdrlength != 120 counter' ip6tables-translate -A INPUT -m ah --ahres -nft add rule ip6 filter INPUT ah reserved 1 counter +nft 'add rule ip6 filter INPUT ah reserved 1 counter' ip6tables-translate -A INPUT -m ah --ahspi 500 ! --ahlen 120 -j DROP -nft add rule ip6 filter INPUT ah spi 500 ah hdrlength != 120 counter drop +nft 'add rule ip6 filter INPUT ah spi 500 ah hdrlength != 120 counter drop' ip6tables-translate -A INPUT -m ah --ahspi 500 --ahlen 120 --ahres -j ACCEPT -nft add rule ip6 filter INPUT ah spi 500 ah hdrlength 120 ah reserved 1 counter accept +nft 'add rule ip6 filter INPUT ah spi 500 ah hdrlength 120 ah reserved 1 counter accept' diff --git a/extensions/libip6t_dst.c b/extensions/libip6t_dst.c index bf0e3e43..baa010f5 100644 --- a/extensions/libip6t_dst.c +++ b/extensions/libip6t_dst.c @@ -125,15 +125,15 @@ static void print_options(unsigned int optsnr, uint16_t *optsp) { unsigned int i; + char sep = ' '; - printf(" "); for(i = 0; i < optsnr; i++) { - printf("%d", (optsp[i] & 0xFF00) >> 8); + printf("%c%d", sep, (optsp[i] & 0xFF00) >> 8); if ((optsp[i] & 0x00FF) != 0x00FF) printf(":%d", (optsp[i] & 0x00FF)); - printf("%c", (i != optsnr - 1) ? ',' : ' '); + sep = ','; } } diff --git a/extensions/libip6t_frag.c b/extensions/libip6t_frag.c index 3842496e..49c787e7 100644 --- a/extensions/libip6t_frag.c +++ b/extensions/libip6t_frag.c @@ -178,7 +178,6 @@ static int frag_xlate(struct xt_xlate *xl, { 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", @@ -190,24 +189,21 @@ static int frag_xlate(struct xt_xlate *xl, 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); - } + /* ignore ineffective IP6T_FRAG_LEN bit */ + + if (fraginfo->flags & IP6T_FRAG_RES) + xt_xlate_add(xl, "frag reserved 1"); + + if (fraginfo->flags & IP6T_FRAG_FST) + xt_xlate_add(xl, "frag frag-off 0"); + + if (fraginfo->flags & IP6T_FRAG_MF) + xt_xlate_add(xl, "frag more-fragments 1"); + + if (fraginfo->flags & IP6T_FRAG_NMF) + xt_xlate_add(xl, "frag more-fragments 0"); return 1; } diff --git a/extensions/libip6t_frag.txlate b/extensions/libip6t_frag.txlate index e8bd9d4b..33fc0631 100644 --- a/extensions/libip6t_frag.txlate +++ b/extensions/libip6t_frag.txlate @@ -1,17 +1,17 @@ ip6tables-translate -t filter -A INPUT -m frag --fragid 100:200 -j ACCEPT -nft add rule ip6 filter INPUT frag id 100-200 counter accept +nft 'add rule ip6 filter INPUT frag id 100-200 counter accept' ip6tables-translate -t filter -A INPUT -m frag --fragid 100 --fragres --fragmore -j ACCEPT -nft add rule ip6 filter INPUT frag id 100 frag reserved 1 frag more-fragments 1 counter accept +nft 'add rule ip6 filter INPUT frag id 100 frag reserved 1 frag more-fragments 1 counter accept' ip6tables-translate -t filter -A INPUT -m frag ! --fragid 100:200 -j ACCEPT -nft add rule ip6 filter INPUT frag id != 100-200 counter accept +nft 'add rule ip6 filter INPUT frag id != 100-200 counter accept' ip6tables-translate -t filter -A INPUT -m frag --fragid 100:200 --fraglast -j ACCEPT -nft add rule ip6 filter INPUT frag id 100-200 frag more-fragments 0 counter accept +nft 'add rule ip6 filter INPUT frag id 100-200 frag more-fragments 0 counter accept' ip6tables-translate -t filter -A INPUT -m frag --fragid 100:200 --fragfirst -j ACCEPT -nft add rule ip6 filter INPUT frag id 100-200 frag frag-off 0 counter accept +nft 'add rule ip6 filter INPUT frag id 100-200 frag frag-off 0 counter accept' ip6tables-translate -t filter -A INPUT -m frag --fraglast -j ACCEPT -nft add rule ip6 filter INPUT frag more-fragments 0 counter accept +nft 'add rule ip6 filter INPUT frag more-fragments 0 counter accept' diff --git a/extensions/libip6t_hbh.txlate b/extensions/libip6t_hbh.txlate index 28101fd7..a753df0d 100644 --- a/extensions/libip6t_hbh.txlate +++ b/extensions/libip6t_hbh.txlate @@ -1,5 +1,5 @@ ip6tables-translate -t filter -A INPUT -m hbh --hbh-len 22 -nft add rule ip6 filter INPUT hbh hdrlength 22 counter +nft 'add rule ip6 filter INPUT hbh hdrlength 22 counter' ip6tables-translate -t filter -A INPUT -m hbh ! --hbh-len 22 -nft add rule ip6 filter INPUT hbh hdrlength != 22 counter +nft 'add rule ip6 filter INPUT hbh hdrlength != 22 counter' diff --git a/extensions/libip6t_hl.txlate b/extensions/libip6t_hl.txlate index 17563938..9ff0df9c 100644 --- a/extensions/libip6t_hl.txlate +++ b/extensions/libip6t_hl.txlate @@ -1,5 +1,5 @@ ip6tables-translate -t nat -A postrouting -m hl --hl-gt 3 -nft add rule ip6 nat postrouting ip6 hoplimit gt 3 counter +nft 'add rule ip6 nat postrouting ip6 hoplimit gt 3 counter' ip6tables-translate -t nat -A postrouting -m hl ! --hl-eq 3 -nft add rule ip6 nat postrouting ip6 hoplimit != 3 counter +nft 'add rule ip6 nat postrouting ip6 hoplimit != 3 counter' diff --git a/extensions/libip6t_icmp6.c b/extensions/libip6t_icmp6.c index cc7bfaeb..439291ea 100644 --- a/extensions/libip6t_icmp6.c +++ b/extensions/libip6t_icmp6.c @@ -12,48 +12,6 @@ enum { O_ICMPV6_TYPE = 0, }; -static const struct xt_icmp_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 }, - - { "time-exceeded", 3, 0, 0xFF }, - /* Alias */ { "ttl-exceeded", 3, 0, 0xFF }, - { "ttl-zero-during-transit", 3, 0, 0 }, - { "ttl-zero-during-reassembly", 3, 1, 1 }, - - { "parameter-problem", 4, 0, 0xFF }, - { "bad-header", 4, 0, 0 }, - { "unknown-header-type", 4, 1, 1 }, - { "unknown-option", 4, 2, 2 }, - - { "echo-request", 128, 0, 0xFF }, - /* Alias */ { "ping", 128, 0, 0xFF }, - - { "echo-reply", 129, 0, 0xFF }, - /* Alias */ { "pong", 129, 0, 0xFF }, - - { "router-solicitation", 133, 0, 0xFF }, - - { "router-advertisement", 134, 0, 0xFF }, - - { "neighbour-solicitation", 135, 0, 0xFF }, - /* Alias */ { "neighbor-solicitation", 135, 0, 0xFF }, - - { "neighbour-advertisement", 136, 0, 0xFF }, - /* Alias */ { "neighbor-advertisement", 136, 0, 0xFF }, - - { "redirect", 137, 0, 0xFF }, - -}; - static void icmp6_help(void) { printf( @@ -70,59 +28,6 @@ static const struct xt_option_entry icmp6_opts[] = { XTOPT_TABLEEND, }; -static void -parse_icmpv6(const char *icmpv6type, uint8_t *type, uint8_t code[]) -{ - static const unsigned int limit = ARRAY_SIZE(icmpv6_codes); - unsigned int match = limit; - unsigned int i; - - for (i = 0; i < limit; i++) { - if (strncasecmp(icmpv6_codes[i].name, icmpv6type, strlen(icmpv6type)) - == 0) { - if (match != limit) - xtables_error(PARAMETER_PROBLEM, - "Ambiguous ICMPv6 type `%s':" - " `%s' or `%s'?", - icmpv6type, - icmpv6_codes[match].name, - icmpv6_codes[i].name); - match = i; - } - } - - if (match != limit) { - *type = icmpv6_codes[match].type; - code[0] = icmpv6_codes[match].code_min; - code[1] = icmpv6_codes[match].code_max; - } else { - char *slash; - char buffer[strlen(icmpv6type) + 1]; - unsigned int number; - - strcpy(buffer, icmpv6type); - slash = strchr(buffer, '/'); - - if (slash) - *slash = '\0'; - - if (!xtables_strtoui(buffer, NULL, &number, 0, UINT8_MAX)) - xtables_error(PARAMETER_PROBLEM, - "Invalid ICMPv6 type `%s'\n", buffer); - *type = number; - if (slash) { - if (!xtables_strtoui(slash+1, NULL, &number, 0, UINT8_MAX)) - xtables_error(PARAMETER_PROBLEM, - "Invalid ICMPv6 code `%s'\n", - slash+1); - code[0] = code[1] = number; - } else { - code[0] = 0; - code[1] = 0xFF; - } - } -} - static void icmp6_init(struct xt_entry_match *m) { struct ip6t_icmp *icmpv6info = (struct ip6t_icmp *)m->data; @@ -135,7 +40,7 @@ static void icmp6_parse(struct xt_option_call *cb) struct ip6t_icmp *icmpv6info = cb->data; xtables_option_parse(cb); - parse_icmpv6(cb->arg, &icmpv6info->type, icmpv6info->code); + ipt_parse_icmpv6(cb->arg, &icmpv6info->type, icmpv6info->code); if (cb->invert) icmpv6info->invflags |= IP6T_ICMP_INV; } diff --git a/extensions/libip6t_icmp6.txlate b/extensions/libip6t_icmp6.txlate index 15481ad6..324a48b9 100644 --- a/extensions/libip6t_icmp6.txlate +++ b/extensions/libip6t_icmp6.txlate @@ -1,8 +1,8 @@ ip6tables-translate -t filter -A INPUT -m icmp6 --icmpv6-type 1 -j LOG -nft add rule ip6 filter INPUT icmpv6 type destination-unreachable counter log +nft 'add rule ip6 filter INPUT icmpv6 type destination-unreachable counter log' ip6tables-translate -t filter -A INPUT -m icmp6 --icmpv6-type neighbour-advertisement -j LOG -nft add rule ip6 filter INPUT icmpv6 type nd-neighbor-advert counter log +nft 'add rule ip6 filter INPUT icmpv6 type nd-neighbor-advert counter log' ip6tables-translate -t filter -A INPUT -m icmp6 ! --icmpv6-type packet-too-big -j LOG -nft add rule ip6 filter INPUT icmpv6 type != packet-too-big counter log +nft 'add rule ip6 filter INPUT icmpv6 type != packet-too-big counter log' diff --git a/extensions/libip6t_mh.c b/extensions/libip6t_mh.c index 64675405..1410d324 100644 --- a/extensions/libip6t_mh.c +++ b/extensions/libip6t_mh.c @@ -97,7 +97,7 @@ static unsigned int name_to_type(const char *name) if (!xtables_strtoui(name, NULL, &number, 0, UINT8_MAX)) xtables_error(PARAMETER_PROBLEM, - "Invalid MH type `%s'\n", name); + "Invalid MH type `%s'", name); return number; } } diff --git a/extensions/libip6t_mh.txlate b/extensions/libip6t_mh.txlate index f5d638c0..4dfaf46a 100644 --- a/extensions/libip6t_mh.txlate +++ b/extensions/libip6t_mh.txlate @@ -1,5 +1,5 @@ ip6tables-translate -A INPUT -p mh --mh-type 1 -j ACCEPT -nft add rule ip6 filter INPUT meta l4proto mobility-header mh type 1 counter accept +nft 'add rule ip6 filter INPUT meta l4proto mobility-header mh type 1 counter accept' ip6tables-translate -A INPUT -p mh --mh-type 1:3 -j ACCEPT -nft add rule ip6 filter INPUT meta l4proto mobility-header mh type 1-3 counter accept +nft 'add rule ip6 filter INPUT meta l4proto mobility-header mh type 1-3 counter accept' diff --git a/extensions/libip6t_rt.c b/extensions/libip6t_rt.c index 9708b5a0..d5b0458b 100644 --- a/extensions/libip6t_rt.c +++ b/extensions/libip6t_rt.c @@ -248,17 +248,15 @@ 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, + xt_xlate_add(xl, "rt seg-left%s ", (rtinfo->invflags & IP6T_RT_INV_SGS) ? " !=" : ""); if (rtinfo->segsleft[0] != rtinfo->segsleft[1]) @@ -266,11 +264,10 @@ static int rt_xlate(struct xt_xlate *xl, 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, + xt_xlate_add(xl, "rt hdrlength%s %u", (rtinfo->invflags & IP6T_RT_INV_LEN) ? " !=" : "", rtinfo->hdrlen); } diff --git a/extensions/libip6t_rt.txlate b/extensions/libip6t_rt.txlate index 6464cf9e..3578bcba 100644 --- a/extensions/libip6t_rt.txlate +++ b/extensions/libip6t_rt.txlate @@ -1,14 +1,14 @@ ip6tables-translate -A INPUT -m rt --rt-type 0 -j DROP -nft add rule ip6 filter INPUT rt type 0 counter drop +nft 'add rule ip6 filter INPUT rt type 0 counter drop' ip6tables-translate -A INPUT -m rt ! --rt-len 22 -j DROP -nft add rule ip6 filter INPUT rt hdrlength != 22 counter drop +nft 'add rule ip6 filter INPUT rt hdrlength != 22 counter drop' ip6tables-translate -A INPUT -m rt --rt-segsleft 26 -j ACCEPT -nft add rule ip6 filter INPUT rt seg-left 26 counter accept +nft 'add rule ip6 filter INPUT rt seg-left 26 counter accept' ip6tables-translate -A INPUT -m rt --rt-type 0 --rt-len 22 -j DROP -nft add rule ip6 filter INPUT rt type 0 rt hdrlength 22 counter drop +nft 'add rule ip6 filter INPUT rt type 0 rt hdrlength 22 counter drop' ip6tables-translate -A INPUT -m rt --rt-type 0 --rt-len 22 ! --rt-segsleft 26 -j ACCEPT -nft add rule ip6 filter INPUT rt type 0 rt seg-left != 26 rt hdrlength 22 counter accept +nft 'add rule ip6 filter INPUT rt type 0 rt seg-left != 26 rt hdrlength 22 counter accept' diff --git a/extensions/libipt_CLUSTERIP.c b/extensions/libipt_CLUSTERIP.c index f4b638b2..b207cde3 100644 --- a/extensions/libipt_CLUSTERIP.c +++ b/extensions/libipt_CLUSTERIP.c @@ -87,12 +87,13 @@ static void CLUSTERIP_parse(struct xt_option_call *cb) else if (strcmp(cb->arg, "sourceip-sourceport-destport") == 0) cipinfo->hash_mode = CLUSTERIP_HASHMODE_SIP_SPT_DPT; else - xtables_error(PARAMETER_PROBLEM, "Unknown hashmode \"%s\"\n", - cb->arg); + xtables_error(PARAMETER_PROBLEM, + "Unknown hashmode \"%s\"", cb->arg); break; case O_CLUSTERMAC: if (!(cipinfo->clustermac[0] & 0x01)) - xtables_error(PARAMETER_PROBLEM, "MAC has to be a multicast ethernet address\n"); + xtables_error(PARAMETER_PROBLEM, + "MAC has to be a multicast ethernet address"); break; case O_LOCAL_NODE: cipinfo->num_local_nodes = 1; @@ -107,7 +108,8 @@ static void CLUSTERIP_check(struct xt_fcheck_call *cb) if ((cb->xflags & F_FULL) == F_FULL) return; - xtables_error(PARAMETER_PROBLEM, "CLUSTERIP target: Invalid parameter combination\n"); + xtables_error(PARAMETER_PROBLEM, + "CLUSTERIP target: Invalid parameter combination"); } static const char *hashmode2str(enum clusterip_hashmode mode) diff --git a/extensions/libipt_CLUSTERIP.t b/extensions/libipt_CLUSTERIP.t index 5af555e0..30b80167 100644 --- a/extensions/libipt_CLUSTERIP.t +++ b/extensions/libipt_CLUSTERIP.t @@ -1,4 +1,4 @@ :INPUT -d 10.31.3.236/32 -i lo -j CLUSTERIP --new --hashmode sourceip --clustermac 01:AA:7B:47:F7:D7 --total-nodes 2 --local-node 0 --hash-init 1;=;FAIL --d 10.31.3.236/32 -i lo -j CLUSTERIP --new --hashmode sourceip --clustermac 01:AA:7B:47:F7:D7 --total-nodes 2 --local-node 1 --hash-init 1;=;OK --d 10.31.3.236/32 -i lo -j CLUSTERIP --new --hashmode sourceip --clustermac 01:AA:7B:47:F7:D7 --total-nodes 2 --local-node 2 --hash-init 1;=;OK +-d 10.31.3.236/32 -i lo -j CLUSTERIP --new --hashmode sourceip --clustermac 01:AA:7B:47:F7:D7 --total-nodes 2 --local-node 1 --hash-init 1;=;OK;LEGACY +-d 10.31.3.236/32 -i lo -j CLUSTERIP --new --hashmode sourceip --clustermac 01:AA:7B:47:F7:D7 --total-nodes 2 --local-node 2 --hash-init 1;=;OK;LEGACY diff --git a/extensions/libipt_DNAT.c b/extensions/libipt_DNAT.c deleted file mode 100644 index 5b33fd23..00000000 --- a/extensions/libipt_DNAT.c +++ /dev/null @@ -1,551 +0,0 @@ -#include <stdio.h> -#include <netdb.h> -#include <string.h> -#include <stdlib.h> -#include <xtables.h> -#include <iptables.h> /* get_kernel_version */ -#include <limits.h> /* INT_MAX in ip_tables.h */ -#include <linux/netfilter_ipv4/ip_tables.h> -#include <linux/netfilter/nf_nat.h> - -enum { - O_TO_DEST = 0, - O_RANDOM, - O_PERSISTENT, - O_X_TO_DEST, /* hidden flag */ - F_TO_DEST = 1 << O_TO_DEST, - F_RANDOM = 1 << O_RANDOM, - F_X_TO_DEST = 1 << O_X_TO_DEST, -}; - -/* Dest NAT data consists of a multi-range, indicating where to map - to. */ -struct ipt_natinfo -{ - struct xt_entry_target t; - struct nf_nat_ipv4_multi_range_compat mr; -}; - -static void DNAT_help(void) -{ - printf( -"DNAT target options:\n" -" --to-destination [<ipaddr>[-<ipaddr>]][:port[-port]]\n" -" Address to map destination to.\n" -"[--random] [--persistent]\n"); -} - -static void DNAT_help_v2(void) -{ - printf( -"DNAT target options:\n" -" --to-destination [<ipaddr>[-<ipaddr>]][:port[-port[/port]]]\n" -" Address to map destination to.\n" -"[--random] [--persistent]\n"); -} - -static const struct xt_option_entry DNAT_opts[] = { - {.name = "to-destination", .id = O_TO_DEST, .type = XTTYPE_STRING, - .flags = XTOPT_MAND | XTOPT_MULTI}, - {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE}, - {.name = "persistent", .id = O_PERSISTENT, .type = XTTYPE_NONE}, - XTOPT_TABLEEND, -}; - -static struct ipt_natinfo * -append_range(struct ipt_natinfo *info, const struct nf_nat_ipv4_range *range) -{ - unsigned int size; - - /* One rangesize already in struct ipt_natinfo */ - size = XT_ALIGN(sizeof(*info) + info->mr.rangesize * sizeof(*range)); - - info = realloc(info, size); - if (!info) - xtables_error(OTHER_PROBLEM, "Out of memory\n"); - - info->t.u.target_size = size; - info->mr.range[info->mr.rangesize] = *range; - info->mr.rangesize++; - - return info; -} - -/* Ranges expected in network order. */ -static struct xt_entry_target * -parse_to(const char *orig_arg, int portok, struct ipt_natinfo *info) -{ - struct nf_nat_ipv4_range range; - char *arg, *colon, *dash, *error; - const struct in_addr *ip; - - arg = xtables_strdup(orig_arg); - memset(&range, 0, sizeof(range)); - colon = strchr(arg, ':'); - - if (colon) { - int port; - - if (!portok) - xtables_error(PARAMETER_PROBLEM, - "Need TCP, UDP, SCTP or DCCP with port specification"); - - range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED; - - port = atoi(colon+1); - if (port <= 0 || port > 65535) - xtables_error(PARAMETER_PROBLEM, - "Port `%s' not valid\n", colon+1); - - error = strchr(colon+1, ':'); - if (error) - xtables_error(PARAMETER_PROBLEM, - "Invalid port:port syntax - use dash\n"); - - dash = strchr(colon, '-'); - if (!dash) { - range.min.tcp.port - = range.max.tcp.port - = htons(port); - } else { - int maxport; - - maxport = atoi(dash + 1); - if (maxport <= 0 || maxport > 65535) - xtables_error(PARAMETER_PROBLEM, - "Port `%s' not valid\n", dash+1); - if (maxport < port) - /* People are stupid. */ - xtables_error(PARAMETER_PROBLEM, - "Port range `%s' funky\n", colon+1); - range.min.tcp.port = htons(port); - range.max.tcp.port = htons(maxport); - } - /* Starts with a colon? No IP info...*/ - if (colon == arg) { - free(arg); - return &(append_range(info, &range)->t); - } - *colon = '\0'; - } - - range.flags |= NF_NAT_RANGE_MAP_IPS; - dash = strchr(arg, '-'); - if (colon && dash && dash > colon) - dash = NULL; - - if (dash) - *dash = '\0'; - - ip = xtables_numeric_to_ipaddr(arg); - if (!ip) - xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n", - arg); - range.min_ip = ip->s_addr; - if (dash) { - ip = xtables_numeric_to_ipaddr(dash+1); - if (!ip) - xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n", - dash+1); - range.max_ip = ip->s_addr; - } else - range.max_ip = range.min_ip; - - free(arg); - return &(append_range(info, &range)->t); -} - -static void DNAT_parse(struct xt_option_call *cb) -{ - const struct ipt_entry *entry = cb->xt_entry; - struct ipt_natinfo *info = (void *)(*cb->target); - int portok; - - if (entry->ip.proto == IPPROTO_TCP - || entry->ip.proto == IPPROTO_UDP - || entry->ip.proto == IPPROTO_SCTP - || entry->ip.proto == IPPROTO_DCCP - || entry->ip.proto == IPPROTO_ICMP) - portok = 1; - else - portok = 0; - - xtables_option_parse(cb); - switch (cb->entry->id) { - case O_TO_DEST: - if (cb->xflags & F_X_TO_DEST) { - if (!kernel_version) - get_kernel_version(); - if (kernel_version > LINUX_VERSION(2, 6, 10)) - xtables_error(PARAMETER_PROBLEM, - "DNAT: Multiple --to-destination not supported"); - } - *cb->target = parse_to(cb->arg, portok, info); - cb->xflags |= F_X_TO_DEST; - break; - case O_PERSISTENT: - info->mr.range[0].flags |= NF_NAT_RANGE_PERSISTENT; - break; - } -} - -static void DNAT_fcheck(struct xt_fcheck_call *cb) -{ - static const unsigned int f = F_TO_DEST | F_RANDOM; - struct nf_nat_ipv4_multi_range_compat *mr = cb->data; - - if ((cb->xflags & f) == f) - mr->range[0].flags |= NF_NAT_RANGE_PROTO_RANDOM; -} - -static void print_range(const struct nf_nat_ipv4_range *r) -{ - if (r->flags & NF_NAT_RANGE_MAP_IPS) { - struct in_addr a; - - a.s_addr = r->min_ip; - printf("%s", xtables_ipaddr_to_numeric(&a)); - if (r->max_ip != r->min_ip) { - a.s_addr = r->max_ip; - printf("-%s", xtables_ipaddr_to_numeric(&a)); - } - } - if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { - printf(":"); - printf("%hu", ntohs(r->min.tcp.port)); - if (r->max.tcp.port != r->min.tcp.port) - printf("-%hu", ntohs(r->max.tcp.port)); - } -} - -static void DNAT_print(const void *ip, const struct xt_entry_target *target, - int numeric) -{ - const struct ipt_natinfo *info = (const void *)target; - unsigned int i = 0; - - printf(" to:"); - for (i = 0; i < info->mr.rangesize; i++) { - 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_PERSISTENT) - printf(" persistent"); - } -} - -static void DNAT_save(const void *ip, const struct xt_entry_target *target) -{ - const struct ipt_natinfo *info = (const void *)target; - unsigned int i = 0; - - for (i = 0; i < info->mr.rangesize; i++) { - printf(" --to-destination "); - 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_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, ":%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 void -parse_to_v2(const char *orig_arg, int portok, struct nf_nat_range2 *range) -{ - char *arg, *colon, *dash, *error; - const struct in_addr *ip; - - arg = xtables_strdup(orig_arg); - - colon = strchr(arg, ':'); - if (colon) { - int port; - - if (!portok) - xtables_error(PARAMETER_PROBLEM, - "Need TCP, UDP, SCTP or DCCP with port specification"); - - range->flags |= NF_NAT_RANGE_PROTO_SPECIFIED; - - port = atoi(colon+1); - if (port <= 0 || port > 65535) - xtables_error(PARAMETER_PROBLEM, - "Port `%s' not valid\n", colon+1); - - error = strchr(colon+1, ':'); - if (error) - xtables_error(PARAMETER_PROBLEM, - "Invalid port:port syntax - use dash\n"); - - dash = strchr(colon, '-'); - if (!dash) { - range->min_proto.tcp.port - = range->max_proto.tcp.port - = htons(port); - } else { - int maxport; - char *slash; - - maxport = atoi(dash + 1); - if (maxport <= 0 || maxport > 65535) - xtables_error(PARAMETER_PROBLEM, - "Port `%s' not valid\n", dash+1); - if (maxport < port) - /* People are stupid. */ - xtables_error(PARAMETER_PROBLEM, - "Port range `%s' funky\n", colon+1); - range->min_proto.tcp.port = htons(port); - range->max_proto.tcp.port = htons(maxport); - - slash = strchr(dash, '/'); - if (slash) { - int baseport; - - baseport = atoi(slash + 1); - if (baseport <= 0 || baseport > 65535) - xtables_error(PARAMETER_PROBLEM, - "Port `%s' not valid\n", slash+1); - range->flags |= NF_NAT_RANGE_PROTO_OFFSET; - range->base_proto.tcp.port = htons(baseport); - } - } - /* Starts with a colon? No IP info...*/ - if (colon == arg) { - free(arg); - return; - } - *colon = '\0'; - } - - range->flags |= NF_NAT_RANGE_MAP_IPS; - dash = strchr(arg, '-'); - if (colon && dash && dash > colon) - dash = NULL; - - if (dash) - *dash = '\0'; - - ip = xtables_numeric_to_ipaddr(arg); - if (!ip) - xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n", - arg); - range->min_addr.in = *ip; - if (dash) { - ip = xtables_numeric_to_ipaddr(dash+1); - if (!ip) - xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n", - dash+1); - range->max_addr.in = *ip; - } else - range->max_addr = range->min_addr; - - free(arg); - return; -} - -static void DNAT_parse_v2(struct xt_option_call *cb) -{ - const struct ipt_entry *entry = cb->xt_entry; - struct nf_nat_range2 *range = cb->data; - int portok; - - if (entry->ip.proto == IPPROTO_TCP - || entry->ip.proto == IPPROTO_UDP - || entry->ip.proto == IPPROTO_SCTP - || entry->ip.proto == IPPROTO_DCCP - || entry->ip.proto == IPPROTO_ICMP) - portok = 1; - else - portok = 0; - - xtables_option_parse(cb); - switch (cb->entry->id) { - case O_TO_DEST: - if (cb->xflags & F_X_TO_DEST) { - xtables_error(PARAMETER_PROBLEM, - "DNAT: Multiple --to-destination not supported"); - } - parse_to_v2(cb->arg, portok, range); - cb->xflags |= F_X_TO_DEST; - break; - case O_PERSISTENT: - range->flags |= NF_NAT_RANGE_PERSISTENT; - break; - } -} - -static void DNAT_fcheck_v2(struct xt_fcheck_call *cb) -{ - static const unsigned int f = F_TO_DEST | F_RANDOM; - struct nf_nat_range2 *range = cb->data; - - if ((cb->xflags & f) == f) - range->flags |= NF_NAT_RANGE_PROTO_RANDOM; -} - -static void print_range_v2(const struct nf_nat_range2 *range) -{ - if (range->flags & NF_NAT_RANGE_MAP_IPS) { - printf("%s", xtables_ipaddr_to_numeric(&range->min_addr.in)); - if (memcmp(&range->min_addr, &range->max_addr, - sizeof(range->min_addr))) - printf("-%s", xtables_ipaddr_to_numeric(&range->max_addr.in)); - } - if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { - printf(":"); - printf("%hu", ntohs(range->min_proto.tcp.port)); - if (range->max_proto.tcp.port != range->min_proto.tcp.port) - printf("-%hu", ntohs(range->max_proto.tcp.port)); - if (range->flags & NF_NAT_RANGE_PROTO_OFFSET) - printf("/%hu", ntohs(range->base_proto.tcp.port)); - } -} - -static void DNAT_print_v2(const void *ip, const struct xt_entry_target *target, - int numeric) -{ - const struct nf_nat_range2 *range = (const void *)target->data; - - printf(" to:"); - print_range_v2(range); - if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) - printf(" random"); - if (range->flags & NF_NAT_RANGE_PERSISTENT) - printf(" persistent"); -} - -static void DNAT_save_v2(const void *ip, const struct xt_entry_target *target) -{ - const struct nf_nat_range2 *range = (const void *)target->data; - - printf(" --to-destination "); - print_range_v2(range); - if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) - printf(" --random"); - if (range->flags & NF_NAT_RANGE_PERSISTENT) - printf(" --persistent"); -} - -static void print_range_xlate_v2(const struct nf_nat_range2 *range, - struct xt_xlate *xl) -{ - if (range->flags & NF_NAT_RANGE_MAP_IPS) { - xt_xlate_add(xl, "%s", xtables_ipaddr_to_numeric(&range->min_addr.in)); - if (memcmp(&range->min_addr, &range->max_addr, - sizeof(range->min_addr))) { - xt_xlate_add(xl, "-%s", xtables_ipaddr_to_numeric(&range->max_addr.in)); - } - } - if (range->flags & NF_NAT_RANGE_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)); - if (range->flags & NF_NAT_RANGE_PROTO_OFFSET) - xt_xlate_add(xl, ";%hu", ntohs(range->base_proto.tcp.port)); - } -} - -static int DNAT_xlate_v2(struct xt_xlate *xl, - const struct xt_xlate_tg_params *params) -{ - const struct nf_nat_range2 *range = (const void *)params->target->data; - bool sep_need = false; - const char *sep = " "; - - xt_xlate_add(xl, "dnat to "); - print_range_xlate_v2(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 dnat_tg_reg[] = { - { - .name = "DNAT", - .version = XTABLES_VERSION, - .family = NFPROTO_IPV4, - .revision = 0, - .size = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), - .userspacesize = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), - .help = DNAT_help, - .print = DNAT_print, - .save = DNAT_save, - .x6_parse = DNAT_parse, - .x6_fcheck = DNAT_fcheck, - .x6_options = DNAT_opts, - .xlate = DNAT_xlate, - }, - { - .name = "DNAT", - .version = XTABLES_VERSION, - .family = NFPROTO_IPV4, - .revision = 2, - .size = XT_ALIGN(sizeof(struct nf_nat_range2)), - .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range2)), - .help = DNAT_help_v2, - .print = DNAT_print_v2, - .save = DNAT_save_v2, - .x6_parse = DNAT_parse_v2, - .x6_fcheck = DNAT_fcheck_v2, - .x6_options = DNAT_opts, - .xlate = DNAT_xlate_v2, - }, -}; - -void _init(void) -{ - xtables_register_targets(dnat_tg_reg, ARRAY_SIZE(dnat_tg_reg)); -} diff --git a/extensions/libipt_DNAT.t b/extensions/libipt_DNAT.t index 1c4413b9..9007572a 100644 --- a/extensions/libipt_DNAT.t +++ b/extensions/libipt_DNAT.t @@ -13,4 +13,8 @@ -p tcp -j DNAT --to-destination 1.1.1.1:1000-2000/65535;=;OK -p tcp -j DNAT --to-destination 1.1.1.1:1000-2000/0;;FAIL -p tcp -j DNAT --to-destination 1.1.1.1:1000-2000/65536;;FAIL +-p tcp -j DNAT --to-destination 1.1.1.1:ssh;-p tcp -j DNAT --to-destination 1.1.1.1:22;OK +-p tcp -j DNAT --to-destination 1.1.1.1:ftp-data;-p tcp -j DNAT --to-destination 1.1.1.1:20;OK +-p tcp -j DNAT --to-destination 1.1.1.1:echo-ssh;;FAIL +-p tcp -j DNAT --to-destination 1.1.1.1:10-20/ftp;-p tcp -j DNAT --to-destination 1.1.1.1:10-20/21;OK -j DNAT;;FAIL diff --git a/extensions/libipt_DNAT.txlate b/extensions/libipt_DNAT.txlate deleted file mode 100644 index e88314d9..00000000 --- a/extensions/libipt_DNAT.txlate +++ /dev/null @@ -1,14 +0,0 @@ -iptables-translate -t nat -A prerouting -p tcp -o eth0 -j DNAT --to-destination 1.2.3.4 -nft add rule ip nat prerouting oifname "eth0" ip protocol tcp counter dnat to 1.2.3.4 - -iptables-translate -t nat -A prerouting -p tcp -d 15.45.23.67 --dport 80 -j DNAT --to-destination 192.168.1.1-192.168.1.10 -nft add rule ip nat prerouting ip daddr 15.45.23.67 tcp dport 80 counter dnat to 192.168.1.1-192.168.1.10 - -iptables-translate -t nat -A prerouting -p tcp -o eth0 -j DNAT --to-destination 1.2.3.4:1-1023 -nft add rule ip nat prerouting oifname "eth0" ip protocol tcp counter dnat to 1.2.3.4:1-1023 - -iptables-translate -t nat -A prerouting -p tcp -o eth0 -j DNAT --to-destination 1.2.3.4 --random -nft add rule ip nat prerouting oifname "eth0" ip protocol tcp counter dnat to 1.2.3.4 random - -iptables-translate -t nat -A prerouting -p tcp -o eth0 -j DNAT --to-destination 1.2.3.4 --random --persistent -nft add rule ip nat prerouting oifname "eth0" ip protocol tcp counter dnat to 1.2.3.4 random,persistent diff --git a/extensions/libipt_LOG.c b/extensions/libipt_LOG.c deleted file mode 100644 index 36e2e73b..00000000 --- a/extensions/libipt_LOG.c +++ /dev/null @@ -1,250 +0,0 @@ -#include <stdio.h> -#include <string.h> -#include <syslog.h> -#include <xtables.h> -#include <linux/netfilter_ipv4/ipt_LOG.h> - -#define LOG_DEFAULT_LEVEL LOG_WARNING - -#ifndef IPT_LOG_UID /* Old kernel */ -#define IPT_LOG_UID 0x08 /* Log UID owning local socket */ -#undef IPT_LOG_MASK -#define IPT_LOG_MASK 0x0f -#endif - -enum { - O_LOG_LEVEL = 0, - O_LOG_PREFIX, - O_LOG_TCPSEQ, - O_LOG_TCPOPTS, - O_LOG_IPOPTS, - O_LOG_UID, - O_LOG_MAC, -}; - -static void LOG_help(void) -{ - printf( -"LOG target options:\n" -" --log-level level Level of logging (numeric or see syslog.conf)\n" -" --log-prefix prefix Prefix log messages with this prefix.\n\n" -" --log-tcp-sequence Log TCP sequence numbers.\n\n" -" --log-tcp-options Log TCP options.\n\n" -" --log-ip-options Log IP options.\n\n" -" --log-uid Log UID owning the local socket.\n\n" -" --log-macdecode Decode MAC addresses and protocol.\n\n"); -} - -#define s struct ipt_log_info -static const struct xt_option_entry LOG_opts[] = { - {.name = "log-level", .id = O_LOG_LEVEL, .type = XTTYPE_SYSLOGLEVEL, - .flags = XTOPT_PUT, XTOPT_POINTER(s, level)}, - {.name = "log-prefix", .id = O_LOG_PREFIX, .type = XTTYPE_STRING, - .flags = XTOPT_PUT, XTOPT_POINTER(s, prefix), .min = 1}, - {.name = "log-tcp-sequence", .id = O_LOG_TCPSEQ, .type = XTTYPE_NONE}, - {.name = "log-tcp-options", .id = O_LOG_TCPOPTS, .type = XTTYPE_NONE}, - {.name = "log-ip-options", .id = O_LOG_IPOPTS, .type = XTTYPE_NONE}, - {.name = "log-uid", .id = O_LOG_UID, .type = XTTYPE_NONE}, - {.name = "log-macdecode", .id = O_LOG_MAC, .type = XTTYPE_NONE}, - XTOPT_TABLEEND, -}; -#undef s - -static void LOG_init(struct xt_entry_target *t) -{ - struct ipt_log_info *loginfo = (struct ipt_log_info *)t->data; - - loginfo->level = LOG_DEFAULT_LEVEL; - -} - -struct ipt_log_names { - const char *name; - unsigned int level; -}; - -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 }, - { .name = "debug", .level = LOG_DEBUG }, - { .name = "emerg", .level = LOG_EMERG }, - { .name = "error", .level = LOG_ERR }, /* DEPRECATED */ - { .name = "info", .level = LOG_INFO }, - { .name = "notice", .level = LOG_NOTICE }, - { .name = "panic", .level = LOG_EMERG }, /* DEPRECATED */ - { .name = "warning", .level = LOG_WARNING } -}; - -static void LOG_parse(struct xt_option_call *cb) -{ - struct ipt_log_info *info = cb->data; - - xtables_option_parse(cb); - switch (cb->entry->id) { - case O_LOG_PREFIX: - if (strchr(cb->arg, '\n') != NULL) - xtables_error(PARAMETER_PROBLEM, - "Newlines not allowed in --log-prefix"); - break; - case O_LOG_TCPSEQ: - info->logflags |= IPT_LOG_TCPSEQ; - break; - case O_LOG_TCPOPTS: - info->logflags |= IPT_LOG_TCPOPT; - break; - case O_LOG_IPOPTS: - info->logflags |= IPT_LOG_IPOPT; - break; - case O_LOG_UID: - info->logflags |= IPT_LOG_UID; - break; - case O_LOG_MAC: - info->logflags |= IPT_LOG_MACDECODE; - break; - } -} - -static void LOG_print(const void *ip, const struct xt_entry_target *target, - int numeric) -{ - const struct ipt_log_info *loginfo - = (const struct ipt_log_info *)target->data; - unsigned int i = 0; - - printf(" LOG"); - if (numeric) - printf(" flags %u level %u", - loginfo->logflags, loginfo->level); - else { - for (i = 0; i < ARRAY_SIZE(ipt_log_names); ++i) - if (loginfo->level == ipt_log_names[i].level) { - printf(" level %s", ipt_log_names[i].name); - break; - } - if (i == ARRAY_SIZE(ipt_log_names)) - printf(" UNKNOWN level %u", loginfo->level); - if (loginfo->logflags & IPT_LOG_TCPSEQ) - printf(" tcp-sequence"); - if (loginfo->logflags & IPT_LOG_TCPOPT) - printf(" tcp-options"); - if (loginfo->logflags & IPT_LOG_IPOPT) - printf(" ip-options"); - if (loginfo->logflags & IPT_LOG_UID) - printf(" uid"); - if (loginfo->logflags & IPT_LOG_MACDECODE) - printf(" macdecode"); - if (loginfo->logflags & ~(IPT_LOG_MASK)) - printf(" unknown-flags"); - } - - if (strcmp(loginfo->prefix, "") != 0) - printf(" prefix \"%s\"", loginfo->prefix); -} - -static void LOG_save(const void *ip, const struct xt_entry_target *target) -{ - const struct ipt_log_info *loginfo - = (const struct ipt_log_info *)target->data; - - if (strcmp(loginfo->prefix, "") != 0) { - printf(" --log-prefix"); - xtables_save_string(loginfo->prefix); - } - - if (loginfo->level != LOG_DEFAULT_LEVEL) - printf(" --log-level %d", loginfo->level); - - if (loginfo->logflags & IPT_LOG_TCPSEQ) - printf(" --log-tcp-sequence"); - if (loginfo->logflags & IPT_LOG_TCPOPT) - printf(" --log-tcp-options"); - if (loginfo->logflags & IPT_LOG_IPOPT) - printf(" --log-ip-options"); - if (loginfo->logflags & IPT_LOG_UID) - printf(" --log-uid"); - if (loginfo->logflags & IPT_LOG_MACDECODE) - 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, - .family = NFPROTO_IPV4, - .size = XT_ALIGN(sizeof(struct ipt_log_info)), - .userspacesize = XT_ALIGN(sizeof(struct ipt_log_info)), - .help = LOG_help, - .init = LOG_init, - .print = LOG_print, - .save = LOG_save, - .x6_parse = LOG_parse, - .x6_options = LOG_opts, - .xlate = LOG_xlate, -}; - -void _init(void) -{ - xtables_register_target(&log_tg_reg); -} diff --git a/extensions/libipt_LOG.txlate b/extensions/libipt_LOG.txlate index 81f64fb2..13a2ef55 100644 --- a/extensions/libipt_LOG.txlate +++ b/extensions/libipt_LOG.txlate @@ -1,5 +1,5 @@ iptables-translate -A FORWARD -p tcp -j LOG --log-level error -nft add rule ip filter FORWARD ip protocol tcp counter log level err +nft 'add rule ip filter FORWARD ip protocol tcp counter log level err' iptables-translate -A FORWARD -p tcp -j LOG --log-prefix "Random prefix" -nft add rule ip filter FORWARD ip protocol tcp counter log prefix \"Random prefix\" +nft 'add rule ip filter FORWARD ip protocol tcp counter log prefix "Random prefix"' diff --git a/extensions/libipt_MASQUERADE.c b/extensions/libipt_MASQUERADE.c deleted file mode 100644 index 90bf6065..00000000 --- a/extensions/libipt_MASQUERADE.c +++ /dev/null @@ -1,190 +0,0 @@ -#include <stdio.h> -#include <netdb.h> -#include <string.h> -#include <stdlib.h> -#include <getopt.h> -#include <xtables.h> -#include <limits.h> /* INT_MAX in ip_tables.h */ -#include <linux/netfilter_ipv4/ip_tables.h> -#include <linux/netfilter/nf_nat.h> - -enum { - O_TO_PORTS = 0, - O_RANDOM, - O_RANDOM_FULLY, -}; - -static void MASQUERADE_help(void) -{ - printf( -"MASQUERADE target options:\n" -" --to-ports <port>[-<port>]\n" -" Port (range) to map to.\n" -" --random\n" -" Randomize source port.\n" -" --random-fully\n" -" Fully randomize source port.\n"); -} - -static const struct xt_option_entry MASQUERADE_opts[] = { - {.name = "to-ports", .id = O_TO_PORTS, .type = XTTYPE_STRING}, - {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE}, - {.name = "random-fully", .id = O_RANDOM_FULLY, .type = XTTYPE_NONE}, - XTOPT_TABLEEND, -}; - -static void MASQUERADE_init(struct xt_entry_target *t) -{ - struct nf_nat_ipv4_multi_range_compat *mr = (struct nf_nat_ipv4_multi_range_compat *)t->data; - - /* Actually, it's 0, but it's ignored at the moment. */ - mr->rangesize = 1; -} - -/* Parses ports */ -static void -parse_ports(const char *arg, struct nf_nat_ipv4_multi_range_compat *mr) -{ - char *end; - unsigned int port, maxport; - - mr->range[0].flags |= NF_NAT_RANGE_PROTO_SPECIFIED; - - if (!xtables_strtoui(arg, &end, &port, 0, UINT16_MAX)) - xtables_param_act(XTF_BAD_VALUE, "MASQUERADE", "--to-ports", arg); - - switch (*end) { - case '\0': - mr->range[0].min.tcp.port - = mr->range[0].max.tcp.port - = htons(port); - return; - case '-': - if (!xtables_strtoui(end + 1, NULL, &maxport, 0, UINT16_MAX)) - break; - - if (maxport < port) - break; - - mr->range[0].min.tcp.port = htons(port); - mr->range[0].max.tcp.port = htons(maxport); - return; - default: - break; - } - xtables_param_act(XTF_BAD_VALUE, "MASQUERADE", "--to-ports", arg); -} - -static void MASQUERADE_parse(struct xt_option_call *cb) -{ - const struct ipt_entry *entry = cb->xt_entry; - int portok; - struct nf_nat_ipv4_multi_range_compat *mr = cb->data; - - if (entry->ip.proto == IPPROTO_TCP - || entry->ip.proto == IPPROTO_UDP - || entry->ip.proto == IPPROTO_SCTP - || entry->ip.proto == IPPROTO_DCCP - || entry->ip.proto == IPPROTO_ICMP) - portok = 1; - else - portok = 0; - - xtables_option_parse(cb); - switch (cb->entry->id) { - case O_TO_PORTS: - if (!portok) - xtables_error(PARAMETER_PROBLEM, - "Need TCP, UDP, SCTP or DCCP with port specification"); - parse_ports(cb->arg, mr); - break; - case O_RANDOM: - mr->range[0].flags |= NF_NAT_RANGE_PROTO_RANDOM; - break; - case O_RANDOM_FULLY: - mr->range[0].flags |= NF_NAT_RANGE_PROTO_RANDOM_FULLY; - break; - } -} - -static void -MASQUERADE_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]; - - if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { - printf(" masq ports: "); - printf("%hu", ntohs(r->min.tcp.port)); - if (r->max.tcp.port != r->min.tcp.port) - printf("-%hu", ntohs(r->max.tcp.port)); - } - - if (r->flags & NF_NAT_RANGE_PROTO_RANDOM) - printf(" random"); - - if (r->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) - printf(" random-fully"); -} - -static void -MASQUERADE_save(const void *ip, const struct xt_entry_target *target) -{ - const struct nf_nat_ipv4_multi_range_compat *mr = (const void *)target->data; - const struct nf_nat_ipv4_range *r = &mr->range[0]; - - if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { - printf(" --to-ports %hu", ntohs(r->min.tcp.port)); - if (r->max.tcp.port != r->min.tcp.port) - printf("-%hu", ntohs(r->max.tcp.port)); - } - - if (r->flags & NF_NAT_RANGE_PROTO_RANDOM) - printf(" --random"); - - if (r->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) - printf(" --random-fully"); -} - -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, - .family = NFPROTO_IPV4, - .size = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), - .userspacesize = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), - .help = MASQUERADE_help, - .init = MASQUERADE_init, - .x6_parse = MASQUERADE_parse, - .print = MASQUERADE_print, - .save = MASQUERADE_save, - .x6_options = MASQUERADE_opts, - .xlate = MASQUERADE_xlate, -}; - -void _init(void) -{ - xtables_register_target(&masquerade_tg_reg); -} diff --git a/extensions/libipt_MASQUERADE.txlate b/extensions/libipt_MASQUERADE.txlate index 40b6958a..0293b05b 100644 --- a/extensions/libipt_MASQUERADE.txlate +++ b/extensions/libipt_MASQUERADE.txlate @@ -1,8 +1,17 @@ iptables-translate -t nat -A POSTROUTING -j MASQUERADE -nft add rule ip nat POSTROUTING counter masquerade +nft 'add rule ip nat POSTROUTING counter masquerade' iptables-translate -t nat -A POSTROUTING -p tcp -j MASQUERADE --to-ports 10 -nft add rule ip nat POSTROUTING ip protocol tcp counter masquerade to :10 +nft 'add rule ip nat POSTROUTING ip protocol tcp counter masquerade to :10' iptables-translate -t nat -A POSTROUTING -p tcp -j MASQUERADE --to-ports 10-20 --random -nft add rule ip nat POSTROUTING ip protocol tcp counter masquerade to :10-20 random +nft 'add rule ip nat POSTROUTING ip protocol tcp counter masquerade to :10-20 random' + +iptables-translate -t nat -A POSTROUTING -p tcp -j MASQUERADE --random +nft 'add rule ip nat POSTROUTING ip protocol tcp counter masquerade random' + +iptables-translate -t nat -A POSTROUTING -p tcp -j MASQUERADE --random-fully +nft 'add rule ip nat POSTROUTING ip protocol tcp counter masquerade fully-random' + +iptables-translate -t nat -A POSTROUTING -p tcp -j MASQUERADE --random --random-fully +nft 'add rule ip nat POSTROUTING ip protocol tcp counter masquerade random,fully-random' diff --git a/extensions/libipt_NETMAP.t b/extensions/libipt_NETMAP.t index 31924b98..0de856f0 100644 --- a/extensions/libipt_NETMAP.t +++ b/extensions/libipt_NETMAP.t @@ -1,4 +1,4 @@ :PREROUTING,INPUT,OUTPUT,POSTROUTING *nat -j NETMAP --to 1.2.3.0/24;=;OK --j NETMAP --to 1.2.3.4;=;OK +-j NETMAP --to 1.2.3.4;-j NETMAP --to 1.2.3.4/32;OK diff --git a/extensions/libipt_REDIRECT.c b/extensions/libipt_REDIRECT.c deleted file mode 100644 index 7850306f..00000000 --- a/extensions/libipt_REDIRECT.c +++ /dev/null @@ -1,174 +0,0 @@ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <xtables.h> -#include <limits.h> /* INT_MAX in ip_tables.h */ -#include <linux/netfilter_ipv4/ip_tables.h> -#include <linux/netfilter/nf_nat.h> - -enum { - O_TO_PORTS = 0, - O_RANDOM, - F_TO_PORTS = 1 << O_TO_PORTS, - F_RANDOM = 1 << O_RANDOM, -}; - -static void REDIRECT_help(void) -{ - printf( -"REDIRECT target options:\n" -" --to-ports <port>[-<port>]\n" -" Port (range) to map to.\n" -" [--random]\n"); -} - -static const struct xt_option_entry REDIRECT_opts[] = { - {.name = "to-ports", .id = O_TO_PORTS, .type = XTTYPE_STRING}, - {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE}, - XTOPT_TABLEEND, -}; - -static void REDIRECT_init(struct xt_entry_target *t) -{ - struct nf_nat_ipv4_multi_range_compat *mr = (struct nf_nat_ipv4_multi_range_compat *)t->data; - - /* Actually, it's 0, but it's ignored at the moment. */ - mr->rangesize = 1; -} - -/* Parses ports */ -static void -parse_ports(const char *arg, struct nf_nat_ipv4_multi_range_compat *mr) -{ - char *end = ""; - unsigned int port, maxport; - - mr->range[0].flags |= NF_NAT_RANGE_PROTO_SPECIFIED; - - if (!xtables_strtoui(arg, &end, &port, 0, UINT16_MAX) && - (port = xtables_service_to_port(arg, NULL)) == (unsigned)-1) - xtables_param_act(XTF_BAD_VALUE, "REDIRECT", "--to-ports", arg); - - switch (*end) { - case '\0': - mr->range[0].min.tcp.port - = mr->range[0].max.tcp.port - = htons(port); - return; - case '-': - if (!xtables_strtoui(end + 1, NULL, &maxport, 0, UINT16_MAX) && - (maxport = xtables_service_to_port(end + 1, NULL)) == (unsigned)-1) - break; - - if (maxport < port) - break; - - mr->range[0].min.tcp.port = htons(port); - mr->range[0].max.tcp.port = htons(maxport); - return; - default: - break; - } - xtables_param_act(XTF_BAD_VALUE, "REDIRECT", "--to-ports", arg); -} - -static void REDIRECT_parse(struct xt_option_call *cb) -{ - const struct ipt_entry *entry = cb->xt_entry; - struct nf_nat_ipv4_multi_range_compat *mr = (void *)(*cb->target)->data; - int portok; - - if (entry->ip.proto == IPPROTO_TCP - || entry->ip.proto == IPPROTO_UDP - || entry->ip.proto == IPPROTO_SCTP - || entry->ip.proto == IPPROTO_DCCP - || entry->ip.proto == IPPROTO_ICMP) - portok = 1; - else - portok = 0; - - xtables_option_parse(cb); - switch (cb->entry->id) { - case O_TO_PORTS: - if (!portok) - xtables_error(PARAMETER_PROBLEM, - "Need TCP, UDP, SCTP or DCCP with port specification"); - parse_ports(cb->arg, mr); - if (cb->xflags & F_RANDOM) - mr->range[0].flags |= NF_NAT_RANGE_PROTO_RANDOM; - break; - case O_RANDOM: - if (cb->xflags & F_TO_PORTS) - mr->range[0].flags |= NF_NAT_RANGE_PROTO_RANDOM; - break; - } -} - -static void REDIRECT_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]; - - if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { - printf(" redir ports "); - printf("%hu", ntohs(r->min.tcp.port)); - if (r->max.tcp.port != r->min.tcp.port) - printf("-%hu", ntohs(r->max.tcp.port)); - if (mr->range[0].flags & NF_NAT_RANGE_PROTO_RANDOM) - printf(" random"); - } -} - -static void REDIRECT_save(const void *ip, const struct xt_entry_target *target) -{ - const struct nf_nat_ipv4_multi_range_compat *mr = (const void *)target->data; - const struct nf_nat_ipv4_range *r = &mr->range[0]; - - if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { - printf(" --to-ports "); - printf("%hu", ntohs(r->min.tcp.port)); - if (r->max.tcp.port != r->min.tcp.port) - printf("-%hu", ntohs(r->max.tcp.port)); - if (mr->range[0].flags & NF_NAT_RANGE_PROTO_RANDOM) - printf(" --random"); - } -} - -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, - .family = NFPROTO_IPV4, - .size = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), - .userspacesize = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), - .help = REDIRECT_help, - .init = REDIRECT_init, - .x6_parse = REDIRECT_parse, - .print = REDIRECT_print, - .save = REDIRECT_save, - .x6_options = REDIRECT_opts, - .xlate = REDIRECT_xlate, -}; - -void _init(void) -{ - xtables_register_target(&redirect_tg_reg); -} diff --git a/extensions/libipt_REDIRECT.t b/extensions/libipt_REDIRECT.t deleted file mode 100644 index a0fb0ed1..00000000 --- a/extensions/libipt_REDIRECT.t +++ /dev/null @@ -1,6 +0,0 @@ -: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_REDIRECT.txlate b/extensions/libipt_REDIRECT.txlate deleted file mode 100644 index 815bb771..00000000 --- a/extensions/libipt_REDIRECT.txlate +++ /dev/null @@ -1,5 +0,0 @@ -iptables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 8080 -nft add rule ip nat prerouting tcp dport 80 counter redirect to :8080 - -iptables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 8080 --random -nft add rule ip nat prerouting tcp dport 80 counter redirect to :8080 random diff --git a/extensions/libipt_REJECT.t b/extensions/libipt_REJECT.t index 5b26b107..3f69a729 100644 --- a/extensions/libipt_REJECT.t +++ b/extensions/libipt_REJECT.t @@ -1,5 +1,5 @@ :INPUT,FORWARD,OUTPUT --j REJECT;=;OK +-j REJECT;-j REJECT --reject-with icmp-port-unreachable;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 diff --git a/extensions/libipt_REJECT.txlate b/extensions/libipt_REJECT.txlate index a1bfb5f4..022166a6 100644 --- a/extensions/libipt_REJECT.txlate +++ b/extensions/libipt_REJECT.txlate @@ -1,8 +1,8 @@ iptables-translate -A FORWARD -p TCP --dport 22 -j REJECT -nft add rule ip filter FORWARD tcp dport 22 counter reject +nft 'add rule ip filter FORWARD tcp dport 22 counter reject' iptables-translate -A FORWARD -p TCP --dport 22 -j REJECT --reject-with icmp-net-unreachable -nft add rule ip filter FORWARD tcp dport 22 counter reject with icmp type net-unreachable +nft 'add rule ip filter FORWARD tcp dport 22 counter reject with icmp type net-unreachable' iptables-translate -A FORWARD -p TCP --dport 22 -j REJECT --reject-with tcp-reset -nft add rule ip filter FORWARD tcp dport 22 counter reject with tcp reset +nft 'add rule ip filter FORWARD tcp dport 22 counter reject with tcp reset' diff --git a/extensions/libipt_SNAT.c b/extensions/libipt_SNAT.c deleted file mode 100644 index c655439e..00000000 --- a/extensions/libipt_SNAT.c +++ /dev/null @@ -1,323 +0,0 @@ -#include <stdio.h> -#include <netdb.h> -#include <string.h> -#include <stdlib.h> -#include <xtables.h> -#include <iptables.h> -#include <limits.h> /* INT_MAX in ip_tables.h */ -#include <linux/netfilter_ipv4/ip_tables.h> -#include <linux/netfilter/nf_nat.h> - -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_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 - to. */ -struct ipt_natinfo -{ - struct xt_entry_target t; - struct nf_nat_ipv4_multi_range_compat mr; -}; - -static void SNAT_help(void) -{ - printf( -"SNAT target options:\n" -" --to-source [<ipaddr>[-<ipaddr>]][:port[-port]]\n" -" Address to map source to.\n" -"[--random] [--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, -}; - -static struct ipt_natinfo * -append_range(struct ipt_natinfo *info, const struct nf_nat_ipv4_range *range) -{ - unsigned int size; - - /* One rangesize already in struct ipt_natinfo */ - size = XT_ALIGN(sizeof(*info) + info->mr.rangesize * sizeof(*range)); - - info = realloc(info, size); - if (!info) - xtables_error(OTHER_PROBLEM, "Out of memory\n"); - - info->t.u.target_size = size; - info->mr.range[info->mr.rangesize] = *range; - info->mr.rangesize++; - - return info; -} - -/* Ranges expected in network order. */ -static struct xt_entry_target * -parse_to(const char *orig_arg, int portok, struct ipt_natinfo *info) -{ - struct nf_nat_ipv4_range range; - char *arg, *colon, *dash, *error; - const struct in_addr *ip; - - arg = xtables_strdup(orig_arg); - memset(&range, 0, sizeof(range)); - colon = strchr(arg, ':'); - - if (colon) { - int port; - - if (!portok) - xtables_error(PARAMETER_PROBLEM, - "Need TCP, UDP, SCTP or DCCP with port specification"); - - range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED; - - port = atoi(colon+1); - if (port <= 0 || port > 65535) - xtables_error(PARAMETER_PROBLEM, - "Port `%s' not valid\n", colon+1); - - error = strchr(colon+1, ':'); - if (error) - xtables_error(PARAMETER_PROBLEM, - "Invalid port:port syntax - use dash\n"); - - dash = strchr(colon, '-'); - if (!dash) { - range.min.tcp.port - = range.max.tcp.port - = htons(port); - } else { - int maxport; - - maxport = atoi(dash + 1); - if (maxport <= 0 || maxport > 65535) - xtables_error(PARAMETER_PROBLEM, - "Port `%s' not valid\n", dash+1); - if (maxport < port) - /* People are stupid. */ - xtables_error(PARAMETER_PROBLEM, - "Port range `%s' funky\n", colon+1); - range.min.tcp.port = htons(port); - range.max.tcp.port = htons(maxport); - } - /* Starts with a colon? No IP info...*/ - if (colon == arg) { - free(arg); - return &(append_range(info, &range)->t); - } - *colon = '\0'; - } - - range.flags |= NF_NAT_RANGE_MAP_IPS; - dash = strchr(arg, '-'); - if (colon && dash && dash > colon) - dash = NULL; - - if (dash) - *dash = '\0'; - - ip = xtables_numeric_to_ipaddr(arg); - if (!ip) - xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n", - arg); - range.min_ip = ip->s_addr; - if (dash) { - ip = xtables_numeric_to_ipaddr(dash+1); - if (!ip) - xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n", - dash+1); - range.max_ip = ip->s_addr; - } else - range.max_ip = range.min_ip; - - free(arg); - return &(append_range(info, &range)->t); -} - -static void SNAT_parse(struct xt_option_call *cb) -{ - const struct ipt_entry *entry = cb->xt_entry; - struct ipt_natinfo *info = (void *)(*cb->target); - int portok; - - if (entry->ip.proto == IPPROTO_TCP - || entry->ip.proto == IPPROTO_UDP - || entry->ip.proto == IPPROTO_SCTP - || entry->ip.proto == IPPROTO_DCCP - || entry->ip.proto == IPPROTO_ICMP) - portok = 1; - else - portok = 0; - - xtables_option_parse(cb); - switch (cb->entry->id) { - case O_TO_SRC: - if (cb->xflags & F_X_TO_SRC) { - if (!kernel_version) - get_kernel_version(); - if (kernel_version > LINUX_VERSION(2, 6, 10)) - xtables_error(PARAMETER_PROBLEM, - "SNAT: Multiple --to-source not supported"); - } - *cb->target = parse_to(cb->arg, portok, info); - cb->xflags |= F_X_TO_SRC; - break; - case O_PERSISTENT: - info->mr.range[0].flags |= NF_NAT_RANGE_PERSISTENT; - break; - } -} - -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) -{ - if (r->flags & NF_NAT_RANGE_MAP_IPS) { - struct in_addr a; - - a.s_addr = r->min_ip; - printf("%s", xtables_ipaddr_to_numeric(&a)); - if (r->max_ip != r->min_ip) { - a.s_addr = r->max_ip; - printf("-%s", xtables_ipaddr_to_numeric(&a)); - } - } - if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { - printf(":"); - printf("%hu", ntohs(r->min.tcp.port)); - if (r->max.tcp.port != r->min.tcp.port) - printf("-%hu", ntohs(r->max.tcp.port)); - } -} - -static void SNAT_print(const void *ip, const struct xt_entry_target *target, - int numeric) -{ - const struct ipt_natinfo *info = (const void *)target; - unsigned int i = 0; - - printf(" to:"); - for (i = 0; i < info->mr.rangesize; i++) { - 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 SNAT_save(const void *ip, const struct xt_entry_target *target) -{ - const struct ipt_natinfo *info = (const void *)target; - unsigned int i = 0; - - for (i = 0; i < info->mr.rangesize; i++) { - printf(" --to-source "); - 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, - .family = NFPROTO_IPV4, - .size = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), - .userspacesize = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), - .help = SNAT_help, - .x6_parse = SNAT_parse, - .x6_fcheck = SNAT_fcheck, - .print = SNAT_print, - .save = SNAT_save, - .x6_options = SNAT_opts, - .xlate = SNAT_xlate, -}; - -void _init(void) -{ - xtables_register_target(&snat_tg_reg); -} diff --git a/extensions/libipt_SNAT.t b/extensions/libipt_SNAT.t index 186e1cb8..c31d6e7c 100644 --- a/extensions/libipt_SNAT.t +++ b/extensions/libipt_SNAT.t @@ -4,6 +4,12 @@ -j SNAT --to-source 1.1.1.1-1.1.1.10;=;OK -j SNAT --to-source 1.1.1.1:1025-65535;;FAIL -j SNAT --to-source 1.1.1.1 --to-source 2.2.2.2;;FAIL +-j SNAT --to-source 1.1.1.1 --random;=;OK +-j SNAT --to-source 1.1.1.1 --random-fully;=;OK +-j SNAT --to-source 1.1.1.1 --persistent;=;OK +-j SNAT --to-source 1.1.1.1 --random --persistent;=;OK +-j SNAT --to-source 1.1.1.1 --random --random-fully;=;OK +-j SNAT --to-source 1.1.1.1 --random --random-fully --persistent;=;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 diff --git a/extensions/libipt_SNAT.txlate b/extensions/libipt_SNAT.txlate index 01592fad..83afef95 100644 --- a/extensions/libipt_SNAT.txlate +++ b/extensions/libipt_SNAT.txlate @@ -1,14 +1,14 @@ iptables-translate -t nat -A postrouting -o eth0 -j SNAT --to 1.2.3.4 -nft add rule ip nat postrouting oifname "eth0" counter snat to 1.2.3.4 +nft 'add rule ip nat postrouting oifname "eth0" counter snat to 1.2.3.4' iptables-translate -t nat -A postrouting -o eth0 -j SNAT --to 1.2.3.4-1.2.3.6 -nft add rule ip nat postrouting oifname "eth0" counter snat to 1.2.3.4-1.2.3.6 +nft 'add rule ip nat postrouting oifname "eth0" counter snat to 1.2.3.4-1.2.3.6' iptables-translate -t nat -A postrouting -p tcp -o eth0 -j SNAT --to 1.2.3.4:1-1023 -nft add rule ip nat postrouting oifname "eth0" ip protocol tcp counter snat to 1.2.3.4:1-1023 +nft 'add rule ip nat postrouting oifname "eth0" ip protocol tcp counter snat to 1.2.3.4:1-1023' iptables-translate -t nat -A postrouting -o eth0 -j SNAT --to 1.2.3.4 --random -nft add rule ip nat postrouting oifname "eth0" counter snat to 1.2.3.4 random +nft 'add rule ip nat postrouting oifname "eth0" counter snat to 1.2.3.4 random' iptables-translate -t nat -A postrouting -o eth0 -j SNAT --to 1.2.3.4 --random --persistent -nft add rule ip nat postrouting oifname "eth0" counter snat to 1.2.3.4 random,persistent +nft 'add rule ip nat postrouting oifname "eth0" counter snat to 1.2.3.4 random,persistent' diff --git a/extensions/libipt_ah.txlate b/extensions/libipt_ah.txlate index ea3ef3e9..897c82b5 100644 --- a/extensions/libipt_ah.txlate +++ b/extensions/libipt_ah.txlate @@ -1,8 +1,8 @@ iptables-translate -A INPUT -p 51 -m ah --ahspi 500 -j DROP -nft add rule ip filter INPUT ah spi 500 counter drop +nft 'add rule ip filter INPUT ah spi 500 counter drop' iptables-translate -A INPUT -p 51 -m ah --ahspi 500:600 -j DROP -nft add rule ip filter INPUT ah spi 500-600 counter drop +nft 'add rule ip filter INPUT ah spi 500-600 counter drop' iptables-translate -A INPUT -p 51 -m ah ! --ahspi 50 -j DROP -nft add rule ip filter INPUT ah spi != 50 counter drop +nft 'add rule ip filter INPUT ah spi != 50 counter drop' diff --git a/extensions/libipt_icmp.c b/extensions/libipt_icmp.c index e5e23661..b0318aeb 100644 --- a/extensions/libipt_icmp.c +++ b/extensions/libipt_icmp.c @@ -19,61 +19,6 @@ enum { O_ICMP_TYPE = 0, }; -static const struct xt_icmp_names icmp_codes[] = { - { "any", 0xFF, 0, 0xFF }, - { "echo-reply", 0, 0, 0xFF }, - /* Alias */ { "pong", 0, 0, 0xFF }, - - { "destination-unreachable", 3, 0, 0xFF }, - { "network-unreachable", 3, 0, 0 }, - { "host-unreachable", 3, 1, 1 }, - { "protocol-unreachable", 3, 2, 2 }, - { "port-unreachable", 3, 3, 3 }, - { "fragmentation-needed", 3, 4, 4 }, - { "source-route-failed", 3, 5, 5 }, - { "network-unknown", 3, 6, 6 }, - { "host-unknown", 3, 7, 7 }, - { "network-prohibited", 3, 9, 9 }, - { "host-prohibited", 3, 10, 10 }, - { "TOS-network-unreachable", 3, 11, 11 }, - { "TOS-host-unreachable", 3, 12, 12 }, - { "communication-prohibited", 3, 13, 13 }, - { "host-precedence-violation", 3, 14, 14 }, - { "precedence-cutoff", 3, 15, 15 }, - - { "source-quench", 4, 0, 0xFF }, - - { "redirect", 5, 0, 0xFF }, - { "network-redirect", 5, 0, 0 }, - { "host-redirect", 5, 1, 1 }, - { "TOS-network-redirect", 5, 2, 2 }, - { "TOS-host-redirect", 5, 3, 3 }, - - { "echo-request", 8, 0, 0xFF }, - /* Alias */ { "ping", 8, 0, 0xFF }, - - { "router-advertisement", 9, 0, 0xFF }, - - { "router-solicitation", 10, 0, 0xFF }, - - { "time-exceeded", 11, 0, 0xFF }, - /* Alias */ { "ttl-exceeded", 11, 0, 0xFF }, - { "ttl-zero-during-transit", 11, 0, 0 }, - { "ttl-zero-during-reassembly", 11, 1, 1 }, - - { "parameter-problem", 12, 0, 0xFF }, - { "ip-header-bad", 12, 0, 0 }, - { "required-option-missing", 12, 1, 1 }, - - { "timestamp-request", 13, 0, 0xFF }, - - { "timestamp-reply", 14, 0, 0xFF }, - - { "address-mask-request", 17, 0, 0xFF }, - - { "address-mask-reply", 18, 0, 0xFF } -}; - static void icmp_help(void) { printf( @@ -90,59 +35,6 @@ static const struct xt_option_entry icmp_opts[] = { XTOPT_TABLEEND, }; -static void -parse_icmp(const char *icmptype, uint8_t *type, uint8_t code[]) -{ - static const unsigned int limit = ARRAY_SIZE(icmp_codes); - unsigned int match = limit; - unsigned int i; - - for (i = 0; i < limit; i++) { - if (strncasecmp(icmp_codes[i].name, icmptype, strlen(icmptype)) - == 0) { - if (match != limit) - xtables_error(PARAMETER_PROBLEM, - "Ambiguous ICMP type `%s':" - " `%s' or `%s'?", - icmptype, - icmp_codes[match].name, - icmp_codes[i].name); - match = i; - } - } - - if (match != limit) { - *type = icmp_codes[match].type; - code[0] = icmp_codes[match].code_min; - code[1] = icmp_codes[match].code_max; - } else { - char *slash; - char buffer[strlen(icmptype) + 1]; - unsigned int number; - - strcpy(buffer, icmptype); - slash = strchr(buffer, '/'); - - if (slash) - *slash = '\0'; - - if (!xtables_strtoui(buffer, NULL, &number, 0, UINT8_MAX)) - xtables_error(PARAMETER_PROBLEM, - "Invalid ICMP type `%s'\n", buffer); - *type = number; - if (slash) { - if (!xtables_strtoui(slash+1, NULL, &number, 0, UINT8_MAX)) - xtables_error(PARAMETER_PROBLEM, - "Invalid ICMP code `%s'\n", - slash+1); - code[0] = code[1] = number; - } else { - code[0] = 0; - code[1] = 0xFF; - } - } -} - static void icmp_init(struct xt_entry_match *m) { struct ipt_icmp *icmpinfo = (struct ipt_icmp *)m->data; @@ -156,7 +48,7 @@ static void icmp_parse(struct xt_option_call *cb) struct ipt_icmp *icmpinfo = cb->data; xtables_option_parse(cb); - parse_icmp(cb->arg, &icmpinfo->type, icmpinfo->code); + ipt_parse_icmp(cb->arg, &icmpinfo->type, icmpinfo->code); if (cb->invert) icmpinfo->invflags |= IPT_ICMP_INV; } diff --git a/extensions/libipt_icmp.txlate b/extensions/libipt_icmp.txlate index a2aec8e2..e7208d8b 100644 --- a/extensions/libipt_icmp.txlate +++ b/extensions/libipt_icmp.txlate @@ -1,11 +1,11 @@ iptables-translate -t filter -A INPUT -m icmp --icmp-type echo-reply -j ACCEPT -nft add rule ip filter INPUT icmp type echo-reply counter accept +nft 'add rule ip filter INPUT icmp type echo-reply counter accept' iptables-translate -t filter -A INPUT -m icmp --icmp-type 3 -j ACCEPT -nft add rule ip filter INPUT icmp type destination-unreachable counter accept +nft 'add rule ip filter INPUT icmp type destination-unreachable counter accept' iptables-translate -t filter -A INPUT -m icmp ! --icmp-type 3 -j ACCEPT -nft add rule ip filter INPUT icmp type != destination-unreachable counter accept +nft 'add rule ip filter INPUT icmp type != destination-unreachable counter accept' iptables-translate -t filter -A INPUT -m icmp --icmp-type any -j ACCEPT -nft add rule ip filter INPUT ip protocol icmp counter accept +nft 'add rule ip filter INPUT ip protocol icmp counter accept' diff --git a/extensions/libipt_realm.txlate b/extensions/libipt_realm.txlate index 7d710294..6d134546 100644 --- a/extensions/libipt_realm.txlate +++ b/extensions/libipt_realm.txlate @@ -1,11 +1,11 @@ iptables-translate -A PREROUTING -m realm --realm 4 -nft add rule ip filter PREROUTING rtclassid 0x4 counter +nft 'add rule ip filter PREROUTING rtclassid 0x4 counter' iptables-translate -A PREROUTING -m realm --realm 5/5 -nft add rule ip filter PREROUTING rtclassid and 0x5 == 0x5 counter +nft 'add rule ip filter PREROUTING rtclassid and 0x5 == 0x5 counter' iptables-translate -A PREROUTING -m realm ! --realm 50 -nft add rule ip filter PREROUTING rtclassid != 0x32 counter +nft 'add rule ip filter PREROUTING rtclassid != 0x32 counter' iptables-translate -A INPUT -m realm --realm 1/0xf -nft add rule ip filter INPUT rtclassid and 0xf == 0x1 counter +nft 'add rule ip filter INPUT rtclassid and 0xf == 0x1 counter' diff --git a/extensions/libipt_ttl.c b/extensions/libipt_ttl.c index 6bdd2196..86ba554e 100644 --- a/extensions/libipt_ttl.c +++ b/extensions/libipt_ttl.c @@ -106,7 +106,7 @@ static int ttl_xlate(struct xt_xlate *xl, const struct ipt_ttl_info *info = (struct ipt_ttl_info *) params->match->data; - switch (info->mode) { + switch (info->mode) { case IPT_TTL_EQ: xt_xlate_add(xl, "ip ttl"); break; @@ -121,7 +121,7 @@ static int ttl_xlate(struct xt_xlate *xl, break; default: /* Should not happen. */ - break; + return 0; } xt_xlate_add(xl, " %u", info->ttl); diff --git a/extensions/libipt_ttl.txlate b/extensions/libipt_ttl.txlate index 3d5d6a70..6b90ff99 100644 --- a/extensions/libipt_ttl.txlate +++ b/extensions/libipt_ttl.txlate @@ -1,5 +1,5 @@ iptables-translate -A INPUT -m ttl --ttl-eq 3 -j ACCEPT -nft add rule ip filter INPUT ip ttl 3 counter accept +nft 'add rule ip filter INPUT ip ttl 3 counter accept' iptables-translate -A INPUT -m ttl --ttl-gt 5 -j ACCEPT -nft add rule ip filter INPUT ip ttl gt 5 counter accept +nft 'add rule ip filter INPUT ip ttl gt 5 counter accept' diff --git a/extensions/libxt_AUDIT.txlate b/extensions/libxt_AUDIT.txlate index abd11eae..c1650b9a 100644 --- a/extensions/libxt_AUDIT.txlate +++ b/extensions/libxt_AUDIT.txlate @@ -1,8 +1,8 @@ iptables-translate -t filter -A INPUT -j AUDIT --type accept -nft add rule ip filter INPUT counter log level audit +nft 'add rule ip filter INPUT counter log level audit' iptables-translate -t filter -A INPUT -j AUDIT --type drop -nft add rule ip filter INPUT counter log level audit +nft 'add rule ip filter INPUT counter log level audit' iptables-translate -t filter -A INPUT -j AUDIT --type reject -nft add rule ip filter INPUT counter log level audit +nft 'add rule ip filter INPUT counter log level audit' diff --git a/extensions/libxt_CLASSIFY.txlate b/extensions/libxt_CLASSIFY.txlate index 3b349237..3150c69e 100644 --- a/extensions/libxt_CLASSIFY.txlate +++ b/extensions/libxt_CLASSIFY.txlate @@ -1,8 +1,8 @@ iptables-translate -A OUTPUT -j CLASSIFY --set-class 0:0 -nft add rule ip filter OUTPUT counter meta priority set none +nft 'add rule ip filter OUTPUT counter meta priority set none' iptables-translate -A OUTPUT -j CLASSIFY --set-class ffff:ffff -nft add rule ip filter OUTPUT counter meta priority set root +nft 'add rule ip filter OUTPUT counter meta priority set root' iptables-translate -A OUTPUT -j CLASSIFY --set-class 1:234 -nft add rule ip filter OUTPUT counter meta priority set 1:234 +nft 'add rule ip filter OUTPUT counter meta priority set 1:234' diff --git a/extensions/libxt_CONNMARK.c b/extensions/libxt_CONNMARK.c index 21e10913..a6568c99 100644 --- a/extensions/libxt_CONNMARK.c +++ b/extensions/libxt_CONNMARK.c @@ -595,11 +595,11 @@ static int connmark_tg_xlate_v2(struct xt_xlate *xl, { const struct xt_connmark_tginfo2 *info = (const void *)params->target->data; - const char *shift_op = xt_connmark_shift_ops[info->shift_dir]; + const char *braces = info->shift_bits ? "( " : ""; switch (info->mode) { case XT_CONNMARK_SET: - xt_xlate_add(xl, "ct mark set "); + xt_xlate_add(xl, "ct mark set %s", braces); if (info->ctmask == 0xFFFFFFFFU) xt_xlate_add(xl, "0x%x ", info->ctmark); else if (info->ctmark == 0) @@ -615,26 +615,31 @@ static int connmark_tg_xlate_v2(struct xt_xlate *xl, info->ctmark, ~info->ctmask); break; case XT_CONNMARK_SAVE: - xt_xlate_add(xl, "ct mark set mark"); + xt_xlate_add(xl, "ct mark set %smark", braces); if (!(info->nfmask == UINT32_MAX && info->ctmask == UINT32_MAX)) { if (info->nfmask == info->ctmask) xt_xlate_add(xl, " and 0x%x", info->nfmask); + else + return 0; } break; case XT_CONNMARK_RESTORE: - xt_xlate_add(xl, "meta mark set ct mark"); + xt_xlate_add(xl, "meta mark set %sct mark", braces); if (!(info->nfmask == UINT32_MAX && info->ctmask == UINT32_MAX)) { if (info->nfmask == info->ctmask) xt_xlate_add(xl, " and 0x%x", info->nfmask); + else + return 0; } break; } if (info->mode <= XT_CONNMARK_RESTORE && info->shift_bits != 0) { - xt_xlate_add(xl, " %s %u", shift_op, info->shift_bits); + xt_xlate_add(xl, " ) %s %u", + info->shift_dir ? ">>" : "<<", info->shift_bits); } return 1; diff --git a/extensions/libxt_CONNMARK.t b/extensions/libxt_CONNMARK.t index 79a838fe..c9b2b4a5 100644 --- a/extensions/libxt_CONNMARK.t +++ b/extensions/libxt_CONNMARK.t @@ -1,7 +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 --restore-mark;-j CONNMARK --restore-mark --nfmask 0xffffffff --ctmask 0xffffffff;OK +-j CONNMARK --save-mark;-j CONNMARK --save-mark --nfmask 0xffffffff --ctmask 0xffffffff;OK +-j CONNMARK --save-mark --nfmask 0xfffffff --ctmask 0xffffffff;=;OK +-j CONNMARK --restore-mark --nfmask 0xfffffff --ctmask 0xffffffff;=;OK -j CONNMARK;;FAIL diff --git a/extensions/libxt_CONNMARK.txlate b/extensions/libxt_CONNMARK.txlate index ce40ae5e..5da4d6c7 100644 --- a/extensions/libxt_CONNMARK.txlate +++ b/extensions/libxt_CONNMARK.txlate @@ -1,20 +1,23 @@ iptables-translate -t mangle -A PREROUTING -j CONNMARK --set-mark 0 -nft add rule ip mangle PREROUTING counter ct mark set 0x0 +nft 'add rule ip mangle PREROUTING counter ct mark set 0x0' iptables-translate -t mangle -A PREROUTING -j CONNMARK --set-mark 0x16 -nft add rule ip mangle PREROUTING counter ct mark set 0x16 +nft 'add rule ip mangle PREROUTING counter ct mark set 0x16' iptables-translate -t mangle -A PREROUTING -j CONNMARK --set-xmark 0x16/0x12 -nft add rule ip mangle PREROUTING counter ct mark set ct mark xor 0x16 and 0xffffffed +nft 'add rule ip mangle PREROUTING counter ct mark set ct mark xor 0x16 and 0xffffffed' iptables-translate -t mangle -A PREROUTING -j CONNMARK --and-mark 0x16 -nft add rule ip mangle PREROUTING counter ct mark set ct mark and 0x16 +nft 'add rule ip mangle PREROUTING counter ct mark set ct mark and 0x16' iptables-translate -t mangle -A PREROUTING -j CONNMARK --or-mark 0x16 -nft add rule ip mangle PREROUTING counter ct mark set ct mark or 0x16 +nft 'add rule ip mangle PREROUTING counter ct mark set ct mark or 0x16' iptables-translate -t mangle -A PREROUTING -j CONNMARK --save-mark -nft add rule ip mangle PREROUTING counter ct mark set mark +nft 'add rule ip mangle PREROUTING counter ct mark set mark' iptables-translate -t mangle -A PREROUTING -j CONNMARK --restore-mark -nft add rule ip mangle PREROUTING counter meta mark set ct mark +nft 'add rule ip mangle PREROUTING counter meta mark set ct mark' + +iptables-translate -t mangle -A PREROUTING -j CONNMARK --set-mark 0x23/0x42 --right-shift-mark 5 +nft 'add rule ip mangle PREROUTING counter ct mark set ( ct mark xor 0x23 and 0xffffff9c ) >> 5' diff --git a/extensions/libxt_CONNSECMARK.c b/extensions/libxt_CONNSECMARK.c index 0b3cd79d..6da589d3 100644 --- a/extensions/libxt_CONNSECMARK.c +++ b/extensions/libxt_CONNSECMARK.c @@ -66,7 +66,8 @@ static void print_connsecmark(const struct xt_connsecmark_target_info *info) break; default: - xtables_error(OTHER_PROBLEM, PFX "invalid mode %hhu\n", info->mode); + xtables_error(OTHER_PROBLEM, + PFX "invalid mode %hhu", info->mode); } } diff --git a/extensions/libxt_CT.c b/extensions/libxt_CT.c index fbbbe266..18824665 100644 --- a/extensions/libxt_CT.c +++ b/extensions/libxt_CT.c @@ -117,7 +117,7 @@ static void ct_parse_zone_id(const char *opt, unsigned int opt_id, if (!xtables_strtoul(opt, NULL, &val, 0, UINT16_MAX)) xtables_error(PARAMETER_PROBLEM, - "Cannot parse %s as a zone ID\n", opt); + "Cannot parse %s as a zone ID", opt); *zone_id = (uint16_t)val; } diff --git a/extensions/libxt_DNAT.man b/extensions/libxt_DNAT.man index 225274ff..af9a3f06 100644 --- a/extensions/libxt_DNAT.man +++ b/extensions/libxt_DNAT.man @@ -10,7 +10,7 @@ should be modified (and all future packets in this connection will also be mangled), and rules should cease being examined. It takes the following options: .TP -\fB\-\-to\-destination\fP [\fIipaddr\fP[\fB\-\fP\fIipaddr\fP]][\fB:\fP\fIport\fP[\fB\-\fP\fIport\fP]] +\fB\-\-to\-destination\fP [\fIipaddr\fP[\fB\-\fP\fIipaddr\fP]][\fB:\fP\fIport\fP[\fB\-\fP\fIport\fP[\fB/\fIbaseport\fP]]] which can specify a single new destination IP address, an inclusive range of IP addresses. Optionally a port range, if the rule also specifies one of the following protocols: @@ -18,17 +18,14 @@ if the rule also specifies one of the following protocols: If no port range is specified, then the destination port will never be modified. If no IP address is specified then only the destination port will be modified. -In Kernels up to 2.6.10 you can add several \-\-to\-destination options. For -those kernels, if you specify more than one destination address, either via an -address range or multiple \-\-to\-destination options, a simple round-robin (one -after another in cycle) load balancing takes place between these addresses. -Later Kernels (>= 2.6.11-rc1) don't have the ability to NAT to multiple ranges -anymore. +If \fBbaseport\fP is given, the difference of the original destination port and +its value is used as offset into the mapping port range. This allows to create +shifted portmap ranges and is available since kernel version 4.18. +For a single port or \fIbaseport\fP, a service name as listed in +\fB/etc/services\fP may be used. .TP \fB\-\-random\fP -If option -\fB\-\-random\fP -is used then port mapping will be randomized (kernel >= 2.6.22). +Randomize source port mapping (kernel >= 2.6.22). .TP \fB\-\-persistent\fP Gives a client the same source-/destination-address for each connection. diff --git a/extensions/libxt_DNAT.txlate b/extensions/libxt_DNAT.txlate new file mode 100644 index 00000000..e005245d --- /dev/null +++ b/extensions/libxt_DNAT.txlate @@ -0,0 +1,35 @@ +iptables-translate -t nat -A prerouting -p tcp -o eth0 -j DNAT --to-destination 1.2.3.4 +nft 'add rule ip nat prerouting oifname "eth0" ip protocol tcp counter dnat to 1.2.3.4' + +iptables-translate -t nat -A prerouting -p tcp -d 15.45.23.67 --dport 80 -j DNAT --to-destination 192.168.1.1-192.168.1.10 +nft 'add rule ip nat prerouting ip daddr 15.45.23.67 tcp dport 80 counter dnat to 192.168.1.1-192.168.1.10' + +iptables-translate -t nat -A prerouting -p tcp -o eth0 -j DNAT --to-destination 1.2.3.4:1-1023 +nft 'add rule ip nat prerouting oifname "eth0" ip protocol tcp counter dnat to 1.2.3.4:1-1023' + +iptables-translate -t nat -A prerouting -p tcp -o eth0 -j DNAT --to-destination 1.2.3.4 --random +nft 'add rule ip nat prerouting oifname "eth0" ip protocol tcp counter dnat to 1.2.3.4 random' + +iptables-translate -t nat -A prerouting -p tcp -o eth0 -j DNAT --to-destination 1.2.3.4 --random --persistent +nft 'add rule ip nat prerouting oifname "eth0" ip protocol tcp counter dnat to 1.2.3.4 random,persistent' + +ip6tables-translate -t nat -A prerouting -p tcp --dport 8080 -j DNAT --to-destination fec0::1234 +nft 'add rule ip6 nat prerouting tcp dport 8080 counter dnat to fec0::1234' + +ip6tables-translate -t nat -A prerouting -p tcp --dport 8080 -j DNAT --to-destination fec0::1234-fec0::2000 +nft 'add rule ip6 nat prerouting tcp dport 8080 counter dnat to fec0::1234-fec0::2000' + +ip6tables-translate -t nat -A prerouting -i eth1 -p tcp --dport 8080 -j DNAT --to-destination [fec0::1234]:80 +nft 'add rule ip6 nat prerouting iifname "eth1" tcp dport 8080 counter dnat to [fec0::1234]:80' + +ip6tables-translate -t nat -A prerouting -p tcp -j DNAT --to-destination [fec0::1234]:1-20 +nft 'add rule ip6 nat prerouting meta l4proto tcp counter dnat to [fec0::1234]:1-20' + +ip6tables-translate -t nat -A prerouting -p tcp -j DNAT --to-destination [fec0::1234-fec0::2000]:1-20 +nft 'add rule ip6 nat prerouting meta l4proto tcp counter dnat to [fec0::1234-fec0::2000]:1-20' + +ip6tables-translate -t nat -A prerouting -p tcp -j DNAT --to-destination [fec0::1234]:80 --persistent +nft 'add rule ip6 nat prerouting meta l4proto tcp counter dnat to [fec0::1234]:80 persistent' + +ip6tables-translate -t nat -A prerouting -p tcp -j DNAT --to-destination [fec0::1234]:80 --random --persistent +nft 'add rule ip6 nat prerouting meta l4proto tcp counter dnat to [fec0::1234]:80 random,persistent' diff --git a/extensions/libxt_DSCP.t b/extensions/libxt_DSCP.t index fcc55986..762fcd31 100644 --- a/extensions/libxt_DSCP.t +++ b/extensions/libxt_DSCP.t @@ -1,6 +1,6 @@ :PREROUTING,INPUT,FORWARD,OUTPUT,POSTROUTING *mangle --j DSCP --set-dscp 0;=;OK +-j DSCP --set-dscp 0x00;=;OK -j DSCP --set-dscp 0x3f;=;OK -j DSCP --set-dscp -1;;FAIL -j DSCP --set-dscp 0x40;;FAIL diff --git a/extensions/libxt_DSCP.txlate b/extensions/libxt_DSCP.txlate index 442742ef..f7801a83 100644 --- a/extensions/libxt_DSCP.txlate +++ b/extensions/libxt_DSCP.txlate @@ -1,5 +1,5 @@ iptables-translate -A OUTPUT -j DSCP --set-dscp 1 -nft add rule ip filter OUTPUT counter ip dscp set 0x01 +nft 'add rule ip filter OUTPUT counter ip dscp set 0x01' ip6tables-translate -A OUTPUT -j DSCP --set-dscp 6 -nft add rule ip6 filter OUTPUT counter ip6 dscp set 0x06 +nft 'add rule ip6 filter OUTPUT counter ip6 dscp set 0x06' diff --git a/extensions/libxt_IDLETIMER.t b/extensions/libxt_IDLETIMER.t index e8f306d2..3345d5be 100644 --- a/extensions/libxt_IDLETIMER.t +++ b/extensions/libxt_IDLETIMER.t @@ -2,4 +2,4 @@ -j IDLETIMER --timeout;;FAIL -j IDLETIMER --timeout 42;;FAIL -j IDLETIMER --timeout 42 --label foo;=;OK --j IDLETIMER --timeout 42 --label foo --alarm;;OK +-j IDLETIMER --timeout 42 --label bar --alarm;=;OK diff --git a/extensions/libxt_LOG.c b/extensions/libxt_LOG.c new file mode 100644 index 00000000..b6fe0b2e --- /dev/null +++ b/extensions/libxt_LOG.c @@ -0,0 +1,204 @@ +#include <stdio.h> +#include <string.h> +#define SYSLOG_NAMES +#include <syslog.h> +#include <xtables.h> +#include <linux/netfilter/xt_LOG.h> + +#define LOG_DEFAULT_LEVEL LOG_WARNING + +enum { + /* make sure the values correspond with XT_LOG_* bit positions */ + O_LOG_TCPSEQ = 0, + O_LOG_TCPOPTS, + O_LOG_IPOPTS, + O_LOG_UID, + __O_LOG_NFLOG, + O_LOG_MAC, + O_LOG_LEVEL, + O_LOG_PREFIX, +}; + +static void LOG_help(void) +{ + printf( +"LOG target options:\n" +" --log-level level Level of logging (numeric or see syslog.conf)\n" +" --log-prefix prefix Prefix log messages with this prefix.\n" +" --log-tcp-sequence Log TCP sequence numbers.\n" +" --log-tcp-options Log TCP options.\n" +" --log-ip-options Log IP options.\n" +" --log-uid Log UID owning the local socket.\n" +" --log-macdecode Decode MAC addresses and protocol.\n"); +} + +#define s struct xt_log_info +static const struct xt_option_entry LOG_opts[] = { + {.name = "log-level", .id = O_LOG_LEVEL, .type = XTTYPE_SYSLOGLEVEL, + .flags = XTOPT_PUT, XTOPT_POINTER(s, level)}, + {.name = "log-prefix", .id = O_LOG_PREFIX, .type = XTTYPE_STRING, + .flags = XTOPT_PUT, XTOPT_POINTER(s, prefix), .min = 1}, + {.name = "log-tcp-sequence", .id = O_LOG_TCPSEQ, .type = XTTYPE_NONE}, + {.name = "log-tcp-options", .id = O_LOG_TCPOPTS, .type = XTTYPE_NONE}, + {.name = "log-ip-options", .id = O_LOG_IPOPTS, .type = XTTYPE_NONE}, + {.name = "log-uid", .id = O_LOG_UID, .type = XTTYPE_NONE}, + {.name = "log-macdecode", .id = O_LOG_MAC, .type = XTTYPE_NONE}, + XTOPT_TABLEEND, +}; +#undef s + +static void LOG_init(struct xt_entry_target *t) +{ + struct xt_log_info *loginfo = (void *)t->data; + + loginfo->level = LOG_DEFAULT_LEVEL; +} + +static void LOG_parse(struct xt_option_call *cb) +{ + struct xt_log_info *info = cb->data; + + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_LOG_PREFIX: + if (strchr(cb->arg, '\n') != NULL) + xtables_error(PARAMETER_PROBLEM, + "Newlines not allowed in --log-prefix"); + break; + case O_LOG_TCPSEQ: + case O_LOG_TCPOPTS: + case O_LOG_IPOPTS: + case O_LOG_UID: + case O_LOG_MAC: + info->logflags |= 1 << cb->entry->id; + break; + } +} + +static const char *priority2name(unsigned char level) +{ + int i; + + for (i = 0; prioritynames[i].c_name; ++i) { + if (level == prioritynames[i].c_val) + return prioritynames[i].c_name; + } + return NULL; +} + +static void LOG_print(const void *ip, const struct xt_entry_target *target, + int numeric) +{ + const struct xt_log_info *loginfo = (const void *)target->data; + + printf(" LOG"); + if (numeric) + printf(" flags %u level %u", + loginfo->logflags, loginfo->level); + else { + const char *pname = priority2name(loginfo->level); + + if (pname) + printf(" level %s", pname); + else + printf(" UNKNOWN level %u", loginfo->level); + if (loginfo->logflags & XT_LOG_TCPSEQ) + printf(" tcp-sequence"); + if (loginfo->logflags & XT_LOG_TCPOPT) + printf(" tcp-options"); + if (loginfo->logflags & XT_LOG_IPOPT) + printf(" ip-options"); + if (loginfo->logflags & XT_LOG_UID) + printf(" uid"); + if (loginfo->logflags & XT_LOG_MACDECODE) + printf(" macdecode"); + if (loginfo->logflags & ~(XT_LOG_MASK)) + printf(" unknown-flags"); + } + + if (strcmp(loginfo->prefix, "") != 0) + printf(" prefix \"%s\"", loginfo->prefix); +} + +static void LOG_save(const void *ip, const struct xt_entry_target *target) +{ + const struct xt_log_info *loginfo = (const void *)target->data; + + if (strcmp(loginfo->prefix, "") != 0) { + printf(" --log-prefix"); + xtables_save_string(loginfo->prefix); + } + + if (loginfo->level != LOG_DEFAULT_LEVEL) + printf(" --log-level %d", loginfo->level); + + if (loginfo->logflags & XT_LOG_TCPSEQ) + printf(" --log-tcp-sequence"); + if (loginfo->logflags & XT_LOG_TCPOPT) + printf(" --log-tcp-options"); + if (loginfo->logflags & XT_LOG_IPOPT) + printf(" --log-ip-options"); + if (loginfo->logflags & XT_LOG_UID) + printf(" --log-uid"); + if (loginfo->logflags & XT_LOG_MACDECODE) + printf(" --log-macdecode"); +} + +static int LOG_xlate(struct xt_xlate *xl, + const struct xt_xlate_tg_params *params) +{ + const struct xt_log_info *loginfo = (const void *)params->target->data; + const char *pname = priority2name(loginfo->level); + + xt_xlate_add(xl, "log"); + if (strcmp(loginfo->prefix, "") != 0) + xt_xlate_add(xl, " prefix \"%s\"", loginfo->prefix); + + if (loginfo->level != LOG_DEFAULT_LEVEL && pname) + xt_xlate_add(xl, " level %s", pname); + else if (!pname) + return 0; + + if ((loginfo->logflags & XT_LOG_MASK) == XT_LOG_MASK) { + xt_xlate_add(xl, " flags all"); + } else { + if (loginfo->logflags & (XT_LOG_TCPSEQ | XT_LOG_TCPOPT)) { + const char *delim = " "; + + xt_xlate_add(xl, " flags tcp"); + if (loginfo->logflags & XT_LOG_TCPSEQ) { + xt_xlate_add(xl, " sequence"); + delim = ","; + } + if (loginfo->logflags & XT_LOG_TCPOPT) + xt_xlate_add(xl, "%soptions", delim); + } + if (loginfo->logflags & XT_LOG_IPOPT) + xt_xlate_add(xl, " flags ip options"); + if (loginfo->logflags & XT_LOG_UID) + xt_xlate_add(xl, " flags skuid"); + if (loginfo->logflags & XT_LOG_MACDECODE) + xt_xlate_add(xl, " flags ether"); + } + + return 1; +} +static struct xtables_target log_tg_reg = { + .name = "LOG", + .version = XTABLES_VERSION, + .family = NFPROTO_UNSPEC, + .size = XT_ALIGN(sizeof(struct xt_log_info)), + .userspacesize = XT_ALIGN(sizeof(struct xt_log_info)), + .help = LOG_help, + .init = LOG_init, + .print = LOG_print, + .save = LOG_save, + .x6_parse = LOG_parse, + .x6_options = LOG_opts, + .xlate = LOG_xlate, +}; + +void _init(void) +{ + xtables_register_target(&log_tg_reg); +} diff --git a/extensions/libxt_LOG.man b/extensions/libxt_LOG.man index 354edf4c..1d5071ba 100644 --- a/extensions/libxt_LOG.man +++ b/extensions/libxt_LOG.man @@ -30,3 +30,6 @@ Log options from the IP/IPv6 packet header. .TP \fB\-\-log\-uid\fP Log the userid of the process which generated the packet. +.TP +\fB\-\-log\-macdecode\fP +Log MAC addresses and protocol. diff --git a/extensions/libxt_MARK.c b/extensions/libxt_MARK.c index b765af6c..100f6a38 100644 --- a/extensions/libxt_MARK.c +++ b/extensions/libxt_MARK.c @@ -77,8 +77,7 @@ static void mark_tg_help(void) " --set-mark value[/mask] Clear bits in mask and OR value into nfmark\n" " --and-mark bits Binary AND the nfmark with bits\n" " --or-mark bits Binary OR the nfmark with bits\n" -" --xor-mark bits Binary XOR the nfmark with bits\n" -"\n"); +" --xor-mark bits Binary XOR the nfmark with bits\n"); } static void MARK_parse_v0(struct xt_option_call *cb) @@ -367,6 +366,8 @@ static int MARK_xlate(struct xt_xlate *xl, case XT_MARK_OR: xt_xlate_add(xl, "mark or 0x%x ", (uint32_t)markinfo->mark); break; + default: + return 0; } return 1; diff --git a/extensions/libxt_MARK.t b/extensions/libxt_MARK.t index 9d1aa7d7..ae026dbb 100644 --- a/extensions/libxt_MARK.t +++ b/extensions/libxt_MARK.t @@ -1,7 +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 0x0;-j MARK --set-xmark 0x0/0xffffffff;OK +-j MARK --set-xmark 4294967295;-j MARK --set-xmark 0xffffffff/0xffffffff;OK -j MARK --set-xmark 4294967296;;FAIL -j MARK --set-xmark -1;;FAIL -j MARK;;FAIL diff --git a/extensions/libxt_MARK.txlate b/extensions/libxt_MARK.txlate index d3250ab6..36ee7a3b 100644 --- a/extensions/libxt_MARK.txlate +++ b/extensions/libxt_MARK.txlate @@ -1,26 +1,26 @@ iptables-translate -t mangle -A OUTPUT -j MARK --set-mark 0 -nft add rule ip mangle OUTPUT counter meta mark set 0x0 +nft 'add rule ip mangle OUTPUT counter meta mark set 0x0' iptables-translate -t mangle -A OUTPUT -j MARK --set-mark 64 -nft add rule ip mangle OUTPUT counter meta mark set 0x40 +nft 'add rule ip mangle OUTPUT counter meta mark set 0x40' iptables-translate -t mangle -A OUTPUT -j MARK --set-xmark 0x40/0x32 -nft add rule ip mangle OUTPUT counter meta mark set mark and 0xffffffcd xor 0x40 +nft 'add rule ip mangle OUTPUT counter meta mark set mark and 0xffffffcd xor 0x40' iptables-translate -t mangle -A OUTPUT -j MARK --or-mark 64 -nft add rule ip mangle OUTPUT counter meta mark set mark or 0x40 +nft 'add rule ip mangle OUTPUT counter meta mark set mark or 0x40' iptables-translate -t mangle -A OUTPUT -j MARK --and-mark 64 -nft add rule ip mangle OUTPUT counter meta mark set mark and 0x40 +nft 'add rule ip mangle OUTPUT counter meta mark set mark and 0x40' iptables-translate -t mangle -A OUTPUT -j MARK --xor-mark 64 -nft add rule ip mangle OUTPUT counter meta mark set mark xor 0x40 +nft 'add rule ip mangle OUTPUT counter meta mark set mark xor 0x40' iptables-translate -t mangle -A PREROUTING -j MARK --set-mark 0x64 -nft add rule ip mangle PREROUTING counter meta mark set 0x64 +nft 'add rule ip mangle PREROUTING counter meta mark set 0x64' iptables-translate -t mangle -A PREROUTING -j MARK --and-mark 0x64 -nft add rule ip mangle PREROUTING counter meta mark set mark and 0x64 +nft 'add rule ip mangle PREROUTING counter meta mark set mark and 0x64' iptables-translate -t mangle -A PREROUTING -j MARK --or-mark 0x64 -nft add rule ip mangle PREROUTING counter meta mark set mark or 0x64 +nft 'add rule ip mangle PREROUTING counter meta mark set mark or 0x64' diff --git a/extensions/libxt_MASQUERADE.man b/extensions/libxt_MASQUERADE.man index 7746f473..26d91ddb 100644 --- a/extensions/libxt_MASQUERADE.man +++ b/extensions/libxt_MASQUERADE.man @@ -20,16 +20,10 @@ if the rule also specifies one of the following protocols: \fBtcp\fP, \fBudp\fP, \fBdccp\fP or \fBsctp\fP. .TP \fB\-\-random\fP -Randomize source port mapping -If option -\fB\-\-random\fP -is used then port mapping will be randomized (kernel >= 2.6.21). +Randomize source port mapping (kernel >= 2.6.21). Since kernel 5.0, \fB\-\-random\fP is identical to \fB\-\-random-fully\fP. .TP \fB\-\-random-fully\fP -Full randomize source port mapping -If option -\fB\-\-random-fully\fP -is used then port mapping will be fully randomized (kernel >= 3.13). +Fully randomize source port mapping (kernel >= 3.13). .TP IPv6 support available since Linux kernels >= 3.7. diff --git a/extensions/libxt_NAT.c b/extensions/libxt_NAT.c new file mode 100644 index 00000000..2a634398 --- /dev/null +++ b/extensions/libxt_NAT.c @@ -0,0 +1,646 @@ +/* + * Copyright (c) 2011 Patrick McHardy <kaber@trash.net> + * + * Based on Rusty Russell's IPv4 DNAT target. Development of IPv6 NAT + * funded by Astaro. + */ + +#include <stdio.h> +#include <netdb.h> +#include <string.h> +#include <stdlib.h> +#include <xtables.h> +#include <iptables.h> /* get_kernel_version */ +#include <limits.h> /* INT_MAX in ip_tables.h */ +#include <arpa/inet.h> +#include <linux/netfilter_ipv4/ip_tables.h> +#include <linux/netfilter_ipv6/ip6_tables.h> +#include <linux/netfilter/nf_nat.h> + +#define TO_IPV4_MRC(ptr) ((const struct nf_nat_ipv4_multi_range_compat *)(ptr)) +#define RANGE2_INIT_FROM_IPV4_MRC(ptr) { \ + .flags = TO_IPV4_MRC(ptr)->range[0].flags, \ + .min_addr.ip = TO_IPV4_MRC(ptr)->range[0].min_ip, \ + .max_addr.ip = TO_IPV4_MRC(ptr)->range[0].max_ip, \ + .min_proto = TO_IPV4_MRC(ptr)->range[0].min, \ + .max_proto = TO_IPV4_MRC(ptr)->range[0].max, \ +}; +#define TO_NF_NAT_RANGE(ptr) ((const struct nf_nat_range *)(ptr)) +#define RANGE2_INIT_FROM_RANGE(ptr) { \ + .flags = TO_NF_NAT_RANGE(ptr)->flags, \ + .min_addr = TO_NF_NAT_RANGE(ptr)->min_addr, \ + .max_addr = TO_NF_NAT_RANGE(ptr)->max_addr, \ + .min_proto = TO_NF_NAT_RANGE(ptr)->min_proto, \ + .max_proto = TO_NF_NAT_RANGE(ptr)->max_proto, \ +}; + +enum { + O_TO_DEST = 0, + O_TO_SRC, + O_TO_PORTS, + O_RANDOM, + O_RANDOM_FULLY, + O_PERSISTENT, +}; + +static void SNAT_help(void) +{ + printf( +"SNAT target options:\n" +" --to-source [<ipaddr>[-<ipaddr>]][:port[-port]]\n" +" Address to map source to.\n" +"[--random] [--random-fully] [--persistent]\n"); +} + +static void MASQUERADE_help(void) +{ + printf( +"MASQUERADE target options:\n" +" --to-ports <port>[-<port>]\n" +" Port (range) to map to.\n" +" --random\n" +" Randomize source port.\n" +" --random-fully\n" +" Fully randomize source port.\n"); +} + +static void DNAT_help(void) +{ + printf( +"DNAT target options:\n" +" --to-destination [<ipaddr>[-<ipaddr>]][:port[-port]]\n" +" Address to map destination to.\n" +"[--random] [--persistent]\n"); +} + +static void DNAT_help_v2(void) +{ + printf( +"DNAT target options:\n" +" --to-destination [<ipaddr>[-<ipaddr>]][:port[-port[/port]]]\n" +" Address to map destination to.\n" +"[--random] [--persistent]\n"); +} + +static void REDIRECT_help(void) +{ + printf( +"REDIRECT target options:\n" +" --to-ports <port>[-<port>]\n" +" Port (range) to map to.\n" +" [--random]\n"); +} + +static const struct xt_option_entry SNAT_opts[] = { + {.name = "to-source", .id = O_TO_SRC, .type = XTTYPE_STRING, + .flags = XTOPT_MAND}, + {.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, +}; + +static const struct xt_option_entry MASQUERADE_opts[] = { + {.name = "to-ports", .id = O_TO_PORTS, .type = XTTYPE_STRING}, + {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE}, + {.name = "random-fully", .id = O_RANDOM_FULLY, .type = XTTYPE_NONE}, + XTOPT_TABLEEND, +}; + +static const struct xt_option_entry DNAT_opts[] = { + {.name = "to-destination", .id = O_TO_DEST, .type = XTTYPE_STRING, + .flags = XTOPT_MAND}, + {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE}, + {.name = "persistent", .id = O_PERSISTENT, .type = XTTYPE_NONE}, + XTOPT_TABLEEND, +}; + +static const struct xt_option_entry REDIRECT_opts[] = { + {.name = "to-ports", .id = O_TO_PORTS, .type = XTTYPE_STRING}, + {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE}, + XTOPT_TABLEEND, +}; + +/* Parses ports */ +static void +parse_ports(const char *arg, bool portok, struct nf_nat_range2 *range) +{ + unsigned int port, maxport, baseport; + char *end = NULL; + + if (!portok) + xtables_error(PARAMETER_PROBLEM, + "Need TCP, UDP, SCTP or DCCP with port specification"); + + range->flags |= NF_NAT_RANGE_PROTO_SPECIFIED; + + if (!xtables_strtoui(arg, &end, &port, 0, UINT16_MAX)) { + port = xtables_service_to_port(arg, NULL); + if (port == (unsigned)-1) + xtables_error(PARAMETER_PROBLEM, + "Port `%s' not valid", arg); + end = ""; + } + + switch (*end) { + case '\0': + range->min_proto.tcp.port + = range->max_proto.tcp.port + = htons(port); + return; + case '-': + arg = end + 1; + break; + case ':': + xtables_error(PARAMETER_PROBLEM, + "Invalid port:port syntax - use dash"); + default: + xtables_error(PARAMETER_PROBLEM, + "Garbage after port value: `%s'", end); + } + + /* it is a range, don't allow service names here */ + if (!xtables_strtoui(arg, &end, &maxport, 0, UINT16_MAX)) + xtables_error(PARAMETER_PROBLEM, "Port `%s' not valid", arg); + + if (maxport < port) + /* People are stupid. */ + xtables_error(PARAMETER_PROBLEM, + "Port range `%s' funky", arg); + + range->min_proto.tcp.port = htons(port); + range->max_proto.tcp.port = htons(maxport); + + switch (*end) { + case '\0': + return; + case '/': + arg = end + 1; + break; + default: + xtables_error(PARAMETER_PROBLEM, + "Garbage after port range: `%s'", end); + } + + if (!xtables_strtoui(arg, &end, &baseport, 1, UINT16_MAX)) { + baseport = xtables_service_to_port(arg, NULL); + if (baseport == (unsigned)-1) + xtables_error(PARAMETER_PROBLEM, + "Port `%s' not valid", arg); + } + + range->flags |= NF_NAT_RANGE_PROTO_OFFSET; + range->base_proto.tcp.port = htons(baseport); +} + +/* Ranges expected in network order. */ +static void +parse_to(const char *orig_arg, bool portok, + struct nf_nat_range2 *range, int family) +{ + char *arg, *start, *end, *colon, *dash; + + arg = xtables_strdup(orig_arg); + start = strchr(arg, '['); + if (!start) { + start = arg; + /* Lets assume one colon is port information. + * Otherwise its an IPv6 address */ + colon = strchr(arg, ':'); + if (colon && strchr(colon + 1, ':')) + colon = NULL; + } else { + start++; + end = strchr(start, ']'); + if (end == NULL || family == AF_INET) + xtables_error(PARAMETER_PROBLEM, + "Invalid address format"); + + *end = '\0'; + colon = strchr(end + 1, ':'); + } + + if (colon) { + parse_ports(colon + 1, portok, range); + + /* Starts with colon or [] colon? No IP info...*/ + if (colon == arg || colon == arg + 2) { + free(arg); + return; + } + *colon = '\0'; + } + + range->flags |= NF_NAT_RANGE_MAP_IPS; + dash = strchr(start, '-'); + if (colon && dash && dash > colon) + dash = NULL; + + if (dash) + *dash = '\0'; + + if (!inet_pton(family, start, &range->min_addr)) + xtables_error(PARAMETER_PROBLEM, + "Bad IP address \"%s\"", start); + if (dash) { + if (!inet_pton(family, dash + 1, &range->max_addr)) + xtables_error(PARAMETER_PROBLEM, + "Bad IP address \"%s\"", dash + 1); + } else { + range->max_addr = range->min_addr; + } + free(arg); + return; +} + +static void __NAT_parse(struct xt_option_call *cb, __u16 proto, + struct nf_nat_range2 *range, int family) +{ + bool portok = proto == IPPROTO_TCP || + proto == IPPROTO_UDP || + proto == IPPROTO_SCTP || + proto == IPPROTO_DCCP || + proto == IPPROTO_ICMP; + + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_TO_DEST: + case O_TO_SRC: + parse_to(cb->arg, portok, range, family); + break; + case O_TO_PORTS: + parse_ports(cb->arg, portok, range); + break; + case O_PERSISTENT: + range->flags |= NF_NAT_RANGE_PERSISTENT; + break; + case O_RANDOM: + range->flags |= NF_NAT_RANGE_PROTO_RANDOM; + break; + case O_RANDOM_FULLY: + range->flags |= NF_NAT_RANGE_PROTO_RANDOM_FULLY; + break; + } +} + +static void NAT_parse(struct xt_option_call *cb) +{ + struct nf_nat_ipv4_multi_range_compat *mr = (void *)cb->data; + const struct ipt_entry *entry = cb->xt_entry; + struct nf_nat_range2 range = {}; + + __NAT_parse(cb, entry->ip.proto, &range, AF_INET); + + switch (cb->entry->id) { + case O_TO_DEST: + case O_TO_SRC: + mr->range->min_ip = range.min_addr.ip; + mr->range->max_ip = range.max_addr.ip; + /* fall through */ + case O_TO_PORTS: + mr->range->min = range.min_proto; + mr->range->max = range.max_proto; + /* fall through */ + case O_PERSISTENT: + case O_RANDOM: + case O_RANDOM_FULLY: + mr->range->flags |= range.flags; + break; + } +} + +static void NAT_parse6(struct xt_option_call *cb) +{ + struct nf_nat_range2 range = RANGE2_INIT_FROM_RANGE(cb->data); + struct nf_nat_range *range_v1 = (void *)cb->data; + const struct ip6t_entry *entry = cb->xt_entry; + + __NAT_parse(cb, entry->ipv6.proto, &range, AF_INET6); + memcpy(range_v1, &range, sizeof(*range_v1)); +} + +static void DNAT_parse_v2(struct xt_option_call *cb) +{ + const struct ipt_entry *entry = cb->xt_entry; + + __NAT_parse(cb, entry->ip.proto, cb->data, AF_INET); +} + +static void DNAT_parse6_v2(struct xt_option_call *cb) +{ + const struct ip6t_entry *entry = cb->xt_entry; + + __NAT_parse(cb, entry->ipv6.proto, cb->data, AF_INET6); +} + +static void SNAT_fcheck(struct xt_fcheck_call *cb) +{ + struct nf_nat_ipv4_multi_range_compat *mr = cb->data; + + mr->rangesize = 1; +} + +static void DNAT_fcheck(struct xt_fcheck_call *cb) +{ + struct nf_nat_ipv4_multi_range_compat *mr = cb->data; + + mr->rangesize = 1; + + if (mr->range[0].flags & NF_NAT_RANGE_PROTO_OFFSET) + xtables_error(PARAMETER_PROBLEM, + "Shifted portmap ranges not supported with this kernel"); +} + +static void DNAT_fcheck6(struct xt_fcheck_call *cb) +{ + struct nf_nat_range *range = (void *)cb->data; + + if (range->flags & NF_NAT_RANGE_PROTO_OFFSET) + xtables_error(PARAMETER_PROBLEM, + "Shifted portmap ranges not supported with this kernel"); +} + +static char *sprint_range(const struct nf_nat_range2 *r, int family) +{ + bool brackets = family == AF_INET6 && + r->flags & NF_NAT_RANGE_PROTO_SPECIFIED; + static char buf[INET6_ADDRSTRLEN * 2 + 3 + 6 * 3]; + + buf[0] = '\0'; + + if (r->flags & NF_NAT_RANGE_MAP_IPS) { + if (brackets) + strcat(buf, "["); + inet_ntop(family, &r->min_addr, + buf + strlen(buf), INET6_ADDRSTRLEN); + if (memcmp(&r->min_addr, &r->max_addr, sizeof(r->min_addr))) { + strcat(buf, "-"); + inet_ntop(family, &r->max_addr, + buf + strlen(buf), INET6_ADDRSTRLEN); + } + if (brackets) + strcat(buf, "]"); + } + if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { + sprintf(buf + strlen(buf), ":%hu", + ntohs(r->min_proto.tcp.port)); + if (r->max_proto.tcp.port != r->min_proto.tcp.port) + sprintf(buf + strlen(buf), "-%hu", + ntohs(r->max_proto.tcp.port)); + if (r->flags & NF_NAT_RANGE_PROTO_OFFSET) + sprintf(buf + strlen(buf), "/%hu", + ntohs(r->base_proto.tcp.port)); + } + return buf; +} + +static void __NAT_print(const struct nf_nat_range2 *r, int family, + const char *rangeopt, const char *flag_pfx, + bool skip_colon) +{ + char *range_str = sprint_range(r, family); + + if (strlen(range_str)) { + if (range_str[0] == ':' && skip_colon) + range_str++; + printf(" %s%s", rangeopt, range_str); + } + if (r->flags & NF_NAT_RANGE_PROTO_RANDOM) + printf(" %srandom", flag_pfx); + if (r->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) + printf(" %srandom-fully", flag_pfx); + if (r->flags & NF_NAT_RANGE_PERSISTENT) + printf(" %spersistent", flag_pfx); +} + +static int +__NAT_xlate(struct xt_xlate *xl, const struct nf_nat_range2 *r, + int family, const char *tgt) +{ + char *range_str = sprint_range(r, family); + const char *sep = " "; + + /* shifted portmap ranges are not supported by nftables */ + if (r->flags & NF_NAT_RANGE_PROTO_OFFSET) + return 0; + + xt_xlate_add(xl, "%s", tgt); + if (strlen(range_str)) + xt_xlate_add(xl, " to %s", range_str); + if (r->flags & NF_NAT_RANGE_PROTO_RANDOM) { + xt_xlate_add(xl, "%srandom", sep); + sep = ","; + } + if (r->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) { + xt_xlate_add(xl, "%sfully-random", sep); + sep = ","; + } + if (r->flags & NF_NAT_RANGE_PERSISTENT) { + xt_xlate_add(xl, "%spersistent", sep); + sep = ","; + } + return 1; +} + +#define PSX_GEN(name, converter, family, \ + print_rangeopt, save_rangeopt, skip_colon, xlate) \ +static void name##_print(const void *ip, const struct xt_entry_target *target, \ + int numeric) \ +{ \ + struct nf_nat_range2 range = converter(target->data); \ + \ + __NAT_print(&range, family, print_rangeopt, "", skip_colon); \ +} \ +static void name##_save(const void *ip, const struct xt_entry_target *target) \ +{ \ + struct nf_nat_range2 range = converter(target->data); \ + \ + __NAT_print(&range, family, save_rangeopt, "--", skip_colon); \ +} \ +static int name##_xlate(struct xt_xlate *xl, \ + const struct xt_xlate_tg_params *params) \ +{ \ + struct nf_nat_range2 range = converter(params->target->data); \ + \ + return __NAT_xlate(xl, &range, family, xlate); \ +} + +PSX_GEN(DNAT, RANGE2_INIT_FROM_IPV4_MRC, \ + AF_INET, "to:", "--to-destination ", false, "dnat") + +PSX_GEN(DNATv2, *(struct nf_nat_range2 *), \ + AF_INET, "to:", "--to-destination ", false, "dnat") + +PSX_GEN(DNAT6, RANGE2_INIT_FROM_RANGE, \ + AF_INET6, "to:", "--to-destination ", false, "dnat") + +PSX_GEN(DNAT6v2, *(struct nf_nat_range2 *), \ + AF_INET6, "to:", "--to-destination ", false, "dnat") + +PSX_GEN(REDIRECT, RANGE2_INIT_FROM_IPV4_MRC, \ + AF_INET, "redir ports ", "--to-ports ", true, "redirect") + +PSX_GEN(REDIRECT6, RANGE2_INIT_FROM_RANGE, \ + AF_INET6, "redir ports ", "--to-ports ", true, "redirect") + +PSX_GEN(SNAT, RANGE2_INIT_FROM_IPV4_MRC, \ + AF_INET, "to:", "--to-source ", false, "snat") + +PSX_GEN(SNAT6, RANGE2_INIT_FROM_RANGE, \ + AF_INET6, "to:", "--to-source ", false, "snat") + +PSX_GEN(MASQUERADE, RANGE2_INIT_FROM_IPV4_MRC, \ + AF_INET, "masq ports: ", "--to-ports ", true, "masquerade") + +PSX_GEN(MASQUERADE6, RANGE2_INIT_FROM_RANGE, \ + AF_INET6, "masq ports: ", "--to-ports ", true, "masquerade") + +static struct xtables_target nat_tg_reg[] = { + { + .name = "SNAT", + .version = XTABLES_VERSION, + .family = NFPROTO_IPV4, + .size = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), + .userspacesize = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), + .help = SNAT_help, + .x6_parse = NAT_parse, + .x6_fcheck = SNAT_fcheck, + .print = SNAT_print, + .save = SNAT_save, + .x6_options = SNAT_opts, + .xlate = SNAT_xlate, + }, + { + .name = "DNAT", + .version = XTABLES_VERSION, + .family = NFPROTO_IPV4, + .revision = 0, + .size = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), + .userspacesize = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), + .help = DNAT_help, + .print = DNAT_print, + .save = DNAT_save, + .x6_parse = NAT_parse, + .x6_fcheck = DNAT_fcheck, + .x6_options = DNAT_opts, + .xlate = DNAT_xlate, + }, + { + .name = "MASQUERADE", + .version = XTABLES_VERSION, + .family = NFPROTO_IPV4, + .size = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), + .userspacesize = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), + .help = MASQUERADE_help, + .x6_parse = NAT_parse, + .x6_fcheck = SNAT_fcheck, + .print = MASQUERADE_print, + .save = MASQUERADE_save, + .x6_options = MASQUERADE_opts, + .xlate = MASQUERADE_xlate, + }, + { + .name = "MASQUERADE", + .version = XTABLES_VERSION, + .family = NFPROTO_IPV6, + .size = XT_ALIGN(sizeof(struct nf_nat_range)), + .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)), + .help = MASQUERADE_help, + .x6_parse = NAT_parse6, + .print = MASQUERADE6_print, + .save = MASQUERADE6_save, + .x6_options = MASQUERADE_opts, + .xlate = MASQUERADE6_xlate, + }, + { + .name = "REDIRECT", + .version = XTABLES_VERSION, + .family = NFPROTO_IPV4, + .revision = 0, + .size = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), + .userspacesize = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), + .help = REDIRECT_help, + .print = REDIRECT_print, + .save = REDIRECT_save, + .x6_parse = NAT_parse, + .x6_fcheck = DNAT_fcheck, + .x6_options = REDIRECT_opts, + .xlate = REDIRECT_xlate, + }, + { + .name = "SNAT", + .version = XTABLES_VERSION, + .family = NFPROTO_IPV6, + .revision = 1, + .size = XT_ALIGN(sizeof(struct nf_nat_range)), + .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)), + .help = SNAT_help, + .x6_parse = NAT_parse6, + .print = SNAT6_print, + .save = SNAT6_save, + .x6_options = SNAT_opts, + .xlate = SNAT6_xlate, + }, + { + .name = "DNAT", + .version = XTABLES_VERSION, + .family = NFPROTO_IPV6, + .revision = 1, + .size = XT_ALIGN(sizeof(struct nf_nat_range)), + .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)), + .help = DNAT_help, + .print = DNAT6_print, + .save = DNAT6_save, + .x6_parse = NAT_parse6, + .x6_fcheck = DNAT_fcheck6, + .x6_options = DNAT_opts, + .xlate = DNAT6_xlate, + }, + { + .name = "REDIRECT", + .version = XTABLES_VERSION, + .family = NFPROTO_IPV6, + .size = XT_ALIGN(sizeof(struct nf_nat_range)), + .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)), + .help = REDIRECT_help, + .print = REDIRECT6_print, + .save = REDIRECT6_save, + .x6_parse = NAT_parse6, + .x6_fcheck = DNAT_fcheck6, + .x6_options = REDIRECT_opts, + .xlate = REDIRECT6_xlate, + }, + { + .name = "DNAT", + .version = XTABLES_VERSION, + .family = NFPROTO_IPV4, + .revision = 2, + .size = XT_ALIGN(sizeof(struct nf_nat_range2)), + .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range2)), + .help = DNAT_help_v2, + .print = DNATv2_print, + .save = DNATv2_save, + .x6_parse = DNAT_parse_v2, + .x6_options = DNAT_opts, + .xlate = DNATv2_xlate, + }, + { + .name = "DNAT", + .version = XTABLES_VERSION, + .family = NFPROTO_IPV6, + .revision = 2, + .size = XT_ALIGN(sizeof(struct nf_nat_range2)), + .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range2)), + .help = DNAT_help_v2, + .print = DNAT6v2_print, + .save = DNAT6v2_save, + .x6_parse = DNAT_parse6_v2, + .x6_options = DNAT_opts, + .xlate = DNAT6v2_xlate, + }, +}; + +void _init(void) +{ + xtables_register_targets(nat_tg_reg, ARRAY_SIZE(nat_tg_reg)); +} diff --git a/extensions/libxt_NFLOG.c b/extensions/libxt_NFLOG.c index 02a1b4aa..d12ef044 100644 --- a/extensions/libxt_NFLOG.c +++ b/extensions/libxt_NFLOG.c @@ -5,6 +5,7 @@ #include <getopt.h> #include <xtables.h> +#include <linux/netfilter/nf_log.h> #include <linux/netfilter/x_tables.h> #include <linux/netfilter/xt_NFLOG.h> @@ -53,12 +54,16 @@ static void NFLOG_init(struct xt_entry_target *t) static void NFLOG_parse(struct xt_option_call *cb) { + char *nf_log_prefix = cb->udata; + xtables_option_parse(cb); switch (cb->entry->id) { case O_PREFIX: if (strchr(cb->arg, '\n') != NULL) xtables_error(PARAMETER_PROBLEM, "Newlines not allowed in --log-prefix"); + + snprintf(nf_log_prefix, NF_LOG_PREFIXLEN, "%s", cb->arg); break; } } @@ -69,7 +74,7 @@ static void NFLOG_check(struct xt_fcheck_call *cb) if (cb->xflags & F_RANGE) fprintf(stderr, "warn: --nflog-range has never worked and is no" - " longer supported, please use --nflog-size insted\n"); + " longer supported, please use --nflog-size instead\n"); if (cb->xflags & F_SIZE) info->flags |= XT_NFLOG_F_COPY_LEN; @@ -78,7 +83,7 @@ static void NFLOG_check(struct xt_fcheck_call *cb) static void nflog_print(const struct xt_nflog_info *info, char *prefix) { if (info->prefix[0] != '\0') { - printf(" %snflog-prefix ", prefix); + printf(" %snflog-prefix", prefix); xtables_save_string(info->prefix); } if (info->group) @@ -107,16 +112,12 @@ static void NFLOG_save(const void *ip, const struct xt_entry_target *target) } static void nflog_print_xlate(const struct xt_nflog_info *info, - struct xt_xlate *xl, bool escape_quotes) + struct xt_xlate *xl) { 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->prefix[0] != '\0') + 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) @@ -130,7 +131,7 @@ static int NFLOG_xlate(struct xt_xlate *xl, const struct xt_nflog_info *info = (struct xt_nflog_info *)params->target->data; - nflog_print_xlate(info, xl, params->escape_quotes); + nflog_print_xlate(info, xl); return 1; } @@ -149,6 +150,7 @@ static struct xtables_target nflog_target = { .save = NFLOG_save, .x6_options = NFLOG_opts, .xlate = NFLOG_xlate, + .udata_size = NF_LOG_PREFIXLEN }; void _init(void) diff --git a/extensions/libxt_NFLOG.t b/extensions/libxt_NFLOG.t index 933fa221..25f332ae 100644 --- a/extensions/libxt_NFLOG.t +++ b/extensions/libxt_NFLOG.t @@ -3,8 +3,10 @@ -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 +# `--nflog-range` is broken and only supported by xtables-legacy. +# It has been superseded by `--nflog--group`. +-j NFLOG --nflog-range 1;=;OK;LEGACY;NOMATCH +-j NFLOG --nflog-range 4294967295;=;OK;LEGACY;NOMATCH -j NFLOG --nflog-range 4294967296;;FAIL -j NFLOG --nflog-range -1;;FAIL -j NFLOG --nflog-size 0;=;OK @@ -12,10 +14,8 @@ -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-prefix xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;=;OK +-j NFLOG --nflog-prefix xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;-j NFLOG --nflog-prefix xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;OK -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 diff --git a/extensions/libxt_NFLOG.txlate b/extensions/libxt_NFLOG.txlate index a0872c9e..ebd81be3 100644 --- a/extensions/libxt_NFLOG.txlate +++ b/extensions/libxt_NFLOG.txlate @@ -1,14 +1,14 @@ iptables-translate -A FORWARD -j NFLOG --nflog-group 32 --nflog-prefix "Prefix 1.0" -nft add rule ip filter FORWARD counter log prefix \"Prefix 1.0\" group 32 +nft 'add rule ip filter FORWARD counter log prefix "Prefix 1.0" group 32' iptables-translate -A OUTPUT -j NFLOG --nflog-group 30 -nft add rule ip filter OUTPUT counter log group 30 +nft 'add rule ip filter OUTPUT counter log group 30' iptables-translate -I INPUT -j NFLOG --nflog-threshold 2 -nft insert rule ip filter INPUT counter log queue-threshold 2 group 0 +nft 'insert rule ip filter INPUT counter log queue-threshold 2 group 0' iptables-translate -I INPUT -j NFLOG --nflog-size 256 -nft insert rule ip filter INPUT counter log snaplen 256 group 0 +nft 'insert rule ip filter INPUT counter log snaplen 256 group 0' iptables-translate -I INPUT -j NFLOG --nflog-threshold 25 -nft insert rule ip filter INPUT counter log queue-threshold 25 group 0 +nft 'insert rule ip filter INPUT counter log queue-threshold 25 group 0' diff --git a/extensions/libxt_NFQUEUE.c b/extensions/libxt_NFQUEUE.c index fe519078..ca6cdaf4 100644 --- a/extensions/libxt_NFQUEUE.c +++ b/extensions/libxt_NFQUEUE.c @@ -64,7 +64,7 @@ static const struct xt_option_entry NFQUEUE_opts[] = { {.name = "queue-num", .id = O_QUEUE_NUM, .type = XTTYPE_UINT16, .flags = XTOPT_PUT, XTOPT_POINTER(s, queuenum), .excl = F_QUEUE_BALANCE}, - {.name = "queue-balance", .id = O_QUEUE_BALANCE, + {.name = "queue-balance", .id = O_QUEUE_BALANCE, .max = UINT16_MAX - 1, .type = XTTYPE_UINT16RC, .excl = F_QUEUE_NUM}, {.name = "queue-bypass", .id = O_QUEUE_BYPASS, .type = XTTYPE_NONE}, {.name = "queue-cpu-fanout", .id = O_QUEUE_CPU_FANOUT, diff --git a/extensions/libxt_NFQUEUE.man b/extensions/libxt_NFQUEUE.man index 1bfb7b84..950b0d24 100644 --- a/extensions/libxt_NFQUEUE.man +++ b/extensions/libxt_NFQUEUE.man @@ -18,6 +18,8 @@ This specifies a range of queues to use. Packets are then balanced across the gi This is useful for multicore systems: start multiple instances of the userspace program on queues x, x+1, .. x+n and use "\-\-queue\-balance \fIx\fP\fB:\fP\fIx+n\fP". Packets belonging to the same connection are put into the same nfqueue. +Due to implementation details, a lower range value of 0 limits the higher range +value to 65534, i.e. one can only balance between at most 65535 queues. .PP .TP \fB\-\-queue\-bypass\fP diff --git a/extensions/libxt_NFQUEUE.t b/extensions/libxt_NFQUEUE.t index b51b19fd..8fb2b760 100644 --- a/extensions/libxt_NFQUEUE.t +++ b/extensions/libxt_NFQUEUE.t @@ -1,12 +1,11 @@ :INPUT,FORWARD,OUTPUT --j NFQUEUE;=;OK +-j NFQUEUE;-j NFQUEUE --queue-num 0;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:65534;=;OK +-j NFQUEUE --queue-balance 0:65535;;FAIL -j NFQUEUE --queue-balance 0:65536;;FAIL -j NFQUEUE --queue-balance -1:65535;;FAIL -j NFQUEUE --queue-num 10 --queue-bypass;=;OK diff --git a/extensions/libxt_NFQUEUE.txlate b/extensions/libxt_NFQUEUE.txlate index 3d188a7a..3698dcbc 100644 --- a/extensions/libxt_NFQUEUE.txlate +++ b/extensions/libxt_NFQUEUE.txlate @@ -1,8 +1,8 @@ iptables-translate -t nat -A PREROUTING -p tcp --dport 80 -j NFQUEUE --queue-num 30 -nft add rule ip nat PREROUTING tcp dport 80 counter queue num 30 +nft 'add rule ip nat PREROUTING tcp dport 80 counter queue num 30' iptables-translate -A FORWARD -j NFQUEUE --queue-num 0 --queue-bypass -p TCP --sport 80 -nft add rule ip filter FORWARD tcp sport 80 counter queue num 0 bypass +nft 'add rule ip filter FORWARD tcp sport 80 counter queue num 0 bypass' iptables-translate -A FORWARD -j NFQUEUE --queue-bypass -p TCP --sport 80 --queue-balance 0:3 --queue-cpu-fanout -nft add rule ip filter FORWARD tcp sport 80 counter queue num 0-3 bypass,fanout +nft 'add rule ip filter FORWARD tcp sport 80 counter queue num 0-3 bypass,fanout' diff --git a/extensions/libxt_NOTRACK.txlate b/extensions/libxt_NOTRACK.txlate index 9d35619d..9490ee8f 100644 --- a/extensions/libxt_NOTRACK.txlate +++ b/extensions/libxt_NOTRACK.txlate @@ -1,2 +1,2 @@ iptables-translate -A PREROUTING -t raw -j NOTRACK -nft add rule ip raw PREROUTING counter notrack +nft 'add rule ip raw PREROUTING counter notrack' diff --git a/extensions/libxt_REDIRECT.man b/extensions/libxt_REDIRECT.man index 28d4d10b..1cbdb9ba 100644 --- a/extensions/libxt_REDIRECT.man +++ b/extensions/libxt_REDIRECT.man @@ -16,10 +16,9 @@ This specifies a destination port or range of ports to use: without this, the destination port is never altered. This is only valid if the rule also specifies one of the following protocols: \fBtcp\fP, \fBudp\fP, \fBdccp\fP or \fBsctp\fP. +For a single port, a service name as listed in \fB/etc/services\fP may be used. .TP \fB\-\-random\fP -If option -\fB\-\-random\fP -is used then port mapping will be randomized (kernel >= 2.6.22). +Randomize source port mapping (kernel >= 2.6.22). .TP IPv6 support available starting Linux kernels >= 3.7. diff --git a/extensions/libxt_REDIRECT.t b/extensions/libxt_REDIRECT.t new file mode 100644 index 00000000..362efa84 --- /dev/null +++ b/extensions/libxt_REDIRECT.t @@ -0,0 +1,17 @@ +:PREROUTING,OUTPUT +*nat +-p tcp -j REDIRECT --to-ports 42;=;OK +-p tcp -j REDIRECT --to-ports 0;=;OK +-p tcp -j REDIRECT --to-ports 65535;=;OK +-p tcp -j REDIRECT --to-ports 65536;;FAIL +-p udp -j REDIRECT --to-ports 0-0;-p udp -j REDIRECT --to-ports 0;OK +-p udp -j REDIRECT --to-ports 512-512;-p udp -j REDIRECT --to-ports 512;OK +-p udp -j REDIRECT --to-ports 42-1234;=;OK +-p tcp -j REDIRECT --to-ports 42-1234 --random;=;OK +-p tcp -j REDIRECT --to-ports 42-1234/567;;FAIL +-p tcp -j REDIRECT --to-ports ssh;-p tcp -j REDIRECT --to-ports 22;OK +-p tcp -j REDIRECT --to-ports ftp-data;-p tcp -j REDIRECT --to-ports 20;OK +-p tcp -j REDIRECT --to-ports ftp-ssh;;FAIL +-p tcp -j REDIRECT --to-ports 10-ssh;;FAIL +-j REDIRECT --to-ports 42;;FAIL +-j REDIRECT --random;=;OK diff --git a/extensions/libxt_REDIRECT.txlate b/extensions/libxt_REDIRECT.txlate new file mode 100644 index 00000000..dc473340 --- /dev/null +++ b/extensions/libxt_REDIRECT.txlate @@ -0,0 +1,29 @@ +iptables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT +nft 'add rule ip nat prerouting tcp dport 80 counter redirect' + +iptables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 0 +nft 'add rule ip nat prerouting tcp dport 80 counter redirect to :0' + +iptables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 8080 +nft 'add rule ip nat prerouting tcp dport 80 counter redirect to :8080' + +iptables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 0-65535 +nft 'add rule ip nat prerouting tcp dport 80 counter redirect to :0-65535' + +iptables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 10-22 +nft 'add rule ip nat prerouting tcp dport 80 counter redirect to :10-22' + +iptables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 8080 --random +nft 'add rule ip nat prerouting tcp dport 80 counter redirect to :8080 random' + +iptables-translate -t nat -A prerouting -j REDIRECT --random +nft 'add rule ip nat prerouting counter redirect random' + +ip6tables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT +nft 'add rule ip6 nat prerouting tcp dport 80 counter redirect' + +ip6tables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 8080 +nft 'add rule ip6 nat prerouting tcp dport 80 counter redirect to :8080' + +ip6tables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 8080 --random +nft 'add rule ip6 nat prerouting tcp dport 80 counter redirect to :8080 random' diff --git a/extensions/libxt_SECMARK.c b/extensions/libxt_SECMARK.c index 24249bd6..a4ee60f0 100644 --- a/extensions/libxt_SECMARK.c +++ b/extensions/libxt_SECMARK.c @@ -60,7 +60,7 @@ static void print_secmark(__u8 mode, const char *secctx) break; default: - xtables_error(OTHER_PROBLEM, PFX "invalid mode %hhu\n", mode); + xtables_error(OTHER_PROBLEM, PFX "invalid mode %hhu", mode); } } diff --git a/extensions/libxt_SNAT.man b/extensions/libxt_SNAT.man index 8cd0b80e..80a698a6 100644 --- a/extensions/libxt_SNAT.man +++ b/extensions/libxt_SNAT.man @@ -19,22 +19,12 @@ If no port range is specified, then source ports below 512 will be mapped to other ports below 512: those between 512 and 1023 inclusive will be mapped to ports below 1024, and other ports will be mapped to 1024 or above. Where possible, no port alteration will occur. -In Kernels up to 2.6.10, you can add several \-\-to\-source options. For those -kernels, if you specify more than one source address, either via an address -range or multiple \-\-to\-source options, a simple round-robin (one after another -in cycle) takes place between these addresses. -Later Kernels (>= 2.6.11-rc1) don't have the ability to NAT to multiple ranges -anymore. .TP \fB\-\-random\fP -If option -\fB\-\-random\fP -is used then port mapping will be randomized through a hash-based algorithm (kernel >= 2.6.21). +Randomize source port mapping 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). +Fully randomize source port mapping 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.txlate b/extensions/libxt_SYNPROXY.txlate index b3de2b2a..b996c4b7 100644 --- a/extensions/libxt_SYNPROXY.txlate +++ b/extensions/libxt_SYNPROXY.txlate @@ -1,2 +1,2 @@ iptables-translate -t mangle -A INPUT -i iifname -p tcp -m tcp --dport 80 -m state --state INVALID,UNTRACKED -j SYNPROXY --sack-perm --timestamp --wscale 7 --mss 1460 -nft add rule ip mangle INPUT iifname "iifname" tcp dport 80 ct state invalid,untracked counter synproxy sack-perm timestamp wscale 7 mss 1460 +nft 'add rule ip mangle INPUT iifname "iifname" tcp dport 80 ct state invalid,untracked counter synproxy sack-perm timestamp wscale 7 mss 1460' diff --git a/extensions/libxt_TCPMSS.c b/extensions/libxt_TCPMSS.c index 0d9b200e..251a5532 100644 --- a/extensions/libxt_TCPMSS.c +++ b/extensions/libxt_TCPMSS.c @@ -131,6 +131,7 @@ static struct xtables_target tcpmss_tg_reg[] = { .x6_parse = TCPMSS_parse, .x6_fcheck = TCPMSS_check, .x6_options = TCPMSS6_opts, + .xlate = TCPMSS_xlate, }, }; diff --git a/extensions/libxt_TCPMSS.t b/extensions/libxt_TCPMSS.t index 553a3452..fbfbfcf8 100644 --- a/extensions/libxt_TCPMSS.t +++ b/extensions/libxt_TCPMSS.t @@ -1,6 +1,6 @@ :FORWARD,OUTPUT,POSTROUTING *mangle -j TCPMSS;;FAIL --p tcp -j TCPMSS --set-mss 42;;FAIL +-p tcp -j TCPMSS --set-mss 42;;FAIL;LEGACY -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_TCPMSS.txlate b/extensions/libxt_TCPMSS.txlate index 3dbbad66..a059c602 100644 --- a/extensions/libxt_TCPMSS.txlate +++ b/extensions/libxt_TCPMSS.txlate @@ -1,5 +1,5 @@ iptables-translate -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu -nft add rule ip filter FORWARD tcp flags syn / syn,rst counter tcp option maxseg size set rt mtu +nft 'add rule ip filter FORWARD tcp flags syn / syn,rst counter tcp option maxseg size set rt mtu' iptables-translate -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 90 -nft add rule ip filter FORWARD tcp flags syn / syn,rst counter tcp option maxseg size set 90 +nft 'add rule ip filter FORWARD tcp flags syn / syn,rst counter tcp option maxseg size set 90' diff --git a/extensions/libxt_TCPOPTSTRIP.c b/extensions/libxt_TCPOPTSTRIP.c index 6ea34892..ff873f98 100644 --- a/extensions/libxt_TCPOPTSTRIP.c +++ b/extensions/libxt_TCPOPTSTRIP.c @@ -142,6 +142,13 @@ tcpoptstrip_print_list(const struct xt_tcpoptstrip_target_info *info, } } +static bool tcpoptstrip_empty(const struct xt_tcpoptstrip_target_info *info) +{ + static const struct xt_tcpoptstrip_target_info empty = {}; + + return memcmp(info, &empty, sizeof(empty)) == 0; +} + static void tcpoptstrip_tg_print(const void *ip, const struct xt_entry_target *target, int numeric) @@ -149,6 +156,9 @@ tcpoptstrip_tg_print(const void *ip, const struct xt_entry_target *target, const struct xt_tcpoptstrip_target_info *info = (const void *)target->data; + if (tcpoptstrip_empty(info)) + return; + printf(" TCPOPTSTRIP options "); tcpoptstrip_print_list(info, numeric); } @@ -159,6 +169,9 @@ tcpoptstrip_tg_save(const void *ip, const struct xt_entry_target *target) const struct xt_tcpoptstrip_target_info *info = (const void *)target->data; + if (tcpoptstrip_empty(info)) + return; + printf(" --strip-options "); tcpoptstrip_print_list(info, true); } diff --git a/extensions/libxt_TEE.txlate b/extensions/libxt_TEE.txlate index 9fcee254..fa1d5fe3 100644 --- a/extensions/libxt_TEE.txlate +++ b/extensions/libxt_TEE.txlate @@ -1,11 +1,11 @@ # iptables-translate -t mangle -A PREROUTING -j TEE --gateway 192.168.0.2 --oif eth0 -# nft add rule ip mangle PREROUTING counter dup to 192.168.0.2 device eth0 +# nft 'add rule ip mangle PREROUTING counter dup to 192.168.0.2 device eth0 # # iptables-translate -t mangle -A PREROUTING -j TEE --gateway 192.168.0.2 -# nft add rule ip mangle PREROUTING counter dup to 192.168.0.2 +# nft 'add rule ip mangle PREROUTING counter dup to 192.168.0.2 ip6tables-translate -t mangle -A PREROUTING -j TEE --gateway ab12:00a1:1112:acba:: -nft add rule ip6 mangle PREROUTING counter dup to ab12:a1:1112:acba:: +nft 'add rule ip6 mangle PREROUTING counter dup to ab12:a1:1112:acba::' ip6tables-translate -t mangle -A PREROUTING -j TEE --gateway ab12:00a1:1112:acba:: --oif eth0 -nft add rule ip6 mangle PREROUTING counter dup to ab12:a1:1112:acba:: device eth0 +nft 'add rule ip6 mangle PREROUTING counter dup to ab12:a1:1112:acba:: device eth0' diff --git a/extensions/libxt_TOS.c b/extensions/libxt_TOS.c index b66fa329..4fc849bd 100644 --- a/extensions/libxt_TOS.c +++ b/extensions/libxt_TOS.c @@ -183,28 +183,41 @@ static void tos_tg_save(const void *ip, const struct xt_entry_target *target) printf(" --set-tos 0x%02x/0x%02x", info->tos_value, info->tos_mask); } +static int __tos_xlate(struct xt_xlate *xl, const char *ip, + uint8_t tos, uint8_t tosmask) +{ + xt_xlate_add(xl, "%s dscp set ", ip); + if ((tosmask & 0x3f) == 0x3f) + xt_xlate_add(xl, "0x%02x", tos >> 2); + else if (!tos) + xt_xlate_add(xl, "%s dscp and 0x%02x", + ip, (uint8_t)~tosmask >> 2); + else if (tos == tosmask) + xt_xlate_add(xl, "%s dscp or 0x%02x", ip, tos >> 2); + else if (!tosmask) + xt_xlate_add(xl, "%s dscp xor 0x%02x", ip, tos >> 2); + else + xt_xlate_add(xl, "%s dscp and 0x%02x xor 0x%02x", + ip, (uint8_t)~tosmask >> 2, tos >> 2); + return 1; +} + static int tos_xlate(struct xt_xlate *xl, const struct xt_xlate_tg_params *params) { const struct ipt_tos_target_info *info = (struct ipt_tos_target_info *) params->target->data; - uint8_t dscp = info->tos >> 2; - - xt_xlate_add(xl, "ip dscp set 0x%02x", dscp); - return 1; + return __tos_xlate(xl, "ip", info->tos, UINT8_MAX); } static int tos_xlate6(struct xt_xlate *xl, const struct xt_xlate_tg_params *params) { - const struct ipt_tos_target_info *info = - (struct ipt_tos_target_info *) params->target->data; - uint8_t dscp = info->tos >> 2; + const struct xt_tos_target_info *info = + (struct xt_tos_target_info *)params->target->data; - xt_xlate_add(xl, "ip6 dscp set 0x%02x", dscp); - - return 1; + return __tos_xlate(xl, "ip6", info->tos_value, info->tos_mask); } static struct xtables_target tos_tg_reg[] = { diff --git a/extensions/libxt_TOS.t b/extensions/libxt_TOS.t index ae8531cc..9f8e33fd 100644 --- a/extensions/libxt_TOS.t +++ b/extensions/libxt_TOS.t @@ -1,15 +1,15 @@ :PREROUTING,INPUT,FORWARD,OUTPUT,POSTROUTING *mangle --j TOS --set-tos 0x1f;=;OK +-j TOS --set-tos 0x1f;-j TOS --set-tos 0x1f/0xff;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 --set-tos Minimize-Delay;-j TOS --set-tos 0x10/0x3f;OK +-j TOS --set-tos Maximize-Throughput;-j TOS --set-tos 0x08/0x3f;OK +-j TOS --set-tos Maximize-Reliability;-j TOS --set-tos 0x04/0x3f;OK +-j TOS --set-tos Minimize-Cost;-j TOS --set-tos 0x02/0x3f;OK +-j TOS --set-tos Normal-Service;-j TOS --set-tos 0x00/0x3f;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 diff --git a/extensions/libxt_TOS.txlate b/extensions/libxt_TOS.txlate index 0952310e..37ef1d86 100644 --- a/extensions/libxt_TOS.txlate +++ b/extensions/libxt_TOS.txlate @@ -1,23 +1,26 @@ ip6tables-translate -A INPUT -j TOS --set-tos 0x1f -nft add rule ip6 filter INPUT counter ip6 dscp set 0x07 +nft 'add rule ip6 filter INPUT counter ip6 dscp set 0x07' ip6tables-translate -A INPUT -j TOS --set-tos 0xff -nft add rule ip6 filter INPUT counter ip6 dscp set 0x3f +nft 'add rule ip6 filter INPUT counter ip6 dscp set 0x3f' ip6tables-translate -A INPUT -j TOS --set-tos Minimize-Delay -nft add rule ip6 filter INPUT counter ip6 dscp set 0x04 +nft 'add rule ip6 filter INPUT counter ip6 dscp set 0x04' ip6tables-translate -A INPUT -j TOS --set-tos Minimize-Cost -nft add rule ip6 filter INPUT counter ip6 dscp set 0x00 +nft 'add rule ip6 filter INPUT counter ip6 dscp set 0x00' ip6tables-translate -A INPUT -j TOS --set-tos Normal-Service -nft add rule ip6 filter INPUT counter ip6 dscp set 0x00 +nft 'add rule ip6 filter INPUT counter ip6 dscp set 0x00' ip6tables-translate -A INPUT -j TOS --and-tos 0x12 -nft add rule ip6 filter INPUT counter ip6 dscp set 0x00 +nft 'add rule ip6 filter INPUT counter ip6 dscp set ip6 dscp and 0x04' ip6tables-translate -A INPUT -j TOS --or-tos 0x12 -nft add rule ip6 filter INPUT counter ip6 dscp set 0x04 +nft 'add rule ip6 filter INPUT counter ip6 dscp set ip6 dscp or 0x04' ip6tables-translate -A INPUT -j TOS --xor-tos 0x12 -nft add rule ip6 filter INPUT counter ip6 dscp set 0x04 +nft 'add rule ip6 filter INPUT counter ip6 dscp set ip6 dscp xor 0x04' + +ip6tables-translate -A INPUT -j TOS --set-tos 0x12/0x34 +nft 'add rule ip6 filter INPUT counter ip6 dscp set ip6 dscp and 0x32 xor 0x04' diff --git a/extensions/libxt_TRACE.txlate b/extensions/libxt_TRACE.txlate index 8e3d2a7a..a9d28fe0 100644 --- a/extensions/libxt_TRACE.txlate +++ b/extensions/libxt_TRACE.txlate @@ -1,2 +1,2 @@ iptables-translate -t raw -A PREROUTING -j TRACE -nft add rule ip raw PREROUTING counter nftrace set 1 +nft 'add rule ip raw PREROUTING counter nftrace set 1' diff --git a/extensions/libxt_addrtype.txlate b/extensions/libxt_addrtype.txlate index a719b2c9..70c0a345 100644 --- a/extensions/libxt_addrtype.txlate +++ b/extensions/libxt_addrtype.txlate @@ -1,11 +1,11 @@ iptables-translate -A INPUT -m addrtype --src-type LOCAL -nft add rule ip filter INPUT fib saddr type local counter +nft 'add rule ip filter INPUT fib saddr type local counter' iptables-translate -A INPUT -m addrtype --dst-type LOCAL -nft add rule ip filter INPUT fib daddr type local counter +nft 'add rule ip filter INPUT fib daddr type local counter' iptables-translate -A INPUT -m addrtype ! --dst-type ANYCAST,LOCAL -nft add rule ip filter INPUT fib daddr type != { local, anycast } counter +nft 'add rule ip filter INPUT fib daddr type != { local, anycast } counter' iptables-translate -A INPUT -m addrtype --limit-iface-in --dst-type ANYCAST,LOCAL -nft add rule ip filter INPUT fib daddr . iif type { local, anycast } counter +nft 'add rule ip filter INPUT fib daddr . iif type { local, anycast } counter' diff --git a/extensions/libxt_bpf.c b/extensions/libxt_bpf.c index eeae86e5..5e035837 100644 --- a/extensions/libxt_bpf.c +++ b/extensions/libxt_bpf.c @@ -83,8 +83,7 @@ static int bpf_obj_get_readonly(const char *filepath) attr.file_flags = 0; return syscall(__NR_bpf, BPF_OBJ_GET, &attr, sizeof(attr)); #else - xtables_error(OTHER_PROBLEM, - "No bpf header, kernel headers too old?\n"); + xtables_error(OTHER_PROBLEM, "No bpf header, kernel headers too old?"); return -EINVAL; #endif } diff --git a/extensions/libxt_cgroup.txlate b/extensions/libxt_cgroup.txlate index 75f2e6ae..6e3aab76 100644 --- a/extensions/libxt_cgroup.txlate +++ b/extensions/libxt_cgroup.txlate @@ -1,5 +1,5 @@ iptables-translate -t filter -A INPUT -m cgroup --cgroup 0 -j ACCEPT -nft add rule ip filter INPUT meta cgroup 0 counter accept +nft 'add rule ip filter INPUT meta cgroup 0 counter accept' iptables-translate -t filter -A INPUT -m cgroup ! --cgroup 0 -j ACCEPT -nft add rule ip filter INPUT meta cgroup != 0 counter accept +nft 'add rule ip filter INPUT meta cgroup != 0 counter accept' diff --git a/extensions/libxt_cluster.txlate b/extensions/libxt_cluster.txlate index 9dcf5707..4dc1c691 100644 --- a/extensions/libxt_cluster.txlate +++ b/extensions/libxt_cluster.txlate @@ -1,26 +1,26 @@ iptables-translate -A PREROUTING -t mangle -i eth1 -m cluster --cluster-total-nodes 2 --cluster-local-node 1 --cluster-hash-seed 0xdeadbeef -j MARK --set-mark 0xffff -nft add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 2 seed 0xdeadbeef eq 1 meta pkttype set host counter meta mark set 0xffff +nft 'add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 2 seed 0xdeadbeef eq 1 meta pkttype set host counter meta mark set 0xffff' iptables-translate -A PREROUTING -t mangle -i eth1 -m cluster --cluster-total-nodes 1 --cluster-local-node 1 --cluster-hash-seed 0xdeadbeef -j MARK --set-mark 0xffff -nft add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 1 seed 0xdeadbeef eq 1 meta pkttype set host counter meta mark set 0xffff +nft 'add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 1 seed 0xdeadbeef eq 1 meta pkttype set host counter meta mark set 0xffff' iptables-translate -A PREROUTING -t mangle -i eth1 -m cluster --cluster-total-nodes 2 --cluster-local-nodemask 1 --cluster-hash-seed 0xdeadbeef -j MARK --set-mark 0xffff -nft add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 2 seed 0xdeadbeef eq 1 meta pkttype set host counter meta mark set 0xffff +nft 'add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 2 seed 0xdeadbeef eq 1 meta pkttype set host counter meta mark set 0xffff' iptables-translate -A PREROUTING -t mangle -i eth1 -m cluster --cluster-total-nodes 1 --cluster-local-nodemask 1 --cluster-hash-seed 0xdeadbeef -j MARK --set-mark 0xffff -nft add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 1 seed 0xdeadbeef eq 1 meta pkttype set host counter meta mark set 0xffff +nft 'add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 1 seed 0xdeadbeef eq 1 meta pkttype set host counter meta mark set 0xffff' iptables-translate -A PREROUTING -t mangle -i eth1 -m cluster --cluster-total-nodes 32 --cluster-local-node 32 --cluster-hash-seed 0xdeadbeef -j MARK --set-mark 0xffff -nft add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 32 seed 0xdeadbeef eq 32 meta pkttype set host counter meta mark set 0xffff +nft 'add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 32 seed 0xdeadbeef eq 32 meta pkttype set host counter meta mark set 0xffff' iptables-translate -A PREROUTING -t mangle -i eth1 -m cluster --cluster-total-nodes 32 --cluster-local-nodemask 32 --cluster-hash-seed 0xdeadbeef -j MARK --set-mark 0xffff -nft add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 32 seed 0xdeadbeef eq 6 meta pkttype set host counter meta mark set 0xffff +nft 'add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 32 seed 0xdeadbeef eq 6 meta pkttype set host counter meta mark set 0xffff' iptables-translate -A PREROUTING -t mangle -i eth1 -m cluster --cluster-total-nodes 32 --cluster-local-nodemask 5 --cluster-hash-seed 0xdeadbeef -j MARK --set-mark 0xffff -nft add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 32 seed 0xdeadbeef { 0, 2 } meta pkttype set host counter meta mark set 0xffff +nft 'add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 32 seed 0xdeadbeef { 0, 2 } meta pkttype set host counter meta mark set 0xffff' iptables-translate -A PREROUTING -t mangle -i eth1 -m cluster --cluster-total-nodes 7 --cluster-local-nodemask 9 --cluster-hash-seed 0xdeadbeef -j MARK --set-mark 0xffff -nft add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 7 seed 0xdeadbeef { 0, 3 } meta pkttype set host counter meta mark set 0xffff +nft 'add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 7 seed 0xdeadbeef { 0, 3 } meta pkttype set host counter meta mark set 0xffff' iptables-translate -A PREROUTING -t mangle -i eth1 -m cluster --cluster-total-nodes 7 --cluster-local-node 5 --cluster-hash-seed 0xdeadbeef -j MARK --set-mark 0xffff -nft add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 7 seed 0xdeadbeef eq 5 meta pkttype set host counter meta mark set 0xffff +nft 'add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 7 seed 0xdeadbeef eq 5 meta pkttype set host counter meta mark set 0xffff' diff --git a/extensions/libxt_comment.c b/extensions/libxt_comment.c index 69795b6c..e9c539f6 100644 --- a/extensions/libxt_comment.c +++ b/extensions/libxt_comment.c @@ -55,12 +55,7 @@ static int comment_xlate(struct xt_xlate *xl, char comment[XT_MAX_COMMENT_LEN + sizeof("\\\"\\\"")]; commentinfo->comment[XT_MAX_COMMENT_LEN - 1] = '\0'; - if (params->escape_quotes) - snprintf(comment, sizeof(comment), "\\\"%s\\\"", - commentinfo->comment); - else - snprintf(comment, sizeof(comment), "\"%s\"", - commentinfo->comment); + snprintf(comment, sizeof(comment), "\"%s\"", commentinfo->comment); xt_xlate_add_comment(xl, comment); diff --git a/extensions/libxt_comment.txlate b/extensions/libxt_comment.txlate index c610b0e5..5d4ce59d 100644 --- a/extensions/libxt_comment.txlate +++ b/extensions/libxt_comment.txlate @@ -1,8 +1,8 @@ iptables-translate -A INPUT -s 192.168.0.0 -m comment --comment "A privatized IP block" -nft add rule ip filter INPUT ip saddr 192.168.0.0 counter comment \"A privatized IP block\" +nft 'add rule ip filter INPUT ip saddr 192.168.0.0 counter comment "A privatized IP block"' iptables-translate -A INPUT -p tcp -m tcp --sport http -s 192.168.0.0/16 -d 192.168.0.0/16 -j LONGNACCEPT -m comment --comment "foobar" -nft add rule ip filter INPUT ip saddr 192.168.0.0/16 ip daddr 192.168.0.0/16 tcp sport 80 counter jump LONGNACCEPT comment \"foobar\" +nft 'add rule ip filter INPUT ip saddr 192.168.0.0/16 ip daddr 192.168.0.0/16 tcp sport 80 counter jump LONGNACCEPT comment "foobar"' iptables-translate -A FORWARD -p tcp -m tcp --sport http -s 192.168.0.0/16 -d 192.168.0.0/16 -j DROP -m comment --comment singlecomment -nft add rule ip filter FORWARD ip saddr 192.168.0.0/16 ip daddr 192.168.0.0/16 tcp sport 80 counter drop comment \"singlecomment\" +nft 'add rule ip filter FORWARD ip saddr 192.168.0.0/16 ip daddr 192.168.0.0/16 tcp sport 80 counter drop comment "singlecomment"' diff --git a/extensions/libxt_connbytes.txlate b/extensions/libxt_connbytes.txlate index f78958d2..a6af1b87 100644 --- a/extensions/libxt_connbytes.txlate +++ b/extensions/libxt_connbytes.txlate @@ -1,14 +1,14 @@ iptables-translate -A OUTPUT -m connbytes --connbytes 200 --connbytes-dir original --connbytes-mode packets -nft add rule ip filter OUTPUT ct original packets ge 200 counter +nft 'add rule ip filter OUTPUT ct original packets ge 200 counter' iptables-translate -A OUTPUT -m connbytes ! --connbytes 200 --connbytes-dir reply --connbytes-mode packets -nft add rule ip filter OUTPUT ct reply packets lt 200 counter +nft 'add rule ip filter OUTPUT ct reply packets lt 200 counter' iptables-translate -A OUTPUT -m connbytes --connbytes 200:600 --connbytes-dir both --connbytes-mode bytes -nft add rule ip filter OUTPUT ct bytes 200-600 counter +nft 'add rule ip filter OUTPUT ct bytes 200-600 counter' iptables-translate -A OUTPUT -m connbytes ! --connbytes 200:600 --connbytes-dir both --connbytes-mode bytes -nft add rule ip filter OUTPUT ct bytes != 200-600 counter +nft 'add rule ip filter OUTPUT ct bytes != 200-600 counter' iptables-translate -A OUTPUT -m connbytes --connbytes 200:200 --connbytes-dir both --connbytes-mode avgpkt -nft add rule ip filter OUTPUT ct avgpkt 200 counter +nft 'add rule ip filter OUTPUT ct avgpkt 200 counter' diff --git a/extensions/libxt_connlabel.txlate b/extensions/libxt_connlabel.txlate index 12e4ac03..cba01d2d 100644 --- a/extensions/libxt_connlabel.txlate +++ b/extensions/libxt_connlabel.txlate @@ -1,5 +1,5 @@ iptables-translate -A INPUT -m connlabel --label 40 -nft add rule ip filter INPUT ct label 40 counter +nft 'add rule ip filter INPUT ct label 40 counter' iptables-translate -A INPUT -m connlabel ! --label 40 --set -nft add rule ip filter INPUT ct label set 40 ct label and 40 != 40 counter +nft 'add rule ip filter INPUT ct label set 40 ct label and 40 != 40 counter' diff --git a/extensions/libxt_connlimit.t b/extensions/libxt_connlimit.t index c7ea61e9..366cea74 100644 --- a/extensions/libxt_connlimit.t +++ b/extensions/libxt_connlimit.t @@ -1,11 +1,11 @@ :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 0;-m connlimit --connlimit-upto 0 --connlimit-mask 32 --connlimit-saddr;OK +-m connlimit --connlimit-upto 4294967295 --connlimit-mask 32 --connlimit-saddr;=;OK +-m connlimit --connlimit-upto 4294967296 --connlimit-mask 32 --connlimit-saddr;;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 0;-m connlimit --connlimit-above 0 --connlimit-mask 32 --connlimit-saddr;OK +-m connlimit --connlimit-above 4294967295 --connlimit-mask 32 --connlimit-saddr;=;OK +-m connlimit --connlimit-above 4294967296 --connlimit-mask 32 --connlimit-saddr;;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 diff --git a/extensions/libxt_connlimit.txlate b/extensions/libxt_connlimit.txlate index 758868c4..3108a529 100644 --- a/extensions/libxt_connlimit.txlate +++ b/extensions/libxt_connlimit.txlate @@ -1,15 +1,15 @@ iptables-translate -A INPUT -m connlimit --connlimit-above 2 -nft add set ip filter connlimit0 { type ipv4_addr; flags dynamic; } -nft add rule ip filter INPUT add @connlimit0 { ip saddr ct count over 2 } counter +nft 'add set ip filter connlimit0 { type ipv4_addr; flags dynamic; }' +nft 'add rule ip filter INPUT add @connlimit0 { ip saddr ct count over 2 } counter' iptables-translate -A INPUT -m connlimit --connlimit-upto 2 -nft add set ip filter connlimit0 { type ipv4_addr; flags dynamic; } -nft add rule ip filter INPUT add @connlimit0 { ip saddr ct count 2 } counter +nft 'add set ip filter connlimit0 { type ipv4_addr; flags dynamic; }' +nft 'add rule ip filter INPUT add @connlimit0 { ip saddr ct count 2 } counter' iptables-translate -A INPUT -m connlimit --connlimit-upto 2 --connlimit-mask 24 -nft add set ip filter connlimit0 { type ipv4_addr; flags dynamic; } -nft add rule ip filter INPUT add @connlimit0 { ip saddr and 255.255.255.0 ct count 2 } counter +nft 'add set ip filter connlimit0 { type ipv4_addr; flags dynamic; }' +nft 'add rule ip filter INPUT add @connlimit0 { ip saddr and 255.255.255.0 ct count 2 } counter' iptables-translate -A INPUT -m connlimit --connlimit-upto 2 --connlimit-daddr -nft add set ip filter connlimit0 { type ipv4_addr; flags dynamic; } -nft add rule ip filter INPUT add @connlimit0 { ip daddr ct count 2 } counter +nft 'add set ip filter connlimit0 { type ipv4_addr; flags dynamic; }' +nft 'add rule ip filter INPUT add @connlimit0 { ip daddr ct count 2 } counter' diff --git a/extensions/libxt_connmark.t b/extensions/libxt_connmark.t index 4dd7d9af..353970a8 100644 --- a/extensions/libxt_connmark.t +++ b/extensions/libxt_connmark.t @@ -2,8 +2,8 @@ *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 0xffffffff/0x0;=;OK +-m connmark --mark 0/0xffffffff;-m connmark --mark 0x0;OK -m connmark --mark -1;;FAIL -m connmark --mark 0xfffffffff;;FAIL -m connmark;;FAIL diff --git a/extensions/libxt_connmark.txlate b/extensions/libxt_connmark.txlate index 89423259..e7bfd721 100644 --- a/extensions/libxt_connmark.txlate +++ b/extensions/libxt_connmark.txlate @@ -1,14 +1,14 @@ iptables-translate -A INPUT -m connmark --mark 2 -j ACCEPT -nft add rule ip filter INPUT ct mark 0x2 counter accept +nft 'add rule ip filter INPUT ct mark 0x2 counter accept' iptables-translate -A INPUT -m connmark ! --mark 2 -j ACCEPT -nft add rule ip filter INPUT ct mark != 0x2 counter accept +nft 'add rule ip filter INPUT ct mark != 0x2 counter accept' iptables-translate -A INPUT -m connmark --mark 10/10 -j ACCEPT -nft add rule ip filter INPUT ct mark and 0xa == 0xa counter accept +nft 'add rule ip filter INPUT ct mark and 0xa == 0xa counter accept' iptables-translate -A INPUT -m connmark ! --mark 10/10 -j ACCEPT -nft add rule ip filter INPUT ct mark and 0xa != 0xa counter accept +nft 'add rule ip filter INPUT ct mark and 0xa != 0xa counter accept' iptables-translate -t mangle -A PREROUTING -p tcp --dport 40 -m connmark --mark 0x40 -nft add rule ip mangle PREROUTING tcp dport 40 ct mark 0x40 counter +nft 'add rule ip mangle PREROUTING tcp dport 40 ct mark 0x40 counter' diff --git a/extensions/libxt_conntrack.c b/extensions/libxt_conntrack.c index 64018ce1..09548c29 100644 --- a/extensions/libxt_conntrack.c +++ b/extensions/libxt_conntrack.c @@ -778,7 +778,7 @@ matchinfo_print(const void *ip, const struct xt_entry_match *match, int numeric, static void conntrack_dump_ports(const char *prefix, const char *opt, - u_int16_t port_low, u_int16_t port_high) + uint16_t port_low, uint16_t port_high) { if (port_high == 0 || port_low == port_high) printf(" %s%s %u", prefix, opt, port_low); @@ -1186,7 +1186,6 @@ static int state_xlate(struct xt_xlate *xl, xt_xlate_add(xl, "ct state "); state_xlate_print(xl, sinfo->state_mask, sinfo->invert_flags & XT_CONNTRACK_STATE); - xt_xlate_add(xl, " "); return 1; } @@ -1289,9 +1288,6 @@ static int _conntrack3_mt_xlate(struct xt_xlate *xl, } 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 ? "!= " : ""); @@ -1301,9 +1297,6 @@ static int _conntrack3_mt_xlate(struct xt_xlate *xl, } 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 ? "!= " : ""); @@ -1313,9 +1306,6 @@ static int _conntrack3_mt_xlate(struct xt_xlate *xl, } 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 ? "!= " : ""); @@ -1325,9 +1315,6 @@ static int _conntrack3_mt_xlate(struct xt_xlate *xl, } 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 ? "!= " : ""); diff --git a/extensions/libxt_conntrack.txlate b/extensions/libxt_conntrack.txlate index 45fba984..0f44a957 100644 --- a/extensions/libxt_conntrack.txlate +++ b/extensions/libxt_conntrack.txlate @@ -1,60 +1,60 @@ iptables-translate -t filter -A INPUT -m conntrack --ctstate NEW,RELATED -j ACCEPT -nft add rule ip filter INPUT ct state new,related counter accept +nft 'add rule ip filter INPUT ct state new,related counter accept' ip6tables-translate -t filter -A INPUT -m conntrack ! --ctstate NEW,RELATED -j ACCEPT -nft add rule ip6 filter INPUT ct state ! new,related counter accept +nft 'add rule ip6 filter INPUT ct state ! new,related counter accept' ip6tables-translate -t filter -A INPUT -m conntrack ! --ctstate NEW -j ACCEPT -nft add rule ip6 filter INPUT ct state ! new counter accept +nft 'add rule ip6 filter INPUT ct state ! new counter accept' iptables-translate -t filter -A INPUT -m conntrack --ctproto UDP -j ACCEPT -nft add rule ip filter INPUT ct original protocol 17 counter accept +nft 'add rule ip filter INPUT ct original protocol 17 counter accept' iptables-translate -t filter -A INPUT -m conntrack ! --ctproto UDP -j ACCEPT -nft add rule ip filter INPUT ct original protocol != 17 counter accept +nft 'add rule ip filter INPUT ct original protocol != 17 counter accept' iptables-translate -t filter -A INPUT -m conntrack --ctorigsrc 10.100.2.131 -j ACCEPT -nft add rule ip filter INPUT ct original saddr 10.100.2.131 counter accept +nft 'add rule ip filter INPUT ct original saddr 10.100.2.131 counter accept' iptables-translate -t filter -A INPUT -m conntrack --ctorigsrc 10.100.0.0/255.255.0.0 -j ACCEPT -nft add rule ip filter INPUT ct original saddr 10.100.0.0/16 counter accept +nft 'add rule ip filter INPUT ct original saddr 10.100.0.0/16 counter accept' iptables-translate -t filter -A INPUT -m conntrack --ctorigdst 10.100.2.131 -j ACCEPT -nft add rule ip filter INPUT ct original daddr 10.100.2.131 counter accept +nft 'add rule ip filter INPUT ct original daddr 10.100.2.131 counter accept' iptables-translate -t filter -A INPUT -m conntrack --ctreplsrc 10.100.2.131 -j ACCEPT -nft add rule ip filter INPUT ct reply saddr 10.100.2.131 counter accept +nft 'add rule ip filter INPUT ct reply saddr 10.100.2.131 counter accept' iptables-translate -t filter -A INPUT -m conntrack --ctrepldst 10.100.2.131 -j ACCEPT -nft add rule ip filter INPUT ct reply daddr 10.100.2.131 counter accept +nft 'add rule ip filter INPUT ct reply daddr 10.100.2.131 counter accept' iptables-translate -t filter -A INPUT -m conntrack --ctproto tcp --ctorigsrcport 443:444 -j ACCEPT -nft add rule ip filter INPUT ct original protocol 6 ct original proto-src 443-444 counter accept +nft 'add rule ip filter INPUT ct original protocol 6 ct original proto-src 443-444 counter accept' iptables-translate -t filter -A INPUT -m conntrack --ctstatus EXPECTED -j ACCEPT -nft add rule ip filter INPUT ct status expected counter accept +nft 'add rule ip filter INPUT ct status expected counter accept' iptables-translate -t filter -A INPUT -m conntrack ! --ctstatus CONFIRMED -j ACCEPT -nft add rule ip filter INPUT ct status ! confirmed counter accept +nft 'add rule ip filter INPUT ct status ! confirmed counter accept' iptables-translate -t filter -A INPUT -m conntrack ! --ctstatus CONFIRMED,ASSURED -j ACCEPT -nft add rule ip filter INPUT ct status ! assured,confirmed counter accept +nft 'add rule ip filter INPUT ct status ! assured,confirmed counter accept' iptables-translate -t filter -A INPUT -m conntrack --ctstatus CONFIRMED,ASSURED -j ACCEPT -nft add rule ip filter INPUT ct status assured,confirmed counter accept +nft 'add rule ip filter INPUT ct status assured,confirmed counter accept' iptables-translate -t filter -A INPUT -m conntrack --ctexpire 3 -j ACCEPT -nft add rule ip filter INPUT ct expiration 3 counter accept +nft 'add rule ip filter INPUT ct expiration 3 counter accept' iptables-translate -t filter -A INPUT -m conntrack --ctdir ORIGINAL -j ACCEPT -nft add rule ip filter INPUT ct direction original counter accept +nft 'add rule ip filter INPUT ct direction original counter accept' iptables-translate -t filter -A INPUT -m conntrack --ctstate NEW --ctproto tcp --ctorigsrc 192.168.0.1 --ctorigdst 192.168.0.1 --ctreplsrc 192.168.0.1 --ctrepldst 192.168.0.1 --ctorigsrcport 12 --ctorigdstport 14 --ctreplsrcport 16 --ctrepldstport 18 --ctexpire 10 --ctstatus SEEN_REPLY --ctdir ORIGINAL -j ACCEPT -nft add rule ip filter INPUT ct direction original ct original protocol 6 ct state new ct status seen-reply ct expiration 10 ct original saddr 192.168.0.1 ct original daddr 192.168.0.1 ct reply saddr 192.168.0.1 ct reply daddr 192.168.0.1 ct original proto-src 12 ct original proto-dst 14 ct reply proto-src 16 ct reply proto-dst 18 counter accept +nft 'add rule ip filter INPUT ct direction original ct original protocol 6 ct state new ct status seen-reply ct expiration 10 ct original saddr 192.168.0.1 ct original daddr 192.168.0.1 ct reply saddr 192.168.0.1 ct reply daddr 192.168.0.1 ct original proto-src 12 ct original proto-dst 14 ct reply proto-src 16 ct reply proto-dst 18 counter accept' iptables-translate -t filter -A INPUT -m conntrack --ctstate SNAT -j ACCEPT -nft add rule ip filter INPUT ct status snat counter accept +nft 'add rule ip filter INPUT ct status snat counter accept' iptables-translate -t filter -A INPUT -m conntrack --ctstate DNAT -j ACCEPT -nft add rule ip filter INPUT ct status dnat counter accept +nft 'add rule ip filter INPUT ct status dnat counter accept' diff --git a/extensions/libxt_cpu.txlate b/extensions/libxt_cpu.txlate index c59b0e02..937c939e 100644 --- a/extensions/libxt_cpu.txlate +++ b/extensions/libxt_cpu.txlate @@ -1,5 +1,5 @@ iptables-translate -A INPUT -p tcp --dport 80 -m cpu --cpu 0 -j ACCEPT -nft add rule ip filter INPUT tcp dport 80 cpu 0 counter accept +nft 'add rule ip filter INPUT tcp dport 80 cpu 0 counter accept' iptables-translate -A INPUT -p tcp --dport 80 -m cpu ! --cpu 1 -j ACCEPT -nft add rule ip filter INPUT tcp dport 80 cpu != 1 counter accept +nft 'add rule ip filter INPUT tcp dport 80 cpu != 1 counter accept' diff --git a/extensions/libxt_dccp.c b/extensions/libxt_dccp.c index abd420fc..bfceced3 100644 --- a/extensions/libxt_dccp.c +++ b/extensions/libxt_dccp.c @@ -343,7 +343,6 @@ static int dccp_xlate(struct xt_xlate *xl, { const struct xt_dccp_info *einfo = (const struct xt_dccp_info *)params->match->data; - char *space = ""; int ret = 1; if (einfo->flags & XT_DCCP_SRC_PORTS) { @@ -353,27 +352,21 @@ static int dccp_xlate(struct xt_xlate *xl, if (einfo->spts[0] != einfo->spts[1]) xt_xlate_add(xl, "-%u", einfo->spts[1]); - - space = " "; } if (einfo->flags & XT_DCCP_DEST_PORTS) { - xt_xlate_add(xl, "%sdccp dport%s %u", space, + xt_xlate_add(xl, "dccp dport%s %u", einfo->invflags & XT_DCCP_DEST_PORTS ? " !=" : "", einfo->dpts[0]); if (einfo->dpts[0] != einfo->dpts[1]) xt_xlate_add(xl, "-%u", einfo->dpts[1]); - - space = " "; } if (einfo->flags & XT_DCCP_TYPE && einfo->typemask) { - xt_xlate_add(xl, "%sdccp type%s ", space, + xt_xlate_add(xl, "dccp type%s ", einfo->invflags & XT_DCCP_TYPE ? " !=" : ""); ret = dccp_type_xlate(einfo, xl); - - space = " "; } /* FIXME: no dccp option support in nftables yet */ diff --git a/extensions/libxt_dccp.txlate b/extensions/libxt_dccp.txlate index ea853f6a..a4da1a79 100644 --- a/extensions/libxt_dccp.txlate +++ b/extensions/libxt_dccp.txlate @@ -1,20 +1,20 @@ iptables-translate -A INPUT -p dccp -m dccp --sport 100 -nft add rule ip filter INPUT dccp sport 100 counter +nft 'add rule ip filter INPUT dccp sport 100 counter' iptables-translate -A INPUT -p dccp -m dccp --dport 100:200 -nft add rule ip filter INPUT dccp dport 100-200 counter +nft 'add rule ip filter INPUT dccp dport 100-200 counter' iptables-translate -A INPUT -p dccp -m dccp ! --dport 100 -nft add rule ip filter INPUT dccp dport != 100 counter +nft 'add rule ip filter INPUT dccp dport != 100 counter' iptables-translate -A INPUT -p dccp -m dccp --dccp-types CLOSE -nft add rule ip filter INPUT dccp type close counter +nft 'add rule ip filter INPUT dccp type close counter' iptables-translate -A INPUT -p dccp -m dccp --dccp-types INVALID -nft add rule ip filter INPUT dccp type 10-15 counter +nft 'add rule ip filter INPUT dccp type 10-15 counter' iptables-translate -A INPUT -p dccp -m dccp --dport 100 --dccp-types REQUEST,RESPONSE,DATA,ACK,DATAACK,CLOSEREQ,CLOSE,SYNC,SYNCACK,INVALID -nft add rule ip filter INPUT dccp dport 100 dccp type {request, response, data, ack, dataack, closereq, close, sync, syncack, 10-15} counter +nft 'add rule ip filter INPUT dccp dport 100 dccp type { request, response, data, ack, dataack, closereq, close, sync, syncack, 10-15 } counter' iptables-translate -A INPUT -p dccp -m dccp --sport 200 --dport 100 -nft add rule ip filter INPUT dccp sport 200 dccp dport 100 counter +nft 'add rule ip filter INPUT dccp sport 200 dccp dport 100 counter' diff --git a/extensions/libxt_devgroup.c b/extensions/libxt_devgroup.c index a88211c5..f60526ff 100644 --- a/extensions/libxt_devgroup.c +++ b/extensions/libxt_devgroup.c @@ -129,7 +129,6 @@ 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) @@ -137,13 +136,12 @@ static void devgroup_show_xlate(const struct xt_devgroup_info *info, 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); + xt_xlate_add(xl, "oifgroup "); print_devgroup_xlate(info->dst_group, op, info->dst_mask, xl, numeric); } diff --git a/extensions/libxt_devgroup.txlate b/extensions/libxt_devgroup.txlate index aeb597bd..dea47a99 100644 --- a/extensions/libxt_devgroup.txlate +++ b/extensions/libxt_devgroup.txlate @@ -1,17 +1,17 @@ iptables-translate -A FORWARD -m devgroup --src-group 0x2 -j ACCEPT -nft add rule ip filter FORWARD iifgroup 0x2 counter accept +nft 'add rule ip filter FORWARD iifgroup 0x2 counter accept' iptables-translate -A FORWARD -m devgroup --dst-group 0xc/0xc -j ACCEPT -nft add rule ip filter FORWARD oifgroup and 0xc == 0xc counter accept +nft 'add rule ip filter FORWARD oifgroup and 0xc == 0xc counter accept' iptables-translate -t mangle -A PREROUTING -p tcp --dport 46000 -m devgroup --src-group 23 -j ACCEPT -nft add rule ip mangle PREROUTING tcp dport 46000 iifgroup 0x17 counter accept +nft 'add rule ip mangle PREROUTING tcp dport 46000 iifgroup 0x17 counter accept' iptables-translate -A FORWARD -m devgroup ! --dst-group 0xc/0xc -j ACCEPT -nft add rule ip filter FORWARD oifgroup and 0xc != 0xc counter accept +nft 'add rule ip filter FORWARD oifgroup and 0xc != 0xc counter accept' iptables-translate -A FORWARD -m devgroup ! --src-group 0x2 -j ACCEPT -nft add rule ip filter FORWARD iifgroup != 0x2 counter accept +nft 'add rule ip filter FORWARD iifgroup != 0x2 counter accept' iptables-translate -A FORWARD -m devgroup ! --src-group 0x2 --dst-group 0xc/0xc -j ACCEPT -nft add rule ip filter FORWARD iifgroup != 0x2 oifgroup and 0xc != 0xc counter accept +nft 'add rule ip filter FORWARD iifgroup != 0x2 oifgroup and 0xc != 0xc counter accept' diff --git a/extensions/libxt_dscp.t b/extensions/libxt_dscp.t index 38d7f04e..e0101906 100644 --- a/extensions/libxt_dscp.t +++ b/extensions/libxt_dscp.t @@ -1,5 +1,5 @@ :INPUT,FORWARD,OUTPUT --m dscp --dscp 0;=;OK +-m dscp --dscp 0x00;=;OK -m dscp --dscp 0x3f;=;OK -m dscp --dscp -1;;FAIL -m dscp --dscp 0x40;;FAIL diff --git a/extensions/libxt_dscp.txlate b/extensions/libxt_dscp.txlate index 2cccc3b4..ca2ec724 100644 --- a/extensions/libxt_dscp.txlate +++ b/extensions/libxt_dscp.txlate @@ -1,5 +1,5 @@ iptables-translate -t filter -A INPUT -m dscp --dscp 0x32 -j ACCEPT -nft add rule ip filter INPUT ip dscp 0x32 counter accept +nft 'add rule ip filter INPUT ip dscp 0x32 counter accept' ip6tables-translate -t filter -A INPUT -m dscp ! --dscp 0x32 -j ACCEPT -nft add rule ip6 filter INPUT ip6 dscp != 0x32 counter accept +nft 'add rule ip6 filter INPUT ip6 dscp != 0x32 counter accept' diff --git a/extensions/libxt_ecn.c b/extensions/libxt_ecn.c index ad3c7a03..83a4acfa 100644 --- a/extensions/libxt_ecn.c +++ b/extensions/libxt_ecn.c @@ -156,6 +156,8 @@ static int ecn_xlate(struct xt_xlate *xl, case 3: xt_xlate_add(xl, "ce"); break; + default: + return 0; } } return 1; diff --git a/extensions/libxt_ecn.txlate b/extensions/libxt_ecn.txlate index f012f128..8488f8ce 100644 --- a/extensions/libxt_ecn.txlate +++ b/extensions/libxt_ecn.txlate @@ -1,29 +1,29 @@ iptables-translate -A INPUT -m ecn --ecn-ip-ect 0 -nft add rule ip filter INPUT ip ecn not-ect counter +nft 'add rule ip filter INPUT ip ecn not-ect counter' iptables-translate -A INPUT -m ecn --ecn-ip-ect 1 -nft add rule ip filter INPUT ip ecn ect1 counter +nft 'add rule ip filter INPUT ip ecn ect1 counter' iptables-translate -A INPUT -m ecn --ecn-ip-ect 2 -nft add rule ip filter INPUT ip ecn ect0 counter +nft 'add rule ip filter INPUT ip ecn ect0 counter' iptables-translate -A INPUT -m ecn --ecn-ip-ect 3 -nft add rule ip filter INPUT ip ecn ce counter +nft 'add rule ip filter INPUT ip ecn ce counter' iptables-translate -A INPUT -m ecn ! --ecn-ip-ect 0 -nft add rule ip filter INPUT ip ecn != not-ect counter +nft 'add rule ip filter INPUT ip ecn != not-ect counter' iptables-translate -A INPUT -m ecn ! --ecn-ip-ect 1 -nft add rule ip filter INPUT ip ecn != ect1 counter +nft 'add rule ip filter INPUT ip ecn != ect1 counter' iptables-translate -A INPUT -m ecn ! --ecn-ip-ect 2 -nft add rule ip filter INPUT ip ecn != ect0 counter +nft 'add rule ip filter INPUT ip ecn != ect0 counter' iptables-translate -A INPUT -m ecn ! --ecn-ip-ect 3 -nft add rule ip filter INPUT ip ecn != ce counter +nft 'add rule ip filter INPUT ip ecn != ce counter' iptables-translate -A INPUT -m ecn ! --ecn-tcp-ece -nft add rule ip filter INPUT tcp flags != ecn counter +nft 'add rule ip filter INPUT tcp flags != ecn counter' iptables-translate -A INPUT -m ecn --ecn-tcp-cwr -nft add rule ip filter INPUT tcp flags cwr counter +nft 'add rule ip filter INPUT tcp flags cwr counter' diff --git a/extensions/libxt_esp.txlate b/extensions/libxt_esp.txlate index 5e2f18fa..f6aba52f 100644 --- a/extensions/libxt_esp.txlate +++ b/extensions/libxt_esp.txlate @@ -1,11 +1,11 @@ iptables-translate -A FORWARD -p esp -j ACCEPT -nft add rule ip filter FORWARD ip protocol esp counter accept +nft 'add rule ip filter FORWARD ip protocol esp counter accept' iptables-translate -A INPUT --in-interface wan --protocol esp -j ACCEPT -nft add rule ip filter INPUT iifname "wan" ip protocol esp counter accept +nft 'add rule ip filter INPUT iifname "wan" ip protocol esp counter accept' iptables-translate -A INPUT -p 50 -m esp --espspi 500 -j DROP -nft add rule ip filter INPUT esp spi 500 counter drop +nft 'add rule ip filter INPUT esp spi 500 counter drop' iptables-translate -A INPUT -p 50 -m esp --espspi 500:600 -j DROP -nft add rule ip filter INPUT esp spi 500-600 counter drop +nft 'add rule ip filter INPUT esp spi 500-600 counter drop' diff --git a/extensions/libxt_hashlimit.c b/extensions/libxt_hashlimit.c index 3f3c4301..24e784ab 100644 --- a/extensions/libxt_hashlimit.c +++ b/extensions/libxt_hashlimit.c @@ -356,12 +356,12 @@ static bool parse_bytes(const char *rate, void *val, struct hashlimit_mt_udata * tmp = (uint64_t) r * factor; if (tmp > max) xtables_error(PARAMETER_PROBLEM, - "Rate value too large \"%"PRIu64"\" (max %"PRIu64")\n", - tmp, max); + "Rate value too large \"%"PRIu64"\" (max %"PRIu64")", + tmp, max); tmp = bytes_to_cost(tmp); if (tmp == 0) - xtables_error(PARAMETER_PROBLEM, "Rate too high \"%s\"\n", rate); + xtables_error(PARAMETER_PROBLEM, "Rate too high \"%s\"", rate); ud->mult = XT_HASHLIMIT_BYTE_EXPIRE; @@ -407,7 +407,7 @@ int parse_rate(const char *rate, void *val, struct hashlimit_mt_udata *ud, int r * 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); + xtables_error(PARAMETER_PROBLEM, "Rate too fast \"%s\"", rate); if(revision == 1) *((uint32_t*)val) = tmp; @@ -1270,7 +1270,7 @@ static void hashlimit_print_subnet_xlate(struct xt_xlate *xl, } } - xt_xlate_add(xl, fmt, acm); + xt_xlate_add_nospc(xl, fmt, acm); if (nblocks > 0) xt_xlate_add(xl, "%c", sep); } diff --git a/extensions/libxt_hashlimit.t b/extensions/libxt_hashlimit.t index 83699337..206d9293 100644 --- a/extensions/libxt_hashlimit.t +++ b/extensions/libxt_hashlimit.t @@ -3,12 +3,12 @@ -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 --m hashlimit --hashlimit-above 1/day --hashlimit-burst 500 --hashlimit-name mini1;=;OK +-m hashlimit --hashlimit-above 1/day --hashlimit-burst 1 --hashlimit-name mini1;=;OK -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 --m hashlimit --hashlimit-upto 1/day --hashlimit-burst 500 --hashlimit-name mini1;=;OK +-m hashlimit --hashlimit-upto 1/day --hashlimit-burst 1 --hashlimit-name mini1;=;OK -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 diff --git a/extensions/libxt_hashlimit.txlate b/extensions/libxt_hashlimit.txlate index 6c8d07f1..306ee783 100644 --- a/extensions/libxt_hashlimit.txlate +++ b/extensions/libxt_hashlimit.txlate @@ -1,5 +1,5 @@ iptables-translate -A OUTPUT -m tcp -p tcp --dport 443 -m hashlimit --hashlimit-above 20kb/s --hashlimit-burst 1mb --hashlimit-mode dstip --hashlimit-name https --hashlimit-dstmask 24 -m state --state NEW -j DROP -nft add rule ip filter OUTPUT tcp dport 443 meter https { ip daddr and 255.255.255.0 timeout 60s limit rate over 20 kbytes/second burst 1 mbytes} ct state new counter drop +nft 'add rule ip filter OUTPUT tcp dport 443 meter https { ip daddr and 255.255.255.0 timeout 60s limit rate over 20 kbytes/second burst 1 mbytes } ct state new counter drop' iptables-translate -A OUTPUT -m tcp -p tcp --dport 443 -m hashlimit --hashlimit-upto 300 --hashlimit-burst 15 --hashlimit-mode srcip,dstip --hashlimit-name https --hashlimit-htable-expire 300000 -m state --state NEW -j DROP -nft add rule ip filter OUTPUT tcp dport 443 meter https { ip daddr . ip saddr timeout 300s limit rate 300/second burst 15 packets} ct state new counter drop +nft 'add rule ip filter OUTPUT tcp dport 443 meter https { ip daddr . ip saddr timeout 300s limit rate 300/second burst 15 packets } ct state new counter drop' diff --git a/extensions/libxt_helper.c b/extensions/libxt_helper.c index 2afbf996..0f72eec6 100644 --- a/extensions/libxt_helper.c +++ b/extensions/libxt_helper.c @@ -50,12 +50,8 @@ static int helper_xlate(struct xt_xlate *xl, { 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); + xt_xlate_add(xl, "ct helper%s \"%s\"", + info->invert ? " !=" : "", info->name); return 1; } diff --git a/extensions/libxt_helper.txlate b/extensions/libxt_helper.txlate index 8259aba3..2d94f740 100644 --- a/extensions/libxt_helper.txlate +++ b/extensions/libxt_helper.txlate @@ -1,5 +1,5 @@ iptables-translate -A FORWARD -m helper --helper sip -nft add rule ip filter FORWARD ct helper \"sip\" counter +nft 'add rule ip filter FORWARD ct helper "sip" counter' iptables-translate -A FORWARD -m helper ! --helper ftp -nft add rule ip filter FORWARD ct helper != \"ftp\" counter +nft 'add rule ip filter FORWARD ct helper != "ftp" counter' diff --git a/extensions/libxt_icmp.h b/extensions/libxt_icmp.h index 5820206e..a763e50c 100644 --- a/extensions/libxt_icmp.h +++ b/extensions/libxt_icmp.h @@ -1,25 +1,249 @@ -struct xt_icmp_names { +static const struct xt_icmp_names { const char *name; uint8_t type; uint8_t code_min, code_max; +} icmp_codes[] = { + { "any", 0xFF, 0, 0xFF }, + { "echo-reply", 0, 0, 0xFF }, + /* Alias */ { "pong", 0, 0, 0xFF }, + + { "destination-unreachable", 3, 0, 0xFF }, + { "network-unreachable", 3, 0, 0 }, + { "host-unreachable", 3, 1, 1 }, + { "protocol-unreachable", 3, 2, 2 }, + { "port-unreachable", 3, 3, 3 }, + { "fragmentation-needed", 3, 4, 4 }, + { "source-route-failed", 3, 5, 5 }, + { "network-unknown", 3, 6, 6 }, + { "host-unknown", 3, 7, 7 }, + { "network-prohibited", 3, 9, 9 }, + { "host-prohibited", 3, 10, 10 }, + { "TOS-network-unreachable", 3, 11, 11 }, + { "TOS-host-unreachable", 3, 12, 12 }, + { "communication-prohibited", 3, 13, 13 }, + { "host-precedence-violation", 3, 14, 14 }, + { "precedence-cutoff", 3, 15, 15 }, + + { "source-quench", 4, 0, 0xFF }, + + { "redirect", 5, 0, 0xFF }, + { "network-redirect", 5, 0, 0 }, + { "host-redirect", 5, 1, 1 }, + { "TOS-network-redirect", 5, 2, 2 }, + { "TOS-host-redirect", 5, 3, 3 }, + + { "echo-request", 8, 0, 0xFF }, + /* Alias */ { "ping", 8, 0, 0xFF }, + + { "router-advertisement", 9, 0, 0xFF }, + + { "router-solicitation", 10, 0, 0xFF }, + + { "time-exceeded", 11, 0, 0xFF }, + /* Alias */ { "ttl-exceeded", 11, 0, 0xFF }, + { "ttl-zero-during-transit", 11, 0, 0 }, + { "ttl-zero-during-reassembly", 11, 1, 1 }, + + { "parameter-problem", 12, 0, 0xFF }, + { "ip-header-bad", 12, 0, 0 }, + { "required-option-missing", 12, 1, 1 }, + + { "timestamp-request", 13, 0, 0xFF }, + + { "timestamp-reply", 14, 0, 0xFF }, + + { "address-mask-request", 17, 0, 0xFF }, + + { "address-mask-reply", 18, 0, 0xFF } +}, 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 }, + + { "time-exceeded", 3, 0, 0xFF }, + /* Alias */ { "ttl-exceeded", 3, 0, 0xFF }, + { "ttl-zero-during-transit", 3, 0, 0 }, + { "ttl-zero-during-reassembly", 3, 1, 1 }, + + { "parameter-problem", 4, 0, 0xFF }, + { "bad-header", 4, 0, 0 }, + { "unknown-header-type", 4, 1, 1 }, + { "unknown-option", 4, 2, 2 }, + + { "echo-request", 128, 0, 0xFF }, + /* Alias */ { "ping", 128, 0, 0xFF }, + + { "echo-reply", 129, 0, 0xFF }, + /* Alias */ { "pong", 129, 0, 0xFF }, + + { "router-solicitation", 133, 0, 0xFF }, + + { "router-advertisement", 134, 0, 0xFF }, + + { "neighbour-solicitation", 135, 0, 0xFF }, + /* Alias */ { "neighbor-solicitation", 135, 0, 0xFF }, + + { "neighbour-advertisement", 136, 0, 0xFF }, + /* Alias */ { "neighbor-advertisement", 136, 0, 0xFF }, + + { "redirect", 137, 0, 0xFF }, +}, igmp_types[] = { + { "membership-query", 0x11 }, + { "membership-report-v1", 0x12 }, + { "membership-report-v2", 0x16 }, + { "leave-group", 0x17 }, + { "membership-report-v3", 0x22 }, }; -static void xt_print_icmp_types(const struct xt_icmp_names *icmp_codes, +static inline char *parse_range(const char *str, unsigned int res[]) +{ + char *next; + + if (!xtables_strtoui(str, &next, &res[0], 0, 255)) + return NULL; + + res[1] = res[0]; + if (*next == ':') { + str = next + 1; + if (!xtables_strtoui(str, &next, &res[1], 0, 255)) + return NULL; + } + + return next; +} + +static void +__parse_icmp(const struct xt_icmp_names codes[], size_t n_codes, + const char *codes_name, const char *fmtstring, + uint8_t type[], uint8_t code[]) +{ + unsigned int match = n_codes; + unsigned int i, number[2]; + + for (i = 0; i < n_codes; i++) { + if (strncasecmp(codes[i].name, fmtstring, strlen(fmtstring))) + continue; + if (match != n_codes) + xtables_error(PARAMETER_PROBLEM, + "Ambiguous %s type `%s': `%s' or `%s'?", + codes_name, fmtstring, codes[match].name, + codes[i].name); + match = i; + } + + if (match < n_codes) { + type[0] = type[1] = codes[match].type; + if (code) { + code[0] = codes[match].code_min; + code[1] = codes[match].code_max; + } + } else { + char *next = parse_range(fmtstring, number); + if (!next) + xtables_error(PARAMETER_PROBLEM, "Unknown %s type `%s'", + codes_name, fmtstring); + type[0] = (uint8_t) number[0]; + type[1] = (uint8_t) number[1]; + switch (*next) { + case 0: + if (code) { + code[0] = 0; + code[1] = 255; + } + return; + case '/': + if (!code) + break; + + next = parse_range(next + 1, number); + if (!next) + xtables_error(PARAMETER_PROBLEM, + "Unknown %s code `%s'", + codes_name, fmtstring); + code[0] = (uint8_t) number[0]; + code[1] = (uint8_t) number[1]; + if (!*next) + break; + /* fallthrough */ + default: + xtables_error(PARAMETER_PROBLEM, + "unknown character %c", *next); + } + } +} + +static inline void +__ipt_parse_icmp(const struct xt_icmp_names *codes, size_t n_codes, + const char *codes_name, const char *fmtstr, + uint8_t *type, uint8_t code[]) +{ + uint8_t types[2]; + + __parse_icmp(codes, n_codes, codes_name, fmtstr, types, code); + if (types[1] != types[0]) + xtables_error(PARAMETER_PROBLEM, + "%s type range not supported", codes_name); + *type = types[0]; +} + +static inline void +ipt_parse_icmp(const char *str, uint8_t *type, uint8_t code[]) +{ + __ipt_parse_icmp(icmp_codes, ARRAY_SIZE(icmp_codes), + "ICMP", str, type, code); +} + +static inline void +ipt_parse_icmpv6(const char *str, uint8_t *type, uint8_t code[]) +{ + __ipt_parse_icmp(icmpv6_codes, ARRAY_SIZE(icmpv6_codes), + "ICMPv6", str, type, code); +} + +static inline void +ebt_parse_icmp(const char *str, uint8_t type[], uint8_t code[]) +{ + __parse_icmp(icmp_codes, ARRAY_SIZE(icmp_codes), + "ICMP", str, type, code); +} + +static inline void +ebt_parse_icmpv6(const char *str, uint8_t type[], uint8_t code[]) +{ + __parse_icmp(icmpv6_codes, ARRAY_SIZE(icmpv6_codes), + "ICMPv6", str, type, code); +} + +static inline void +ebt_parse_igmp(const char *str, uint8_t type[]) +{ + __parse_icmp(igmp_types, ARRAY_SIZE(igmp_types), + "IGMP", str, type, NULL); +} + +static void xt_print_icmp_types(const struct xt_icmp_names *_icmp_codes, unsigned int n_codes) { unsigned int i; for (i = 0; i < n_codes; ++i) { - if (i && icmp_codes[i].type == icmp_codes[i-1].type) { - if (icmp_codes[i].code_min == icmp_codes[i-1].code_min - && (icmp_codes[i].code_max - == icmp_codes[i-1].code_max)) - printf(" (%s)", icmp_codes[i].name); + if (i && _icmp_codes[i].type == _icmp_codes[i-1].type) { + if (_icmp_codes[i].code_min == _icmp_codes[i-1].code_min + && (_icmp_codes[i].code_max + == _icmp_codes[i-1].code_max)) + printf(" (%s)", _icmp_codes[i].name); else - printf("\n %s", icmp_codes[i].name); + printf("\n %s", _icmp_codes[i].name); } else - printf("\n%s", icmp_codes[i].name); + printf("\n%s", _icmp_codes[i].name); } printf("\n"); } diff --git a/extensions/libxt_ipcomp.c b/extensions/libxt_ipcomp.c index b5c43128..4171c4a1 100644 --- a/extensions/libxt_ipcomp.c +++ b/extensions/libxt_ipcomp.c @@ -101,6 +101,8 @@ static int comp_xlate(struct xt_xlate *xl, const struct xt_ipcomp *compinfo = (struct xt_ipcomp *)params->match->data; + /* ignore compinfo->hdrres like kernel's xt_ipcomp.c does */ + xt_xlate_add(xl, "comp cpi %s", compinfo->invflags & XT_IPCOMP_INV_SPI ? "!= " : ""); if (compinfo->spis[0] != compinfo->spis[1]) diff --git a/extensions/libxt_ipcomp.c.man b/extensions/libxt_ipcomp.c.man index f3b17d21..824f5b3d 100644 --- a/extensions/libxt_ipcomp.c.man +++ b/extensions/libxt_ipcomp.c.man @@ -2,6 +2,3 @@ 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_ipcomp.txlate b/extensions/libxt_ipcomp.txlate index f9efe53c..877cccbb 100644 --- a/extensions/libxt_ipcomp.txlate +++ b/extensions/libxt_ipcomp.txlate @@ -1,5 +1,5 @@ iptables-translate -t filter -A INPUT -m ipcomp --ipcompspi 0x12 -j ACCEPT -nft add rule ip filter INPUT comp cpi 18 counter accept +nft 'add rule ip filter INPUT comp cpi 18 counter accept' iptables-translate -t filter -A INPUT -m ipcomp ! --ipcompspi 0x12 -j ACCEPT -nft add rule ip filter INPUT comp cpi != 18 counter accept +nft 'add rule ip filter INPUT comp cpi != 18 counter accept' diff --git a/extensions/libxt_iprange.c b/extensions/libxt_iprange.c index 04ce7b36..0df709d5 100644 --- a/extensions/libxt_iprange.c +++ b/extensions/libxt_iprange.c @@ -317,16 +317,14 @@ 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, + xt_xlate_add(xl, "ip daddr%s", info->flags & IPRANGE_DST_INV ? " !=" : ""); print_iprange_xlate(&info->dst, xl); } @@ -339,7 +337,6 @@ static int iprange_mt4_xlate(struct xt_xlate *xl, { 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", @@ -347,10 +344,9 @@ static int iprange_mt4_xlate(struct xt_xlate *xl, 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, + xt_xlate_add(xl, "ip daddr%s %s", info->flags & IPRANGE_DST_INV ? " !=" : "", xtables_ipaddr_to_numeric(&info->dst_min.in)); xt_xlate_add(xl, "-%s", @@ -365,7 +361,6 @@ static int iprange_mt6_xlate(struct xt_xlate *xl, { 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", @@ -373,10 +368,9 @@ static int iprange_mt6_xlate(struct xt_xlate *xl, 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, + xt_xlate_add(xl, "ip6 daddr%s %s", info->flags & IPRANGE_DST_INV ? " !=" : "", xtables_ip6addr_to_numeric(&info->dst_min.in6)); xt_xlate_add(xl, "-%s", diff --git a/extensions/libxt_iprange.txlate b/extensions/libxt_iprange.txlate index 999f4b72..80369650 100644 --- a/extensions/libxt_iprange.txlate +++ b/extensions/libxt_iprange.txlate @@ -1,14 +1,14 @@ iptables-translate -A INPUT -m iprange --src-range 192.168.25.149-192.168.25.151 -j ACCEPT -nft add rule ip filter INPUT ip saddr 192.168.25.149-192.168.25.151 counter accept +nft 'add rule ip filter INPUT ip saddr 192.168.25.149-192.168.25.151 counter accept' iptables-translate -A INPUT -m iprange --dst-range 192.168.25.149-192.168.25.151 -j ACCEPT -nft add rule ip filter INPUT ip daddr 192.168.25.149-192.168.25.151 counter accept +nft 'add rule ip filter INPUT ip daddr 192.168.25.149-192.168.25.151 counter accept' iptables-translate -A INPUT -m iprange --dst-range 3.3.3.3-6.6.6.6 --src-range 4.4.4.4-7.7.7.7 -j ACCEPT -nft add rule ip filter INPUT ip saddr 4.4.4.4-7.7.7.7 ip daddr 3.3.3.3-6.6.6.6 counter accept +nft 'add rule ip filter INPUT ip saddr 4.4.4.4-7.7.7.7 ip daddr 3.3.3.3-6.6.6.6 counter accept' ip6tables-translate -A INPUT -m iprange ! --dst-range ::2d01-::2d03 -j ACCEPT -nft add rule ip6 filter INPUT ip6 daddr != ::2d01-::2d03 counter accept +nft 'add rule ip6 filter INPUT ip6 daddr != ::2d01-::2d03 counter accept' ip6tables-translate -A INPUT -m iprange ! --dst-range ::2d01-::2d03 --src-range ::2d01-::2d03 -j ACCEPT -nft add rule ip6 filter INPUT ip6 saddr ::2d01-::2d03 ip6 daddr != ::2d01-::2d03 counter accept +nft 'add rule ip6 filter INPUT ip6 saddr ::2d01-::2d03 ip6 daddr != ::2d01-::2d03 counter accept' diff --git a/extensions/libxt_length.t b/extensions/libxt_length.t index 0b6624ee..8b70fc31 100644 --- a/extensions/libxt_length.t +++ b/extensions/libxt_length.t @@ -2,7 +2,7 @@ -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 4:;-m length --length 4:65535;OK -m length --length 0:65535;=;OK -m length ! --length 0:65535;=;OK -m length --length 0:65536;;FAIL diff --git a/extensions/libxt_length.txlate b/extensions/libxt_length.txlate index e777c265..38f835dc 100644 --- a/extensions/libxt_length.txlate +++ b/extensions/libxt_length.txlate @@ -1,11 +1,11 @@ iptables-translate -A INPUT -p icmp -m length --length 86:0xffff -j DROP -nft add rule ip filter INPUT ip protocol icmp meta length 86-65535 counter drop +nft 'add rule ip filter INPUT ip protocol icmp meta length 86-65535 counter drop' iptables-translate -A INPUT -p udp -m length --length :400 -nft add rule ip filter INPUT ip protocol udp meta length 0-400 counter +nft 'add rule ip filter INPUT ip protocol udp meta length 0-400 counter' iptables-translate -A INPUT -p udp -m length --length 40 -nft add rule ip filter INPUT ip protocol udp meta length 40 counter +nft 'add rule ip filter INPUT ip protocol udp meta length 40 counter' iptables-translate -A INPUT -p udp -m length ! --length 40 -nft add rule ip filter INPUT ip protocol udp meta length != 40 counter +nft 'add rule ip filter INPUT ip protocol udp meta length != 40 counter' diff --git a/extensions/libxt_limit.c b/extensions/libxt_limit.c index 1b324657..e6ec67f3 100644 --- a/extensions/libxt_limit.c +++ b/extensions/libxt_limit.c @@ -77,7 +77,7 @@ int parse_rate(const char *rate, uint32_t *val) * 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); + xtables_error(PARAMETER_PROBLEM, "Rate too fast \"%s\"", rate); return 1; } @@ -93,7 +93,7 @@ static void limit_init(struct xt_entry_match *m) /* FIXME: handle overflow: if (r->avg*r->burst/r->burst != r->avg) xtables_error(PARAMETER_PROBLEM, - "Sorry: burst too large for that avg rate.\n"); + "Sorry: burst too large for that avg rate."); */ static void limit_parse(struct xt_option_call *cb) diff --git a/extensions/libxt_limit.txlate b/extensions/libxt_limit.txlate index df9ed2d5..fa8e1bc0 100644 --- a/extensions/libxt_limit.txlate +++ b/extensions/libxt_limit.txlate @@ -1,8 +1,8 @@ iptables-translate -A INPUT -m limit --limit 3/m --limit-burst 3 -nft add rule ip filter INPUT limit rate 3/minute burst 3 packets counter +nft 'add rule ip filter INPUT limit rate 3/minute burst 3 packets counter' iptables-translate -A INPUT -m limit --limit 10/s --limit-burst 5 -nft add rule ip filter INPUT limit rate 10/second burst 5 packets counter +nft 'add rule ip filter INPUT limit rate 10/second burst 5 packets counter' iptables-translate -A INPUT -m limit --limit 10/s --limit-burst 0 -nft add rule ip filter INPUT limit rate 10/second counter +nft 'add rule ip filter INPUT limit rate 10/second counter' diff --git a/extensions/libxt_mac.txlate b/extensions/libxt_mac.txlate index 08696f3d..16800179 100644 --- a/extensions/libxt_mac.txlate +++ b/extensions/libxt_mac.txlate @@ -1,5 +1,5 @@ iptables-translate -A INPUT -m mac --mac-source 0a:12:3e:4f:b2:c6 -j DROP -nft add rule ip filter INPUT ether saddr 0a:12:3e:4f:b2:c6 counter drop +nft 'add rule ip filter INPUT ether saddr 0a:12:3e:4f:b2:c6 counter drop' iptables-translate -A INPUT -p tcp --dport 80 -m mac --mac-source 0a:12:3e:4f:b2:c6 -j ACCEPT -nft add rule ip filter INPUT tcp dport 80 ether saddr 0a:12:3e:4f:b2:c6 counter accept +nft 'add rule ip filter INPUT tcp dport 80 ether saddr 0a:12:3e:4f:b2:c6 counter accept' diff --git a/extensions/libxt_mark.t b/extensions/libxt_mark.t index 7c005379..12c05865 100644 --- a/extensions/libxt_mark.t +++ b/extensions/libxt_mark.t @@ -1,7 +1,8 @@ :INPUT,FORWARD,OUTPUT -m mark --mark 0xfeedcafe/0xfeedcafe;=;OK --m mark --mark 0;=;OK +-m mark --mark 0x0;=;OK -m mark --mark 4294967295;-m mark --mark 0xffffffff;OK -m mark --mark 4294967296;;FAIL -m mark --mark -1;;FAIL -m mark;;FAIL +-s 1.2.0.0/15 -m mark --mark 0x0/0xff0;=;OK diff --git a/extensions/libxt_mark.txlate b/extensions/libxt_mark.txlate index 6bfb5243..6e097091 100644 --- a/extensions/libxt_mark.txlate +++ b/extensions/libxt_mark.txlate @@ -1,5 +1,5 @@ iptables-translate -I INPUT -p tcp -m mark ! --mark 0xa/0xa -nft insert rule ip filter INPUT ip protocol tcp mark and 0xa != 0xa counter +nft 'insert rule ip filter INPUT ip protocol tcp mark and 0xa != 0xa counter' iptables-translate -I INPUT -p tcp -m mark ! --mark 0x1 -nft insert rule ip filter INPUT ip protocol tcp mark != 0x1 counter +nft 'insert rule ip filter INPUT ip protocol tcp mark != 0x1 counter' diff --git a/extensions/libxt_multiport.c b/extensions/libxt_multiport.c index 6b0c8190..f3136d8a 100644 --- a/extensions/libxt_multiport.c +++ b/extensions/libxt_multiport.c @@ -497,7 +497,7 @@ static int __multiport_xlate(struct xt_xlate *xl, xt_xlate_add(xl, "{ "); for (i = 0; i < multiinfo->count; i++) - xt_xlate_add(xl, "%s%u", i ? "," : "", multiinfo->ports[i]); + xt_xlate_add(xl, "%s%u", i ? ", " : "", multiinfo->ports[i]); if (multiinfo->count > 1) xt_xlate_add(xl, "}"); @@ -560,7 +560,7 @@ static int __multiport_xlate_v1(struct xt_xlate *xl, xt_xlate_add(xl, "{ "); for (i = 0; i < multiinfo->count; i++) { - xt_xlate_add(xl, "%s%u", i ? "," : "", multiinfo->ports[i]); + xt_xlate_add(xl, "%s%u", i ? ", " : "", multiinfo->ports[i]); if (multiinfo->pflags[i]) xt_xlate_add(xl, "-%u", multiinfo->ports[++i]); } diff --git a/extensions/libxt_multiport.txlate b/extensions/libxt_multiport.txlate index bced1b84..aa5f006d 100644 --- a/extensions/libxt_multiport.txlate +++ b/extensions/libxt_multiport.txlate @@ -1,14 +1,14 @@ iptables-translate -t filter -A INPUT -p tcp -m multiport --dports 80,81 -j ACCEPT -nft add rule ip filter INPUT ip protocol tcp tcp dport { 80,81} counter accept +nft 'add rule ip filter INPUT ip protocol tcp tcp dport { 80, 81 } counter accept' iptables-translate -t filter -A INPUT -p tcp -m multiport --dports 80:88 -j ACCEPT -nft add rule ip filter INPUT ip protocol tcp tcp dport 80-88 counter accept +nft 'add rule ip filter INPUT ip protocol tcp tcp dport 80-88 counter accept' iptables-translate -t filter -A INPUT -p tcp -m multiport ! --dports 80:88 -j ACCEPT -nft add rule ip filter INPUT ip protocol tcp tcp dport != 80-88 counter accept +nft 'add rule ip filter INPUT ip protocol tcp tcp dport != 80-88 counter accept' iptables-translate -t filter -A INPUT -p tcp -m multiport --sports 50 -j ACCEPT -nft add rule ip filter INPUT ip protocol tcp tcp sport 50 counter accept +nft 'add rule ip filter INPUT ip protocol tcp tcp sport 50 counter accept' iptables-translate -t filter -I INPUT -p tcp -m multiport --ports 10 -nft insert rule ip filter INPUT ip protocol tcp tcp sport . tcp dport { 0-65535 . 10, 10 . 0-65535 } counter +nft 'insert rule ip filter INPUT ip protocol tcp tcp sport . tcp dport { 0-65535 . 10, 10 . 0-65535 } counter' diff --git a/extensions/libxt_owner.txlate b/extensions/libxt_owner.txlate index 86fb0585..8fbd68eb 100644 --- a/extensions/libxt_owner.txlate +++ b/extensions/libxt_owner.txlate @@ -1,8 +1,8 @@ iptables-translate -t nat -A OUTPUT -p tcp --dport 80 -m owner --uid-owner root -j ACCEPT -nft add rule ip nat OUTPUT tcp dport 80 skuid 0 counter accept +nft 'add rule ip nat OUTPUT tcp dport 80 skuid 0 counter accept' iptables-translate -t nat -A OUTPUT -p tcp --dport 80 -m owner --gid-owner 0-10 -j ACCEPT -nft add rule ip nat OUTPUT tcp dport 80 skgid 0-10 counter accept +nft 'add rule ip nat OUTPUT tcp dport 80 skgid 0-10 counter accept' iptables-translate -t nat -A OUTPUT -p tcp --dport 80 -m owner ! --uid-owner 1000 -j ACCEPT -nft add rule ip nat OUTPUT tcp dport 80 skuid != 1000 counter accept +nft 'add rule ip nat OUTPUT tcp dport 80 skuid != 1000 counter accept' diff --git a/extensions/libxt_pkttype.c b/extensions/libxt_pkttype.c index bf6f5b96..a76310b0 100644 --- a/extensions/libxt_pkttype.c +++ b/extensions/libxt_pkttype.c @@ -30,8 +30,8 @@ static const struct pkttypes supported_types[] = { {"unicast", PACKET_HOST, 1, "to us"}, {"broadcast", PACKET_BROADCAST, 1, "to all"}, {"multicast", PACKET_MULTICAST, 1, "to group"}, -/* {"otherhost", PACKET_OTHERHOST, 1, "to someone else"}, +/* {"outgoing", PACKET_OUTGOING, 1, "outgoing of any type"}, */ /* aliases */ diff --git a/extensions/libxt_pkttype.txlate b/extensions/libxt_pkttype.txlate index 6506a380..c69f56f9 100644 --- a/extensions/libxt_pkttype.txlate +++ b/extensions/libxt_pkttype.txlate @@ -1,8 +1,8 @@ iptables-translate -A INPUT -m pkttype --pkt-type broadcast -j DROP -nft add rule ip filter INPUT pkttype broadcast counter drop +nft 'add rule ip filter INPUT pkttype broadcast counter drop' iptables-translate -A INPUT -m pkttype ! --pkt-type unicast -j DROP -nft add rule ip filter INPUT pkttype != unicast counter drop +nft 'add rule ip filter INPUT pkttype != unicast counter drop' iptables-translate -A INPUT -m pkttype --pkt-type multicast -j ACCEPT -nft add rule ip filter INPUT pkttype multicast counter accept +nft 'add rule ip filter INPUT pkttype multicast counter accept' diff --git a/extensions/libxt_policy.txlate b/extensions/libxt_policy.txlate index 66788a76..a960b395 100644 --- a/extensions/libxt_policy.txlate +++ b/extensions/libxt_policy.txlate @@ -1,5 +1,5 @@ iptables-translate -A INPUT -m policy --pol ipsec --dir in -nft add rule ip filter INPUT meta secpath exists counter +nft 'add rule ip filter INPUT meta secpath exists counter' iptables-translate -A INPUT -m policy --pol none --dir in -nft add rule ip filter INPUT meta secpath missing counter +nft 'add rule ip filter INPUT meta secpath missing counter' diff --git a/extensions/libxt_quota.txlate b/extensions/libxt_quota.txlate index 91142141..6edd925d 100644 --- a/extensions/libxt_quota.txlate +++ b/extensions/libxt_quota.txlate @@ -1,5 +1,5 @@ iptables-translate -A OUTPUT -m quota --quota 111 -nft add rule ip filter OUTPUT quota 111 bytes counter +nft 'add rule ip filter OUTPUT quota 111 bytes counter' iptables-translate -A OUTPUT -m quota ! --quota 111 -nft add rule ip filter OUTPUT quota over 111 bytes counter +nft 'add rule ip filter OUTPUT quota over 111 bytes counter' diff --git a/extensions/libxt_recent.t b/extensions/libxt_recent.t index 9a83918e..cf23aabc 100644 --- a/extensions/libxt_recent.t +++ b/extensions/libxt_recent.t @@ -1,8 +1,8 @@ :INPUT,FORWARD,OUTPUT --m recent --set;=;OK +-m recent --set;-m recent --set --name DEFAULT --mask 255.255.255.255 --rsource;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 --update --rttl;-m recent --update --rttl --name DEFAULT --mask 255.255.255.255 --rsource;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: diff --git a/extensions/libxt_rpfilter.txlate b/extensions/libxt_rpfilter.txlate index 8d7733ba..a551c419 100644 --- a/extensions/libxt_rpfilter.txlate +++ b/extensions/libxt_rpfilter.txlate @@ -1,8 +1,8 @@ iptables-translate -t mangle -A PREROUTING -m rpfilter -nft add rule ip mangle PREROUTING fib saddr . iif oif != 0 counter +nft 'add rule ip mangle PREROUTING fib saddr . iif oif != 0 counter' iptables-translate -t mangle -A PREROUTING -m rpfilter --validmark --loose -nft add rule ip mangle PREROUTING fib saddr . mark oif != 0 counter +nft 'add rule ip mangle PREROUTING fib saddr . mark oif != 0 counter' ip6tables-translate -t mangle -A PREROUTING -m rpfilter --validmark --invert -nft add rule ip6 mangle PREROUTING fib saddr . mark . iif oif 0 counter +nft 'add rule ip6 mangle PREROUTING fib saddr . mark . iif oif 0 counter' diff --git a/extensions/libxt_sctp.c b/extensions/libxt_sctp.c index a4c5415f..fe5f5621 100644 --- a/extensions/libxt_sctp.c +++ b/extensions/libxt_sctp.c @@ -112,9 +112,13 @@ static const struct sctp_chunk_names sctp_chunk_names[] { .name = "ECN_ECNE", .chunk_type = 12, .valid_flags = "--------", .nftname = "ecne" }, { .name = "ECN_CWR", .chunk_type = 13, .valid_flags = "--------", .nftname = "cwr" }, { .name = "SHUTDOWN_COMPLETE", .chunk_type = 14, .valid_flags = "-------T", .nftname = "shutdown-complete" }, + { .name = "I_DATA", .chunk_type = 64, .valid_flags = "----IUBE", .nftname = "i-data"}, + { .name = "RE_CONFIG", .chunk_type = 130, .valid_flags = "--------", .nftname = "re-config"}, + { .name = "PAD", .chunk_type = 132, .valid_flags = "--------", .nftname = "pad"}, { .name = "ASCONF", .chunk_type = 193, .valid_flags = "--------", .nftname = "asconf" }, { .name = "ASCONF_ACK", .chunk_type = 128, .valid_flags = "--------", .nftname = "asconf-ack" }, { .name = "FORWARD_TSN", .chunk_type = 192, .valid_flags = "--------", .nftname = "forward-tsn" }, + { .name = "I_FORWARD_TSN", .chunk_type = 194, .valid_flags = "--------", .nftname = "i-forward-tsn" }, }; static void @@ -140,10 +144,8 @@ save_chunk_flag_info(struct xt_sctp_flag_info *flag_info, } if (*flag_count == XT_NUM_SCTP_FLAGS) { - xtables_error (PARAMETER_PROBLEM, - "Number of chunk types with flags exceeds currently allowed limit." - "Increasing this limit involves changing IPT_NUM_SCTP_FLAGS and" - "recompiling both the kernel space and user space modules\n"); + xtables_error(PARAMETER_PROBLEM, + "Number of chunk types with flags exceeds currently allowed limit. Increasing this limit involves changing IPT_NUM_SCTP_FLAGS and recompiling both the kernel space and user space modules"); } flag_info[*flag_count].chunktype = chunktype; @@ -215,7 +217,8 @@ parse_sctp_chunk(struct xt_sctp_info *einfo, isupper(chunk_flags[j])); } else { xtables_error(PARAMETER_PROBLEM, - "Invalid flags for chunk type %d\n", i); + "Invalid flags for chunk type %d", + i); } } } @@ -486,24 +489,24 @@ static void sctp_save(const void *ip, const struct xt_entry_match *match) } } -static const char *sctp_xlate_chunk(struct xt_xlate *xl, const char *space, - const struct xt_sctp_info *einfo, - const struct sctp_chunk_names *scn) +static void sctp_xlate_chunk(struct xt_xlate *xl, + const struct xt_sctp_info *einfo, + const struct sctp_chunk_names *scn) { bool inv = einfo->invflags & XT_SCTP_CHUNK_TYPES; const struct xt_sctp_flag_info *flag_info = NULL; int i; if (!scn->nftname) - return space; + return; if (!SCTP_CHUNKMAP_IS_SET(einfo->chunkmap, scn->chunk_type)) { if (einfo->chunk_match_type != SCTP_CHUNK_MATCH_ONLY) - return space; + return; - xt_xlate_add(xl, "%ssctp chunk %s %s", space, + xt_xlate_add(xl, "sctp chunk %s %s", scn->nftname, inv ? "exists" : "missing"); - return " "; + return; } for (i = 0; i < einfo->flag_count; i++) { @@ -514,16 +517,14 @@ static const char *sctp_xlate_chunk(struct xt_xlate *xl, const char *space, } if (!flag_info) { - xt_xlate_add(xl, "%ssctp chunk %s %s", space, + xt_xlate_add(xl, "sctp chunk %s %s", scn->nftname, inv ? "missing" : "exists"); - return " "; + return; } - xt_xlate_add(xl, "%ssctp chunk %s flags & 0x%x %s 0x%x", space, + xt_xlate_add(xl, "sctp chunk %s flags & 0x%x %s 0x%x", scn->nftname, flag_info->flag_mask, inv ? "!=" : "==", flag_info->flag); - - return " "; } static int sctp_xlate(struct xt_xlate *xl, @@ -531,7 +532,6 @@ static int sctp_xlate(struct xt_xlate *xl, { const struct xt_sctp_info *einfo = (const struct xt_sctp_info *)params->match->data; - const char *space = ""; if (!einfo->flags) return 0; @@ -545,19 +545,17 @@ static int sctp_xlate(struct xt_xlate *xl, xt_xlate_add(xl, "sctp 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, "%ssctp dport%s %u-%u", space, + xt_xlate_add(xl, "sctp dport%s %u-%u", einfo->invflags & XT_SCTP_DEST_PORTS ? " !=" : "", einfo->dpts[0], einfo->dpts[1]); else - xt_xlate_add(xl, "%ssctp dport%s %u", space, + xt_xlate_add(xl, "sctp dport%s %u", einfo->invflags & XT_SCTP_DEST_PORTS ? " !=" : "", einfo->dpts[0]); - space = " "; } if (einfo->flags & XT_SCTP_CHUNK_TYPES) { @@ -567,8 +565,7 @@ static int sctp_xlate(struct xt_xlate *xl, return 0; for (i = 0; i < ARRAY_SIZE(sctp_chunk_names); i++) - space = sctp_xlate_chunk(xl, space, einfo, - &sctp_chunk_names[i]); + sctp_xlate_chunk(xl, einfo, &sctp_chunk_names[i]); } return 1; diff --git a/extensions/libxt_sctp.man b/extensions/libxt_sctp.man index 3e5ffa09..06da04f8 100644 --- a/extensions/libxt_sctp.man +++ b/extensions/libxt_sctp.man @@ -19,12 +19,14 @@ Match if any of the given chunk types is present with given flags. only Match if only the given chunk types are present with given flags and none are missing. -Chunk types: DATA INIT INIT_ACK SACK HEARTBEAT HEARTBEAT_ACK ABORT SHUTDOWN SHUTDOWN_ACK ERROR COOKIE_ECHO COOKIE_ACK ECN_ECNE ECN_CWR SHUTDOWN_COMPLETE ASCONF ASCONF_ACK FORWARD_TSN +Chunk types: DATA INIT INIT_ACK SACK HEARTBEAT HEARTBEAT_ACK ABORT SHUTDOWN SHUTDOWN_ACK ERROR COOKIE_ECHO COOKIE_ACK ECN_ECNE ECN_CWR SHUTDOWN_COMPLETE I_DATA RE_CONFIG PAD ASCONF ASCONF_ACK FORWARD_TSN I_FORWARD_TSN chunk type available flags .br DATA I U B E i u b e .br +I_DATA I U B E i u b e +.br ABORT T t .br SHUTDOWN_COMPLETE T t diff --git a/extensions/libxt_sctp.t b/extensions/libxt_sctp.t index 4016e4fb..4d3b113d 100644 --- a/extensions/libxt_sctp.t +++ b/extensions/libxt_sctp.t @@ -27,3 +27,7 @@ -p sctp -m sctp --chunk-types all ASCONF_ACK;=;OK -p sctp -m sctp --chunk-types all FORWARD_TSN;=;OK -p sctp -m sctp --chunk-types all SHUTDOWN_COMPLETE;=;OK +-p sctp -m sctp --chunk-types all I_DATA;=;OK +-p sctp -m sctp --chunk-types all RE_CONFIG;=;OK +-p sctp -m sctp --chunk-types all PAD;=;OK +-p sctp -m sctp --chunk-types all I_FORWARD_TSN;=;OK diff --git a/extensions/libxt_sctp.txlate b/extensions/libxt_sctp.txlate index bb817525..0aa7371d 100644 --- a/extensions/libxt_sctp.txlate +++ b/extensions/libxt_sctp.txlate @@ -1,44 +1,44 @@ iptables-translate -A INPUT -p sctp --dport 80 -j DROP -nft add rule ip filter INPUT sctp dport 80 counter drop +nft 'add rule ip filter INPUT sctp dport 80 counter drop' iptables-translate -A INPUT -p sctp --sport 50 -j DROP -nft add rule ip filter INPUT sctp sport 50 counter drop +nft 'add rule ip filter INPUT sctp sport 50 counter drop' iptables-translate -A INPUT -p sctp ! --dport 80 -j DROP -nft add rule ip filter INPUT sctp dport != 80 counter drop +nft 'add rule ip filter INPUT sctp dport != 80 counter drop' iptables-translate -A INPUT -p sctp ! --sport 50 -j DROP -nft add rule ip filter INPUT sctp sport != 50 counter drop +nft 'add rule ip filter INPUT sctp sport != 50 counter drop' iptables-translate -A INPUT -p sctp --sport 80:100 -j ACCEPT -nft add rule ip filter INPUT sctp sport 80-100 counter accept +nft 'add rule ip filter INPUT sctp sport 80-100 counter accept' iptables-translate -A INPUT -p sctp --dport 50:56 -j ACCEPT -nft add rule ip filter INPUT sctp dport 50-56 counter accept +nft 'add rule ip filter INPUT sctp dport 50-56 counter accept' iptables-translate -A INPUT -p sctp ! --sport 80:100 -j ACCEPT -nft add rule ip filter INPUT sctp sport != 80-100 counter accept +nft 'add rule ip filter INPUT sctp sport != 80-100 counter accept' iptables-translate -A INPUT -p sctp ! --dport 50:56 -j ACCEPT -nft add rule ip filter INPUT sctp dport != 50-56 counter accept +nft 'add rule ip filter INPUT sctp dport != 50-56 counter accept' iptables-translate -A INPUT -p sctp --dport 80 --sport 50 -j ACCEPT -nft add rule ip filter INPUT sctp sport 50 sctp dport 80 counter accept +nft 'add rule ip filter INPUT sctp sport 50 sctp dport 80 counter accept' iptables-translate -A INPUT -p sctp --dport 80:100 --sport 50 -j ACCEPT -nft add rule ip filter INPUT sctp sport 50 sctp dport 80-100 counter accept +nft 'add rule ip filter INPUT sctp sport 50 sctp dport 80-100 counter accept' iptables-translate -A INPUT -p sctp --dport 80 --sport 50:55 -j ACCEPT -nft add rule ip filter INPUT sctp sport 50-55 sctp dport 80 counter accept +nft 'add rule ip filter INPUT sctp sport 50-55 sctp dport 80 counter accept' iptables-translate -A INPUT -p sctp ! --dport 80:100 --sport 50 -j ACCEPT -nft add rule ip filter INPUT sctp sport 50 sctp dport != 80-100 counter accept +nft 'add rule ip filter INPUT sctp sport 50 sctp dport != 80-100 counter accept' iptables-translate -A INPUT -p sctp --dport 80 ! --sport 50:55 -j ACCEPT -nft add rule ip filter INPUT sctp sport != 50-55 sctp dport 80 counter accept +nft 'add rule ip filter INPUT sctp sport != 50-55 sctp dport 80 counter accept' iptables-translate -A INPUT -p sctp --chunk-types all INIT,DATA:iUbE,SACK,ABORT:T -j ACCEPT -nft add rule ip filter INPUT sctp chunk data flags & 0xf == 0x5 sctp chunk init exists sctp chunk sack exists sctp chunk abort flags & 0x1 == 0x1 counter accept +nft 'add rule ip filter INPUT sctp chunk data flags & 0xf == 0x5 sctp chunk init exists sctp chunk sack exists sctp chunk abort flags & 0x1 == 0x1 counter accept' iptables-translate -A INPUT -p sctp --chunk-types only SHUTDOWN_COMPLETE -j ACCEPT -nft add rule ip filter INPUT sctp chunk data missing sctp chunk init missing sctp chunk init-ack missing sctp chunk sack missing sctp chunk heartbeat missing sctp chunk heartbeat-ack missing sctp chunk abort missing sctp chunk shutdown missing sctp chunk shutdown-ack missing sctp chunk error missing sctp chunk cookie-echo missing sctp chunk cookie-ack missing sctp chunk ecne missing sctp chunk cwr missing sctp chunk shutdown-complete exists sctp chunk asconf missing sctp chunk asconf-ack missing sctp chunk forward-tsn missing counter accept +nft 'add rule ip filter INPUT sctp chunk data missing sctp chunk init missing sctp chunk init-ack missing sctp chunk sack missing sctp chunk heartbeat missing sctp chunk heartbeat-ack missing sctp chunk abort missing sctp chunk shutdown missing sctp chunk shutdown-ack missing sctp chunk error missing sctp chunk cookie-echo missing sctp chunk cookie-ack missing sctp chunk ecne missing sctp chunk cwr missing sctp chunk shutdown-complete exists sctp chunk i-data missing sctp chunk re-config missing sctp chunk pad missing sctp chunk asconf missing sctp chunk asconf-ack missing sctp chunk forward-tsn missing sctp chunk i-forward-tsn missing counter accept' diff --git a/extensions/libxt_set.c b/extensions/libxt_set.c index 16921023..471bde8a 100644 --- a/extensions/libxt_set.c +++ b/extensions/libxt_set.c @@ -22,6 +22,12 @@ #include <linux/netfilter/xt_set.h> #include "libxt_set.h" +#ifdef DEBUG +#define DEBUGP(x, args...) fprintf(stderr, x, ## args) +#else +#define DEBUGP(x, args...) +#endif + /* Revision 0 */ static void @@ -328,8 +334,7 @@ parse_counter(const char *opt) if (!xtables_strtoul(opt, NULL, &value, 0, UINT64_MAX)) xtables_error(PARAMETER_PROBLEM, - "Cannot parse %s as a counter value\n", - opt); + "Cannot parse %s as a counter value", opt); return (uint64_t)value; } @@ -348,60 +353,54 @@ set_parse_v3(int c, char **argv, int invert, unsigned int *flags, case '0': if (info->bytes.op != IPSET_COUNTER_NONE) xtables_error(PARAMETER_PROBLEM, - "only one of the --bytes-[eq|lt|gt]" - " is allowed\n"); + "only one of the --bytes-[eq|lt|gt] is allowed"); if (invert) xtables_error(PARAMETER_PROBLEM, - "--bytes-gt option cannot be inverted\n"); + "--bytes-gt option cannot be inverted"); 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"); + "only one of the --bytes-[eq|lt|gt] is allowed"); if (invert) xtables_error(PARAMETER_PROBLEM, - "--bytes-lt option cannot be inverted\n"); + "--bytes-lt option cannot be inverted"); 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"); + "only one of the --bytes-[eq|lt|gt] is allowed"); 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"); + "only one of the --packets-[eq|lt|gt] is allowed"); if (invert) xtables_error(PARAMETER_PROBLEM, - "--packets-gt option cannot be inverted\n"); + "--packets-gt option cannot be inverted"); 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"); + "only one of the --packets-[eq|lt|gt] is allowed"); if (invert) xtables_error(PARAMETER_PROBLEM, - "--packets-lt option cannot be inverted\n"); + "--packets-lt option cannot be inverted"); 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"); + "only one of the --packets-[eq|lt|gt] is allowed"); info->packets.op = invert ? IPSET_COUNTER_NE : IPSET_COUNTER_EQ; info->packets.value = parse_counter(optarg); break; @@ -412,7 +411,7 @@ set_parse_v3(int c, char **argv, int invert, unsigned int *flags, case '3': if (invert) xtables_error(PARAMETER_PROBLEM, - "--return-nomatch flag cannot be inverted\n"); + "--return-nomatch flag cannot be inverted"); info->flags |= IPSET_FLAG_RETURN_NOMATCH; break; case '2': @@ -517,60 +516,54 @@ set_parse_v4(int c, char **argv, int invert, unsigned int *flags, case '0': if (info->bytes.op != IPSET_COUNTER_NONE) xtables_error(PARAMETER_PROBLEM, - "only one of the --bytes-[eq|lt|gt]" - " is allowed\n"); + "only one of the --bytes-[eq|lt|gt] is allowed"); if (invert) xtables_error(PARAMETER_PROBLEM, - "--bytes-gt option cannot be inverted\n"); + "--bytes-gt option cannot be inverted"); 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"); + "only one of the --bytes-[eq|lt|gt] is allowed"); if (invert) xtables_error(PARAMETER_PROBLEM, - "--bytes-lt option cannot be inverted\n"); + "--bytes-lt option cannot be inverted"); 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"); + "only one of the --bytes-[eq|lt|gt] is allowed"); 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"); + "only one of the --packets-[eq|lt|gt] is allowed"); if (invert) xtables_error(PARAMETER_PROBLEM, - "--packets-gt option cannot be inverted\n"); + "--packets-gt option cannot be inverted"); 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"); + "only one of the --packets-[eq|lt|gt] is allowed"); if (invert) xtables_error(PARAMETER_PROBLEM, - "--packets-lt option cannot be inverted\n"); + "--packets-lt option cannot be inverted"); 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"); + "only one of the --packets-[eq|lt|gt] is allowed"); info->packets.op = invert ? IPSET_COUNTER_NE : IPSET_COUNTER_EQ; info->packets.value = parse_counter(optarg); break; @@ -581,7 +574,7 @@ set_parse_v4(int c, char **argv, int invert, unsigned int *flags, case '3': if (invert) xtables_error(PARAMETER_PROBLEM, - "--return-nomatch flag cannot be inverted\n"); + "--return-nomatch flag cannot be inverted"); info->flags |= IPSET_FLAG_RETURN_NOMATCH; break; case '2': diff --git a/extensions/libxt_set.h b/extensions/libxt_set.h index ad895a75..597bf7eb 100644 --- a/extensions/libxt_set.h +++ b/extensions/libxt_set.h @@ -6,7 +6,6 @@ #include <sys/types.h> #include <sys/socket.h> #include <errno.h> -#include "../iptables/xshared.h" static int get_version(unsigned *version) diff --git a/extensions/libxt_statistic.c b/extensions/libxt_statistic.c index 4f3341a3..37915adc 100644 --- a/extensions/libxt_statistic.c +++ b/extensions/libxt_statistic.c @@ -141,13 +141,19 @@ static int statistic_xlate(struct xt_xlate *xl, switch (info->mode) { case XT_STATISTIC_MODE_RANDOM: - return 0; + xt_xlate_add(xl, "meta random & %u %s %u", + INT_MAX, + info->flags & XT_STATISTIC_INVERT ? ">=" : "<", + info->u.random.probability); + break; 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; + default: + return 0; } return 1; diff --git a/extensions/libxt_statistic.txlate b/extensions/libxt_statistic.txlate index 4c3dea43..627120c5 100644 --- a/extensions/libxt_statistic.txlate +++ b/extensions/libxt_statistic.txlate @@ -1,8 +1,8 @@ iptables-translate -A OUTPUT -m statistic --mode nth --every 10 --packet 1 -nft add rule ip filter OUTPUT numgen inc mod 10 1 counter +nft 'add rule ip filter OUTPUT numgen inc mod 10 1 counter' iptables-translate -A OUTPUT -m statistic --mode nth ! --every 10 --packet 5 -nft add rule ip filter OUTPUT numgen inc mod 10 != 5 counter +nft 'add rule ip filter OUTPUT numgen inc mod 10 != 5 counter' iptables-translate -A OUTPUT -m statistic --mode random --probability 0.1 -nft # -A OUTPUT -m statistic --mode random --probability 0.1 +nft 'add rule ip filter OUTPUT meta random & 2147483647 < 214748365 counter' diff --git a/extensions/libxt_string.c b/extensions/libxt_string.c index 739a8e7f..5d72a5cd 100644 --- a/extensions/libxt_string.c +++ b/extensions/libxt_string.c @@ -78,14 +78,13 @@ static void string_init(struct xt_entry_match *m) static void parse_string(const char *s, struct xt_string_info *info) -{ +{ /* xt_string does not need \0 at the end of the pattern */ - if (strlen(s) <= XT_STRING_MAX_PATTERN_SIZE) { - memcpy(info->pattern, s, XT_STRING_MAX_PATTERN_SIZE); - info->patlen = strnlen(s, XT_STRING_MAX_PATTERN_SIZE); - return; - } - xtables_error(PARAMETER_PROBLEM, "STRING too long \"%s\"", s); + if (strlen(s) > sizeof(info->pattern)) + xtables_error(PARAMETER_PROBLEM, "STRING too long \"%s\"", s); + + info->patlen = strnlen(s, sizeof(info->pattern)); + memcpy(info->pattern, s, info->patlen); } static void @@ -269,7 +268,7 @@ string_print(const void *ip, const struct xt_entry_match *match, int numeric) printf(" ALGO name %s", info->algo); if (info->from_offset != 0) printf(" FROM %u", info->from_offset); - if (info->to_offset != 0) + if (info->to_offset != UINT16_MAX) printf(" TO %u", info->to_offset); if (revision > 0 && info->u.v1.flags & XT_STRING_FLAG_IGNORECASE) printf(" ICASE"); @@ -293,7 +292,7 @@ static void string_save(const void *ip, const struct xt_entry_match *match) printf(" --algo %s", info->algo); if (info->from_offset != 0) printf(" --from %u", info->from_offset); - if (info->to_offset != 0) + if (info->to_offset != UINT16_MAX) printf(" --to %u", info->to_offset); if (revision > 0 && info->u.v1.flags & XT_STRING_FLAG_IGNORECASE) printf(" --icase"); diff --git a/extensions/libxt_string.t b/extensions/libxt_string.t index d68f099d..2f4b30cb 100644 --- a/extensions/libxt_string.t +++ b/extensions/libxt_string.t @@ -1,18 +1,11 @@ :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 bm --string "test";-m string --string "test" --algo bm;OK +-m string --string "test" --algo kmp;=;OK +-m string ! --string "test" --algo kmp;=;OK +-m string --string "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" --algo bm;=;OK +-m string --string "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" --algo bm;;FAIL +-m string --hex-string "|0a0a0a0a|" --algo bm;=;OK +-m string --algo bm --from 0 --to 65535 --string "test";-m string --string "test" --algo bm;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 0b115cdd..f8257282 100644 --- a/extensions/libxt_tcp.c +++ b/extensions/libxt_tcp.c @@ -380,10 +380,9 @@ static void print_tcp_xlate(struct xt_xlate *xl, uint8_t flags) 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); + xt_xlate_add(xl, "%s%s", + have_flag ? "," : "", + tcp_flag_names_xlate[i].name); have_flag = 1; flags &= ~tcp_flag_names_xlate[i].flag; @@ -398,7 +397,6 @@ static int tcp_xlate(struct xt_xlate *xl, { 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]) { @@ -412,30 +410,29 @@ static int tcp_xlate(struct xt_xlate *xl, "!= " : "", 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, + xt_xlate_add(xl, "tcp dport %s%u-%u", tcpinfo->invflags & XT_TCP_INV_DSTPT ? "!= " : "", tcpinfo->dpts[0], tcpinfo->dpts[1]); } else { - xt_xlate_add(xl, "%stcp dport %s%u", space, + xt_xlate_add(xl, "tcp dport %s%u", 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->option) + xt_xlate_add(xl, "tcp option %u %s", tcpinfo->option, + tcpinfo->invflags & XT_TCP_INV_OPTION ? + "missing" : "exists"); if (tcpinfo->flg_mask || (tcpinfo->invflags & XT_TCP_INV_FLAGS)) { - xt_xlate_add(xl, "%stcp flags %s", space, + xt_xlate_add(xl, "tcp flags %s", tcpinfo->invflags & XT_TCP_INV_FLAGS ? "!= ": ""); print_tcp_xlate(xl, tcpinfo->flg_cmp); xt_xlate_add(xl, " / "); diff --git a/extensions/libxt_tcp.t b/extensions/libxt_tcp.t index b0e8006e..7a3bbd08 100644 --- a/extensions/libxt_tcp.t +++ b/extensions/libxt_tcp.t @@ -22,5 +22,8 @@ -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 +-m tcp --dport 1;;FAIL +-m tcp --dport 1 -p tcp;-p tcp -m tcp --dport 1;OK +-m tcp --dport 1 -p 6;-p tcp -m tcp --dport 1;OK # should we accept this below? -p tcp -m tcp;=;OK diff --git a/extensions/libxt_tcp.txlate b/extensions/libxt_tcp.txlate index 921d4af0..9802ddfe 100644 --- a/extensions/libxt_tcp.txlate +++ b/extensions/libxt_tcp.txlate @@ -1,26 +1,32 @@ iptables-translate -A INPUT -p tcp -i eth0 --sport 53 -j ACCEPT -nft add rule ip filter INPUT iifname "eth0" tcp sport 53 counter accept +nft 'add rule ip filter INPUT iifname "eth0" tcp sport 53 counter accept' iptables-translate -A OUTPUT -p tcp -o eth0 --dport 53:66 -j DROP -nft add rule ip filter OUTPUT oifname "eth0" tcp dport 53-66 counter drop +nft 'add rule ip filter OUTPUT oifname "eth0" tcp dport 53-66 counter drop' iptables-translate -I OUTPUT -p tcp -d 8.8.8.8 -j ACCEPT -nft insert rule ip filter OUTPUT ip protocol tcp ip daddr 8.8.8.8 counter accept +nft 'insert rule ip filter OUTPUT ip protocol tcp ip daddr 8.8.8.8 counter accept' iptables-translate -I OUTPUT -p tcp --dport 1020:1023 --sport 53 -j ACCEPT -nft insert rule ip filter OUTPUT tcp sport 53 tcp dport 1020-1023 counter accept +nft 'insert rule ip filter OUTPUT tcp sport 53 tcp dport 1020-1023 counter accept' iptables -A INPUT -p tcp --tcp-flags ACK,FIN FIN -j DROP -nft add rule ip filter INPUT tcp flags fin / fin,ack counter drop +nft 'add rule ip filter INPUT tcp flags fin / fin,ack counter drop' iptables-translate -A INPUT -p tcp --syn -j ACCEPT -nft add rule ip filter INPUT tcp flags syn / fin,syn,rst,ack counter accept +nft 'add rule ip filter INPUT tcp flags syn / fin,syn,rst,ack counter accept' iptables-translate -A INPUT -p tcp --syn --dport 80 -j ACCEPT -nft add rule ip filter INPUT tcp dport 80 tcp flags syn / fin,syn,rst,ack counter accept +nft 'add rule ip filter INPUT tcp dport 80 tcp flags syn / fin,syn,rst,ack counter accept' iptables-translate -A INPUT -f -p tcp -nft add rule ip filter INPUT ip frag-off & 0x1fff != 0 ip protocol tcp counter +nft 'add rule ip filter INPUT ip frag-off & 0x1fff != 0 ip protocol tcp counter' iptables-translate -A INPUT ! -f -p tcp --dport 22 -nft add rule ip filter INPUT ip frag-off & 0x1fff 0 tcp dport 22 counter +nft 'add rule ip filter INPUT ip frag-off & 0x1fff 0 tcp dport 22 counter' + +iptables-translate -A INPUT -p tcp --tcp-option 23 +nft 'add rule ip filter INPUT tcp option 23 exists counter' + +iptables-translate -A INPUT -p tcp ! --tcp-option 23 +nft 'add rule ip filter INPUT tcp option 23 missing counter' diff --git a/extensions/libxt_tcpmss.c b/extensions/libxt_tcpmss.c index bcd357aa..61b853d1 100644 --- a/extensions/libxt_tcpmss.c +++ b/extensions/libxt_tcpmss.c @@ -60,6 +60,21 @@ static void tcpmss_save(const void *ip, const struct xt_entry_match *match) printf("%u:%u", info->mss_min, info->mss_max); } +static int tcpmss_xlate(struct xt_xlate *xl, + const struct xt_xlate_mt_params *params) +{ + const struct xt_tcpmss_match_info *info = (void *)params->match->data; + + xt_xlate_add(xl, "tcp option maxseg size %s", info->invert ? "!= " : ""); + + if (info->mss_min == info->mss_max) + xt_xlate_add(xl, "%u", info->mss_min); + else + xt_xlate_add(xl, "%u-%u", info->mss_min, info->mss_max); + + return 1; +} + static struct xtables_match tcpmss_match = { .family = NFPROTO_UNSPEC, .name = "tcpmss", @@ -71,6 +86,7 @@ static struct xtables_match tcpmss_match = { .save = tcpmss_save, .x6_parse = tcpmss_parse, .x6_options = tcpmss_opts, + .xlate = tcpmss_xlate, }; void _init(void) diff --git a/extensions/libxt_tcpmss.txlate b/extensions/libxt_tcpmss.txlate new file mode 100644 index 00000000..82475e67 --- /dev/null +++ b/extensions/libxt_tcpmss.txlate @@ -0,0 +1,11 @@ +iptables-translate -A INPUT -m tcpmss --mss 42 +nft 'add rule ip filter INPUT tcp option maxseg size 42 counter' + +iptables-translate -A INPUT -m tcpmss ! --mss 42 +nft 'add rule ip filter INPUT tcp option maxseg size != 42 counter' + +iptables-translate -A INPUT -m tcpmss --mss 42:1024 +nft 'add rule ip filter INPUT tcp option maxseg size 42-1024 counter' + +iptables-translate -A INPUT -m tcpmss ! --mss 1461:65535 +nft 'add rule ip filter INPUT tcp option maxseg size != 1461-65535 counter' diff --git a/extensions/libxt_time.c b/extensions/libxt_time.c index d27d84ca..580861d3 100644 --- a/extensions/libxt_time.c +++ b/extensions/libxt_time.c @@ -466,9 +466,10 @@ static int time_xlate(struct xt_xlate *xl, const struct xt_time_info *info = (const struct xt_time_info *)params->match->data; unsigned int h, m, s, - i, sep, mask, count; + i, mask, count; time_t tt_start, tt_stop; struct tm *t_start, *t_stop; + const char *sep = ""; if (info->date_start != 0 || info->date_stop != INT_MAX) { @@ -498,7 +499,6 @@ static int time_xlate(struct xt_xlate *xl, if (info->monthdays_match != XT_TIME_ALL_MONTHDAYS) return 0; if (info->weekdays_match != XT_TIME_ALL_WEEKDAYS) { - sep = 0; mask = info->weekdays_match; count = time_count_weekdays(mask); @@ -507,12 +507,8 @@ static int time_xlate(struct xt_xlate *xl, xt_xlate_add(xl, "{"); for (i = 1; i <= 7; ++i) if (mask & (1 << i)) { - if (sep) - xt_xlate_add(xl, ",%u", i%7); - else { - xt_xlate_add(xl, "%u", i%7); - ++sep; - } + xt_xlate_add(xl, "%s%u", sep, i%7); + sep = ", "; } if (count > 1) xt_xlate_add(xl, "}"); diff --git a/extensions/libxt_time.txlate b/extensions/libxt_time.txlate index ff4a7b88..ed64b957 100644 --- a/extensions/libxt_time.txlate +++ b/extensions/libxt_time.txlate @@ -1,26 +1,26 @@ iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --weekdays Sa,Su -j REJECT -nft add rule ip filter INPUT icmp type echo-request meta day {6,0} counter reject +nft 'add rule ip filter INPUT icmp type echo-request meta day { 6, 0 } counter reject' iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --timestart 12:00 -j REJECT -nft add rule ip filter INPUT icmp type echo-request meta hour "12:00:00"-"23:59:59" counter reject +nft 'add rule ip filter INPUT icmp type echo-request meta hour "12:00:00"-"23:59:59" counter reject' iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --timestop 12:00 -j REJECT -nft add rule ip filter INPUT icmp type echo-request meta hour "00:00:00"-"12:00:00" counter reject +nft 'add rule ip filter INPUT icmp type echo-request meta hour "00:00:00"-"12:00:00" counter reject' iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --datestart 2021 -j REJECT -nft add rule ip filter INPUT icmp type echo-request meta time "2021-01-01 00:00:00"-"2038-01-19 03:14:07" counter reject +nft 'add rule ip filter INPUT icmp type echo-request meta time "2021-01-01 00:00:00"-"2038-01-19 03:14:07" counter reject' iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --datestop 2021 -j REJECT -nft add rule ip filter INPUT icmp type echo-request meta time "1970-01-01 00:00:00"-"2021-01-01 00:00:00" counter reject +nft 'add rule ip filter INPUT icmp type echo-request meta time "1970-01-01 00:00:00"-"2021-01-01 00:00:00" counter reject' iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --datestop 2021-01-29T00:00:00 -j REJECT -nft add rule ip filter INPUT icmp type echo-request meta time "1970-01-01 00:00:00"-"2021-01-29 00:00:00" counter reject +nft 'add rule ip filter INPUT icmp type echo-request meta time "1970-01-01 00:00:00"-"2021-01-29 00:00:00" counter reject' iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --datestart 2020-01-29T00:00:00 --timestart 12:00 -j REJECT -nft add rule ip filter INPUT icmp type echo-request meta time "2020-01-29 00:00:00"-"2038-01-19 03:14:07" meta hour "12:00:00"-"23:59:59" counter reject +nft 'add rule ip filter INPUT icmp type echo-request meta time "2020-01-29 00:00:00"-"2038-01-19 03:14:07" meta hour "12:00:00"-"23:59:59" counter reject' iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --datestart 2020-01-29T00:00:00 --timestart 12:00 --timestop 19:00 --weekdays Mon,Tue,Wed,Thu,Fri -j REJECT -nft add rule ip filter INPUT icmp type echo-request meta time "2020-01-29 00:00:00"-"2038-01-19 03:14:07" meta hour "12:00:00"-"19:00:00" meta day {1,2,3,4,5} counter reject +nft 'add rule ip filter INPUT icmp type echo-request meta time "2020-01-29 00:00:00"-"2038-01-19 03:14:07" meta hour "12:00:00"-"19:00:00" meta day { 1, 2, 3, 4, 5 } counter reject' iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --datestart 2020-01-29T00:00:00 --timestart 12:00 --timestop 19:00 ! --weekdays Mon,Tue,Wed,Thu,Fri -j REJECT -nft add rule ip filter INPUT icmp type echo-request meta time "2020-01-29 00:00:00"-"2038-01-19 03:14:07" meta hour "12:00:00"-"19:00:00" meta day {6,0} counter reject +nft 'add rule ip filter INPUT icmp type echo-request meta time "2020-01-29 00:00:00"-"2038-01-19 03:14:07" meta hour "12:00:00"-"19:00:00" meta day { 6, 0 } counter reject' diff --git a/extensions/libxt_tos.t b/extensions/libxt_tos.t index ccbe8009..6cceeeb4 100644 --- a/extensions/libxt_tos.t +++ b/extensions/libxt_tos.t @@ -4,10 +4,10 @@ -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 0xff;-m tos --tos 0xff/0xff;OK +-m tos ! --tos 0xff;-m tos ! --tos 0xff/0xff;OK +-m tos --tos 0x00;-m tos --tos 0x00/0xff;OK +-m tos --tos 0x0f;-m tos --tos 0x0f/0xff;OK -m tos --tos 0x0f/0x0f;=;OK -m tos --tos wrong;;FAIL -m tos;;FAIL diff --git a/extensions/libxt_udp.c b/extensions/libxt_udp.c index 0c7a4bc2..ba1c3eb7 100644 --- a/extensions/libxt_udp.c +++ b/extensions/libxt_udp.c @@ -156,7 +156,6 @@ 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]) { @@ -170,17 +169,16 @@ static int udp_xlate(struct xt_xlate *xl, "!= ": "", 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, + xt_xlate_add(xl,"udp dport %s%u-%u", udpinfo->invflags & XT_UDP_INV_SRCPT ? "!= ": "", udpinfo->dpts[0], udpinfo->dpts[1]); } else { - xt_xlate_add(xl,"%sudp dport %s%u", space, + xt_xlate_add(xl,"udp dport %s%u", udpinfo->invflags & XT_UDP_INV_SRCPT ? "!= ": "", udpinfo->dpts[0]); diff --git a/extensions/libxt_udp.t b/extensions/libxt_udp.t index 1b4d3dd6..f5347701 100644 --- a/extensions/libxt_udp.t +++ b/extensions/libxt_udp.t @@ -18,5 +18,8 @@ # -p udp -m udp --sport 65536;;FAIL -p udp -m udp --sport -1;;FAIL -p udp -m udp --dport -1;;FAIL +-m udp --dport 1;;FAIL +-m udp --dport 1 -p udp;-p udp -m udp --dport 1;OK +-m udp --dport 1 -p 17;-p udp -m udp --dport 1;OK # should we accept this below? -p udp -m udp;=;OK diff --git a/extensions/libxt_udp.txlate b/extensions/libxt_udp.txlate index fbca5c12..28e7ca20 100644 --- a/extensions/libxt_udp.txlate +++ b/extensions/libxt_udp.txlate @@ -1,11 +1,11 @@ iptables-translate -A INPUT -p udp -i eth0 --sport 53 -j ACCEPT -nft add rule ip filter INPUT iifname "eth0" udp sport 53 counter accept +nft 'add rule ip filter INPUT iifname "eth0" udp sport 53 counter accept' iptables-translate -A OUTPUT -p udp -o eth0 --dport 53:66 -j DROP -nft add rule ip filter OUTPUT oifname "eth0" udp dport 53-66 counter drop +nft 'add rule ip filter OUTPUT oifname "eth0" udp dport 53-66 counter drop' iptables-translate -I OUTPUT -p udp -d 8.8.8.8 -j ACCEPT -nft insert rule ip filter OUTPUT ip protocol udp ip daddr 8.8.8.8 counter accept +nft 'insert rule ip filter OUTPUT ip protocol udp ip daddr 8.8.8.8 counter accept' iptables-translate -I OUTPUT -p udp --dport 1020:1023 --sport 53 -j ACCEPT -nft insert rule ip filter OUTPUT udp sport 53 udp dport 1020-1023 counter accept +nft 'insert rule ip filter OUTPUT udp sport 53 udp dport 1020-1023 counter accept' diff --git a/include/Makefile.am b/include/Makefile.am index ea34c2fe..07c88b90 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -1,16 +1,18 @@ # -*- Makefile -*- -include_HEADERS = -nobase_include_HEADERS = xtables.h xtables-version.h +include_HEADERS = xtables.h +nodist_include_HEADERS = xtables-version.h if ENABLE_LIBIPQ include_HEADERS += libipq/libipq.h endif -nobase_include_HEADERS += \ +nobase_include_HEADERS = \ libiptc/ipt_kernel_headers.h libiptc/libiptc.h \ libiptc/libip6tc.h libiptc/libxtc.h libiptc/xtcshared.h +EXTRA_DIST = iptables linux iptables.h ip6tables.h + uninstall-hook: dir=${includedir}/libiptc; { \ test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; \ diff --git a/include/libipq/libipq.h b/include/libipq/libipq.h index 3cd13292..dd0cb205 100644 --- a/include/libipq/libipq.h +++ b/include/libipq/libipq.h @@ -24,7 +24,7 @@ #include <errno.h> #include <unistd.h> #include <fcntl.h> -#include <sys/types.h> +#include <stdint.h> #include <sys/socket.h> #include <sys/uio.h> #include <asm/types.h> @@ -48,19 +48,19 @@ typedef unsigned long ipq_id_t; struct ipq_handle { int fd; - u_int8_t blocking; + uint8_t blocking; struct sockaddr_nl local; struct sockaddr_nl peer; }; -struct ipq_handle *ipq_create_handle(u_int32_t flags, u_int32_t protocol); +struct ipq_handle *ipq_create_handle(uint32_t flags, uint32_t protocol); int ipq_destroy_handle(struct ipq_handle *h); ssize_t ipq_read(const struct ipq_handle *h, unsigned char *buf, size_t len, int timeout); -int ipq_set_mode(const struct ipq_handle *h, u_int8_t mode, size_t len); +int ipq_set_mode(const struct ipq_handle *h, uint8_t mode, size_t len); ipq_packet_msg_t *ipq_get_packet(const unsigned char *buf); diff --git a/include/libiptc/libxtc.h b/include/libiptc/libxtc.h index 37010188..a1d16ef9 100644 --- a/include/libiptc/libxtc.h +++ b/include/libiptc/libxtc.h @@ -10,7 +10,7 @@ extern "C" { #endif #ifndef XT_MIN_ALIGN -/* xt_entry has pointers and u_int64_t's in it, so if you align to +/* xt_entry has pointers and uint64_t's in it, so if you align to it, you'll also align to any crazy matches and targets someone might write */ #define XT_MIN_ALIGN (__alignof__(struct xt_entry)) diff --git a/include/linux/netfilter/nf_log.h b/include/linux/netfilter/nf_log.h new file mode 100644 index 00000000..2ae00932 --- /dev/null +++ b/include/linux/netfilter/nf_log.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _NETFILTER_NF_LOG_H +#define _NETFILTER_NF_LOG_H + +#define NF_LOG_TCPSEQ 0x01 /* Log TCP sequence numbers */ +#define NF_LOG_TCPOPT 0x02 /* Log TCP options */ +#define NF_LOG_IPOPT 0x04 /* Log IP options */ +#define NF_LOG_UID 0x08 /* Log UID owning local socket */ +#define NF_LOG_NFLOG 0x10 /* Unsupported, don't reuse */ +#define NF_LOG_MACDECODE 0x20 /* Decode MAC header */ +#define NF_LOG_MASK 0x2f + +#define NF_LOG_PREFIXLEN 128 + +#endif /* _NETFILTER_NF_LOG_H */ diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h index 66dceee0..e94d1fa5 100644 --- a/include/linux/netfilter/nf_tables.h +++ b/include/linux/netfilter/nf_tables.h @@ -8,6 +8,7 @@ #define NFT_SET_MAXNAMELEN NFT_NAME_MAXLEN #define NFT_OBJ_MAXNAMELEN NFT_NAME_MAXLEN #define NFT_USERDATA_MAXLEN 256 +#define NFT_OSF_MAXGENRELEN 16 /** * enum nft_registers - nf_tables registers @@ -47,6 +48,7 @@ enum nft_registers { #define NFT_REG_SIZE 16 #define NFT_REG32_SIZE 4 +#define NFT_REG32_COUNT (NFT_REG32_15 - NFT_REG32_00 + 1) /** * enum nft_verdicts - nf_tables internal verdicts @@ -131,7 +133,7 @@ enum nf_tables_msg_types { * @NFTA_LIST_ELEM: list element (NLA_NESTED) */ enum nft_list_attributes { - NFTA_LIST_UNPEC, + NFTA_LIST_UNSPEC, NFTA_LIST_ELEM, __NFTA_LIST_MAX }; @@ -143,12 +145,14 @@ enum nft_list_attributes { * @NFTA_HOOK_HOOKNUM: netfilter hook number (NLA_U32) * @NFTA_HOOK_PRIORITY: netfilter hook priority (NLA_U32) * @NFTA_HOOK_DEV: netdevice name (NLA_STRING) + * @NFTA_HOOK_DEVS: list of netdevices (NLA_NESTED) */ enum nft_hook_attributes { NFTA_HOOK_UNSPEC, NFTA_HOOK_HOOKNUM, NFTA_HOOK_PRIORITY, NFTA_HOOK_DEV, + NFTA_HOOK_DEVS, __NFTA_HOOK_MAX }; #define NFTA_HOOK_MAX (__NFTA_HOOK_MAX - 1) @@ -160,7 +164,10 @@ enum nft_hook_attributes { */ enum nft_table_flags { NFT_TABLE_F_DORMANT = 0x1, + NFT_TABLE_F_OWNER = 0x2, }; +#define NFT_TABLE_F_MASK (NFT_TABLE_F_DORMANT | \ + NFT_TABLE_F_OWNER) /** * enum nft_table_attributes - nf_tables table netlink attributes @@ -168,6 +175,8 @@ enum nft_table_flags { * @NFTA_TABLE_NAME: name of the table (NLA_STRING) * @NFTA_TABLE_FLAGS: bitmask of enum nft_table_flags (NLA_U32) * @NFTA_TABLE_USE: number of chains in this table (NLA_U32) + * @NFTA_TABLE_USERDATA: user data (NLA_BINARY) + * @NFTA_TABLE_OWNER: owner of this table through netlink portID (NLA_U32) */ enum nft_table_attributes { NFTA_TABLE_UNSPEC, @@ -176,10 +185,21 @@ enum nft_table_attributes { NFTA_TABLE_USE, NFTA_TABLE_HANDLE, NFTA_TABLE_PAD, + NFTA_TABLE_USERDATA, + NFTA_TABLE_OWNER, __NFTA_TABLE_MAX }; #define NFTA_TABLE_MAX (__NFTA_TABLE_MAX - 1) +enum nft_chain_flags { + NFT_CHAIN_BASE = (1 << 0), + NFT_CHAIN_HW_OFFLOAD = (1 << 1), + NFT_CHAIN_BINDING = (1 << 2), +}; +#define NFT_CHAIN_FLAGS (NFT_CHAIN_BASE | \ + NFT_CHAIN_HW_OFFLOAD | \ + NFT_CHAIN_BINDING) + /** * enum nft_chain_attributes - nf_tables chain netlink attributes * @@ -191,6 +211,9 @@ enum nft_table_attributes { * @NFTA_CHAIN_USE: number of references to this chain (NLA_U32) * @NFTA_CHAIN_TYPE: type name of the string (NLA_NUL_STRING) * @NFTA_CHAIN_COUNTERS: counter specification of the chain (NLA_NESTED: nft_counter_attributes) + * @NFTA_CHAIN_FLAGS: chain flags + * @NFTA_CHAIN_ID: uniquely identifies a chain in a transaction (NLA_U32) + * @NFTA_CHAIN_USERDATA: user data (NLA_BINARY) */ enum nft_chain_attributes { NFTA_CHAIN_UNSPEC, @@ -203,6 +226,9 @@ enum nft_chain_attributes { NFTA_CHAIN_TYPE, NFTA_CHAIN_COUNTERS, NFTA_CHAIN_PAD, + NFTA_CHAIN_FLAGS, + NFTA_CHAIN_ID, + NFTA_CHAIN_USERDATA, __NFTA_CHAIN_MAX }; #define NFTA_CHAIN_MAX (__NFTA_CHAIN_MAX - 1) @@ -218,6 +244,7 @@ enum nft_chain_attributes { * @NFTA_RULE_POSITION: numeric handle of the previous rule (NLA_U64) * @NFTA_RULE_USERDATA: user data (NLA_BINARY, NFT_USERDATA_MAXLEN) * @NFTA_RULE_ID: uniquely identifies a rule in a transaction (NLA_U32) + * @NFTA_RULE_POSITION_ID: transaction unique identifier of the previous rule (NLA_U32) */ enum nft_rule_attributes { NFTA_RULE_UNSPEC, @@ -230,6 +257,8 @@ enum nft_rule_attributes { NFTA_RULE_USERDATA, NFTA_RULE_PAD, NFTA_RULE_ID, + NFTA_RULE_POSITION_ID, + NFTA_RULE_CHAIN_ID, __NFTA_RULE_MAX }; #define NFTA_RULE_MAX (__NFTA_RULE_MAX - 1) @@ -266,8 +295,10 @@ enum nft_rule_compat_attributes { * @NFT_SET_INTERVAL: set contains intervals * @NFT_SET_MAP: set is used as a dictionary * @NFT_SET_TIMEOUT: set uses timeouts - * @NFT_SET_EVAL: set contains expressions for evaluation + * @NFT_SET_EVAL: set can be updated from the evaluation path * @NFT_SET_OBJECT: set contains stateful objects + * @NFT_SET_CONCAT: set contains a concatenation + * @NFT_SET_EXPR: set contains expressions */ enum nft_set_flags { NFT_SET_ANONYMOUS = 0x1, @@ -277,6 +308,8 @@ enum nft_set_flags { NFT_SET_TIMEOUT = 0x10, NFT_SET_EVAL = 0x20, NFT_SET_OBJECT = 0x40, + NFT_SET_CONCAT = 0x80, + NFT_SET_EXPR = 0x100, }; /** @@ -294,15 +327,29 @@ enum nft_set_policies { * enum nft_set_desc_attributes - set element description * * @NFTA_SET_DESC_SIZE: number of elements in set (NLA_U32) + * @NFTA_SET_DESC_CONCAT: description of field concatenation (NLA_NESTED) */ enum nft_set_desc_attributes { NFTA_SET_DESC_UNSPEC, NFTA_SET_DESC_SIZE, + NFTA_SET_DESC_CONCAT, __NFTA_SET_DESC_MAX }; #define NFTA_SET_DESC_MAX (__NFTA_SET_DESC_MAX - 1) /** + * enum nft_set_field_attributes - attributes of concatenated fields + * + * @NFTA_SET_FIELD_LEN: length of single field, in bits (NLA_U32) + */ +enum nft_set_field_attributes { + NFTA_SET_FIELD_UNSPEC, + NFTA_SET_FIELD_LEN, + __NFTA_SET_FIELD_MAX +}; +#define NFTA_SET_FIELD_MAX (__NFTA_SET_FIELD_MAX - 1) + +/** * enum nft_set_attributes - nf_tables set netlink attributes * * @NFTA_SET_TABLE: table name (NLA_STRING) @@ -320,6 +367,8 @@ enum nft_set_desc_attributes { * @NFTA_SET_USERDATA: user data (NLA_BINARY) * @NFTA_SET_OBJ_TYPE: stateful object type (NLA_U32: NFT_OBJECT_*) * @NFTA_SET_HANDLE: set handle (NLA_U64) + * @NFTA_SET_EXPR: set expression (NLA_NESTED: nft_expr_attributes) + * @NFTA_SET_EXPRESSIONS: list of expressions (NLA_NESTED: nft_list_attributes) */ enum nft_set_attributes { NFTA_SET_UNSPEC, @@ -339,6 +388,8 @@ enum nft_set_attributes { NFTA_SET_PAD, NFTA_SET_OBJ_TYPE, NFTA_SET_HANDLE, + NFTA_SET_EXPR, + NFTA_SET_EXPRESSIONS, __NFTA_SET_MAX }; #define NFTA_SET_MAX (__NFTA_SET_MAX - 1) @@ -347,9 +398,11 @@ enum nft_set_attributes { * enum nft_set_elem_flags - nf_tables set element flags * * @NFT_SET_ELEM_INTERVAL_END: element ends the previous interval + * @NFT_SET_ELEM_CATCHALL: special catch-all element */ enum nft_set_elem_flags { NFT_SET_ELEM_INTERVAL_END = 0x1, + NFT_SET_ELEM_CATCHALL = 0x2, }; /** @@ -363,6 +416,8 @@ enum nft_set_elem_flags { * @NFTA_SET_ELEM_USERDATA: user data (NLA_BINARY) * @NFTA_SET_ELEM_EXPR: expression (NLA_NESTED: nft_expr_attributes) * @NFTA_SET_ELEM_OBJREF: stateful object reference (NLA_STRING) + * @NFTA_SET_ELEM_KEY_END: closing key value (NLA_NESTED: nft_data) + * @NFTA_SET_ELEM_EXPRESSIONS: list of expressions (NLA_NESTED: nft_list_attributes) */ enum nft_set_elem_attributes { NFTA_SET_ELEM_UNSPEC, @@ -375,6 +430,8 @@ enum nft_set_elem_attributes { NFTA_SET_ELEM_EXPR, NFTA_SET_ELEM_PAD, NFTA_SET_ELEM_OBJREF, + NFTA_SET_ELEM_KEY_END, + NFTA_SET_ELEM_EXPRESSIONS, __NFTA_SET_ELEM_MAX }; #define NFTA_SET_ELEM_MAX (__NFTA_SET_ELEM_MAX - 1) @@ -440,11 +497,13 @@ enum nft_data_attributes { * * @NFTA_VERDICT_CODE: nf_tables verdict (NLA_U32: enum nft_verdicts) * @NFTA_VERDICT_CHAIN: jump target chain name (NLA_STRING) + * @NFTA_VERDICT_CHAIN_ID: jump target chain ID (NLA_U32) */ enum nft_verdict_attributes { NFTA_VERDICT_UNSPEC, NFTA_VERDICT_CODE, NFTA_VERDICT_CHAIN, + NFTA_VERDICT_CHAIN_ID, __NFTA_VERDICT_MAX }; #define NFTA_VERDICT_MAX (__NFTA_VERDICT_MAX - 1) @@ -478,6 +537,20 @@ enum nft_immediate_attributes { #define NFTA_IMMEDIATE_MAX (__NFTA_IMMEDIATE_MAX - 1) /** + * enum nft_bitwise_ops - nf_tables bitwise operations + * + * @NFT_BITWISE_BOOL: mask-and-xor operation used to implement NOT, AND, OR and + * XOR boolean operations + * @NFT_BITWISE_LSHIFT: left-shift operation + * @NFT_BITWISE_RSHIFT: right-shift operation + */ +enum nft_bitwise_ops { + NFT_BITWISE_BOOL, + NFT_BITWISE_LSHIFT, + NFT_BITWISE_RSHIFT, +}; + +/** * enum nft_bitwise_attributes - nf_tables bitwise expression netlink attributes * * @NFTA_BITWISE_SREG: source register (NLA_U32: nft_registers) @@ -485,16 +558,20 @@ enum nft_immediate_attributes { * @NFTA_BITWISE_LEN: length of operands (NLA_U32) * @NFTA_BITWISE_MASK: mask value (NLA_NESTED: nft_data_attributes) * @NFTA_BITWISE_XOR: xor value (NLA_NESTED: nft_data_attributes) + * @NFTA_BITWISE_OP: type of operation (NLA_U32: nft_bitwise_ops) + * @NFTA_BITWISE_DATA: argument for non-boolean operations + * (NLA_NESTED: nft_data_attributes) * - * The bitwise expression performs the following operation: + * The bitwise expression supports boolean and shift operations. It implements + * the boolean operations by performing the following operation: * * dreg = (sreg & mask) ^ xor * - * which allow to express all bitwise operations: + * with these mask and xor values: * * mask xor * NOT: 1 1 - * OR: 0 x + * OR: ~x x * XOR: 1 x * AND: x 0 */ @@ -505,6 +582,8 @@ enum nft_bitwise_attributes { NFTA_BITWISE_LEN, NFTA_BITWISE_MASK, NFTA_BITWISE_XOR, + NFTA_BITWISE_OP, + NFTA_BITWISE_DATA, __NFTA_BITWISE_MAX }; #define NFTA_BITWISE_MAX (__NFTA_BITWISE_MAX - 1) @@ -631,10 +710,12 @@ enum nft_lookup_attributes { enum nft_dynset_ops { NFT_DYNSET_OP_ADD, NFT_DYNSET_OP_UPDATE, + NFT_DYNSET_OP_DELETE, }; enum nft_dynset_flags { NFT_DYNSET_F_INV = (1 << 0), + NFT_DYNSET_F_EXPR = (1 << 1), }; /** @@ -648,6 +729,7 @@ enum nft_dynset_flags { * @NFTA_DYNSET_TIMEOUT: timeout value for the new element (NLA_U64) * @NFTA_DYNSET_EXPR: expression (NLA_NESTED: nft_expr_attributes) * @NFTA_DYNSET_FLAGS: flags (NLA_U32) + * @NFTA_DYNSET_EXPRESSIONS: list of expressions (NLA_NESTED: nft_list_attributes) */ enum nft_dynset_attributes { NFTA_DYNSET_UNSPEC, @@ -660,6 +742,7 @@ enum nft_dynset_attributes { NFTA_DYNSET_EXPR, NFTA_DYNSET_PAD, NFTA_DYNSET_FLAGS, + NFTA_DYNSET_EXPRESSIONS, __NFTA_DYNSET_MAX, }; #define NFTA_DYNSET_MAX (__NFTA_DYNSET_MAX - 1) @@ -682,10 +765,12 @@ enum nft_payload_bases { * * @NFT_PAYLOAD_CSUM_NONE: no checksumming * @NFT_PAYLOAD_CSUM_INET: internet checksum (RFC 791) + * @NFT_PAYLOAD_CSUM_SCTP: CRC-32c, for use in SCTP header (RFC 3309) */ enum nft_payload_csum_types { NFT_PAYLOAD_CSUM_NONE, NFT_PAYLOAD_CSUM_INET, + NFT_PAYLOAD_CSUM_SCTP, }; enum nft_payload_csum_flags { @@ -727,10 +812,14 @@ enum nft_exthdr_flags { * * @NFT_EXTHDR_OP_IPV6: match against ipv6 extension headers * @NFT_EXTHDR_OP_TCP: match against tcp options + * @NFT_EXTHDR_OP_IPV4: match against ipv4 options + * @NFT_EXTHDR_OP_SCTP: match against sctp chunks */ enum nft_exthdr_op { NFT_EXTHDR_OP_IPV6, NFT_EXTHDR_OP_TCPOPT, + NFT_EXTHDR_OP_IPV4, + NFT_EXTHDR_OP_SCTP, __NFT_EXTHDR_OP_MAX }; #define NFT_EXTHDR_OP_MAX (__NFT_EXTHDR_OP_MAX - 1) @@ -788,6 +877,15 @@ enum nft_exthdr_attributes { * @NFT_META_CGROUP: socket control group (skb->sk->sk_classid) * @NFT_META_PRANDOM: a 32bit pseudo-random number * @NFT_META_SECPATH: boolean, secpath_exists (!!skb->sp) + * @NFT_META_IIFKIND: packet input interface kind name (dev->rtnl_link_ops->kind) + * @NFT_META_OIFKIND: packet output interface kind name (dev->rtnl_link_ops->kind) + * @NFT_META_BRI_IIFPVID: packet input bridge port pvid + * @NFT_META_BRI_IIFVPROTO: packet input bridge vlan proto + * @NFT_META_TIME_NS: time since epoch (in nanoseconds) + * @NFT_META_TIME_DAY: day of week (from 0 = Sunday to 6 = Saturday) + * @NFT_META_TIME_HOUR: hour of day (in seconds) + * @NFT_META_SDIF: slave device interface index + * @NFT_META_SDIFNAME: slave device interface name */ enum nft_meta_keys { NFT_META_LEN, @@ -816,6 +914,15 @@ enum nft_meta_keys { NFT_META_CGROUP, NFT_META_PRANDOM, NFT_META_SECPATH, + NFT_META_IIFKIND, + NFT_META_OIFKIND, + NFT_META_BRI_IIFPVID, + NFT_META_BRI_IIFVPROTO, + NFT_META_TIME_NS, + NFT_META_TIME_DAY, + NFT_META_TIME_HOUR, + NFT_META_SDIF, + NFT_META_SDIFNAME, }; /** @@ -825,13 +932,17 @@ enum nft_meta_keys { * @NFT_RT_NEXTHOP4: routing nexthop for IPv4 * @NFT_RT_NEXTHOP6: routing nexthop for IPv6 * @NFT_RT_TCPMSS: fetch current path tcp mss + * @NFT_RT_XFRM: boolean, skb->dst->xfrm != NULL */ enum nft_rt_keys { NFT_RT_CLASSID, NFT_RT_NEXTHOP4, NFT_RT_NEXTHOP6, NFT_RT_TCPMSS, + NFT_RT_XFRM, + __NFT_RT_MAX }; +#define NFT_RT_MAX (__NFT_RT_MAX - 1) /** * enum nft_hash_types - nf_tables hash expression types @@ -854,6 +965,8 @@ enum nft_hash_types { * @NFTA_HASH_SEED: seed value (NLA_U32) * @NFTA_HASH_OFFSET: add this offset value to hash result (NLA_U32) * @NFTA_HASH_TYPE: hash operation (NLA_U32: nft_hash_types) + * @NFTA_HASH_SET_NAME: name of the map to lookup (NLA_STRING) + * @NFTA_HASH_SET_ID: id of the map (NLA_U32) */ enum nft_hash_attributes { NFTA_HASH_UNSPEC, @@ -864,6 +977,8 @@ enum nft_hash_attributes { NFTA_HASH_SEED, NFTA_HASH_OFFSET, NFTA_HASH_TYPE, + NFTA_HASH_SET_NAME, /* deprecated */ + NFTA_HASH_SET_ID, /* deprecated */ __NFTA_HASH_MAX, }; #define NFTA_HASH_MAX (__NFTA_HASH_MAX - 1) @@ -899,6 +1014,39 @@ enum nft_rt_attributes { #define NFTA_RT_MAX (__NFTA_RT_MAX - 1) /** + * enum nft_socket_attributes - nf_tables socket expression netlink attributes + * + * @NFTA_SOCKET_KEY: socket key to match + * @NFTA_SOCKET_DREG: destination register + * @NFTA_SOCKET_LEVEL: cgroups2 ancestor level (only for cgroupsv2) + */ +enum nft_socket_attributes { + NFTA_SOCKET_UNSPEC, + NFTA_SOCKET_KEY, + NFTA_SOCKET_DREG, + NFTA_SOCKET_LEVEL, + __NFTA_SOCKET_MAX +}; +#define NFTA_SOCKET_MAX (__NFTA_SOCKET_MAX - 1) + +/* + * enum nft_socket_keys - nf_tables socket expression keys + * + * @NFT_SOCKET_TRANSPARENT: Value of the IP(V6)_TRANSPARENT socket option + * @NFT_SOCKET_MARK: Value of the socket mark + * @NFT_SOCKET_WILDCARD: Whether the socket is zero-bound (e.g. 0.0.0.0 or ::0) + * @NFT_SOCKET_CGROUPV2: Match on cgroups version 2 + */ +enum nft_socket_keys { + NFT_SOCKET_TRANSPARENT, + NFT_SOCKET_MARK, + NFT_SOCKET_WILDCARD, + NFT_SOCKET_CGROUPV2, + __NFT_SOCKET_MAX +}; +#define NFT_SOCKET_MAX (__NFT_SOCKET_MAX - 1) + +/** * enum nft_ct_keys - nf_tables ct expression keys * * @NFT_CT_STATE: conntrack state (bitmask of enum ip_conntrack_info) @@ -909,8 +1057,8 @@ enum nft_rt_attributes { * @NFT_CT_EXPIRATION: relative conntrack expiration time in ms * @NFT_CT_HELPER: connection tracking helper assigned to conntrack * @NFT_CT_L3PROTOCOL: conntrack layer 3 protocol - * @NFT_CT_SRC: conntrack layer 3 protocol source (IPv4/IPv6 address) - * @NFT_CT_DST: conntrack layer 3 protocol destination (IPv4/IPv6 address) + * @NFT_CT_SRC: conntrack layer 3 protocol source (IPv4/IPv6 address, deprecated) + * @NFT_CT_DST: conntrack layer 3 protocol destination (IPv4/IPv6 address, deprecated) * @NFT_CT_PROTOCOL: conntrack layer 4 protocol * @NFT_CT_PROTO_SRC: conntrack layer 4 protocol source * @NFT_CT_PROTO_DST: conntrack layer 4 protocol destination @@ -920,6 +1068,11 @@ enum nft_rt_attributes { * @NFT_CT_AVGPKT: conntrack average bytes per packet * @NFT_CT_ZONE: conntrack zone * @NFT_CT_EVENTMASK: ctnetlink events to be generated for this conntrack + * @NFT_CT_SRC_IP: conntrack layer 3 protocol source (IPv4 address) + * @NFT_CT_DST_IP: conntrack layer 3 protocol destination (IPv4 address) + * @NFT_CT_SRC_IP6: conntrack layer 3 protocol source (IPv6 address) + * @NFT_CT_DST_IP6: conntrack layer 3 protocol destination (IPv6 address) + * @NFT_CT_ID: conntrack id */ enum nft_ct_keys { NFT_CT_STATE, @@ -941,7 +1094,14 @@ enum nft_ct_keys { NFT_CT_AVGPKT, NFT_CT_ZONE, NFT_CT_EVENTMASK, + NFT_CT_SRC_IP, + NFT_CT_DST_IP, + NFT_CT_SRC_IP6, + NFT_CT_DST_IP6, + NFT_CT_ID, + __NFT_CT_MAX }; +#define NFT_CT_MAX (__NFT_CT_MAX - 1) /** * enum nft_ct_attributes - nf_tables ct expression netlink attributes @@ -1002,6 +1162,24 @@ enum nft_limit_attributes { }; #define NFTA_LIMIT_MAX (__NFTA_LIMIT_MAX - 1) +enum nft_connlimit_flags { + NFT_CONNLIMIT_F_INV = (1 << 0), +}; + +/** + * enum nft_connlimit_attributes - nf_tables connlimit expression netlink attributes + * + * @NFTA_CONNLIMIT_COUNT: number of connections (NLA_U32) + * @NFTA_CONNLIMIT_FLAGS: flags (NLA_U32: enum nft_connlimit_flags) + */ +enum nft_connlimit_attributes { + NFTA_CONNLIMIT_UNSPEC, + NFTA_CONNLIMIT_COUNT, + NFTA_CONNLIMIT_FLAGS, + __NFTA_CONNLIMIT_MAX +}; +#define NFTA_CONNLIMIT_MAX (__NFTA_CONNLIMIT_MAX - 1) + /** * enum nft_counter_attributes - nf_tables counter expression netlink attributes * @@ -1018,6 +1196,21 @@ enum nft_counter_attributes { #define NFTA_COUNTER_MAX (__NFTA_COUNTER_MAX - 1) /** + * enum nft_last_attributes - nf_tables last expression netlink attributes + * + * @NFTA_LAST_SET: last update has been set, zero means never updated (NLA_U32) + * @NFTA_LAST_MSECS: milliseconds since last update (NLA_U64) + */ +enum nft_last_attributes { + NFTA_LAST_UNSPEC, + NFTA_LAST_SET, + NFTA_LAST_MSECS, + NFTA_LAST_PAD, + __NFTA_LAST_MAX +}; +#define NFTA_LAST_MAX (__NFTA_LAST_MAX - 1) + +/** * enum nft_log_attributes - nf_tables log expression netlink attributes * * @NFTA_LOG_GROUP: netlink group to send messages to (NLA_U32) @@ -1040,6 +1233,33 @@ enum nft_log_attributes { #define NFTA_LOG_MAX (__NFTA_LOG_MAX - 1) /** + * enum nft_log_level - nf_tables log levels + * + * @NFT_LOGLEVEL_EMERG: system is unusable + * @NFT_LOGLEVEL_ALERT: action must be taken immediately + * @NFT_LOGLEVEL_CRIT: critical conditions + * @NFT_LOGLEVEL_ERR: error conditions + * @NFT_LOGLEVEL_WARNING: warning conditions + * @NFT_LOGLEVEL_NOTICE: normal but significant condition + * @NFT_LOGLEVEL_INFO: informational + * @NFT_LOGLEVEL_DEBUG: debug-level messages + * @NFT_LOGLEVEL_AUDIT: enabling audit logging + */ +enum nft_log_level { + NFT_LOGLEVEL_EMERG, + NFT_LOGLEVEL_ALERT, + NFT_LOGLEVEL_CRIT, + NFT_LOGLEVEL_ERR, + NFT_LOGLEVEL_WARNING, + NFT_LOGLEVEL_NOTICE, + NFT_LOGLEVEL_INFO, + NFT_LOGLEVEL_DEBUG, + NFT_LOGLEVEL_AUDIT, + __NFT_LOGLEVEL_MAX +}; +#define NFT_LOGLEVEL_MAX (__NFT_LOGLEVEL_MAX - 1) + +/** * enum nft_queue_attributes - nf_tables queue expression netlink attributes * * @NFTA_QUEUE_NUM: netlink queue to send messages to (NLA_U16) @@ -1084,6 +1304,21 @@ enum nft_quota_attributes { #define NFTA_QUOTA_MAX (__NFTA_QUOTA_MAX - 1) /** + * enum nft_secmark_attributes - nf_tables secmark object netlink attributes + * + * @NFTA_SECMARK_CTX: security context (NLA_STRING) + */ +enum nft_secmark_attributes { + NFTA_SECMARK_UNSPEC, + NFTA_SECMARK_CTX, + __NFTA_SECMARK_MAX, +}; +#define NFTA_SECMARK_MAX (__NFTA_SECMARK_MAX - 1) + +/* Max security context length */ +#define NFT_SECMARK_CTX_MAXLEN 256 + +/** * enum nft_reject_types - nf_tables reject expression reject types * * @NFT_REJECT_ICMP_UNREACH: reject using ICMP unreachable @@ -1165,6 +1400,22 @@ enum nft_nat_attributes { #define NFTA_NAT_MAX (__NFTA_NAT_MAX - 1) /** + * enum nft_tproxy_attributes - nf_tables tproxy expression netlink attributes + * + * NFTA_TPROXY_FAMILY: Target address family (NLA_U32: nft_registers) + * NFTA_TPROXY_REG_ADDR: Target address register (NLA_U32: nft_registers) + * NFTA_TPROXY_REG_PORT: Target port register (NLA_U32: nft_registers) + */ +enum nft_tproxy_attributes { + NFTA_TPROXY_UNSPEC, + NFTA_TPROXY_FAMILY, + NFTA_TPROXY_REG_ADDR, + NFTA_TPROXY_REG_PORT, + __NFTA_TPROXY_MAX +}; +#define NFTA_TPROXY_MAX (__NFTA_TPROXY_MAX - 1) + +/** * enum nft_masq_attributes - nf_tables masquerade expression attributes * * @NFTA_MASQ_FLAGS: NAT flags (see NF_NAT_RANGE_* in linux/netfilter/nf_nat.h) (NLA_U32) @@ -1214,10 +1465,14 @@ enum nft_dup_attributes { * enum nft_fwd_attributes - nf_tables fwd expression netlink attributes * * @NFTA_FWD_SREG_DEV: source register of output interface (NLA_U32: nft_register) + * @NFTA_FWD_SREG_ADDR: source register of destination address (NLA_U32: nft_register) + * @NFTA_FWD_NFPROTO: layer 3 family of source register address (NLA_U32: enum nfproto) */ enum nft_fwd_attributes { NFTA_FWD_UNSPEC, NFTA_FWD_SREG_DEV, + NFTA_FWD_SREG_ADDR, + NFTA_FWD_NFPROTO, __NFTA_FWD_MAX }; #define NFTA_FWD_MAX (__NFTA_FWD_MAX - 1) @@ -1302,12 +1557,38 @@ enum nft_ct_helper_attributes { }; #define NFTA_CT_HELPER_MAX (__NFTA_CT_HELPER_MAX - 1) +enum nft_ct_timeout_timeout_attributes { + NFTA_CT_TIMEOUT_UNSPEC, + NFTA_CT_TIMEOUT_L3PROTO, + NFTA_CT_TIMEOUT_L4PROTO, + NFTA_CT_TIMEOUT_DATA, + __NFTA_CT_TIMEOUT_MAX, +}; +#define NFTA_CT_TIMEOUT_MAX (__NFTA_CT_TIMEOUT_MAX - 1) + +enum nft_ct_expectation_attributes { + NFTA_CT_EXPECT_UNSPEC, + NFTA_CT_EXPECT_L3PROTO, + NFTA_CT_EXPECT_L4PROTO, + NFTA_CT_EXPECT_DPORT, + NFTA_CT_EXPECT_TIMEOUT, + NFTA_CT_EXPECT_SIZE, + __NFTA_CT_EXPECT_MAX, +}; +#define NFTA_CT_EXPECT_MAX (__NFTA_CT_EXPECT_MAX - 1) + #define NFT_OBJECT_UNSPEC 0 #define NFT_OBJECT_COUNTER 1 #define NFT_OBJECT_QUOTA 2 #define NFT_OBJECT_CT_HELPER 3 #define NFT_OBJECT_LIMIT 4 -#define __NFT_OBJECT_MAX 5 +#define NFT_OBJECT_CONNLIMIT 5 +#define NFT_OBJECT_TUNNEL 6 +#define NFT_OBJECT_CT_TIMEOUT 7 +#define NFT_OBJECT_SECMARK 8 +#define NFT_OBJECT_CT_EXPECT 9 +#define NFT_OBJECT_SYNPROXY 10 +#define __NFT_OBJECT_MAX 11 #define NFT_OBJECT_MAX (__NFT_OBJECT_MAX - 1) /** @@ -1319,6 +1600,7 @@ enum nft_ct_helper_attributes { * @NFTA_OBJ_DATA: stateful object data (NLA_NESTED) * @NFTA_OBJ_USE: number of references to this expression (NLA_U32) * @NFTA_OBJ_HANDLE: object handle (NLA_U64) + * @NFTA_OBJ_USERDATA: user data (NLA_BINARY) */ enum nft_object_attributes { NFTA_OBJ_UNSPEC, @@ -1329,11 +1611,25 @@ enum nft_object_attributes { NFTA_OBJ_USE, NFTA_OBJ_HANDLE, NFTA_OBJ_PAD, + NFTA_OBJ_USERDATA, __NFTA_OBJ_MAX }; #define NFTA_OBJ_MAX (__NFTA_OBJ_MAX - 1) /** + * enum nft_flowtable_flags - nf_tables flowtable flags + * + * @NFT_FLOWTABLE_HW_OFFLOAD: flowtable hardware offload is enabled + * @NFT_FLOWTABLE_COUNTER: enable flow counters + */ +enum nft_flowtable_flags { + NFT_FLOWTABLE_HW_OFFLOAD = 0x1, + NFT_FLOWTABLE_COUNTER = 0x2, + NFT_FLOWTABLE_MASK = (NFT_FLOWTABLE_HW_OFFLOAD | + NFT_FLOWTABLE_COUNTER) +}; + +/** * enum nft_flowtable_attributes - nf_tables flow table netlink attributes * * @NFTA_FLOWTABLE_TABLE: name of the table containing the expression (NLA_STRING) @@ -1341,6 +1637,7 @@ enum nft_object_attributes { * @NFTA_FLOWTABLE_HOOK: netfilter hook configuration(NLA_U32) * @NFTA_FLOWTABLE_USE: number of references to this flow table (NLA_U32) * @NFTA_FLOWTABLE_HANDLE: object handle (NLA_U64) + * @NFTA_FLOWTABLE_FLAGS: flags (NLA_U32) */ enum nft_flowtable_attributes { NFTA_FLOWTABLE_UNSPEC, @@ -1350,6 +1647,7 @@ enum nft_flowtable_attributes { NFTA_FLOWTABLE_USE, NFTA_FLOWTABLE_HANDLE, NFTA_FLOWTABLE_PAD, + NFTA_FLOWTABLE_FLAGS, __NFTA_FLOWTABLE_MAX }; #define NFTA_FLOWTABLE_MAX (__NFTA_FLOWTABLE_MAX - 1) @@ -1371,6 +1669,42 @@ enum nft_flowtable_hook_attributes { #define NFTA_FLOWTABLE_HOOK_MAX (__NFTA_FLOWTABLE_HOOK_MAX - 1) /** + * enum nft_osf_attributes - nftables osf expression netlink attributes + * + * @NFTA_OSF_DREG: destination register (NLA_U32: nft_registers) + * @NFTA_OSF_TTL: Value of the TTL osf option (NLA_U8) + * @NFTA_OSF_FLAGS: flags (NLA_U32) + */ +enum nft_osf_attributes { + NFTA_OSF_UNSPEC, + NFTA_OSF_DREG, + NFTA_OSF_TTL, + NFTA_OSF_FLAGS, + __NFTA_OSF_MAX, +}; +#define NFTA_OSF_MAX (__NFTA_OSF_MAX - 1) + +enum nft_osf_flags { + NFT_OSF_F_VERSION = (1 << 0), +}; + +/** + * enum nft_synproxy_attributes - nf_tables synproxy expression netlink attributes + * + * @NFTA_SYNPROXY_MSS: mss value sent to the backend (NLA_U16) + * @NFTA_SYNPROXY_WSCALE: wscale value sent to the backend (NLA_U8) + * @NFTA_SYNPROXY_FLAGS: flags (NLA_U32) + */ +enum nft_synproxy_attributes { + NFTA_SYNPROXY_UNSPEC, + NFTA_SYNPROXY_MSS, + NFTA_SYNPROXY_WSCALE, + NFTA_SYNPROXY_FLAGS, + __NFTA_SYNPROXY_MAX, +}; +#define NFTA_SYNPROXY_MAX (__NFTA_SYNPROXY_MAX - 1) + +/** * enum nft_device_attributes - nf_tables device netlink attributes * * @NFTA_DEVICE_NAME: name of this device (NLA_STRING) @@ -1382,6 +1716,35 @@ enum nft_devices_attributes { }; #define NFTA_DEVICE_MAX (__NFTA_DEVICE_MAX - 1) +/* + * enum nft_xfrm_attributes - nf_tables xfrm expr netlink attributes + * + * @NFTA_XFRM_DREG: destination register (NLA_U32) + * @NFTA_XFRM_KEY: enum nft_xfrm_keys (NLA_U32) + * @NFTA_XFRM_DIR: direction (NLA_U8) + * @NFTA_XFRM_SPNUM: index in secpath array (NLA_U32) + */ +enum nft_xfrm_attributes { + NFTA_XFRM_UNSPEC, + NFTA_XFRM_DREG, + NFTA_XFRM_KEY, + NFTA_XFRM_DIR, + NFTA_XFRM_SPNUM, + __NFTA_XFRM_MAX +}; +#define NFTA_XFRM_MAX (__NFTA_XFRM_MAX - 1) + +enum nft_xfrm_keys { + NFT_XFRM_KEY_UNSPEC, + NFT_XFRM_KEY_DADDR_IP4, + NFT_XFRM_KEY_DADDR_IP6, + NFT_XFRM_KEY_SADDR_IP4, + NFT_XFRM_KEY_SADDR_IP6, + NFT_XFRM_KEY_REQID, + NFT_XFRM_KEY_SPI, + __NFT_XFRM_KEY_MAX, +}; +#define NFT_XFRM_KEY_MAX (__NFT_XFRM_KEY_MAX - 1) /** * enum nft_trace_attributes - nf_tables trace netlink attributes @@ -1442,6 +1805,8 @@ enum nft_trace_types { * @NFTA_NG_MODULUS: maximum counter value (NLA_U32) * @NFTA_NG_TYPE: operation type (NLA_U32) * @NFTA_NG_OFFSET: offset to be added to the counter (NLA_U32) + * @NFTA_NG_SET_NAME: name of the map to lookup (NLA_STRING) + * @NFTA_NG_SET_ID: id of the map (NLA_U32) */ enum nft_ng_attributes { NFTA_NG_UNSPEC, @@ -1449,6 +1814,8 @@ enum nft_ng_attributes { NFTA_NG_MODULUS, NFTA_NG_TYPE, NFTA_NG_OFFSET, + NFTA_NG_SET_NAME, /* deprecated */ + NFTA_NG_SET_ID, /* deprecated */ __NFTA_NG_MAX }; #define NFTA_NG_MAX (__NFTA_NG_MAX - 1) @@ -1460,4 +1827,104 @@ enum nft_ng_types { }; #define NFT_NG_MAX (__NFT_NG_MAX - 1) +enum nft_tunnel_key_ip_attributes { + NFTA_TUNNEL_KEY_IP_UNSPEC, + NFTA_TUNNEL_KEY_IP_SRC, + NFTA_TUNNEL_KEY_IP_DST, + __NFTA_TUNNEL_KEY_IP_MAX +}; +#define NFTA_TUNNEL_KEY_IP_MAX (__NFTA_TUNNEL_KEY_IP_MAX - 1) + +enum nft_tunnel_ip6_attributes { + NFTA_TUNNEL_KEY_IP6_UNSPEC, + NFTA_TUNNEL_KEY_IP6_SRC, + NFTA_TUNNEL_KEY_IP6_DST, + NFTA_TUNNEL_KEY_IP6_FLOWLABEL, + __NFTA_TUNNEL_KEY_IP6_MAX +}; +#define NFTA_TUNNEL_KEY_IP6_MAX (__NFTA_TUNNEL_KEY_IP6_MAX - 1) + +enum nft_tunnel_opts_attributes { + NFTA_TUNNEL_KEY_OPTS_UNSPEC, + NFTA_TUNNEL_KEY_OPTS_VXLAN, + NFTA_TUNNEL_KEY_OPTS_ERSPAN, + NFTA_TUNNEL_KEY_OPTS_GENEVE, + __NFTA_TUNNEL_KEY_OPTS_MAX +}; +#define NFTA_TUNNEL_KEY_OPTS_MAX (__NFTA_TUNNEL_KEY_OPTS_MAX - 1) + +enum nft_tunnel_opts_vxlan_attributes { + NFTA_TUNNEL_KEY_VXLAN_UNSPEC, + NFTA_TUNNEL_KEY_VXLAN_GBP, + __NFTA_TUNNEL_KEY_VXLAN_MAX +}; +#define NFTA_TUNNEL_KEY_VXLAN_MAX (__NFTA_TUNNEL_KEY_VXLAN_MAX - 1) + +enum nft_tunnel_opts_erspan_attributes { + NFTA_TUNNEL_KEY_ERSPAN_UNSPEC, + NFTA_TUNNEL_KEY_ERSPAN_VERSION, + NFTA_TUNNEL_KEY_ERSPAN_V1_INDEX, + NFTA_TUNNEL_KEY_ERSPAN_V2_HWID, + NFTA_TUNNEL_KEY_ERSPAN_V2_DIR, + __NFTA_TUNNEL_KEY_ERSPAN_MAX +}; +#define NFTA_TUNNEL_KEY_ERSPAN_MAX (__NFTA_TUNNEL_KEY_ERSPAN_MAX - 1) + +enum nft_tunnel_opts_geneve_attributes { + NFTA_TUNNEL_KEY_GENEVE_UNSPEC, + NFTA_TUNNEL_KEY_GENEVE_CLASS, + NFTA_TUNNEL_KEY_GENEVE_TYPE, + NFTA_TUNNEL_KEY_GENEVE_DATA, + __NFTA_TUNNEL_KEY_GENEVE_MAX +}; +#define NFTA_TUNNEL_KEY_GENEVE_MAX (__NFTA_TUNNEL_KEY_GENEVE_MAX - 1) + +enum nft_tunnel_flags { + NFT_TUNNEL_F_ZERO_CSUM_TX = (1 << 0), + NFT_TUNNEL_F_DONT_FRAGMENT = (1 << 1), + NFT_TUNNEL_F_SEQ_NUMBER = (1 << 2), +}; +#define NFT_TUNNEL_F_MASK (NFT_TUNNEL_F_ZERO_CSUM_TX | \ + NFT_TUNNEL_F_DONT_FRAGMENT | \ + NFT_TUNNEL_F_SEQ_NUMBER) + +enum nft_tunnel_key_attributes { + NFTA_TUNNEL_KEY_UNSPEC, + NFTA_TUNNEL_KEY_ID, + NFTA_TUNNEL_KEY_IP, + NFTA_TUNNEL_KEY_IP6, + NFTA_TUNNEL_KEY_FLAGS, + NFTA_TUNNEL_KEY_TOS, + NFTA_TUNNEL_KEY_TTL, + NFTA_TUNNEL_KEY_SPORT, + NFTA_TUNNEL_KEY_DPORT, + NFTA_TUNNEL_KEY_OPTS, + __NFTA_TUNNEL_KEY_MAX +}; +#define NFTA_TUNNEL_KEY_MAX (__NFTA_TUNNEL_KEY_MAX - 1) + +enum nft_tunnel_keys { + NFT_TUNNEL_PATH, + NFT_TUNNEL_ID, + __NFT_TUNNEL_MAX +}; +#define NFT_TUNNEL_MAX (__NFT_TUNNEL_MAX - 1) + +enum nft_tunnel_mode { + NFT_TUNNEL_MODE_NONE, + NFT_TUNNEL_MODE_RX, + NFT_TUNNEL_MODE_TX, + __NFT_TUNNEL_MODE_MAX +}; +#define NFT_TUNNEL_MODE_MAX (__NFT_TUNNEL_MODE_MAX - 1) + +enum nft_tunnel_attributes { + NFTA_TUNNEL_UNSPEC, + NFTA_TUNNEL_KEY, + NFTA_TUNNEL_DREG, + NFTA_TUNNEL_MODE, + __NFTA_TUNNEL_MAX +}; +#define NFTA_TUNNEL_MAX (__NFTA_TUNNEL_MAX - 1) + #endif /* _LINUX_NF_TABLES_H */ diff --git a/include/linux/netfilter_arp/arpt_mangle.h b/include/linux/netfilter_arp/arpt_mangle.h index 250f5029..8c2b16a1 100644 --- a/include/linux/netfilter_arp/arpt_mangle.h +++ b/include/linux/netfilter_arp/arpt_mangle.h @@ -13,7 +13,7 @@ struct arpt_mangle union { struct in_addr tgt_ip; } u_t; - u_int8_t flags; + __u8 flags; int target; }; diff --git a/include/linux/netfilter_bridge/ebt_ip.h b/include/linux/netfilter_bridge/ebt_ip.h index c4bbc41b..ae5d4d10 100644 --- a/include/linux/netfilter_bridge/ebt_ip.h +++ b/include/linux/netfilter_bridge/ebt_ip.h @@ -23,8 +23,10 @@ #define EBT_IP_PROTO 0x08 #define EBT_IP_SPORT 0x10 #define EBT_IP_DPORT 0x20 +#define EBT_IP_ICMP 0x40 +#define EBT_IP_IGMP 0x80 #define EBT_IP_MASK (EBT_IP_SOURCE | EBT_IP_DEST | EBT_IP_TOS | EBT_IP_PROTO |\ - EBT_IP_SPORT | EBT_IP_DPORT ) + EBT_IP_SPORT | EBT_IP_DPORT | EBT_IP_ICMP | EBT_IP_IGMP) #define EBT_IP_MATCH "ip" /* the same values are used for the invflags */ @@ -37,8 +39,15 @@ struct ebt_ip_info { __u8 protocol; __u8 bitmask; __u8 invflags; - __u16 sport[2]; - __u16 dport[2]; + union { + __u16 sport[2]; + __u8 icmp_type[2]; + __u8 igmp_type[2]; + }; + union { + __u16 dport[2]; + __u8 icmp_code[2]; + }; }; #endif diff --git a/include/xtables.h b/include/xtables.h index e51f4bfd..087a1d60 100644 --- a/include/xtables.h +++ b/include/xtables.h @@ -203,6 +203,7 @@ struct xtables_lmap { enum xtables_ext_flags { XTABLES_EXT_ALIAS = 1 << 0, + XTABLES_EXT_WATCHER = 1 << 1, }; struct xt_xlate; @@ -211,14 +212,14 @@ struct xt_xlate_mt_params { const void *ip; const struct xt_entry_match *match; int numeric; - bool escape_quotes; + bool escape_quotes; /* not used anymore, retained for ABI */ }; struct xt_xlate_tg_params { const void *ip; const struct xt_entry_target *target; int numeric; - bool escape_quotes; + bool escape_quotes; /* not used anymore, retained for ABI */ }; /* Include file for additions: new matches and targets. */ @@ -395,7 +396,7 @@ struct xtables_rule_match { */ struct xtables_pprot { const char *name; - uint16_t num; + uint8_t num; }; enum xtables_tryload { @@ -585,18 +586,6 @@ static inline void xtables_print_mark_mask(unsigned int mark, xtables_print_val_mask(mark, mask, NULL); } -#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS) -# ifdef _INIT -# undef _init -# define _init _INIT -# endif - extern void init_extensions(void); - extern void init_extensions4(void); - extern void init_extensions6(void); -#else -# define _init __attribute__((constructor)) _INIT -#endif - extern const struct xtables_pprot xtables_chain_protos[]; extern uint16_t xtables_parse_protocol(const char *s); @@ -633,8 +622,11 @@ extern const char *xtables_lmap_id2name(const struct xtables_lmap *, int); struct xt_xlate *xt_xlate_alloc(int size); void xt_xlate_free(struct xt_xlate *xl); void xt_xlate_add(struct xt_xlate *xl, const char *fmt, ...) __attribute__((format(printf,2,3))); +void xt_xlate_add_nospc(struct xt_xlate *xl, const char *fmt, ...) __attribute__((format(printf,2,3))); #define xt_xlate_rule_add xt_xlate_add +#define xt_xlate_rule_add_nospc xt_xlate_add_nospc void xt_xlate_set_add(struct xt_xlate *xl, const char *fmt, ...) __attribute__((format(printf,2,3))); +void xt_xlate_set_add_nospc(struct xt_xlate *xl, const char *fmt, ...) __attribute__((format(printf,2,3))); void xt_xlate_add_comment(struct xt_xlate *xl, const char *comment); const char *xt_xlate_get_comment(struct xt_xlate *xl); void xl_xlate_set_family(struct xt_xlate *xl, uint8_t family); @@ -643,6 +635,9 @@ const char *xt_xlate_get(struct xt_xlate *xl); #define xt_xlate_rule_get xt_xlate_get const char *xt_xlate_set_get(struct xt_xlate *xl); +/* informed target lookups */ +void xtables_announce_chain(const char *name); + #ifdef XTABLES_INTERNAL /* Shipped modules rely on this... */ @@ -651,9 +646,55 @@ const char *xt_xlate_set_get(struct xt_xlate *xl); # define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) # endif +#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS) +# ifdef _INIT +# undef _init +# define _init _INIT +# endif + extern void init_extensions(void); + extern void init_extensions4(void); + extern void init_extensions6(void); + extern void init_extensionsa(void); + extern void init_extensionsb(void); +#else +# define _init __attribute__((constructor)) _INIT +# define EMPTY_FUNC_DEF(x) static inline void x(void) {} + EMPTY_FUNC_DEF(init_extensions) + EMPTY_FUNC_DEF(init_extensions4) + EMPTY_FUNC_DEF(init_extensions6) + EMPTY_FUNC_DEF(init_extensionsa) + EMPTY_FUNC_DEF(init_extensionsb) +# undef EMPTY_FUNC_DEF +#endif + extern void _init(void); -#endif +/** + * xtables_afinfo - protocol family dependent information + * @kmod: kernel module basename (e.g. "ip_tables") + * @proc_exists: file which exists in procfs when module already loaded + * @libprefix: prefix of .so library name (e.g. "libipt_") + * @family: nfproto family + * @ipproto: used by setsockopt (e.g. IPPROTO_IP) + * @so_rev_match: optname to check revision support of match + * @so_rev_target: optname to check revision support of target + */ +struct xtables_afinfo { + const char *kmod; + const char *proc_exists; + const char *libprefix; + uint8_t family; + uint8_t ipproto; + int so_rev_match; + int so_rev_target; +}; + +extern const struct xtables_afinfo *afinfo; + +/* base offset of merged extensions' consecutive options */ +#define XT_OPTION_OFFSET_SCALE 256 + +#endif /* XTABLES_INTERNAL */ #ifdef __cplusplus } /* extern "C" */ diff --git a/iptables-test.py b/iptables-test.py index 0ba3d368..de1e1e95 100755 --- a/iptables-test.py +++ b/iptables-test.py @@ -54,12 +54,12 @@ def print_error(reason, filename=None, lineno=None): ": line %d (%s)" % (lineno, reason), file=sys.stderr) -def delete_rule(iptables, rule, filename, lineno): +def delete_rule(iptables, rule, filename, lineno, netns = None): ''' Removes an iptables rule ''' cmd = iptables + " -D " + rule - ret = execute_cmd(cmd, filename, lineno) + ret = execute_cmd(cmd, filename, lineno, netns) if ret == 1: reason = "cannot delete: " + iptables + " -I " + rule print_error(reason, filename, lineno) @@ -73,26 +73,24 @@ def run_test(iptables, rule, rule_save, res, filename, lineno, netns): Executes an unit test. Returns the output of delete_rule(). Parameters: - :param iptables: string with the iptables command to execute + :param iptables: string with the iptables command to execute :param rule: string with iptables arguments for the rule to test - :param rule_save: string to find the rule in the output of iptables -save + :param rule_save: string to find the rule in the output of iptables-save :param res: expected result of the rule. Valid values: "OK", "FAIL" :param filename: name of the file tested (used for print_error purposes) :param lineno: line number being tested (used for print_error purposes) + :param netns: network namespace to call commands in (or None) ''' ret = 0 cmd = iptables + " -A " + rule - if netns: - cmd = "ip netns exec ____iptables-container-test " + EXECUTEABLE + " " + cmd - - ret = execute_cmd(cmd, filename, lineno) + ret = execute_cmd(cmd, filename, lineno, netns) # # report failed test # if ret: - if res == "OK": + if res != "FAIL": reason = "cannot load: " + cmd print_error(reason, filename, lineno) return -1 @@ -103,32 +101,32 @@ def run_test(iptables, rule, rule_save, res, filename, lineno, netns): if res == "FAIL": reason = "should fail: " + cmd print_error(reason, filename, lineno) - delete_rule(iptables, rule, filename, lineno) + delete_rule(iptables, rule, filename, lineno, netns) return -1 matching = 0 - splitted = iptables.split(" ") - if len(splitted) == 2: - if splitted[1] == '-4': + tokens = iptables.split(" ") + if len(tokens) == 2: + if tokens[1] == '-4': command = IPTABLES_SAVE - elif splitted[1] == '-6': + elif tokens[1] == '-6': command = IP6TABLES_SAVE - elif len(splitted) == 1: - if splitted[0] == IPTABLES: + elif len(tokens) == 1: + if tokens[0] == IPTABLES: command = IPTABLES_SAVE - elif splitted[0] == IP6TABLES: + elif tokens[0] == IP6TABLES: command = IP6TABLES_SAVE - elif splitted[0] == ARPTABLES: + elif tokens[0] == ARPTABLES: command = ARPTABLES_SAVE - elif splitted[0] == EBTABLES: + elif tokens[0] == EBTABLES: command = EBTABLES_SAVE - command = EXECUTEABLE + " " + command + command = EXECUTABLE + " " + command if netns: - command = "ip netns exec ____iptables-container-test " + command + command = "ip netns exec " + netns + " " + command - args = splitted[1:] + args = tokens[1:] proc = subprocess.Popen(command, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) @@ -140,16 +138,26 @@ def run_test(iptables, rule, rule_save, res, filename, lineno, netns): if proc.returncode == -11: reason = "iptables-save segfaults: " + cmd print_error(reason, filename, lineno) - delete_rule(iptables, rule, filename, lineno) + delete_rule(iptables, rule, filename, lineno, netns) return -1 # find the rule matching = out.find(rule_save.encode('utf-8')) if matching < 0: - reason = "cannot find: " + iptables + " -I " + rule - print_error(reason, filename, lineno) - delete_rule(iptables, rule, filename, lineno) - return -1 + if res == "OK": + reason = "cannot find: " + iptables + " -I " + rule + print_error(reason, filename, lineno) + delete_rule(iptables, rule, filename, lineno, netns) + return -1 + else: + # do not report this error + return 0 + else: + if res != "OK": + reason = "should not match: " + cmd + print_error(reason, filename, lineno) + delete_rule(iptables, rule, filename, lineno, netns) + return -1 # Test "ip netns del NETNS" path with rules in place if netns: @@ -157,7 +165,7 @@ def run_test(iptables, rule, rule_save, res, filename, lineno, netns): return delete_rule(iptables, rule, filename, lineno) -def execute_cmd(cmd, filename, lineno): +def execute_cmd(cmd, filename, lineno = 0, netns = None): ''' Executes a command, checking for segfaults and returning the command exit code. @@ -165,10 +173,14 @@ def execute_cmd(cmd, filename, lineno): :param cmd: string with the command to be executed :param filename: name of the file tested (used for print_error purposes) :param lineno: line number being tested (used for print_error purposes) + :param netns: network namespace to run command in ''' global log_file if cmd.startswith('iptables ') or cmd.startswith('ip6tables ') or cmd.startswith('ebtables ') or cmd.startswith('arptables '): - cmd = EXECUTEABLE + " " + cmd + cmd = EXECUTABLE + " " + cmd + + if netns: + cmd = "ip netns exec " + netns + " " + cmd print("command: {}".format(cmd), file=log_file) ret = subprocess.call(cmd, shell=True, universal_newlines=True, @@ -176,17 +188,197 @@ def execute_cmd(cmd, filename, lineno): log_file.flush() # generic check for segfaults - if ret == -11: + if ret == -11: reason = "command segfaults: " + cmd print_error(reason, filename, lineno) return ret +def variant_res(res, variant, alt_res=None): + ''' + Adjust expected result with given variant + + If expected result is scoped to a variant, the other one yields a different + result. Therefore map @res to itself if given variant is current, use the + alternate result, @alt_res, if specified, invert @res otherwise. + + :param res: expected result from test spec ("OK", "FAIL" or "NOMATCH") + :param variant: variant @res is scoped to by test spec ("NFT" or "LEGACY") + :param alt_res: optional expected result for the alternate variant. + ''' + variant_executable = { + "NFT": "xtables-nft-multi", + "LEGACY": "xtables-legacy-multi" + } + res_inverse = { + "OK": "FAIL", + "FAIL": "OK", + "NOMATCH": "OK" + } + + if variant_executable[variant] == EXECUTABLE: + return res + if alt_res is not None: + return alt_res + return res_inverse[res] + +def fast_run_possible(filename): + ''' + Keep things simple, run only for simple test files: + - no external commands + - no multiple tables + - no variant-specific results + ''' + table = None + rulecount = 0 + for line in open(filename): + if line[0] in ["#", ":"] or len(line.strip()) == 0: + continue + if line[0] == "*": + if table or rulecount > 0: + return False + table = line.rstrip()[1:] + if line[0] in ["@", "%"]: + return False + if len(line.split(";")) > 3: + return False + rulecount += 1 + + return True + +def run_test_file_fast(iptables, filename, netns): + ''' + Run a test file, but fast + + :param filename: name of the file with the test rules + :param netns: network namespace to perform test run in + ''' + + f = open(filename) + + rules = {} + table = "filter" + chain_array = [] + tests = 0 + + for lineno, line in enumerate(f): + if line[0] == "#" or len(line.strip()) == 0: + continue + + if line[0] == "*": + table = line.rstrip()[1:] + continue + + if line[0] == ":": + chain_array = line.rstrip()[1:].split(",") + continue + + if len(chain_array) == 0: + return -1 + + tests += 1 + + for chain in chain_array: + item = line.split(";") + rule = chain + " " + item[0] + + if item[1] == "=": + rule_save = chain + " " + item[0] + else: + rule_save = chain + " " + item[1] + + if iptables == EBTABLES and rule_save.find('-j') < 0: + rule_save += " -j CONTINUE" + + res = item[2].rstrip() + if res != "OK": + rule = chain + " -t " + table + " " + item[0] + ret = run_test(iptables, rule, rule_save, + res, filename, lineno + 1, netns) + + if ret < 0: + return -1 + continue + + if not chain in rules.keys(): + rules[chain] = [] + rules[chain].append((rule, rule_save)) + + restore_data = ["*" + table] + out_expect = [] + for chain in ["PREROUTING", "INPUT", "FORWARD", "OUTPUT", "POSTROUTING"]: + if not chain in rules.keys(): + continue + for rule in rules[chain]: + restore_data.append("-A " + rule[0]) + out_expect.append("-A " + rule[1]) + restore_data.append("COMMIT") + + out_expect = "\n".join(out_expect) + + # load all rules via iptables_restore + + command = EXECUTABLE + " " + iptables + "-restore" + if netns: + command = "ip netns exec " + netns + " " + command + + for line in restore_data: + print(iptables + "-restore: " + line, file=log_file) + + proc = subprocess.Popen(command, shell = True, text = True, + stdin = subprocess.PIPE, + stdout = subprocess.PIPE, + stderr = subprocess.PIPE) + restore_data = "\n".join(restore_data) + "\n" + out, err = proc.communicate(input = restore_data) + + if proc.returncode == -11: + reason = iptables + "-restore segfaults: " + cmd + print_error(reason, filename, lineno) + return -1 + + if proc.returncode != 0: + print("%s-restore returned %d: %s" % (iptables, proc.returncode, err), + file=log_file) + return -1 + + # find all rules in iptables_save output + + command = EXECUTABLE + " " + iptables + "-save" + if netns: + command = "ip netns exec " + netns + " " + command + + proc = subprocess.Popen(command, shell = True, + stdin = subprocess.PIPE, + stdout = subprocess.PIPE, + stderr = subprocess.PIPE) + out, err = proc.communicate() + + if proc.returncode == -11: + reason = iptables + "-save segfaults: " + cmd + print_error(reason, filename, lineno) + return -1 + + cmd = iptables + " -F -t " + table + execute_cmd(cmd, filename, 0, netns) + + out = out.decode('utf-8').rstrip() + if out.find(out_expect) < 0: + msg = ["dumps differ!"] + msg.extend(["expect: " + l for l in out_expect.split("\n")]) + msg.extend(["got: " + l for l in out.split("\n") + if not l[0] in ['*', ':', '#']]) + print("\n".join(msg), file=log_file) + return -1 + + return tests + def run_test_file(filename, netns): ''' Runs a test file :param filename: name of the file with the test rules + :param netns: network namespace to perform test run in ''' # # if this is not a test file, skip. @@ -202,18 +394,26 @@ def run_test_file(filename, netns): iptables = IPTABLES elif "libarpt_" in filename: # only supported with nf_tables backend - if EXECUTEABLE != "xtables-nft-multi": + if EXECUTABLE != "xtables-nft-multi": return 0, 0 iptables = ARPTABLES elif "libebt_" in filename: # only supported with nf_tables backend - if EXECUTEABLE != "xtables-nft-multi": + if EXECUTABLE != "xtables-nft-multi": return 0, 0 iptables = EBTABLES else: # default to iptables if not known prefix iptables = IPTABLES + fast_failed = False + if fast_run_possible(filename): + tests = run_test_file_fast(iptables, filename, netns) + if tests > 0: + print(filename + ": " + maybe_colored('green', "OK", STDOUT_IS_TTY)) + return tests, tests + fast_failed = True + f = open(filename) tests = 0 @@ -223,7 +423,7 @@ def run_test_file(filename, netns): total_test_passed = True if netns: - execute_cmd("ip netns add ____iptables-container-test", filename, 0) + execute_cmd("ip netns add " + netns, filename) for lineno, line in enumerate(f): if line[0] == "#" or len(line.strip()) == 0: @@ -233,20 +433,11 @@ def run_test_file(filename, netns): chain_array = line.rstrip()[1:].split(",") continue - # external non-iptables invocation, executed as is. - if line[0] == "@": - external_cmd = line.rstrip()[1:] - if netns: - external_cmd = "ip netns exec ____iptables-container-test " + external_cmd - execute_cmd(external_cmd, filename, lineno) - continue - - # external iptables invocation, executed as is. - if line[0] == "%": + # external command invocation, executed as is. + # detects iptables commands to prefix with EXECUTABLE automatically + if line[0] in ["@", "%"]: external_cmd = line.rstrip()[1:] - if netns: - external_cmd = "ip netns exec ____iptables-container-test " + EXECUTEABLE + " " + external_cmd - execute_cmd(external_cmd, filename, lineno) + execute_cmd(external_cmd, filename, lineno, netns) continue if line[0] == "*": @@ -275,6 +466,14 @@ def run_test_file(filename, netns): rule_save = chain + " " + item[1] res = item[2].rstrip() + if len(item) > 3: + variant = item[3].rstrip() + if len(item) > 4: + alt_res = item[4].rstrip() + else: + alt_res = None + res = variant_res(res, variant, alt_res) + ret = run_test(iptables, rule, rule_save, res, filename, lineno + 1, netns) @@ -287,9 +486,12 @@ def run_test_file(filename, netns): passed += 1 if netns: - execute_cmd("ip netns del ____iptables-container-test", filename, 0) + execute_cmd("ip netns del " + netns, filename) if total_test_passed: - print(filename + ": " + maybe_colored('green', "OK", STDOUT_IS_TTY)) + suffix = "" + if fast_failed: + suffix = maybe_colored('red', " but fast mode failed!", STDOUT_IS_TTY) + print(filename + ": " + maybe_colored('green', "OK", STDOUT_IS_TTY) + suffix) f.close() return tests, passed @@ -353,7 +555,8 @@ def main(): help='Check for missing tests') parser.add_argument('-n', '--nftables', action='store_true', help='Test iptables-over-nftables') - parser.add_argument('-N', '--netns', action='store_true', + parser.add_argument('-N', '--netns', action='store_const', + const='____iptables-container-test', help='Test netnamespace path') parser.add_argument('--no-netns', action='store_true', help='Do not run testsuite in own network namespace') @@ -366,14 +569,17 @@ def main(): show_missing() return - global EXECUTEABLE - EXECUTEABLE = "xtables-legacy-multi" + variants = [] + if args.legacy: + variants.append("legacy") if args.nftables: - EXECUTEABLE = "xtables-nft-multi" + variants.append("nft") + if len(variants) == 0: + variants = [ "legacy", "nft" ] if os.getuid() != 0: print("You need to be root to run this, sorry", file=sys.stderr) - return + return 77 if not args.netns and not args.no_netns and not spawn_netns(): print("Cannot run in own namespace, connectivity might break", @@ -384,36 +590,51 @@ def main(): os.putenv("PATH", "%s/iptables:%s" % (os.path.abspath(os.path.curdir), os.getenv("PATH"))) - test_files = 0 - tests = 0 - passed = 0 - - # setup global var log file - global log_file - try: - log_file = open(LOGFILE, 'w') - except IOError: - print("Couldn't open log file %s" % LOGFILE, file=sys.stderr) - return - - if args.filename: - file_list = args.filename - else: - file_list = [os.path.join(EXTENSIONS_PATH, i) - for i in os.listdir(EXTENSIONS_PATH) - if i.endswith('.t')] - file_list.sort() - - for filename in file_list: - file_tests, file_passed = run_test_file(filename, args.netns) - if file_tests: - tests += file_tests - passed += file_passed - test_files += 1 - - print("%d test files, %d unit tests, %d passed" % (test_files, tests, passed)) - return passed - tests - + total_test_files = 0 + total_passed = 0 + total_tests = 0 + for variant in variants: + global EXECUTABLE + EXECUTABLE = "xtables-" + variant + "-multi" + + test_files = 0 + tests = 0 + passed = 0 + + # setup global var log file + global log_file + try: + log_file = open(LOGFILE, 'w') + except IOError: + print("Couldn't open log file %s" % LOGFILE, file=sys.stderr) + return + + if args.filename: + file_list = args.filename + else: + file_list = [os.path.join(EXTENSIONS_PATH, i) + for i in os.listdir(EXTENSIONS_PATH) + if i.endswith('.t')] + file_list.sort() + + for filename in file_list: + file_tests, file_passed = run_test_file(filename, args.netns) + if file_tests: + tests += file_tests + passed += file_passed + test_files += 1 + + print("%s: %d test files, %d unit tests, %d passed" + % (variant, test_files, tests, passed)) + + total_passed += passed + total_tests += tests + total_test_files = max(total_test_files, test_files) + + if len(variants) > 1: + print("total: %d test files, %d unit tests, %d passed" + % (total_test_files, total_tests, total_passed)) + return total_passed - total_tests if __name__ == '__main__': sys.exit(main()) diff --git a/iptables/.gitignore b/iptables/.gitignore index cd7d87b1..8141e34d 100644 --- a/iptables/.gitignore +++ b/iptables/.gitignore @@ -1,6 +1,11 @@ +/ebtables-translate.8 /ip6tables +/ip6tables.8 +/ip6tables-apply.8 /ip6tables-save +/ip6tables-save.8 /ip6tables-restore +/ip6tables-restore.8 /ip6tables-static /ip6tables-translate.8 /ip6tables-restore-translate.8 diff --git a/iptables/Makefile.am b/iptables/Makefile.am index f7895210..1f37640f 100644 --- a/iptables/Makefile.am +++ b/iptables/Makefile.am @@ -2,49 +2,56 @@ AM_CFLAGS = ${regular_CFLAGS} AM_CPPFLAGS = ${regular_CPPFLAGS} -I${top_builddir}/include -I${top_srcdir}/include -I${top_srcdir} ${kinclude_CPPFLAGS} ${libmnl_CFLAGS} ${libnftnl_CFLAGS} ${libnetfilter_conntrack_CFLAGS} +AM_LDFLAGS = ${regular_LDFLAGS} BUILT_SOURCES = -xtables_legacy_multi_SOURCES = xtables-legacy-multi.c iptables-xml.c -xtables_legacy_multi_CFLAGS = ${AM_CFLAGS} -xtables_legacy_multi_LDADD = ../extensions/libext.a +common_sources = iptables-xml.c xtables-multi.h xshared.c xshared.h +common_ldadd = ../extensions/libext.a ../libxtables/libxtables.la -lm +common_cflags = ${AM_CFLAGS} if ENABLE_STATIC -xtables_legacy_multi_CFLAGS += -DALL_INCLUSIVE +common_cflags += -DALL_INCLUSIVE endif + +xtables_legacy_multi_SOURCES = ${common_sources} xtables-legacy-multi.c \ + iptables-restore.c iptables-save.c +xtables_legacy_multi_CFLAGS = ${common_cflags} +xtables_legacy_multi_LDADD = ${common_ldadd} if ENABLE_IPV4 -xtables_legacy_multi_SOURCES += iptables-standalone.c iptables.c +xtables_legacy_multi_SOURCES += iptables-standalone.c iptables.c iptables-multi.h xtables_legacy_multi_CFLAGS += -DENABLE_IPV4 xtables_legacy_multi_LDADD += ../libiptc/libip4tc.la ../extensions/libext4.a endif if ENABLE_IPV6 -xtables_legacy_multi_SOURCES += ip6tables-standalone.c ip6tables.c +xtables_legacy_multi_SOURCES += ip6tables-standalone.c ip6tables.c ip6tables-multi.h xtables_legacy_multi_CFLAGS += -DENABLE_IPV6 xtables_legacy_multi_LDADD += ../libiptc/libip6tc.la ../extensions/libext6.a endif -xtables_legacy_multi_SOURCES += xshared.c iptables-restore.c iptables-save.c -xtables_legacy_multi_LDADD += ../libxtables/libxtables.la -lm # iptables using nf_tables api if ENABLE_NFTABLES -xtables_nft_multi_SOURCES = xtables-nft-multi.c iptables-xml.c -xtables_nft_multi_CFLAGS = ${AM_CFLAGS} -xtables_nft_multi_LDADD = ../extensions/libext.a ../extensions/libext_ebt.a -if ENABLE_STATIC -xtables_nft_multi_CFLAGS += -DALL_INCLUSIVE -endif +xtables_nft_multi_SOURCES = ${common_sources} xtables-nft-multi.c +xtables_nft_multi_CFLAGS = ${common_cflags} +xtables_nft_multi_LDADD = ${common_ldadd} \ + ../extensions/libext_arpt.a \ + ../extensions/libext_ebt.a \ + ../extensions/libext4.a \ + ../extensions/libext6.a \ + ${libmnl_LIBS} ${libnftnl_LIBS} \ + ${libnetfilter_conntrack_LIBS} xtables_nft_multi_CFLAGS += -DENABLE_NFTABLES -DENABLE_IPV4 -DENABLE_IPV6 -xtables_nft_multi_SOURCES += xtables-save.c xtables-restore.c \ - xtables-standalone.c xtables.c nft.c \ - nft-shared.c nft-ipv4.c nft-ipv6.c nft-arp.c \ - xtables-monitor.c nft-cache.c \ - xtables-arp-standalone.c xtables-arp.c \ - nft-bridge.c nft-cmd.c nft-chain.c \ - xtables-eb-standalone.c xtables-eb.c \ - xtables-eb-translate.c \ - xtables-translate.c -xtables_nft_multi_LDADD += ${libmnl_LIBS} ${libnftnl_LIBS} ${libnetfilter_conntrack_LIBS} ../extensions/libext4.a ../extensions/libext6.a ../extensions/libext_ebt.a ../extensions/libext_arpt.a -xtables_nft_multi_SOURCES += xshared.c -xtables_nft_multi_LDADD += ../libxtables/libxtables.la -lm +xtables_nft_multi_SOURCES += nft.c nft.h \ + nft-arp.c nft-ipv4.c nft-ipv6.c \ + nft-bridge.c nft-bridge.h \ + nft-cache.c nft-cache.h \ + nft-chain.c nft-chain.h \ + nft-cmd.c nft-cmd.h \ + nft-shared.c nft-shared.h \ + xtables-monitor.c \ + xtables.c xtables-arp.c xtables-eb.c \ + xtables-standalone.c xtables-eb-standalone.c \ + xtables-translate.c xtables-eb-translate.c \ + xtables-save.c xtables-restore.c endif sbin_PROGRAMS = xtables-legacy-multi @@ -56,22 +63,19 @@ man_MANS = iptables.8 iptables-restore.8 iptables-save.8 \ ip6tables-save.8 iptables-extensions.8 \ iptables-apply.8 ip6tables-apply.8 -sbin_SCRIPTS = iptables-apply +dist_sbin_SCRIPTS = iptables-apply +dist_pkgdata_DATA = iptables.xslt if ENABLE_NFTABLES -man_MANS += xtables-nft.8 xtables-translate.8 xtables-legacy.8 \ - iptables-translate.8 ip6tables-translate.8 \ +man_MANS += iptables-translate.8 ip6tables-translate.8 \ iptables-restore-translate.8 ip6tables-restore-translate.8 \ - xtables-monitor.8 \ - arptables-nft.8 arptables-nft-restore.8 arptables-nft-save.8 \ - ebtables-nft.8 + xtables-monitor.8 ebtables-translate.8 + +dist_man_MANS = xtables-nft.8 xtables-translate.8 xtables-legacy.8 \ + arptables-nft.8 arptables-nft-restore.8 arptables-nft-save.8 \ + ebtables-nft.8 endif -CLEANFILES = iptables.8 xtables-monitor.8 \ - iptables-xml.1 iptables-apply.8 \ - iptables-extensions.8 iptables-extensions.8.tmpl \ - iptables-restore.8 iptables-save.8 \ - iptables-restore-translate.8 ip6tables-restore-translate.8 \ - iptables-translate.8 ip6tables-translate.8 +CLEANFILES = ${man_MANS} iptables-extensions.8.tmpl vx_bin_links = iptables-xml if ENABLE_IPV4 @@ -85,7 +89,7 @@ endif if ENABLE_NFTABLES x_sbin_links = iptables-nft iptables-nft-restore iptables-nft-save \ ip6tables-nft ip6tables-nft-restore ip6tables-nft-save \ - iptables-translate ip6tables-translate \ + iptables-translate ip6tables-translate ebtables-translate \ iptables-restore-translate ip6tables-restore-translate \ arptables-nft arptables \ arptables-nft-restore arptables-restore \ @@ -101,9 +105,12 @@ iptables-extensions.8: iptables-extensions.8.tmpl ../extensions/matches.man ../e -e '/@MATCH@/ r ../extensions/matches.man' \ -e '/@TARGET@/ r ../extensions/targets.man' $< >$@; -iptables-translate.8 ip6tables-translate.8 iptables-restore-translate.8 ip6tables-restore-translate.8: +iptables-translate.8 ip6tables-translate.8 iptables-restore-translate.8 ip6tables-restore-translate.8 ebtables-translate.8: ${AM_VERBOSE_GEN} echo '.so man8/xtables-translate.8' >$@ +ip6tables.8 ip6tables-apply.8 ip6tables-restore.8 ip6tables-save.8: + ${AM_VERBOSE_GEN} echo "$@" | sed 's|^ip6|.so man8/ip|' >$@ + pkgconfig_DATA = xtables.pc # Using if..fi avoids an ugly "error (ignored)" message :) @@ -138,3 +145,5 @@ uninstall-hook: ); \ ( cd "$$dir" && rm -f ip6tables-apply ); \ } + +EXTRA_DIST = tests diff --git a/iptables/ebtables-nft.8 b/iptables/ebtables-nft.8 index 08e9766f..d75aae24 100644 --- a/iptables/ebtables-nft.8 +++ b/iptables/ebtables-nft.8 @@ -307,6 +307,12 @@ of the ebtables kernel table. Replace the current table data by the initial table data. .SS MISCELLANOUS COMMANDS .TP +.B "-v, --verbose" +Verbose mode. +For appending, insertion, deletion and replacement, this causes +detailed information on the rule or rules to be printed. \fB\-v\fP may be +specified multiple times to possibly emit more detailed debug statements. +.TP .B "-V, --version" Show the version of the ebtables userspace program. .TP diff --git a/iptables/ip6tables-apply.8 b/iptables/ip6tables-apply.8 deleted file mode 100644 index 994b487a..00000000 --- a/iptables/ip6tables-apply.8 +++ /dev/null @@ -1 +0,0 @@ -.so man8/iptables-apply.8 diff --git a/iptables/ip6tables-restore.8 b/iptables/ip6tables-restore.8 deleted file mode 100644 index cf4ea3e7..00000000 --- a/iptables/ip6tables-restore.8 +++ /dev/null @@ -1 +0,0 @@ -.so man8/iptables-restore.8 diff --git a/iptables/ip6tables-save.8 b/iptables/ip6tables-save.8 deleted file mode 100644 index 182f55c1..00000000 --- a/iptables/ip6tables-save.8 +++ /dev/null @@ -1 +0,0 @@ -.so man8/iptables-save.8 diff --git a/iptables/ip6tables-standalone.c b/iptables/ip6tables-standalone.c index 105b83ba..7c8bb0c2 100644 --- a/iptables/ip6tables-standalone.c +++ b/iptables/ip6tables-standalone.c @@ -52,11 +52,8 @@ ip6tables_main(int argc, char *argv[]) ip6tables_globals.program_version); exit(1); } - -#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS) init_extensions(); init_extensions6(); -#endif ret = do_command6(argc, argv, &table, &handle, false); if (ret) { diff --git a/iptables/ip6tables.8 b/iptables/ip6tables.8 deleted file mode 100644 index 0dee41ad..00000000 --- a/iptables/ip6tables.8 +++ /dev/null @@ -1 +0,0 @@ -.so man8/iptables.8 diff --git a/iptables/ip6tables.c b/iptables/ip6tables.c index e967c040..345af451 100644 --- a/iptables/ip6tables.c +++ b/iptables/ip6tables.c @@ -87,134 +87,13 @@ static struct option original_opts[] = { {NULL}, }; -void ip6tables_exit_error(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3))); struct xtables_globals ip6tables_globals = { .option_offset = 0, - .program_version = PACKAGE_VERSION, + .program_version = PACKAGE_VERSION " (legacy)", .orig_opts = original_opts, - .exit_err = ip6tables_exit_error, .compat_rev = xtables_compatible_revision, }; -#define opts ip6tables_globals.opts -#define prog_name ip6tables_globals.program_name -#define prog_vers ip6tables_globals.program_version - -static void __attribute__((noreturn)) -exit_tryhelp(int status) -{ - if (line != -1) - fprintf(stderr, "Error occurred at line: %d\n", line); - fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n", - prog_name, prog_name); - xtables_free_opts(1); - exit(status); -} - -static void -exit_printhelp(const struct xtables_rule_match *matches) -{ - printf("%s v%s\n\n" -"Usage: %s -[ACD] chain rule-specification [options]\n" -" %s -I chain [rulenum] rule-specification [options]\n" -" %s -R chain rulenum rule-specification [options]\n" -" %s -D chain rulenum [options]\n" -" %s -[LS] [chain [rulenum]] [options]\n" -" %s -[FZ] [chain] [options]\n" -" %s -[NX] chain\n" -" %s -E old-chain-name new-chain-name\n" -" %s -P chain target [options]\n" -" %s -h (print this help information)\n\n", - prog_name, prog_vers, prog_name, prog_name, - prog_name, prog_name, prog_name, prog_name, - prog_name, prog_name, prog_name, prog_name); - - printf( -"Commands:\n" -"Either long or short options are allowed.\n" -" --append -A chain Append to chain\n" -" --check -C chain Check for the existence of a rule\n" -" --delete -D chain Delete matching rule from chain\n" -" --delete -D chain rulenum\n" -" Delete rule rulenum (1 = first) from chain\n" -" --insert -I chain [rulenum]\n" -" Insert in chain as rulenum (default 1=first)\n" -" --replace -R chain rulenum\n" -" Replace rule rulenum (1 = first) in chain\n" -" --list -L [chain [rulenum]]\n" -" List the rules in a chain or all chains\n" -" --list-rules -S [chain [rulenum]]\n" -" Print the rules in a chain or all chains\n" -" --flush -F [chain] Delete all rules in chain or all chains\n" -" --zero -Z [chain [rulenum]]\n" -" Zero counters in chain or all chains\n" -" --new -N chain Create a new user-defined chain\n" -" --delete-chain\n" -" -X [chain] Delete a user-defined chain\n" -" --policy -P chain target\n" -" Change policy on chain to target\n" -" --rename-chain\n" -" -E old-chain new-chain\n" -" Change chain name, (moving any references)\n" - -"Options:\n" -" --ipv4 -4 Error (line is ignored by ip6tables-restore)\n" -" --ipv6 -6 Nothing (line is ignored by iptables-restore)\n" -"[!] --protocol -p proto protocol: by number or name, eg. `tcp'\n" -"[!] --source -s address[/mask][,...]\n" -" source specification\n" -"[!] --destination -d address[/mask][,...]\n" -" destination specification\n" -"[!] --in-interface -i input name[+]\n" -" network interface name ([+] for wildcard)\n" -" --jump -j target\n" -" target for rule (may load target extension)\n" -#ifdef IP6T_F_GOTO -" --goto -g chain\n" -" jump to chain with no return\n" -#endif -" --match -m match\n" -" extended match (may load extension)\n" -" --numeric -n numeric output of addresses and ports\n" -"[!] --out-interface -o output name[+]\n" -" network interface name ([+] for wildcard)\n" -" --table -t table table to manipulate (default: `filter')\n" -" --verbose -v verbose mode\n" -" --wait -w [seconds] maximum wait to acquire xtables lock before give up\n" -" --wait-interval -W [usecs] wait time to try to acquire xtables lock\n" -" interval to wait for xtables lock\n" -" default is 1 second\n" -" --line-numbers print line numbers when listing\n" -" --exact -x expand numbers (display exact values)\n" -/*"[!] --fragment -f match second or further fragments only\n"*/ -" --modprobe=<command> try to insert modules using this command\n" -" --set-counters PKTS BYTES set the counter during insert/append\n" -"[!] --version -V print package version.\n"); - - print_extension_helps(xtables_targets, matches); - exit(0); -} - -void -ip6tables_exit_error(enum xtables_exittype status, const char *msg, ...) -{ - va_list args; - - va_start(args, msg); - fprintf(stderr, "%s v%s (legacy): ", prog_name, prog_vers); - vfprintf(stderr, msg, args); - va_end(args); - fprintf(stderr, "\n"); - if (status == PARAMETER_PROBLEM) - exit_tryhelp(status); - if (status == VERSION_PROBLEM) - fprintf(stderr, - "Perhaps ip6tables or your kernel needs to be upgraded.\n"); - /* On error paths, make sure that we don't leak memory */ - xtables_free_opts(1); - exit(status); -} - /* * All functions starting with "parse" should succeed, otherwise * the program fails. @@ -224,91 +103,6 @@ ip6tables_exit_error(enum xtables_exittype status, const char *msg, ...) * return global static data. */ -/* These are invalid numbers as upper layer protocol */ -static int is_exthdr(uint16_t proto) -{ - return (proto == IPPROTO_ROUTING || - proto == IPPROTO_FRAGMENT || - proto == IPPROTO_AH || - proto == IPPROTO_DSTOPTS); -} - -static void -parse_chain(const char *chainname) -{ - const char *ptr; - - if (strlen(chainname) >= XT_EXTENSION_MAXNAMELEN) - xtables_error(PARAMETER_PROBLEM, - "chain name `%s' too long (must be under %u chars)", - chainname, XT_EXTENSION_MAXNAMELEN); - - if (*chainname == '-' || *chainname == '!') - xtables_error(PARAMETER_PROBLEM, - "chain name not allowed to start " - "with `%c'\n", *chainname); - - if (xtables_find_target(chainname, XTF_TRY_LOAD)) - xtables_error(PARAMETER_PROBLEM, - "chain name may not clash " - "with target name\n"); - - for (ptr = chainname; *ptr; ptr++) - if (isspace(*ptr)) - xtables_error(PARAMETER_PROBLEM, - "Invalid chain name `%s'", chainname); -} - -static void -print_header(unsigned int format, const char *chain, struct xtc_handle *handle) -{ - struct xt_counters counters; - const char *pol = ip6tc_get_policy(chain, &counters, handle); - printf("Chain %s", chain); - if (pol) { - printf(" (policy %s", pol); - if (!(format & FMT_NOCOUNTS)) { - fputc(' ', stdout); - xtables_print_num(counters.pcnt, (format|FMT_NOTABLE)); - fputs("packets, ", stdout); - xtables_print_num(counters.bcnt, (format|FMT_NOTABLE)); - fputs("bytes", stdout); - } - printf(")\n"); - } else { - unsigned int refs; - if (!ip6tc_get_references(&refs, chain, handle)) - printf(" (ERROR obtaining refs)\n"); - else - printf(" (%u references)\n", refs); - } - - if (format & FMT_LINENUMBERS) - printf(FMT("%-4s ", "%s "), "num"); - if (!(format & FMT_NOCOUNTS)) { - if (format & FMT_KILOMEGAGIGA) { - printf(FMT("%5s ","%s "), "pkts"); - printf(FMT("%5s ","%s "), "bytes"); - } else { - printf(FMT("%8s ","%s "), "pkts"); - printf(FMT("%10s ","%s "), "bytes"); - } - } - if (!(format & FMT_NOTARGET)) - printf(FMT("%-9s ","%s "), "target"); - fputs(" prot ", stdout); - if (format & FMT_OPTIONS) - fputs("opt", stdout); - if (format & FMT_VIA) { - printf(FMT(" %-6s ","%s "), "in"); - printf(FMT("%-6s ","%s "), "out"); - } - printf(FMT(" %-19s ","%s "), "source"); - printf(FMT(" %-19s "," %s "), "destination"); - printf("\n"); -} - - static int print_match(const struct xt_entry_match *m, const struct ip6t_ip6 *ip, @@ -328,6 +122,9 @@ print_match(const struct xt_entry_match *m, printf("%s%s ", match->name, unsupported_rev); else printf("%s ", match->name); + + if (match->next == match) + free(match); } else { if (name[0]) printf("UNKNOWN match `%s' ", name); @@ -355,33 +152,10 @@ print_firewall(const struct ip6t_entry *fw, t = ip6t_get_target((struct ip6t_entry *)fw); - if (format & FMT_LINENUMBERS) - printf(FMT("%-4u ", "%u "), num); - - if (!(format & FMT_NOCOUNTS)) { - xtables_print_num(fw->counters.pcnt, format); - xtables_print_num(fw->counters.bcnt, format); - } - - if (!(format & FMT_NOTARGET)) - printf(FMT("%-9s ", "%s "), targname); + print_rule_details(num, &fw->counters, targname, fw->ipv6.proto, + fw->ipv6.flags, fw->ipv6.invflags, format); - fputc(fw->ipv6.invflags & XT_INV_PROTO ? '!' : ' ', stdout); - { - const char *pname = proto_to_name(fw->ipv6.proto, format&FMT_NUMERIC); - if (pname) - printf(FMT("%-5s", "%s "), pname); - else - printf(FMT("%-5hu", "%hu "), fw->ipv6.proto); - } - - if (format & FMT_OPTIONS) { - if (format & FMT_NOTABLE) - fputs("opt ", stdout); - fputc(' ', stdout); /* Invert flag of FRAG */ - fputc(' ', stdout); /* -f */ - fputc(' ', stdout); - } + print_fragment(fw->ipv6.flags, fw->ipv6.invflags, format, true); print_ifaces(fw->ipv6.iniface, fw->ipv6.outiface, fw->ipv6.invflags, format); @@ -408,6 +182,9 @@ print_firewall(const struct ip6t_entry *fw, tg->print(&fw->ipv6, t, format & FMT_NUMERIC); else if (target->print) printf(" %s%s", target->name, unsupported_rev); + + if (target->next == target) + free(target); } else if (t->u.target_size != sizeof(*t)) printf("[%u bytes of unknown target data] ", (unsigned int)(t->u.target_size - sizeof(*t))); @@ -506,40 +283,6 @@ insert_entry(const xt_chainlabel chain, return ret; } -static unsigned char * -make_delete_mask(const struct xtables_rule_match *matches, - const struct xtables_target *target) -{ - /* Establish mask for comparison */ - unsigned int size; - const struct xtables_rule_match *matchp; - unsigned char *mask, *mptr; - - size = sizeof(struct ip6t_entry); - for (matchp = matches; matchp; matchp = matchp->next) - size += XT_ALIGN(sizeof(struct xt_entry_match)) + matchp->match->size; - - mask = xtables_calloc(1, size - + XT_ALIGN(sizeof(struct xt_entry_target)) - + target->size); - - memset(mask, 0xFF, sizeof(struct ip6t_entry)); - mptr = mask + sizeof(struct ip6t_entry); - - for (matchp = matches; matchp; matchp = matchp->next) { - memset(mptr, 0xFF, - XT_ALIGN(sizeof(struct xt_entry_match)) - + matchp->match->userspacesize); - mptr += XT_ALIGN(sizeof(struct xt_entry_match)) + matchp->match->size; - } - - memset(mptr, 0xFF, - XT_ALIGN(sizeof(struct xt_entry_target)) - + target->userspacesize); - - return mask; -} - static int delete_entry(const xt_chainlabel chain, struct ip6t_entry *fw, @@ -558,7 +301,7 @@ delete_entry(const xt_chainlabel chain, int ret = 1; unsigned char *mask; - mask = make_delete_mask(matches, target); + mask = make_delete_mask(matches, target, sizeof(*fw)); for (i = 0; i < nsaddrs; i++) { fw->ipv6.src = saddrs[i]; fw->ipv6.smsk = smasks[i]; @@ -588,7 +331,7 @@ check_entry(const xt_chainlabel chain, struct ip6t_entry *fw, int ret = 1; unsigned char *mask; - mask = make_delete_mask(matches, target); + mask = make_delete_mask(matches, target, sizeof(fw)); for (i = 0; i < nsaddrs; i++) { fw->ipv6.src = saddrs[i]; fw->ipv6.smsk = smasks[i]; @@ -711,8 +454,18 @@ list_entries(const xt_chainlabel chain, int rulenum, int verbose, int numeric, if (found) printf("\n"); - if (!rulenum) - print_header(format, this, handle); + if (!rulenum) { + struct xt_counters counters; + unsigned int urefs; + const char *pol; + int refs = - 1; + + pol = ip6tc_get_policy(this, &counters, handle); + if (!pol && ip6tc_get_references(&urefs, this, handle)) + refs = urefs; + + print_header(format, this, pol, &counters, refs, 0); + } i = ip6tc_first_rule(this, handle); num = 0; @@ -733,97 +486,6 @@ list_entries(const xt_chainlabel chain, int rulenum, int verbose, int numeric, return found; } -/* This assumes that mask is contiguous, and byte-bounded. */ -static void -print_iface(char letter, const char *iface, const unsigned char *mask, - int invert) -{ - unsigned int i; - - if (mask[0] == 0) - return; - - printf("%s -%c ", invert ? " !" : "", letter); - - for (i = 0; i < IFNAMSIZ; i++) { - if (mask[i] != 0) { - if (iface[i] != '\0') - printf("%c", iface[i]); - } else { - /* we can access iface[i-1] here, because - * a few lines above we make sure that mask[0] != 0 */ - if (iface[i-1] != '\0') - printf("+"); - break; - } - } -} - -static void print_proto(uint16_t proto, int invert) -{ - if (proto) { - const char *pname = proto_to_name(proto, 0); - const char *invertstr = invert ? " !" : ""; - - if (pname) - printf("%s -p %s", invertstr, pname); - else - printf("%s -p %u", invertstr, proto); - } -} - -static int print_match_save(const struct xt_entry_match *e, - const struct ip6t_ip6 *ip) -{ - const char *name = e->u.user.name; - const int revision = e->u.user.revision; - struct xtables_match *match, *mt, *mt2; - - match = xtables_find_match(name, XTF_TRY_LOAD, NULL); - if (match) { - mt = mt2 = xtables_find_match_revision(name, XTF_TRY_LOAD, - match, revision); - if (!mt2) - mt2 = match; - printf(" -m %s", mt2->alias ? mt2->alias(e) : name); - - /* some matches don't provide a save function */ - if (mt && mt->save) - mt->save(ip, e); - else if (match->save) - printf(unsupported_rev); - } else { - if (e->u.match_size) { - fprintf(stderr, - "Can't find library for match `%s'\n", - name); - exit(1); - } - } - return 0; -} - -/* Print a given ip including mask if necessary. */ -static void print_ip(const char *prefix, const struct in6_addr *ip, - const struct in6_addr *mask, int invert) -{ - char buf[51]; - int l = xtables_ip6mask_to_cidr(mask); - - if (l == 0 && !invert) - return; - - printf("%s %s %s", - invert ? " !" : "", - prefix, - inet_ntop(AF_INET6, ip, buf, sizeof buf)); - - if (l == -1) - printf("/%s", inet_ntop(AF_INET6, mask, buf, sizeof buf)); - else - printf("/%d", l); -} - /* We want this to be readable, so only print out necessary fields. * Because that's the kind of world I want to live in. */ @@ -841,19 +503,15 @@ void print_rule6(const struct ip6t_entry *e, printf("-A %s", chain); /* Print IP part. */ - print_ip("-s", &(e->ipv6.src), &(e->ipv6.smsk), - e->ipv6.invflags & IP6T_INV_SRCIP); - - print_ip("-d", &(e->ipv6.dst), &(e->ipv6.dmsk), - e->ipv6.invflags & IP6T_INV_DSTIP); + save_ipv6_addr('s', &e->ipv6.src, &e->ipv6.smsk, + e->ipv6.invflags & IP6T_INV_SRCIP); - print_iface('i', e->ipv6.iniface, e->ipv6.iniface_mask, - e->ipv6.invflags & IP6T_INV_VIA_IN); + save_ipv6_addr('d', &e->ipv6.dst, &e->ipv6.dmsk, + e->ipv6.invflags & IP6T_INV_DSTIP); - print_iface('o', e->ipv6.outiface, e->ipv6.outiface_mask, - e->ipv6.invflags & IP6T_INV_VIA_OUT); - - print_proto(e->ipv6.proto, e->ipv6.invflags & XT_INV_PROTO); + save_rule_details(e->ipv6.iniface, e->ipv6.iniface_mask, + e->ipv6.outiface, e->ipv6.outiface_mask, + e->ipv6.proto, 0, e->ipv6.invflags); #if 0 /* not definied in ipv6 @@ -1008,10 +666,23 @@ generate_entry(const struct ip6t_entry *fw, int do_command6(int argc, char *argv[], char **table, struct xtc_handle **handle, bool restore) { + struct xt_cmd_parse_ops cmd_parse_ops = { + .proto_parse = ipv6_proto_parse, + .post_parse = ipv6_post_parse, + }; + struct xt_cmd_parse p = { + .table = *table, + .restore = restore, + .line = line, + .ops = &cmd_parse_ops, + }; struct iptables_command_state cs = { .jumpto = "", .argv = argv, }; + struct xtables_args args = { + .family = AF_INET6, + }; struct ip6t_entry *e = NULL; unsigned int nsaddrs = 0, ndaddrs = 0; struct in6_addr *saddrs = NULL, *daddrs = NULL; @@ -1019,444 +690,31 @@ int do_command6(int argc, char *argv[], char **table, int verbose = 0; int wait = 0; - struct timeval wait_interval = { - .tv_sec = 1, - }; - bool wait_interval_set = false; const char *chain = NULL; - const char *shostnetworkmask = NULL, *dhostnetworkmask = NULL; const char *policy = NULL, *newname = NULL; unsigned int rulenum = 0, command = 0; - const char *pcnt = NULL, *bcnt = NULL; int ret = 1; - struct xtables_match *m; - struct xtables_rule_match *matchp; - struct xtables_target *t; - unsigned long long cnt; - bool table_set = false; - uint16_t invflags = 0; - bool invert = false; - - /* re-set optind to 0 in case do_command6 gets called - * a second time */ - optind = 0; - - /* clear mflags in case do_command6 gets called a second time - * (we clear the global list of all matches for security)*/ - for (m = xtables_matches; m; m = m->next) - m->mflags = 0; - - for (t = xtables_targets; t; t = t->next) { - t->tflags = 0; - t->used = 0; - } - - /* Suppress error messages: we may add new options if we - demand-load a protocol. */ - opterr = 0; - - opts = xt_params->orig_opts; - while ((cs.c = getopt_long(argc, argv, - "-:A:C:D:R:I:L::S::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:bvw::W::nt:m:xc:g:46", - opts, NULL)) != -1) { - switch (cs.c) { - /* - * Command selection - */ - case 'A': - add_command(&command, CMD_APPEND, CMD_NONE, invert); - chain = optarg; - break; - - case 'C': - add_command(&command, CMD_CHECK, CMD_NONE, invert); - chain = optarg; - break; - - case 'D': - add_command(&command, CMD_DELETE, CMD_NONE, invert); - chain = optarg; - if (xs_has_arg(argc, argv)) { - rulenum = parse_rulenumber(argv[optind++]); - command = CMD_DELETE_NUM; - } - break; - - case 'R': - add_command(&command, CMD_REPLACE, CMD_NONE, invert); - chain = optarg; - if (xs_has_arg(argc, argv)) - rulenum = parse_rulenumber(argv[optind++]); - else - xtables_error(PARAMETER_PROBLEM, - "-%c requires a rule number", - cmd2char(CMD_REPLACE)); - break; - - case 'I': - add_command(&command, CMD_INSERT, CMD_NONE, invert); - chain = optarg; - if (xs_has_arg(argc, argv)) - rulenum = parse_rulenumber(argv[optind++]); - else rulenum = 1; - break; - - case 'L': - add_command(&command, CMD_LIST, - CMD_ZERO | CMD_ZERO_NUM, invert); - if (optarg) chain = optarg; - else if (xs_has_arg(argc, argv)) - chain = argv[optind++]; - if (xs_has_arg(argc, argv)) - rulenum = parse_rulenumber(argv[optind++]); - break; - - case 'S': - add_command(&command, CMD_LIST_RULES, - CMD_ZERO | CMD_ZERO_NUM, invert); - if (optarg) chain = optarg; - else if (xs_has_arg(argc, argv)) - chain = argv[optind++]; - if (xs_has_arg(argc, argv)) - rulenum = parse_rulenumber(argv[optind++]); - break; - - case 'F': - add_command(&command, CMD_FLUSH, CMD_NONE, invert); - if (optarg) chain = optarg; - else if (xs_has_arg(argc, argv)) - chain = argv[optind++]; - break; - - case 'Z': - add_command(&command, CMD_ZERO, CMD_LIST|CMD_LIST_RULES, - invert); - if (optarg) chain = optarg; - else if (xs_has_arg(argc, argv)) - chain = argv[optind++]; - if (xs_has_arg(argc, argv)) { - rulenum = parse_rulenumber(argv[optind++]); - command = CMD_ZERO_NUM; - } - break; - - case 'N': - parse_chain(optarg); - add_command(&command, CMD_NEW_CHAIN, CMD_NONE, invert); - chain = optarg; - break; - - case 'X': - add_command(&command, CMD_DELETE_CHAIN, CMD_NONE, - invert); - if (optarg) chain = optarg; - else if (xs_has_arg(argc, argv)) - chain = argv[optind++]; - break; - - case 'E': - add_command(&command, CMD_RENAME_CHAIN, CMD_NONE, - invert); - chain = optarg; - if (xs_has_arg(argc, argv)) - newname = argv[optind++]; - else - xtables_error(PARAMETER_PROBLEM, - "-%c requires old-chain-name and " - "new-chain-name", - cmd2char(CMD_RENAME_CHAIN)); - break; - - case 'P': - add_command(&command, CMD_SET_POLICY, CMD_NONE, - invert); - chain = optarg; - if (xs_has_arg(argc, argv)) - policy = argv[optind++]; - else - xtables_error(PARAMETER_PROBLEM, - "-%c requires a chain and a policy", - cmd2char(CMD_SET_POLICY)); - break; - - case 'h': - if (!optarg) - optarg = argv[optind]; - - /* ip6tables -p icmp -h */ - if (!cs.matches && cs.protocol) - xtables_find_match(cs.protocol, XTF_TRY_LOAD, - &cs.matches); - - exit_printhelp(cs.matches); - /* - * Option selection - */ - case 'p': - set_option(&cs.options, OPT_PROTOCOL, &invflags, - invert); - - /* Canonicalize into lower case */ - for (cs.protocol = optarg; *cs.protocol; cs.protocol++) - *cs.protocol = tolower(*cs.protocol); - - cs.protocol = optarg; - cs.fw6.ipv6.proto = xtables_parse_protocol(cs.protocol); - cs.fw6.ipv6.flags |= IP6T_F_PROTO; - - if (cs.fw6.ipv6.proto == 0 && (invflags & XT_INV_PROTO)) - xtables_error(PARAMETER_PROBLEM, - "rule would never match protocol"); - - if (is_exthdr(cs.fw6.ipv6.proto) - && (invflags & XT_INV_PROTO) == 0) - fprintf(stderr, - "Warning: never matched protocol: %s. " - "use extension match instead.\n", - cs.protocol); - break; - - case 's': - set_option(&cs.options, OPT_SOURCE, &invflags, invert); - shostnetworkmask = optarg; - break; - - case 'd': - set_option(&cs.options, OPT_DESTINATION, &invflags, - invert); - dhostnetworkmask = optarg; - break; - -#ifdef IP6T_F_GOTO - case 'g': - set_option(&cs.options, OPT_JUMP, &invflags, invert); - cs.fw6.ipv6.flags |= IP6T_F_GOTO; - cs.jumpto = xt_parse_target(optarg); - break; -#endif - - case 'j': - set_option(&cs.options, OPT_JUMP, &invflags, invert); - command_jump(&cs, optarg); - break; - - - case 'i': - if (*optarg == '\0') - xtables_error(PARAMETER_PROBLEM, - "Empty interface is likely to be " - "undesired"); - set_option(&cs.options, OPT_VIANAMEIN, &invflags, - invert); - xtables_parse_interface(optarg, - cs.fw6.ipv6.iniface, - cs.fw6.ipv6.iniface_mask); - break; - - case 'o': - if (*optarg == '\0') - xtables_error(PARAMETER_PROBLEM, - "Empty interface is likely to be " - "undesired"); - set_option(&cs.options, OPT_VIANAMEOUT, &invflags, - invert); - xtables_parse_interface(optarg, - cs.fw6.ipv6.outiface, - cs.fw6.ipv6.outiface_mask); - break; - - case 'v': - if (!verbose) - set_option(&cs.options, OPT_VERBOSE, - &invflags, invert); - verbose++; - break; - - case 'w': - if (restore) { - xtables_error(PARAMETER_PROBLEM, - "You cannot use `-w' from " - "ip6tables-restore"); - } - wait = parse_wait_time(argc, argv); - break; - - case 'W': - if (restore) { - xtables_error(PARAMETER_PROBLEM, - "You cannot use `-W' from " - "ip6tables-restore"); - } - parse_wait_interval(argc, argv, &wait_interval); - wait_interval_set = true; - break; - - case 'm': - command_match(&cs, invert); - break; - - case 'n': - set_option(&cs.options, OPT_NUMERIC, &invflags, invert); - break; - - case 't': - if (invert) - xtables_error(PARAMETER_PROBLEM, - "unexpected ! flag before --table"); - if (restore && table_set) - xtables_error(PARAMETER_PROBLEM, - "The -t option (seen in line %u) cannot be used in %s.\n", - line, xt_params->program_name); - *table = optarg; - table_set = true; - break; - - case 'x': - set_option(&cs.options, OPT_EXPANDED, &invflags, - invert); - break; - - case 'V': - if (invert) - printf("Not %s ;-)\n", prog_vers); - else - printf("%s v%s (legacy)\n", - prog_name, prog_vers); - exit(0); - - case '0': - set_option(&cs.options, OPT_LINENUMBERS, &invflags, - invert); - break; - - case 'M': - xtables_modprobe_program = optarg; - break; - - case 'c': - - set_option(&cs.options, OPT_COUNTERS, &invflags, - invert); - pcnt = optarg; - bcnt = strchr(pcnt + 1, ','); - if (bcnt) - bcnt++; - if (!bcnt && xs_has_arg(argc, argv)) - bcnt = argv[optind++]; - if (!bcnt) - xtables_error(PARAMETER_PROBLEM, - "-%c requires packet and byte counter", - opt2char(OPT_COUNTERS)); - - if (sscanf(pcnt, "%llu", &cnt) != 1) - xtables_error(PARAMETER_PROBLEM, - "-%c packet counter not numeric", - opt2char(OPT_COUNTERS)); - cs.fw6.counters.pcnt = cnt; - - if (sscanf(bcnt, "%llu", &cnt) != 1) - xtables_error(PARAMETER_PROBLEM, - "-%c byte counter not numeric", - opt2char(OPT_COUNTERS)); - cs.fw6.counters.bcnt = cnt; - break; - - case '4': - /* This is not the IPv4 iptables */ - if (line != -1) - return 1; /* success: line ignored */ - fprintf(stderr, "This is the IPv6 version of ip6tables.\n"); - exit_tryhelp(2); - - case '6': - /* This is indeed the IPv6 ip6tables */ - break; - - case 1: /* non option */ - if (optarg[0] == '!' && optarg[1] == '\0') { - if (invert) - xtables_error(PARAMETER_PROBLEM, - "multiple consecutive ! not" - " allowed"); - invert = true; - optarg[0] = '\0'; - continue; - } - fprintf(stderr, "Bad argument `%s'\n", optarg); - exit_tryhelp(2); - - default: - if (command_default(&cs, &ip6tables_globals, invert)) - /* - * If new options were loaded, we must retry - * getopt immediately and not allow - * invert=false to be executed. - */ - continue; - break; - } - invert = false; - } - - if (!wait && wait_interval_set) - xtables_error(PARAMETER_PROBLEM, - "--wait-interval only makes sense with --wait\n"); - - if (strcmp(*table, "nat") == 0 && - ((policy != NULL && strcmp(policy, "DROP") == 0) || - (cs.jumpto != NULL && strcmp(cs.jumpto, "DROP") == 0))) - xtables_error(PARAMETER_PROBLEM, - "\nThe \"nat\" table is not intended for filtering, " - "the use of DROP is therefore inhibited.\n\n"); - - for (matchp = cs.matches; matchp; matchp = matchp->next) - xtables_option_mfcall(matchp->match); - if (cs.target != NULL) - xtables_option_tfcall(cs.target); - - /* Fix me: must put inverse options checking here --MN */ - - if (optind < argc) - xtables_error(PARAMETER_PROBLEM, - "unknown arguments found on commandline"); - if (!command) - xtables_error(PARAMETER_PROBLEM, "no command specified"); - if (invert) - xtables_error(PARAMETER_PROBLEM, - "nothing appropriate following !"); - - cs.fw6.ipv6.invflags = invflags; - - if (command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND | CMD_CHECK)) { - if (!(cs.options & OPT_DESTINATION)) - dhostnetworkmask = "::0/0"; - if (!(cs.options & OPT_SOURCE)) - shostnetworkmask = "::0/0"; - } - - if (shostnetworkmask) - xtables_ip6parse_multiple(shostnetworkmask, &saddrs, - &smasks, &nsaddrs); - - if (dhostnetworkmask) - xtables_ip6parse_multiple(dhostnetworkmask, &daddrs, - &dmasks, &ndaddrs); - - if ((nsaddrs > 1 || ndaddrs > 1) && - (cs.fw6.ipv6.invflags & (IP6T_INV_SRCIP | IP6T_INV_DSTIP))) - xtables_error(PARAMETER_PROBLEM, "! not allowed with multiple" - " source or destination IP addresses"); - - if (command == CMD_REPLACE && (nsaddrs != 1 || ndaddrs != 1)) - xtables_error(PARAMETER_PROBLEM, "Replacement rule does not " - "specify a unique address"); - - generic_opt_check(command, cs.options); + do_parse(argc, argv, &p, &cs, &args); + + command = p.command; + chain = p.chain; + *table = p.table; + rulenum = p.rulenum; + policy = p.policy; + newname = p.newname; + verbose = p.verbose; + wait = args.wait; + nsaddrs = args.s.naddrs; + ndaddrs = args.d.naddrs; + saddrs = args.s.addr.v6; + daddrs = args.d.addr.v6; + smasks = args.s.mask.v6; + dmasks = args.d.mask.v6; /* Attempt to acquire the xtables lock */ if (!restore) - xtables_lock_or_exit(wait, &wait_interval); + xtables_lock_or_exit(wait); /* only allocate handle if we weren't called with a handle */ if (!*handle) @@ -1476,26 +734,6 @@ int do_command6(int argc, char *argv[], char **table, || command == CMD_CHECK || command == CMD_INSERT || command == CMD_REPLACE) { - if (strcmp(chain, "PREROUTING") == 0 - || strcmp(chain, "INPUT") == 0) { - /* -o not valid with incoming packets. */ - if (cs.options & OPT_VIANAMEOUT) - xtables_error(PARAMETER_PROBLEM, - "Can't use -%c with %s\n", - opt2char(OPT_VIANAMEOUT), - chain); - } - - if (strcmp(chain, "POSTROUTING") == 0 - || strcmp(chain, "OUTPUT") == 0) { - /* -i not valid with outgoing packets */ - if (cs.options & OPT_VIANAMEIN) - xtables_error(PARAMETER_PROBLEM, - "Can't use -%c with %s\n", - opt2char(OPT_VIANAMEIN), - chain); - } - if (cs.target && ip6tc_is_chain(cs.jumpto, *handle)) { fprintf(stderr, "Warning: using chain %s, not extension\n", @@ -1534,13 +772,12 @@ int do_command6(int argc, char *argv[], char **table, #ifdef IP6T_F_GOTO if (cs.fw6.ipv6.flags & IP6T_F_GOTO) xtables_error(PARAMETER_PROBLEM, - "goto '%s' is not a chain\n", - cs.jumpto); + "goto '%s' is not a chain", + cs.jumpto); #endif xtables_find_target(cs.jumpto, XTF_LOAD_MUST_SUCCEED); } else { e = generate_entry(&cs.fw6, cs.matches, cs.target->t); - free(cs.target->t); } } @@ -1631,15 +868,18 @@ int do_command6(int argc, char *argv[], char **table, case CMD_SET_POLICY: ret = ip6tc_set_policy(chain, policy, cs.options&OPT_COUNTERS ? &cs.fw6.counters : NULL, *handle); break; + case CMD_NONE: + /* do_parse ignored the line (eg: -4 with ip6tables-restore) */ + break; default: /* We should never reach this... */ - exit_tryhelp(2); + exit_tryhelp(2, line); } if (verbose > 1) dump_entries6(*handle); - xtables_rule_matches_free(&cs.matches); + xtables_clear_iptables_command_state(&cs); if (e != NULL) { free(e); diff --git a/iptables/iptables-restore.8.in b/iptables/iptables-restore.8.in index b4b62f92..20216842 100644 --- a/iptables/iptables-restore.8.in +++ b/iptables/iptables-restore.8.in @@ -54,6 +54,7 @@ Only parse and construct the ruleset, but do not commit it. .TP \fB\-v\fP, \fB\-\-verbose\fP Print additional debug info during ruleset processing. +Specify multiple times to increase debug level. .TP \fB\-V\fP, \fB\-\-version\fP Print the program version number. @@ -66,13 +67,6 @@ the program will exit if the lock cannot be obtained. This option will make the program wait (indefinitely or for optional \fIseconds\fP) until the exclusive lock can be obtained. .TP -\fB\-W\fP, \fB\-\-wait-interval\fP \fImicroseconds\fP -Interval to wait per each iteration. -When running latency sensitive applications, waiting for the xtables lock -for extended durations may not be acceptable. This option will make each -iteration take the amount of time specified. The default interval is -1 second. This option only works with \fB\-w\fP. -.TP \fB\-M\fP, \fB\-\-modprobe\fP \fImodprobe_program\fP Specify the path to the modprobe program. By default, iptables-restore will inspect /proc/sys/kernel/modprobe to determine the executable's path. diff --git a/iptables/iptables-restore.c b/iptables/iptables-restore.c index cc2c2b8b..6f7ddf93 100644 --- a/iptables/iptables-restore.c +++ b/iptables/iptables-restore.c @@ -22,10 +22,6 @@ static int counters, verbose, noflush, wait; -static struct timeval wait_interval = { - .tv_sec = 1, -}; - /* Keeping track of external matches and targets. */ static const struct option options[] = { {.name = "counters", .has_arg = 0, .val = 'c'}, @@ -51,7 +47,6 @@ static void print_usage(const char *name, const char *version) " [ --help ]\n" " [ --noflush ]\n" " [ --wait=<seconds>\n" - " [ --wait-interval=<usecs>\n" " [ --table=<TABLE> ]\n" " [ --modprobe=<command> ]\n", name); } @@ -83,8 +78,9 @@ create_handle(const struct iptables_restore_cb *cb, const char *tablename) } if (!handle) - xtables_error(PARAMETER_PROBLEM, "%s: unable to initialize " - "table '%s'\n", xt_params->program_name, tablename); + xtables_error(PARAMETER_PROBLEM, + "%s: unable to initialize table '%s'", + xt_params->program_name, tablename); return handle; } @@ -101,6 +97,7 @@ ip46tables_restore_main(const struct iptables_restore_cb *cb, FILE *in; int in_table = 0, testing = 0; const char *tablename = NULL; + bool wait_interval_set = false; line = 0; lock = XT_LOCK_NOT_ACQUIRED; @@ -114,10 +111,10 @@ ip46tables_restore_main(const struct iptables_restore_cb *cb, counters = 1; break; case 'v': - verbose = 1; + verbose++; break; case 'V': - printf("%s v%s (legacy)\n", + printf("%s v%s\n", xt_params->program_name, xt_params->program_version); exit(0); @@ -135,7 +132,8 @@ ip46tables_restore_main(const struct iptables_restore_cb *cb, wait = parse_wait_time(argc, argv); break; case 'W': - parse_wait_interval(argc, argv, &wait_interval); + parse_wait_interval(argc, argv); + wait_interval_set = true; break; case 'M': xtables_modprobe_program = optarg; @@ -165,7 +163,7 @@ ip46tables_restore_main(const struct iptables_restore_cb *cb, } else in = stdin; - if (!wait_interval.tv_sec && !wait) { + if (wait_interval_set && !wait) { fprintf(stderr, "Option --wait-interval requires option --wait\n"); exit(1); } @@ -187,12 +185,12 @@ ip46tables_restore_main(const struct iptables_restore_cb *cb, if (!testing) { DEBUGP("Calling commit\n"); ret = cb->ops->commit(handle); - cb->ops->free(handle); - handle = NULL; } else { DEBUGP("Not calling commit, testing\n"); ret = 1; } + cb->ops->free(handle); + handle = NULL; /* Done with the current table, release the lock. */ if (lock >= 0) { @@ -203,7 +201,7 @@ ip46tables_restore_main(const struct iptables_restore_cb *cb, in_table = 0; } else if ((buffer[0] == '*') && (!in_table)) { /* Acquire a lock before we create a new table handle */ - lock = xtables_lock_or_exit(wait, &wait_interval); + lock = xtables_lock_or_exit(wait); /* New table */ char *table; @@ -212,8 +210,8 @@ ip46tables_restore_main(const struct iptables_restore_cb *cb, DEBUGP("line %u, table '%s'\n", line, table); if (!table) xtables_error(PARAMETER_PROBLEM, - "%s: line %u table name invalid\n", - xt_params->program_name, line); + "%s: line %u table name invalid", + xt_params->program_name, line); strncpy(curtable, table, XT_TABLE_MAXNAMELEN); curtable[XT_TABLE_MAXNAMELEN] = '\0'; @@ -252,8 +250,8 @@ ip46tables_restore_main(const struct iptables_restore_cb *cb, DEBUGP("line %u, chain '%s'\n", line, chain); if (!chain) xtables_error(PARAMETER_PROBLEM, - "%s: line %u chain name invalid\n", - xt_params->program_name, line); + "%s: line %u chain name invalid", + xt_params->program_name, line); if (strlen(chain) >= XT_EXTENSION_MAXNAMELEN) xtables_error(PARAMETER_PROBLEM, @@ -266,16 +264,14 @@ ip46tables_restore_main(const struct iptables_restore_cb *cb, DEBUGP("Flushing existing user defined chain '%s'\n", chain); if (!cb->ops->flush_entries(chain, handle)) xtables_error(PARAMETER_PROBLEM, - "error flushing chain " - "'%s':%s\n", chain, - strerror(errno)); + "error flushing chain '%s':%s", + chain, strerror(errno)); } else { DEBUGP("Creating new chain '%s'\n", chain); if (!cb->ops->create_chain(chain, handle)) xtables_error(PARAMETER_PROBLEM, - "error creating chain " - "'%s':%s\n", chain, - strerror(errno)); + "error creating chain '%s':%s", + chain, strerror(errno)); } } @@ -283,8 +279,8 @@ ip46tables_restore_main(const struct iptables_restore_cb *cb, DEBUGP("line %u, policy '%s'\n", line, policy); if (!policy) xtables_error(PARAMETER_PROBLEM, - "%s: line %u policy invalid\n", - xt_params->program_name, line); + "%s: line %u policy invalid", + xt_params->program_name, line); if (strcmp(policy, "-") != 0) { struct xt_counters count = {}; @@ -295,8 +291,8 @@ ip46tables_restore_main(const struct iptables_restore_cb *cb, if (!ctrs || !parse_counters(ctrs, &count)) xtables_error(PARAMETER_PROBLEM, - "invalid policy counters " - "for chain '%s'\n", chain); + "invalid policy counters for chain '%s'", + chain); } DEBUGP("Setting policy of chain %s to %s\n", @@ -305,23 +301,27 @@ ip46tables_restore_main(const struct iptables_restore_cb *cb, if (!cb->ops->set_policy(chain, policy, &count, handle)) xtables_error(OTHER_PROBLEM, - "Can't set policy `%s'" - " on `%s' line %u: %s\n", - policy, chain, line, - cb->ops->strerror(errno)); + "Can't set policy `%s' on `%s' line %u: %s", + policy, chain, line, + cb->ops->strerror(errno)); } + xtables_announce_chain(chain); ret = 1; } else if (in_table) { char *pcnt = NULL; char *bcnt = NULL; char *parsestart = buffer; + int i; add_argv(&av_store, argv[0], 0); add_argv(&av_store, "-t", 0); add_argv(&av_store, curtable, 0); + for (i = 0; !noflush && i < verbose; i++) + add_argv(&av_store, "-v", 0); + tokenize_rule_counters(&parsestart, &pcnt, &bcnt, line); if (counters && pcnt && bcnt) { add_argv(&av_store, "--set-counters", 0); @@ -382,10 +382,8 @@ iptables_restore_main(int argc, char *argv[]) iptables_globals.program_version); exit(1); } -#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS) init_extensions(); init_extensions4(); -#endif ret = ip46tables_restore_main(&ipt_restore_cb, argc, argv); @@ -416,10 +414,8 @@ ip6tables_restore_main(int argc, char *argv[]) ip6tables_globals.program_version); exit(1); } -#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS) init_extensions(); init_extensions6(); -#endif ret = ip46tables_restore_main(&ip6t_restore_cb, argc, argv); diff --git a/iptables/iptables-save.c b/iptables/iptables-save.c index 4efd6667..094adf22 100644 --- a/iptables/iptables-save.c +++ b/iptables/iptables-save.c @@ -61,8 +61,7 @@ for_each_table(int (*func)(struct iptables_save_cb *cb, const char *tablename), while (fgets(tablename, sizeof(tablename), procfile)) { if (tablename[strlen(tablename) - 1] != '\n') xtables_error(OTHER_PROBLEM, - "Badly formed tablename `%s'\n", - tablename); + "Badly formed tablename `%s'", tablename); tablename[strlen(tablename) - 1] = '\0'; ret &= func(cb, tablename); } @@ -85,7 +84,7 @@ static int do_output(struct iptables_save_cb *cb, const char *tablename) h = cb->ops->init(tablename); } if (!h) - xtables_error(OTHER_PROBLEM, "Cannot initialize: %s\n", + xtables_error(OTHER_PROBLEM, "Cannot initialize: %s", cb->ops->strerror(errno)); time_t now = time(NULL); @@ -173,7 +172,7 @@ do_iptables_save(struct iptables_save_cb *cb, int argc, char *argv[]) do_output(cb, tablename); exit(0); case 'V': - printf("%s v%s (legacy)\n", + printf("%s v%s\n", xt_params->program_name, xt_params->program_version); exit(0); @@ -227,10 +226,8 @@ iptables_save_main(int argc, char *argv[]) iptables_globals.program_version); exit(1); } -#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS) init_extensions(); init_extensions4(); -#endif ret = do_iptables_save(&ipt_save_cb, argc, argv); @@ -273,10 +270,8 @@ ip6tables_save_main(int argc, char *argv[]) ip6tables_globals.program_version); exit(1); } -#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS) init_extensions(); init_extensions6(); -#endif ret = do_iptables_save(&ip6t_save_cb, argc, argv); diff --git a/iptables/iptables-standalone.c b/iptables/iptables-standalone.c index 8c67ea4d..0f263f6f 100644 --- a/iptables/iptables-standalone.c +++ b/iptables/iptables-standalone.c @@ -53,10 +53,8 @@ iptables_main(int argc, char *argv[]) iptables_globals.program_version); exit(1); } -#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS) init_extensions(); init_extensions4(); -#endif ret = do_command4(argc, argv, &table, &handle, false); if (ret) { diff --git a/iptables/iptables-xml.c b/iptables/iptables-xml.c index 6cf059fb..396c0a12 100644 --- a/iptables/iptables-xml.c +++ b/iptables/iptables-xml.c @@ -210,8 +210,8 @@ saveChain(char *chain, char *policy, struct xt_counters *ctr) { if (nextChain >= maxChains) xtables_error(PARAMETER_PROBLEM, - "%s: line %u chain name invalid\n", - prog_name, line); + "%s: line %u chain name invalid", + prog_name, line); chains[nextChain].chain = xtables_strdup(chain); chains[nextChain].policy = xtables_strdup(policy); @@ -225,13 +225,13 @@ finishChains(void) { int c; - for (c = 0; c < nextChain; c++) - if (!chains[c].created) { + for (c = 0; c < nextChain; c++) { + if (!chains[c].created) openChain(chains[c].chain, chains[c].policy, &(chains[c].count), '/'); - free(chains[c].chain); - free(chains[c].policy); - } + free(chains[c].chain); + free(chains[c].policy); + } nextChain = 0; } @@ -610,8 +610,8 @@ iptables_xml_main(int argc, char *argv[]) DEBUGP("line %u, table '%s'\n", line, table); if (!table) xtables_error(PARAMETER_PROBLEM, - "%s: line %u table name invalid\n", - prog_name, line); + "%s: line %u table name invalid", + prog_name, line); openTable(table); @@ -626,8 +626,8 @@ iptables_xml_main(int argc, char *argv[]) DEBUGP("line %u, chain '%s'\n", line, chain); if (!chain) xtables_error(PARAMETER_PROBLEM, - "%s: line %u chain name invalid\n", - prog_name, line); + "%s: line %u chain name invalid", + prog_name, line); DEBUGP("Creating new chain '%s'\n", chain); @@ -635,8 +635,8 @@ iptables_xml_main(int argc, char *argv[]) DEBUGP("line %u, policy '%s'\n", line, policy); if (!policy) xtables_error(PARAMETER_PROBLEM, - "%s: line %u policy invalid\n", - prog_name, line); + "%s: line %u policy invalid", + prog_name, line); ctrs = strtok(NULL, " \t\n"); parse_counters(ctrs, &count); diff --git a/iptables/iptables.8.in b/iptables/iptables.8.in index 759ec54f..f81c632f 100644 --- a/iptables/iptables.8.in +++ b/iptables/iptables.8.in @@ -360,7 +360,11 @@ byte counters are also listed, with the suffix 'K', 'M' or 'G' for the \fB\-x\fP flag to change this). For appending, insertion, deletion and replacement, this causes detailed information on the rule or rules to be printed. \fB\-v\fP may be -specified multiple times to possibly emit more detailed debug statements. +specified multiple times to possibly emit more detailed debug statements: +Specified twice, \fBiptables-legacy\fP will dump table info and entries in +libiptc, \fBiptables-nft\fP dumps rules in netlink (VM code) presentation. +Specified three times, \fBiptables-nft\fP will also dump any netlink messages +sent to kernel. .TP \fB\-V\fP, \fB\-\-version\fP Show program version and the kernel API used. @@ -373,13 +377,6 @@ the program will exit if the lock cannot be obtained. This option will make the program wait (indefinitely or for optional \fIseconds\fP) until the exclusive lock can be obtained. .TP -\fB\-W\fP, \fB\-\-wait-interval\fP \fImicroseconds\fP -Interval to wait per each iteration. -When running latency sensitive applications, waiting for the xtables lock -for extended durations may not be acceptable. This option will make each -iteration take the amount of time specified. The default interval is -1 second. This option only works with \fB\-w\fP. -.TP \fB\-n\fP, \fB\-\-numeric\fP Numeric output. IP addresses and port numbers will be printed in numeric format. @@ -420,6 +417,11 @@ other errors cause an exit code of 1. .SH BUGS Bugs? What's this? ;-) Well, you might want to have a look at http://bugzilla.netfilter.org/ +\fBiptables\fP will exit immediately with an error code of 111 if it finds +that it was called as a setuid-to-root program. +iptables cannot be used safely in this manner because it trusts +the shared libraries (matches, targets) loaded at run time, the search +path can be set using environment variables. .SH COMPATIBILITY WITH IPCHAINS This \fBiptables\fP is very similar to ipchains by Rusty Russell. The main difference is diff --git a/iptables/iptables.c b/iptables/iptables.c index b925f089..6f7b3476 100644 --- a/iptables/iptables.c +++ b/iptables/iptables.c @@ -84,134 +84,13 @@ static struct option original_opts[] = { {NULL}, }; -void iptables_exit_error(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3))); - struct xtables_globals iptables_globals = { .option_offset = 0, - .program_version = PACKAGE_VERSION, + .program_version = PACKAGE_VERSION " (legacy)", .orig_opts = original_opts, - .exit_err = iptables_exit_error, .compat_rev = xtables_compatible_revision, }; -#define opts iptables_globals.opts -#define prog_name iptables_globals.program_name -#define prog_vers iptables_globals.program_version - -static void __attribute__((noreturn)) -exit_tryhelp(int status) -{ - if (line != -1) - fprintf(stderr, "Error occurred at line: %d\n", line); - fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n", - prog_name, prog_name); - xtables_free_opts(1); - exit(status); -} - -static void -exit_printhelp(const struct xtables_rule_match *matches) -{ - printf("%s v%s\n\n" -"Usage: %s -[ACD] chain rule-specification [options]\n" -" %s -I chain [rulenum] rule-specification [options]\n" -" %s -R chain rulenum rule-specification [options]\n" -" %s -D chain rulenum [options]\n" -" %s -[LS] [chain [rulenum]] [options]\n" -" %s -[FZ] [chain] [options]\n" -" %s -[NX] chain\n" -" %s -E old-chain-name new-chain-name\n" -" %s -P chain target [options]\n" -" %s -h (print this help information)\n\n", - prog_name, prog_vers, prog_name, prog_name, - prog_name, prog_name, prog_name, prog_name, - prog_name, prog_name, prog_name, prog_name); - - printf( -"Commands:\n" -"Either long or short options are allowed.\n" -" --append -A chain Append to chain\n" -" --check -C chain Check for the existence of a rule\n" -" --delete -D chain Delete matching rule from chain\n" -" --delete -D chain rulenum\n" -" Delete rule rulenum (1 = first) from chain\n" -" --insert -I chain [rulenum]\n" -" Insert in chain as rulenum (default 1=first)\n" -" --replace -R chain rulenum\n" -" Replace rule rulenum (1 = first) in chain\n" -" --list -L [chain [rulenum]]\n" -" List the rules in a chain or all chains\n" -" --list-rules -S [chain [rulenum]]\n" -" Print the rules in a chain or all chains\n" -" --flush -F [chain] Delete all rules in chain or all chains\n" -" --zero -Z [chain [rulenum]]\n" -" Zero counters in chain or all chains\n" -" --new -N chain Create a new user-defined chain\n" -" --delete-chain\n" -" -X [chain] Delete a user-defined chain\n" -" --policy -P chain target\n" -" Change policy on chain to target\n" -" --rename-chain\n" -" -E old-chain new-chain\n" -" Change chain name, (moving any references)\n" - -"Options:\n" -" --ipv4 -4 Nothing (line is ignored by ip6tables-restore)\n" -" --ipv6 -6 Error (line is ignored by iptables-restore)\n" -"[!] --protocol -p proto protocol: by number or name, eg. `tcp'\n" -"[!] --source -s address[/mask][...]\n" -" source specification\n" -"[!] --destination -d address[/mask][...]\n" -" destination specification\n" -"[!] --in-interface -i input name[+]\n" -" network interface name ([+] for wildcard)\n" -" --jump -j target\n" -" target for rule (may load target extension)\n" -#ifdef IPT_F_GOTO -" --goto -g chain\n" -" jump to chain with no return\n" -#endif -" --match -m match\n" -" extended match (may load extension)\n" -" --numeric -n numeric output of addresses and ports\n" -"[!] --out-interface -o output name[+]\n" -" network interface name ([+] for wildcard)\n" -" --table -t table table to manipulate (default: `filter')\n" -" --verbose -v verbose mode\n" -" --wait -w [seconds] maximum wait to acquire xtables lock before give up\n" -" --wait-interval -W [usecs] wait time to try to acquire xtables lock\n" -" default is 1 second\n" -" --line-numbers print line numbers when listing\n" -" --exact -x expand numbers (display exact values)\n" -"[!] --fragment -f match second or further fragments only\n" -" --modprobe=<command> try to insert modules using this command\n" -" --set-counters PKTS BYTES set the counter during insert/append\n" -"[!] --version -V print package version.\n"); - - print_extension_helps(xtables_targets, matches); - exit(0); -} - -void -iptables_exit_error(enum xtables_exittype status, const char *msg, ...) -{ - va_list args; - - va_start(args, msg); - fprintf(stderr, "%s v%s (legacy): ", prog_name, prog_vers); - vfprintf(stderr, msg, args); - va_end(args); - fprintf(stderr, "\n"); - if (status == PARAMETER_PROBLEM) - exit_tryhelp(status); - if (status == VERSION_PROBLEM) - fprintf(stderr, - "Perhaps iptables or your kernel needs to be upgraded.\n"); - /* On error paths, make sure that we don't leak memory */ - xtables_free_opts(1); - exit(status); -} - /* * All functions starting with "parse" should succeed, otherwise * the program fails. @@ -223,81 +102,6 @@ iptables_exit_error(enum xtables_exittype status, const char *msg, ...) /* Christophe Burki wants `-p 6' to imply `-m tcp'. */ -static void -parse_chain(const char *chainname) -{ - const char *ptr; - - if (strlen(chainname) >= XT_EXTENSION_MAXNAMELEN) - xtables_error(PARAMETER_PROBLEM, - "chain name `%s' too long (must be under %u chars)", - chainname, XT_EXTENSION_MAXNAMELEN); - - if (*chainname == '-' || *chainname == '!') - xtables_error(PARAMETER_PROBLEM, - "chain name not allowed to start " - "with `%c'\n", *chainname); - - if (xtables_find_target(chainname, XTF_TRY_LOAD)) - xtables_error(PARAMETER_PROBLEM, - "chain name may not clash " - "with target name\n"); - - for (ptr = chainname; *ptr; ptr++) - if (isspace(*ptr)) - xtables_error(PARAMETER_PROBLEM, - "Invalid chain name `%s'", chainname); -} - -static void -print_header(unsigned int format, const char *chain, struct xtc_handle *handle) -{ - struct xt_counters counters; - const char *pol = iptc_get_policy(chain, &counters, handle); - printf("Chain %s", chain); - if (pol) { - printf(" (policy %s", pol); - if (!(format & FMT_NOCOUNTS)) { - fputc(' ', stdout); - xtables_print_num(counters.pcnt, (format|FMT_NOTABLE)); - fputs("packets, ", stdout); - xtables_print_num(counters.bcnt, (format|FMT_NOTABLE)); - fputs("bytes", stdout); - } - printf(")\n"); - } else { - unsigned int refs; - if (!iptc_get_references(&refs, chain, handle)) - printf(" (ERROR obtaining refs)\n"); - else - printf(" (%u references)\n", refs); - } - - if (format & FMT_LINENUMBERS) - printf(FMT("%-4s ", "%s "), "num"); - if (!(format & FMT_NOCOUNTS)) { - if (format & FMT_KILOMEGAGIGA) { - printf(FMT("%5s ","%s "), "pkts"); - printf(FMT("%5s ","%s "), "bytes"); - } else { - printf(FMT("%8s ","%s "), "pkts"); - printf(FMT("%10s ","%s "), "bytes"); - } - } - if (!(format & FMT_NOTARGET)) - printf(FMT("%-9s ","%s "), "target"); - fputs(" prot ", stdout); - if (format & FMT_OPTIONS) - fputs("opt", stdout); - if (format & FMT_VIA) { - printf(FMT(" %-6s ","%s "), "in"); - printf(FMT("%-6s ","%s "), "out"); - } - printf(FMT(" %-19s ","%s "), "source"); - printf(FMT(" %-19s "," %s "), "destination"); - printf("\n"); -} - static int print_match(const struct xt_entry_match *m, @@ -318,6 +122,9 @@ print_match(const struct xt_entry_match *m, printf("%s%s ", match->name, unsupported_rev); else printf("%s ", match->name); + + if (match->next == match) + free(match); } else { if (name[0]) printf("UNKNOWN match `%s' ", name); @@ -336,7 +143,6 @@ print_firewall(const struct ipt_entry *fw, { struct xtables_target *target, *tg; const struct xt_entry_target *t; - uint8_t flags; if (!iptc_is_chain(targname, handle)) target = xtables_find_target(targname, XTF_TRY_LOAD); @@ -345,35 +151,11 @@ print_firewall(const struct ipt_entry *fw, XTF_LOAD_MUST_SUCCEED); t = ipt_get_target((struct ipt_entry *)fw); - flags = fw->ip.flags; - - if (format & FMT_LINENUMBERS) - printf(FMT("%-4u ", "%u "), num); - - if (!(format & FMT_NOCOUNTS)) { - xtables_print_num(fw->counters.pcnt, format); - xtables_print_num(fw->counters.bcnt, format); - } - if (!(format & FMT_NOTARGET)) - printf(FMT("%-9s ", "%s "), targname); + print_rule_details(num, &fw->counters, targname, fw->ip.proto, + fw->ip.flags, fw->ip.invflags, format); - fputc(fw->ip.invflags & XT_INV_PROTO ? '!' : ' ', stdout); - { - const char *pname = proto_to_name(fw->ip.proto, format&FMT_NUMERIC); - if (pname) - printf(FMT("%-5s", "%s "), pname); - else - printf(FMT("%-5hu", "%hu "), fw->ip.proto); - } - - if (format & FMT_OPTIONS) { - if (format & FMT_NOTABLE) - fputs("opt ", stdout); - fputc(fw->ip.invflags & IPT_INV_FRAG ? '!' : '-', stdout); - fputc(flags & IPT_F_FRAG ? 'f' : '-', stdout); - fputc(' ', stdout); - } + print_fragment(fw->ip.flags, fw->ip.invflags, format, false); print_ifaces(fw->ip.iniface, fw->ip.outiface, fw->ip.invflags, format); @@ -399,6 +181,9 @@ print_firewall(const struct ipt_entry *fw, tg->print(&fw->ip, t, format & FMT_NUMERIC); else if (target->print) printf(" %s%s", target->name, unsupported_rev); + + if (target->next == target) + free(target); } else if (t->u.target_size != sizeof(*t)) printf("[%u bytes of unknown target data] ", (unsigned int)(t->u.target_size - sizeof(*t))); @@ -497,40 +282,6 @@ insert_entry(const xt_chainlabel chain, return ret; } -static unsigned char * -make_delete_mask(const struct xtables_rule_match *matches, - const struct xtables_target *target) -{ - /* Establish mask for comparison */ - unsigned int size; - const struct xtables_rule_match *matchp; - unsigned char *mask, *mptr; - - size = sizeof(struct ipt_entry); - for (matchp = matches; matchp; matchp = matchp->next) - size += XT_ALIGN(sizeof(struct xt_entry_match)) + matchp->match->size; - - mask = xtables_calloc(1, size - + XT_ALIGN(sizeof(struct xt_entry_target)) - + target->size); - - memset(mask, 0xFF, sizeof(struct ipt_entry)); - mptr = mask + sizeof(struct ipt_entry); - - for (matchp = matches; matchp; matchp = matchp->next) { - memset(mptr, 0xFF, - XT_ALIGN(sizeof(struct xt_entry_match)) - + matchp->match->userspacesize); - mptr += XT_ALIGN(sizeof(struct xt_entry_match)) + matchp->match->size; - } - - memset(mptr, 0xFF, - XT_ALIGN(sizeof(struct xt_entry_target)) - + target->userspacesize); - - return mask; -} - static int delete_entry(const xt_chainlabel chain, struct ipt_entry *fw, @@ -549,7 +300,7 @@ delete_entry(const xt_chainlabel chain, int ret = 1; unsigned char *mask; - mask = make_delete_mask(matches, target); + mask = make_delete_mask(matches, target, sizeof(*fw)); for (i = 0; i < nsaddrs; i++) { fw->ip.src.s_addr = saddrs[i].s_addr; fw->ip.smsk.s_addr = smasks[i].s_addr; @@ -579,7 +330,7 @@ check_entry(const xt_chainlabel chain, struct ipt_entry *fw, int ret = 1; unsigned char *mask; - mask = make_delete_mask(matches, target); + mask = make_delete_mask(matches, target, sizeof(*fw)); for (i = 0; i < nsaddrs; i++) { fw->ip.src.s_addr = saddrs[i].s_addr; fw->ip.smsk.s_addr = smasks[i].s_addr; @@ -702,8 +453,18 @@ list_entries(const xt_chainlabel chain, int rulenum, int verbose, int numeric, if (found) printf("\n"); - if (!rulenum) - print_header(format, this, handle); + if (!rulenum) { + struct xt_counters counters; + unsigned int urefs; + const char *pol; + int refs = -1; + + pol = iptc_get_policy(this, &counters, handle); + if (!pol && iptc_get_references(&urefs, this, handle)) + refs = urefs; + + print_header(format, this, pol, &counters, refs, 0); + } i = iptc_first_rule(this, handle); num = 0; @@ -724,19 +485,6 @@ list_entries(const xt_chainlabel chain, int rulenum, int verbose, int numeric, return found; } -static void print_proto(uint16_t proto, int invert) -{ - if (proto) { - const char *pname = proto_to_name(proto, 0); - const char *invertstr = invert ? " !" : ""; - - if (pname) - printf("%s -p %s", invertstr, pname); - else - printf("%s -p %u", invertstr, proto); - } -} - #define IP_PARTS_NATIVE(n) \ (unsigned int)((n)>>24)&0xFF, \ (unsigned int)((n)>>16)&0xFF, \ @@ -745,93 +493,6 @@ static void print_proto(uint16_t proto, int invert) #define IP_PARTS(n) IP_PARTS_NATIVE(ntohl(n)) -/* This assumes that mask is contiguous, and byte-bounded. */ -static void -print_iface(char letter, const char *iface, const unsigned char *mask, - int invert) -{ - unsigned int i; - - if (mask[0] == 0) - return; - - printf("%s -%c ", invert ? " !" : "", letter); - - for (i = 0; i < IFNAMSIZ; i++) { - if (mask[i] != 0) { - if (iface[i] != '\0') - printf("%c", iface[i]); - } else { - /* we can access iface[i-1] here, because - * a few lines above we make sure that mask[0] != 0 */ - if (iface[i-1] != '\0') - printf("+"); - break; - } - } -} - -static int print_match_save(const struct xt_entry_match *e, - const struct ipt_ip *ip) -{ - const char *name = e->u.user.name; - const int revision = e->u.user.revision; - struct xtables_match *match, *mt, *mt2; - - match = xtables_find_match(name, XTF_TRY_LOAD, NULL); - if (match) { - mt = mt2 = xtables_find_match_revision(name, XTF_TRY_LOAD, - match, revision); - if (!mt2) - mt2 = match; - printf(" -m %s", mt2->alias ? mt2->alias(e) : name); - - /* some matches don't provide a save function */ - if (mt && mt->save) - mt->save(ip, e); - else if (match->save) - printf(unsupported_rev); - } else { - if (e->u.match_size) { - fprintf(stderr, - "Can't find library for match `%s'\n", - name); - exit(1); - } - } - return 0; -} - -/* Print a given ip including mask if necessary. */ -static void print_ip(const char *prefix, uint32_t ip, - uint32_t mask, int invert) -{ - uint32_t bits, hmask = ntohl(mask); - int i; - - if (!mask && !ip && !invert) - return; - - printf("%s %s %u.%u.%u.%u", - invert ? " !" : "", - prefix, - IP_PARTS(ip)); - - if (mask == 0xFFFFFFFFU) { - printf("/32"); - return; - } - - i = 32; - bits = 0xFFFFFFFEU; - while (--i >= 0 && hmask != bits) - bits <<= 1; - if (i >= 0) - printf("/%u", i); - else - printf("/%u.%u.%u.%u", IP_PARTS(mask)); -} - /* We want this to be readable, so only print out necessary fields. * Because that's the kind of world I want to live in. */ @@ -849,23 +510,16 @@ void print_rule4(const struct ipt_entry *e, printf("-A %s", chain); /* Print IP part. */ - print_ip("-s", e->ip.src.s_addr,e->ip.smsk.s_addr, - e->ip.invflags & IPT_INV_SRCIP); + save_ipv4_addr('s', &e->ip.src, &e->ip.smsk, + e->ip.invflags & IPT_INV_SRCIP); - print_ip("-d", e->ip.dst.s_addr, e->ip.dmsk.s_addr, + save_ipv4_addr('d', &e->ip.dst, &e->ip.dmsk, e->ip.invflags & IPT_INV_DSTIP); - print_iface('i', e->ip.iniface, e->ip.iniface_mask, - e->ip.invflags & IPT_INV_VIA_IN); - - print_iface('o', e->ip.outiface, e->ip.outiface_mask, - e->ip.invflags & IPT_INV_VIA_OUT); - - print_proto(e->ip.proto, e->ip.invflags & XT_INV_PROTO); - - if (e->ip.flags & IPT_F_FRAG) - printf("%s -f", - e->ip.invflags & IPT_INV_FRAG ? " !" : ""); + save_rule_details(e->ip.iniface, e->ip.iniface_mask, + e->ip.outiface, e->ip.outiface_mask, + e->ip.proto, e->ip.flags & IPT_F_FRAG, + e->ip.invflags); /* Print matchinfo part */ if (e->target_offset) @@ -1006,448 +660,54 @@ generate_entry(const struct ipt_entry *fw, int do_command4(int argc, char *argv[], char **table, struct xtc_handle **handle, bool restore) { + struct xt_cmd_parse_ops cmd_parse_ops = { + .proto_parse = ipv4_proto_parse, + .post_parse = ipv4_post_parse, + }; + struct xt_cmd_parse p = { + .table = *table, + .restore = restore, + .line = line, + .ops = &cmd_parse_ops, + }; struct iptables_command_state cs = { .jumpto = "", .argv = argv, }; + struct xtables_args args = { + .family = AF_INET, + }; struct ipt_entry *e = NULL; unsigned int nsaddrs = 0, ndaddrs = 0; struct in_addr *saddrs = NULL, *smasks = NULL; struct in_addr *daddrs = NULL, *dmasks = NULL; - struct timeval wait_interval = { - .tv_sec = 1, - }; - bool wait_interval_set = false; int verbose = 0; int wait = 0; const char *chain = NULL; - const char *shostnetworkmask = NULL, *dhostnetworkmask = NULL; const char *policy = NULL, *newname = NULL; unsigned int rulenum = 0, command = 0; - const char *pcnt = NULL, *bcnt = NULL; int ret = 1; - struct xtables_match *m; - struct xtables_rule_match *matchp; - struct xtables_target *t; - unsigned long long cnt; - bool table_set = false; - uint16_t invflags = 0; - bool invert = false; - - /* re-set optind to 0 in case do_command4 gets called - * a second time */ - optind = 0; - - /* clear mflags in case do_command4 gets called a second time - * (we clear the global list of all matches for security)*/ - for (m = xtables_matches; m; m = m->next) - m->mflags = 0; - - for (t = xtables_targets; t; t = t->next) { - t->tflags = 0; - t->used = 0; - } - - /* Suppress error messages: we may add new options if we - demand-load a protocol. */ - opterr = 0; - opts = xt_params->orig_opts; - while ((cs.c = getopt_long(argc, argv, - "-:A:C:D:R:I:L::S::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:fbvw::W::nt:m:xc:g:46", - opts, NULL)) != -1) { - switch (cs.c) { - /* - * Command selection - */ - case 'A': - add_command(&command, CMD_APPEND, CMD_NONE, invert); - chain = optarg; - break; - - case 'C': - add_command(&command, CMD_CHECK, CMD_NONE, invert); - chain = optarg; - break; - - case 'D': - add_command(&command, CMD_DELETE, CMD_NONE, invert); - chain = optarg; - if (xs_has_arg(argc, argv)) { - rulenum = parse_rulenumber(argv[optind++]); - command = CMD_DELETE_NUM; - } - break; - - case 'R': - add_command(&command, CMD_REPLACE, CMD_NONE, invert); - chain = optarg; - if (xs_has_arg(argc, argv)) - rulenum = parse_rulenumber(argv[optind++]); - else - xtables_error(PARAMETER_PROBLEM, - "-%c requires a rule number", - cmd2char(CMD_REPLACE)); - break; - - case 'I': - add_command(&command, CMD_INSERT, CMD_NONE, invert); - chain = optarg; - if (xs_has_arg(argc, argv)) - rulenum = parse_rulenumber(argv[optind++]); - else rulenum = 1; - break; - - case 'L': - add_command(&command, CMD_LIST, - CMD_ZERO | CMD_ZERO_NUM, invert); - if (optarg) chain = optarg; - else if (xs_has_arg(argc, argv)) - chain = argv[optind++]; - if (xs_has_arg(argc, argv)) - rulenum = parse_rulenumber(argv[optind++]); - break; - - case 'S': - add_command(&command, CMD_LIST_RULES, - CMD_ZERO|CMD_ZERO_NUM, invert); - if (optarg) chain = optarg; - else if (xs_has_arg(argc, argv)) - chain = argv[optind++]; - if (xs_has_arg(argc, argv)) - rulenum = parse_rulenumber(argv[optind++]); - break; - - case 'F': - add_command(&command, CMD_FLUSH, CMD_NONE, invert); - if (optarg) chain = optarg; - else if (xs_has_arg(argc, argv)) - chain = argv[optind++]; - break; - - case 'Z': - add_command(&command, CMD_ZERO, CMD_LIST|CMD_LIST_RULES, - invert); - if (optarg) chain = optarg; - else if (xs_has_arg(argc, argv)) - chain = argv[optind++]; - if (xs_has_arg(argc, argv)) { - rulenum = parse_rulenumber(argv[optind++]); - command = CMD_ZERO_NUM; - } - break; - - case 'N': - parse_chain(optarg); - add_command(&command, CMD_NEW_CHAIN, CMD_NONE, invert); - chain = optarg; - break; - - case 'X': - add_command(&command, CMD_DELETE_CHAIN, CMD_NONE, - invert); - if (optarg) chain = optarg; - else if (xs_has_arg(argc, argv)) - chain = argv[optind++]; - break; - - case 'E': - add_command(&command, CMD_RENAME_CHAIN, CMD_NONE, - invert); - chain = optarg; - if (xs_has_arg(argc, argv)) - newname = argv[optind++]; - else - xtables_error(PARAMETER_PROBLEM, - "-%c requires old-chain-name and " - "new-chain-name", - cmd2char(CMD_RENAME_CHAIN)); - break; - - case 'P': - add_command(&command, CMD_SET_POLICY, CMD_NONE, - invert); - chain = optarg; - if (xs_has_arg(argc, argv)) - policy = argv[optind++]; - else - xtables_error(PARAMETER_PROBLEM, - "-%c requires a chain and a policy", - cmd2char(CMD_SET_POLICY)); - break; - - case 'h': - if (!optarg) - optarg = argv[optind]; - - /* iptables -p icmp -h */ - if (!cs.matches && cs.protocol) - xtables_find_match(cs.protocol, - XTF_TRY_LOAD, &cs.matches); - - exit_printhelp(cs.matches); - - /* - * Option selection - */ - case 'p': - set_option(&cs.options, OPT_PROTOCOL, &invflags, - invert); - - /* Canonicalize into lower case */ - for (cs.protocol = optarg; *cs.protocol; cs.protocol++) - *cs.protocol = tolower(*cs.protocol); - - cs.protocol = optarg; - cs.fw.ip.proto = xtables_parse_protocol(cs.protocol); - - if (cs.fw.ip.proto == 0 && (invflags & XT_INV_PROTO)) - xtables_error(PARAMETER_PROBLEM, - "rule would never match protocol"); - break; - case 's': - set_option(&cs.options, OPT_SOURCE, &invflags, invert); - shostnetworkmask = optarg; - break; - - case 'd': - set_option(&cs.options, OPT_DESTINATION, &invflags, - invert); - dhostnetworkmask = optarg; - break; - -#ifdef IPT_F_GOTO - case 'g': - set_option(&cs.options, OPT_JUMP, &invflags, invert); - cs.fw.ip.flags |= IPT_F_GOTO; - cs.jumpto = xt_parse_target(optarg); - break; -#endif - - case 'j': - set_option(&cs.options, OPT_JUMP, &invflags, invert); - command_jump(&cs, optarg); - break; - - - case 'i': - if (*optarg == '\0') - xtables_error(PARAMETER_PROBLEM, - "Empty interface is likely to be " - "undesired"); - set_option(&cs.options, OPT_VIANAMEIN, &invflags, - invert); - xtables_parse_interface(optarg, - cs.fw.ip.iniface, - cs.fw.ip.iniface_mask); - break; - - case 'o': - if (*optarg == '\0') - xtables_error(PARAMETER_PROBLEM, - "Empty interface is likely to be " - "undesired"); - set_option(&cs.options, OPT_VIANAMEOUT, &invflags, - invert); - xtables_parse_interface(optarg, - cs.fw.ip.outiface, - cs.fw.ip.outiface_mask); - break; - - case 'f': - set_option(&cs.options, OPT_FRAGMENT, &invflags, - invert); - cs.fw.ip.flags |= IPT_F_FRAG; - break; - - case 'v': - if (!verbose) - set_option(&cs.options, OPT_VERBOSE, - &invflags, invert); - verbose++; - break; - - case 'w': - if (restore) { - xtables_error(PARAMETER_PROBLEM, - "You cannot use `-w' from " - "iptables-restore"); - } - wait = parse_wait_time(argc, argv); - break; - - case 'W': - if (restore) { - xtables_error(PARAMETER_PROBLEM, - "You cannot use `-W' from " - "iptables-restore"); - } - parse_wait_interval(argc, argv, &wait_interval); - wait_interval_set = true; - break; - - case 'm': - command_match(&cs, invert); - break; - - case 'n': - set_option(&cs.options, OPT_NUMERIC, &invflags, - invert); - break; - - case 't': - if (invert) - xtables_error(PARAMETER_PROBLEM, - "unexpected ! flag before --table"); - if (restore && table_set) - xtables_error(PARAMETER_PROBLEM, - "The -t option (seen in line %u) cannot be used in %s.\n", - line, xt_params->program_name); - *table = optarg; - table_set = true; - break; - - case 'x': - set_option(&cs.options, OPT_EXPANDED, &invflags, - invert); - break; - - case 'V': - if (invert) - printf("Not %s ;-)\n", prog_vers); - else - printf("%s v%s (legacy)\n", - prog_name, prog_vers); - exit(0); - - case '0': - set_option(&cs.options, OPT_LINENUMBERS, &invflags, - invert); - break; - - case 'M': - xtables_modprobe_program = optarg; - break; - - case 'c': - - set_option(&cs.options, OPT_COUNTERS, &invflags, - invert); - pcnt = optarg; - bcnt = strchr(pcnt + 1, ','); - if (bcnt) - bcnt++; - if (!bcnt && xs_has_arg(argc, argv)) - bcnt = argv[optind++]; - if (!bcnt) - xtables_error(PARAMETER_PROBLEM, - "-%c requires packet and byte counter", - opt2char(OPT_COUNTERS)); - - if (sscanf(pcnt, "%llu", &cnt) != 1) - xtables_error(PARAMETER_PROBLEM, - "-%c packet counter not numeric", - opt2char(OPT_COUNTERS)); - cs.fw.counters.pcnt = cnt; - - if (sscanf(bcnt, "%llu", &cnt) != 1) - xtables_error(PARAMETER_PROBLEM, - "-%c byte counter not numeric", - opt2char(OPT_COUNTERS)); - cs.fw.counters.bcnt = cnt; - break; - - case '4': - /* This is indeed the IPv4 iptables */ - break; - - case '6': - /* This is not the IPv6 ip6tables */ - if (line != -1) - return 1; /* success: line ignored */ - fprintf(stderr, "This is the IPv4 version of iptables.\n"); - exit_tryhelp(2); - - case 1: /* non option */ - if (optarg[0] == '!' && optarg[1] == '\0') { - if (invert) - xtables_error(PARAMETER_PROBLEM, - "multiple consecutive ! not" - " allowed"); - invert = true; - optarg[0] = '\0'; - continue; - } - fprintf(stderr, "Bad argument `%s'\n", optarg); - exit_tryhelp(2); - - default: - if (command_default(&cs, &iptables_globals, invert)) - /* cf. ip6tables.c */ - continue; - break; - } - invert = false; - } - - if (!wait && wait_interval_set) - xtables_error(PARAMETER_PROBLEM, - "--wait-interval only makes sense with --wait\n"); - - if (strcmp(*table, "nat") == 0 && - ((policy != NULL && strcmp(policy, "DROP") == 0) || - (cs.jumpto != NULL && strcmp(cs.jumpto, "DROP") == 0))) - xtables_error(PARAMETER_PROBLEM, - "\nThe \"nat\" table is not intended for filtering, " - "the use of DROP is therefore inhibited.\n\n"); - - for (matchp = cs.matches; matchp; matchp = matchp->next) - xtables_option_mfcall(matchp->match); - if (cs.target != NULL) - xtables_option_tfcall(cs.target); - - /* Fix me: must put inverse options checking here --MN */ - - if (optind < argc) - xtables_error(PARAMETER_PROBLEM, - "unknown arguments found on commandline"); - if (!command) - xtables_error(PARAMETER_PROBLEM, "no command specified"); - if (invert) - xtables_error(PARAMETER_PROBLEM, - "nothing appropriate following !"); - - cs.fw.ip.invflags = invflags; - - if (command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND | CMD_CHECK)) { - if (!(cs.options & OPT_DESTINATION)) - dhostnetworkmask = "0.0.0.0/0"; - if (!(cs.options & OPT_SOURCE)) - shostnetworkmask = "0.0.0.0/0"; - } - - if (shostnetworkmask) - xtables_ipparse_multiple(shostnetworkmask, &saddrs, - &smasks, &nsaddrs); - - if (dhostnetworkmask) - xtables_ipparse_multiple(dhostnetworkmask, &daddrs, - &dmasks, &ndaddrs); - - if ((nsaddrs > 1 || ndaddrs > 1) && - (cs.fw.ip.invflags & (IPT_INV_SRCIP | IPT_INV_DSTIP))) - xtables_error(PARAMETER_PROBLEM, "! not allowed with multiple" - " source or destination IP addresses"); - - if (command == CMD_REPLACE && (nsaddrs != 1 || ndaddrs != 1)) - xtables_error(PARAMETER_PROBLEM, "Replacement rule does not " - "specify a unique address"); - - generic_opt_check(command, cs.options); + do_parse(argc, argv, &p, &cs, &args); + + command = p.command; + chain = p.chain; + *table = p.table; + rulenum = p.rulenum; + policy = p.policy; + newname = p.newname; + verbose = p.verbose; + wait = args.wait; + nsaddrs = args.s.naddrs; + ndaddrs = args.d.naddrs; + saddrs = args.s.addr.v4; + daddrs = args.d.addr.v4; + smasks = args.s.mask.v4; + dmasks = args.d.mask.v4; /* Attempt to acquire the xtables lock */ if (!restore) - xtables_lock_or_exit(wait, &wait_interval); + xtables_lock_or_exit(wait); /* only allocate handle if we weren't called with a handle */ if (!*handle) @@ -1467,26 +727,6 @@ int do_command4(int argc, char *argv[], char **table, || command == CMD_CHECK || command == CMD_INSERT || command == CMD_REPLACE) { - if (strcmp(chain, "PREROUTING") == 0 - || strcmp(chain, "INPUT") == 0) { - /* -o not valid with incoming packets. */ - if (cs.options & OPT_VIANAMEOUT) - xtables_error(PARAMETER_PROBLEM, - "Can't use -%c with %s\n", - opt2char(OPT_VIANAMEOUT), - chain); - } - - if (strcmp(chain, "POSTROUTING") == 0 - || strcmp(chain, "OUTPUT") == 0) { - /* -i not valid with outgoing packets */ - if (cs.options & OPT_VIANAMEIN) - xtables_error(PARAMETER_PROBLEM, - "Can't use -%c with %s\n", - opt2char(OPT_VIANAMEIN), - chain); - } - if (cs.target && iptc_is_chain(cs.jumpto, *handle)) { fprintf(stderr, "Warning: using chain %s, not extension\n", @@ -1527,13 +767,12 @@ int do_command4(int argc, char *argv[], char **table, #ifdef IPT_F_GOTO if (cs.fw.ip.flags & IPT_F_GOTO) xtables_error(PARAMETER_PROBLEM, - "goto '%s' is not a chain\n", - cs.jumpto); + "goto '%s' is not a chain", + cs.jumpto); #endif xtables_find_target(cs.jumpto, XTF_LOAD_MUST_SUCCEED); } else { e = generate_entry(&cs.fw, cs.matches, cs.target->t); - free(cs.target->t); } } @@ -1624,15 +863,18 @@ int do_command4(int argc, char *argv[], char **table, case CMD_SET_POLICY: ret = iptc_set_policy(chain, policy, cs.options&OPT_COUNTERS ? &cs.fw.counters : NULL, *handle); break; + case CMD_NONE: + /* do_parse ignored the line (eg: -4 with ip6tables-restore) */ + break; default: /* We should never reach this... */ - exit_tryhelp(2); + exit_tryhelp(2, line); } if (verbose > 1) dump_entries(*handle); - xtables_rule_matches_free(&cs.matches); + xtables_clear_iptables_command_state(&cs); if (e != NULL) { free(e); diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c index 2a9387a1..210f43d2 100644 --- a/iptables/nft-arp.c +++ b/iptables/nft-arp.c @@ -25,22 +25,8 @@ #include <linux/netfilter/nf_tables.h> #include "nft-shared.h" -#include "nft-arp.h" #include "nft.h" - -/* a few names */ -char *arp_opcodes[] = -{ - "Request", - "Reply", - "Request_Reverse", - "Reply_Reverse", - "DRARP_Request", - "DRARP_Reply", - "DRARP_Error", - "InARP_Request", - "ARP_NAK", -}; +#include "xshared.h" static bool need_devaddr(struct arpt_devaddr_info *info) { @@ -54,59 +40,65 @@ static bool need_devaddr(struct arpt_devaddr_info *info) return false; } -static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, void *data) +static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, + struct iptables_command_state *cs) { - struct iptables_command_state *cs = data; struct arpt_entry *fw = &cs->arp; uint32_t op; int ret = 0; if (fw->arp.iniface[0] != '\0') { op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_VIA_IN); - add_iniface(r, fw->arp.iniface, op); + add_iniface(h, r, fw->arp.iniface, op); } if (fw->arp.outiface[0] != '\0') { op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_VIA_OUT); - add_outiface(r, fw->arp.outiface, op); + add_outiface(h, r, fw->arp.outiface, op); } if (fw->arp.arhrd != 0 || fw->arp.invflags & IPT_INV_ARPHRD) { + uint8_t reg; + op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_ARPHRD); - add_payload(r, offsetof(struct arphdr, ar_hrd), 2, - NFT_PAYLOAD_NETWORK_HEADER); - add_cmp_u16(r, fw->arp.arhrd, op); + add_payload(h, r, offsetof(struct arphdr, ar_hrd), 2, + NFT_PAYLOAD_NETWORK_HEADER, ®); + add_cmp_u16(r, fw->arp.arhrd, op, reg); } if (fw->arp.arpro != 0 || fw->arp.invflags & IPT_INV_PROTO) { + uint8_t reg; + op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_PROTO); - add_payload(r, offsetof(struct arphdr, ar_pro), 2, - NFT_PAYLOAD_NETWORK_HEADER); - add_cmp_u16(r, fw->arp.arpro, op); + add_payload(h, r, offsetof(struct arphdr, ar_pro), 2, + NFT_PAYLOAD_NETWORK_HEADER, ®); + add_cmp_u16(r, fw->arp.arpro, op, reg); } if (fw->arp.arhln != 0 || fw->arp.invflags & IPT_INV_ARPHLN) { op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_ARPHLN); - add_proto(r, offsetof(struct arphdr, ar_hln), 1, + add_proto(h, r, offsetof(struct arphdr, ar_hln), 1, fw->arp.arhln, op); } - add_proto(r, offsetof(struct arphdr, ar_pln), 1, 4, NFT_CMP_EQ); + add_proto(h, r, offsetof(struct arphdr, ar_pln), 1, 4, NFT_CMP_EQ); if (fw->arp.arpop != 0 || fw->arp.invflags & IPT_INV_ARPOP) { + uint8_t reg; + op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_ARPOP); - add_payload(r, offsetof(struct arphdr, ar_op), 2, - NFT_PAYLOAD_NETWORK_HEADER); - add_cmp_u16(r, fw->arp.arpop, op); + add_payload(h, r, offsetof(struct arphdr, ar_op), 2, + NFT_PAYLOAD_NETWORK_HEADER, ®); + add_cmp_u16(r, fw->arp.arpop, op, reg); } if (need_devaddr(&fw->arp.src_devaddr)) { op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_SRCDEVADDR); - add_addr(r, NFT_PAYLOAD_NETWORK_HEADER, + add_addr(h, r, NFT_PAYLOAD_NETWORK_HEADER, sizeof(struct arphdr), &fw->arp.src_devaddr.addr, &fw->arp.src_devaddr.mask, @@ -118,7 +110,7 @@ static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, void *data) fw->arp.smsk.s_addr != 0 || fw->arp.invflags & IPT_INV_SRCIP) { op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_SRCIP); - add_addr(r, NFT_PAYLOAD_NETWORK_HEADER, + add_addr(h, r, NFT_PAYLOAD_NETWORK_HEADER, sizeof(struct arphdr) + fw->arp.arhln, &fw->arp.src.s_addr, &fw->arp.smsk.s_addr, sizeof(struct in_addr), op); @@ -127,7 +119,7 @@ static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, void *data) if (need_devaddr(&fw->arp.tgt_devaddr)) { op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_TGTDEVADDR); - add_addr(r, NFT_PAYLOAD_NETWORK_HEADER, + add_addr(h, r, NFT_PAYLOAD_NETWORK_HEADER, sizeof(struct arphdr) + fw->arp.arhln + sizeof(struct in_addr), &fw->arp.tgt_devaddr.addr, &fw->arp.tgt_devaddr.mask, @@ -138,7 +130,7 @@ static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, void *data) fw->arp.tmsk.s_addr != 0 || fw->arp.invflags & IPT_INV_DSTIP) { op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_DSTIP); - add_addr(r, NFT_PAYLOAD_NETWORK_HEADER, + add_addr(h, r, NFT_PAYLOAD_NETWORK_HEADER, sizeof(struct arphdr) + fw->arp.arhln + sizeof(struct in_addr) + fw->arp.arhln, &fw->arp.tgt.s_addr, &fw->arp.tmsk.s_addr, sizeof(struct in_addr), op); @@ -168,34 +160,30 @@ static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, void *data) return ret; } -static void nft_arp_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e, - void *data) +static void nft_arp_parse_meta(struct nft_xt_ctx *ctx, + const struct nft_xt_ctx_reg *reg, + struct nftnl_expr *e, + struct iptables_command_state *cs) { - struct iptables_command_state *cs = data; struct arpt_entry *fw = &cs->arp; uint8_t flags = 0; - parse_meta(e, ctx->meta.key, fw->arp.iniface, fw->arp.iniface_mask, + if (parse_meta(ctx, e, reg->meta_dreg.key, fw->arp.iniface, fw->arp.iniface_mask, fw->arp.outiface, fw->arp.outiface_mask, - &flags); - - fw->arp.invflags |= flags; -} - -static void nft_arp_parse_immediate(const char *jumpto, bool nft_goto, - void *data) -{ - struct iptables_command_state *cs = data; + &flags) == 0) { + fw->arp.invflags |= flags; + return; + } - cs->jumpto = jumpto; + ctx->errmsg = "Unknown arp meta key"; } -static void parse_mask_ipv4(struct nft_xt_ctx *ctx, struct in_addr *mask) +static void parse_mask_ipv4(const struct nft_xt_ctx_reg *reg, struct in_addr *mask) { - mask->s_addr = ctx->bitwise.mask[0]; + mask->s_addr = reg->bitwise.mask[0]; } -static bool nft_arp_parse_devaddr(struct nft_xt_ctx *ctx, +static bool nft_arp_parse_devaddr(const struct nft_xt_ctx_reg *reg, struct nftnl_expr *e, struct arpt_devaddr_info *info) { @@ -209,28 +197,27 @@ static bool nft_arp_parse_devaddr(struct nft_xt_ctx *ctx, get_cmp_data(e, info->addr, ETH_ALEN, &inv); - if (ctx->flags & NFT_XT_CTX_BITWISE) { - memcpy(info->mask, ctx->bitwise.mask, ETH_ALEN); - ctx->flags &= ~NFT_XT_CTX_BITWISE; - } else { + if (reg->bitwise.set) + memcpy(info->mask, reg->bitwise.mask, ETH_ALEN); + else memset(info->mask, 0xff, - min(ctx->payload.len, ETH_ALEN)); - } + min(reg->payload.len, ETH_ALEN)); return inv; } static void nft_arp_parse_payload(struct nft_xt_ctx *ctx, - struct nftnl_expr *e, void *data) + const struct nft_xt_ctx_reg *reg, + struct nftnl_expr *e, + struct iptables_command_state *cs) { - struct iptables_command_state *cs = data; struct arpt_entry *fw = &cs->arp; struct in_addr addr; uint16_t ar_hrd, ar_pro, ar_op; - uint8_t ar_hln; + uint8_t ar_hln, ar_pln; bool inv; - switch (ctx->payload.offset) { + switch (reg->payload.offset) { case offsetof(struct arphdr, ar_hrd): get_cmp_data(e, &ar_hrd, sizeof(ar_hrd), &inv); fw->arp.arhrd = ar_hrd; @@ -259,47 +246,50 @@ static void nft_arp_parse_payload(struct nft_xt_ctx *ctx, if (inv) fw->arp.invflags |= IPT_INV_ARPOP; break; + case offsetof(struct arphdr, ar_pln): + get_cmp_data(e, &ar_pln, sizeof(ar_pln), &inv); + if (ar_pln != 4 || inv) + ctx->errmsg = "unexpected ARP protocol length match"; + break; default: - if (ctx->payload.offset == sizeof(struct arphdr)) { - if (nft_arp_parse_devaddr(ctx, e, &fw->arp.src_devaddr)) + if (reg->payload.offset == sizeof(struct arphdr)) { + if (nft_arp_parse_devaddr(reg, e, &fw->arp.src_devaddr)) fw->arp.invflags |= IPT_INV_SRCDEVADDR; - } else if (ctx->payload.offset == sizeof(struct arphdr) + + } else if (reg->payload.offset == sizeof(struct arphdr) + fw->arp.arhln) { get_cmp_data(e, &addr, sizeof(addr), &inv); fw->arp.src.s_addr = addr.s_addr; - if (ctx->flags & NFT_XT_CTX_BITWISE) { - parse_mask_ipv4(ctx, &fw->arp.smsk); - ctx->flags &= ~NFT_XT_CTX_BITWISE; - } else { + if (reg->bitwise.set) + parse_mask_ipv4(reg, &fw->arp.smsk); + else memset(&fw->arp.smsk, 0xff, - min(ctx->payload.len, + min(reg->payload.len, sizeof(struct in_addr))); - } if (inv) fw->arp.invflags |= IPT_INV_SRCIP; - } else if (ctx->payload.offset == sizeof(struct arphdr) + + } else if (reg->payload.offset == sizeof(struct arphdr) + fw->arp.arhln + sizeof(struct in_addr)) { - if (nft_arp_parse_devaddr(ctx, e, &fw->arp.tgt_devaddr)) + if (nft_arp_parse_devaddr(reg, e, &fw->arp.tgt_devaddr)) fw->arp.invflags |= IPT_INV_TGTDEVADDR; - } else if (ctx->payload.offset == sizeof(struct arphdr) + + } else if (reg->payload.offset == sizeof(struct arphdr) + fw->arp.arhln + sizeof(struct in_addr) + fw->arp.arhln) { get_cmp_data(e, &addr, sizeof(addr), &inv); fw->arp.tgt.s_addr = addr.s_addr; - if (ctx->flags & NFT_XT_CTX_BITWISE) { - parse_mask_ipv4(ctx, &fw->arp.tmsk); - ctx->flags &= ~NFT_XT_CTX_BITWISE; - } else { + if (reg->bitwise.set) + parse_mask_ipv4(reg, &fw->arp.tmsk); + else memset(&fw->arp.tmsk, 0xff, - min(ctx->payload.len, + min(reg->payload.len, sizeof(struct in_addr))); - } if (inv) fw->arp.invflags |= IPT_INV_DSTIP; + } else { + ctx->errmsg = "unknown payload offset"; } break; } @@ -308,11 +298,10 @@ static void nft_arp_parse_payload(struct nft_xt_ctx *ctx, static void nft_arp_print_header(unsigned int format, const char *chain, const char *pol, const struct xt_counters *counters, - bool basechain, uint32_t refs, - uint32_t entries) + int refs, uint32_t entries) { printf("Chain %s", chain); - if (basechain && pol) { + if (pol) { printf(" (policy %s", pol); if (!(format & FMT_NOCOUNTS)) { fputc(' ', stdout); @@ -323,7 +312,7 @@ static void nft_arp_print_header(unsigned int format, const char *chain, } printf(")\n"); } else { - printf(" (%u references)\n", refs); + printf(" (%d references)\n", refs); } } @@ -433,7 +422,7 @@ after_devdst: printf("%s%s", sep, fw->arp.invflags & IPT_INV_ARPOP ? "! " : ""); - if (tmp <= NUMOPCODES && !(format & FMT_NUMERIC)) + if (tmp <= ARP_NUMOPCODES && !(format & FMT_NUMERIC)) printf("--opcode %s", arp_opcodes[tmp-1]); else printf("--opcode %d", tmp); @@ -473,12 +462,11 @@ after_devdst: } static void -nft_arp_save_rule(const void *data, unsigned int format) +nft_arp_save_rule(const struct iptables_command_state *cs, unsigned int format) { - const struct iptables_command_state *cs = data; - format |= FMT_NUMERIC; + printf(" "); nft_arp_print_rule_details(cs, format); if (cs->target && cs->target->save) cs->target->save(&cs->fw, cs->target->t); @@ -509,14 +497,14 @@ nft_arp_print_rule(struct nft_handle *h, struct nftnl_rule *r, if (!(format & FMT_NONEWLINE)) fputc('\n', stdout); - nft_clear_iptables_command_state(&cs); + xtables_clear_iptables_command_state(&cs); } -static bool nft_arp_is_same(const void *data_a, - const void *data_b) +static bool nft_arp_is_same(const struct iptables_command_state *cs_a, + const struct iptables_command_state *cs_b) { - const struct arpt_entry *a = data_a; - const struct arpt_entry *b = data_b; + const struct arpt_entry *a = &cs_a->arp; + const struct arpt_entry *b = &cs_b->arp; if (a->arp.src.s_addr != b->arp.src.s_addr || a->arp.tgt.s_addr != b->arp.tgt.s_addr @@ -546,19 +534,270 @@ static void nft_arp_save_chain(const struct nftnl_chain *c, const char *policy) printf(":%s %s\n", chain, policy ?: "-"); } +static int getlength_and_mask(const char *from, uint8_t *to, uint8_t *mask) +{ + char *dup = strdup(from); + char *p, *buffer; + int i, ret = -1; + + if (!dup) + return -1; + + if ( (p = strrchr(dup, '/')) != NULL) { + *p = '\0'; + i = strtol(p+1, &buffer, 10); + if (*buffer != '\0' || i < 0 || i > 255) + goto out_err; + *mask = (uint8_t)i; + } else + *mask = 255; + i = strtol(dup, &buffer, 10); + if (*buffer != '\0' || i < 0 || i > 255) + goto out_err; + *to = (uint8_t)i; + ret = 0; +out_err: + free(dup); + return ret; + +} + +static int get16_and_mask(const char *from, uint16_t *to, + uint16_t *mask, int base) +{ + char *dup = strdup(from); + char *p, *buffer; + int i, ret = -1; + + if (!dup) + return -1; + + if ( (p = strrchr(dup, '/')) != NULL) { + *p = '\0'; + i = strtol(p+1, &buffer, base); + if (*buffer != '\0' || i < 0 || i > 65535) + goto out_err; + *mask = htons((uint16_t)i); + } else + *mask = 65535; + i = strtol(dup, &buffer, base); + if (*buffer != '\0' || i < 0 || i > 65535) + goto out_err; + *to = htons((uint16_t)i); + ret = 0; +out_err: + free(dup); + return ret; +} + +static void nft_arp_post_parse(int command, + struct iptables_command_state *cs, + struct xtables_args *args) +{ + cs->arp.arp.invflags = args->invflags; + + memcpy(cs->arp.arp.iniface, args->iniface, IFNAMSIZ); + memcpy(cs->arp.arp.iniface_mask, args->iniface_mask, IFNAMSIZ); + + memcpy(cs->arp.arp.outiface, args->outiface, IFNAMSIZ); + memcpy(cs->arp.arp.outiface_mask, args->outiface_mask, IFNAMSIZ); + + cs->arp.counters.pcnt = args->pcnt_cnt; + cs->arp.counters.bcnt = args->bcnt_cnt; + + if (command & (CMD_REPLACE | CMD_INSERT | + CMD_DELETE | CMD_APPEND | CMD_CHECK)) { + if (!(cs->options & OPT_DESTINATION)) + args->dhostnetworkmask = "0.0.0.0/0"; + if (!(cs->options & OPT_SOURCE)) + args->shostnetworkmask = "0.0.0.0/0"; + } + + if (args->shostnetworkmask) + xtables_ipparse_multiple(args->shostnetworkmask, + &args->s.addr.v4, &args->s.mask.v4, + &args->s.naddrs); + if (args->dhostnetworkmask) + xtables_ipparse_multiple(args->dhostnetworkmask, + &args->d.addr.v4, &args->d.mask.v4, + &args->d.naddrs); + + if ((args->s.naddrs > 1 || args->d.naddrs > 1) && + (cs->arp.arp.invflags & (ARPT_INV_SRCIP | ARPT_INV_TGTIP))) + xtables_error(PARAMETER_PROBLEM, + "! not allowed with multiple" + " source or destination IP addresses"); + + if (args->src_mac && + xtables_parse_mac_and_mask(args->src_mac, + cs->arp.arp.src_devaddr.addr, + cs->arp.arp.src_devaddr.mask)) + xtables_error(PARAMETER_PROBLEM, + "Problem with specified source mac"); + if (args->dst_mac && + xtables_parse_mac_and_mask(args->dst_mac, + cs->arp.arp.tgt_devaddr.addr, + cs->arp.arp.tgt_devaddr.mask)) + xtables_error(PARAMETER_PROBLEM, + "Problem with specified destination mac"); + if (args->arp_hlen) { + getlength_and_mask(args->arp_hlen, &cs->arp.arp.arhln, + &cs->arp.arp.arhln_mask); + + if (cs->arp.arp.arhln != 6) + xtables_error(PARAMETER_PROBLEM, + "Only harware address length of 6 is supported currently."); + } + if (args->arp_opcode) { + if (get16_and_mask(args->arp_opcode, &cs->arp.arp.arpop, + &cs->arp.arp.arpop_mask, 10)) { + int i; + + for (i = 0; i < ARP_NUMOPCODES; i++) + if (!strcasecmp(arp_opcodes[i], + args->arp_opcode)) + break; + if (i == ARP_NUMOPCODES) + xtables_error(PARAMETER_PROBLEM, + "Problem with specified opcode"); + cs->arp.arp.arpop = htons(i+1); + } + } + if (args->arp_htype) { + if (get16_and_mask(args->arp_htype, &cs->arp.arp.arhrd, + &cs->arp.arp.arhrd_mask, 16)) { + if (strcasecmp(args->arp_htype, "Ethernet")) + xtables_error(PARAMETER_PROBLEM, + "Problem with specified hardware type"); + cs->arp.arp.arhrd = htons(1); + } + } + if (args->arp_ptype) { + if (get16_and_mask(args->arp_ptype, &cs->arp.arp.arpro, + &cs->arp.arp.arpro_mask, 0)) { + if (strcasecmp(args->arp_ptype, "ipv4")) + xtables_error(PARAMETER_PROBLEM, + "Problem with specified protocol type"); + cs->arp.arp.arpro = htons(0x800); + } + } +} + +static void nft_arp_init_cs(struct iptables_command_state *cs) +{ + cs->arp.arp.arhln = 6; + cs->arp.arp.arhln_mask = 255; + cs->arp.arp.arhrd = htons(ARPHRD_ETHER); + cs->arp.arp.arhrd_mask = 65535; +} + +static int +nft_arp_add_entry(struct nft_handle *h, + const char *chain, const char *table, + struct iptables_command_state *cs, + struct xtables_args *args, bool verbose, + bool append, int rulenum) +{ + unsigned int i, j; + int ret = 1; + + for (i = 0; i < args->s.naddrs; i++) { + cs->arp.arp.src.s_addr = args->s.addr.v4[i].s_addr; + cs->arp.arp.smsk.s_addr = args->s.mask.v4[i].s_addr; + for (j = 0; j < args->d.naddrs; j++) { + cs->arp.arp.tgt.s_addr = args->d.addr.v4[j].s_addr; + cs->arp.arp.tmsk.s_addr = args->d.mask.v4[j].s_addr; + if (append) { + ret = nft_cmd_rule_append(h, chain, table, cs, NULL, + verbose); + } else { + ret = nft_cmd_rule_insert(h, chain, table, cs, + rulenum, verbose); + } + } + } + + return ret; +} + +static int +nft_arp_delete_entry(struct nft_handle *h, + const char *chain, const char *table, + struct iptables_command_state *cs, + struct xtables_args *args, bool verbose) +{ + unsigned int i, j; + int ret = 1; + + for (i = 0; i < args->s.naddrs; i++) { + cs->arp.arp.src.s_addr = args->s.addr.v4[i].s_addr; + cs->arp.arp.smsk.s_addr = args->s.mask.v4[i].s_addr; + for (j = 0; j < args->d.naddrs; j++) { + cs->arp.arp.tgt.s_addr = args->d.addr.v4[j].s_addr; + cs->arp.arp.tmsk.s_addr = args->d.mask.v4[j].s_addr; + ret = nft_cmd_rule_delete(h, chain, table, cs, verbose); + } + } + + return ret; +} + +static int +nft_arp_check_entry(struct nft_handle *h, + const char *chain, const char *table, + struct iptables_command_state *cs, + struct xtables_args *args, bool verbose) +{ + unsigned int i, j; + int ret = 1; + + for (i = 0; i < args->s.naddrs; i++) { + cs->arp.arp.src.s_addr = args->s.addr.v4[i].s_addr; + cs->arp.arp.smsk.s_addr = args->s.mask.v4[i].s_addr; + for (j = 0; j < args->d.naddrs; j++) { + cs->arp.arp.tgt.s_addr = args->d.addr.v4[j].s_addr; + cs->arp.arp.tmsk.s_addr = args->d.mask.v4[j].s_addr; + ret = nft_cmd_rule_check(h, chain, table, cs, verbose); + } + } + + return ret; +} + +static int +nft_arp_replace_entry(struct nft_handle *h, + const char *chain, const char *table, + struct iptables_command_state *cs, + struct xtables_args *args, bool verbose, + int rulenum) +{ + cs->arp.arp.src.s_addr = args->s.addr.v4->s_addr; + cs->arp.arp.tgt.s_addr = args->d.addr.v4->s_addr; + cs->arp.arp.smsk.s_addr = args->s.mask.v4->s_addr; + cs->arp.arp.tmsk.s_addr = args->d.mask.v4->s_addr; + + return nft_cmd_rule_replace(h, chain, table, cs, rulenum, verbose); +} + struct nft_family_ops nft_family_ops_arp = { .add = nft_arp_add, .is_same = nft_arp_is_same, .print_payload = NULL, .parse_meta = nft_arp_parse_meta, .parse_payload = nft_arp_parse_payload, - .parse_immediate = nft_arp_parse_immediate, .print_header = nft_arp_print_header, .print_rule = nft_arp_print_rule, .save_rule = nft_arp_save_rule, .save_chain = nft_arp_save_chain, - .post_parse = NULL, + .cmd_parse = { + .post_parse = nft_arp_post_parse, + }, .rule_to_cs = nft_rule_to_iptables_command_state, - .clear_cs = nft_clear_iptables_command_state, + .init_cs = nft_arp_init_cs, + .clear_cs = xtables_clear_iptables_command_state, .parse_target = nft_ipv46_parse_target, + .add_entry = nft_arp_add_entry, + .delete_entry = nft_arp_delete_entry, + .check_entry = nft_arp_check_entry, + .replace_entry = nft_arp_replace_entry, }; diff --git a/iptables/nft-arp.h b/iptables/nft-arp.h deleted file mode 100644 index 3411fc3d..00000000 --- a/iptables/nft-arp.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _NFT_ARP_H_ -#define _NFT_ARP_H_ - -extern char *arp_opcodes[]; -#define NUMOPCODES 9 - -#endif diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index 11f3df35..83cbe315 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -65,30 +65,34 @@ static void ebt_print_mac_and_mask(const unsigned char *mac, const unsigned char xtables_print_mac_and_mask(mac, mask); } -static void add_logical_iniface(struct nftnl_rule *r, char *iface, uint32_t op) +static void add_logical_iniface(struct nft_handle *h, struct nftnl_rule *r, + char *iface, uint32_t op) { int iface_len; + uint8_t reg; iface_len = strlen(iface); - add_meta(r, NFT_META_BRI_IIFNAME); + add_meta(h, r, NFT_META_BRI_IIFNAME, ®); if (iface[iface_len - 1] == '+') - add_cmp_ptr(r, op, iface, iface_len - 1); + add_cmp_ptr(r, op, iface, iface_len - 1, reg); else - add_cmp_ptr(r, op, iface, iface_len + 1); + add_cmp_ptr(r, op, iface, iface_len + 1, reg); } -static void add_logical_outiface(struct nftnl_rule *r, char *iface, uint32_t op) +static void add_logical_outiface(struct nft_handle *h, struct nftnl_rule *r, + char *iface, uint32_t op) { int iface_len; + uint8_t reg; iface_len = strlen(iface); - add_meta(r, NFT_META_BRI_OIFNAME); + add_meta(h, r, NFT_META_BRI_OIFNAME, ®); if (iface[iface_len - 1] == '+') - add_cmp_ptr(r, op, iface, iface_len - 1); + add_cmp_ptr(r, op, iface, iface_len - 1, reg); else - add_cmp_ptr(r, op, iface, iface_len + 1); + add_cmp_ptr(r, op, iface, iface_len + 1, reg); } static int _add_action(struct nftnl_rule *r, struct iptables_command_state *cs) @@ -96,60 +100,81 @@ static int _add_action(struct nftnl_rule *r, struct iptables_command_state *cs) return add_action(r, cs, false); } +static int +nft_bridge_add_match(struct nft_handle *h, const struct ebt_entry *fw, + struct nftnl_rule *r, struct xt_entry_match *m) +{ + if (!strcmp(m->u.user.name, "802_3") && + !(fw->bitmask & EBT_802_3)) + xtables_error(PARAMETER_PROBLEM, + "For 802.3 DSAP/SSAP filtering the protocol must be LENGTH"); + + return add_match(h, r, m); +} + static int nft_bridge_add(struct nft_handle *h, - struct nftnl_rule *r, void *data) + struct nftnl_rule *r, + struct iptables_command_state *cs) { - struct iptables_command_state *cs = data; struct ebt_match *iter; struct ebt_entry *fw = &cs->eb; uint32_t op; if (fw->in[0] != '\0') { op = nft_invflags2cmp(fw->invflags, EBT_IIN); - add_iniface(r, fw->in, op); + add_iniface(h, r, fw->in, op); } if (fw->out[0] != '\0') { op = nft_invflags2cmp(fw->invflags, EBT_IOUT); - add_outiface(r, fw->out, op); + add_outiface(h, r, fw->out, op); } if (fw->logical_in[0] != '\0') { op = nft_invflags2cmp(fw->invflags, EBT_ILOGICALIN); - add_logical_iniface(r, fw->logical_in, op); + add_logical_iniface(h, r, fw->logical_in, op); } if (fw->logical_out[0] != '\0') { op = nft_invflags2cmp(fw->invflags, EBT_ILOGICALOUT); - add_logical_outiface(r, fw->logical_out, op); + add_logical_outiface(h, r, fw->logical_out, op); } if (fw->bitmask & EBT_ISOURCE) { op = nft_invflags2cmp(fw->invflags, EBT_ISOURCE); - add_addr(r, NFT_PAYLOAD_LL_HEADER, + add_addr(h, r, NFT_PAYLOAD_LL_HEADER, offsetof(struct ethhdr, h_source), fw->sourcemac, fw->sourcemsk, ETH_ALEN, op); } if (fw->bitmask & EBT_IDEST) { op = nft_invflags2cmp(fw->invflags, EBT_IDEST); - add_addr(r, NFT_PAYLOAD_LL_HEADER, + add_addr(h, r, NFT_PAYLOAD_LL_HEADER, offsetof(struct ethhdr, h_dest), fw->destmac, fw->destmsk, ETH_ALEN, op); } if ((fw->bitmask & EBT_NOPROTO) == 0) { + uint16_t ethproto = fw->ethproto; + uint8_t reg; + op = nft_invflags2cmp(fw->invflags, EBT_IPROTO); - add_payload(r, offsetof(struct ethhdr, h_proto), 2, - NFT_PAYLOAD_LL_HEADER); - add_cmp_u16(r, fw->ethproto, op); + add_payload(h, r, offsetof(struct ethhdr, h_proto), 2, + NFT_PAYLOAD_LL_HEADER, ®); + + if (fw->bitmask & EBT_802_3) { + op = (op == NFT_CMP_EQ ? NFT_CMP_LT : NFT_CMP_GTE); + ethproto = htons(0x0600); + } + + add_cmp_u16(r, ethproto, op, reg); } add_compat(r, fw->ethproto, fw->invflags & EBT_IPROTO); for (iter = cs->match_list; iter; iter = iter->next) { if (iter->ismatch) { - if (add_match(h, r, iter->u.match->m)) + if (nft_bridge_add_match(h, fw, r, iter->u.match->m)) break; } else { if (add_target(r, iter->u.watcher->t)) @@ -164,16 +189,25 @@ static int nft_bridge_add(struct nft_handle *h, } static void nft_bridge_parse_meta(struct nft_xt_ctx *ctx, - struct nftnl_expr *e, void *data) + const struct nft_xt_ctx_reg *reg, + struct nftnl_expr *e, + struct iptables_command_state *cs) { - struct iptables_command_state *cs = data; struct ebt_entry *fw = &cs->eb; uint8_t invflags = 0; char iifname[IFNAMSIZ] = {}, oifname[IFNAMSIZ] = {}; - parse_meta(e, ctx->meta.key, iifname, NULL, oifname, NULL, &invflags); + switch (reg->meta_dreg.key) { + case NFT_META_PROTOCOL: + return; + } + + if (parse_meta(ctx, e, reg->meta_dreg.key, iifname, NULL, oifname, NULL, &invflags) < 0) { + ctx->errmsg = "unknown meta key"; + return; + } - switch (ctx->meta.key) { + switch (reg->meta_dreg.key) { case NFT_META_BRI_IIFNAME: if (invflags & IPT_INV_VIA_IN) cs->eb.invflags |= EBT_ILOGICALIN; @@ -195,21 +229,24 @@ static void nft_bridge_parse_meta(struct nft_xt_ctx *ctx, snprintf(fw->out, sizeof(fw->out), "%s", oifname); break; default: + ctx->errmsg = "unknown bridge meta key"; break; } } static void nft_bridge_parse_payload(struct nft_xt_ctx *ctx, - struct nftnl_expr *e, void *data) + const struct nft_xt_ctx_reg *reg, + struct nftnl_expr *e, + struct iptables_command_state *cs) { - struct iptables_command_state *cs = data; struct ebt_entry *fw = &cs->eb; unsigned char addr[ETH_ALEN]; unsigned short int ethproto; + uint8_t op; bool inv; int i; - switch (ctx->payload.offset) { + switch (reg->payload.offset) { case offsetof(struct ethhdr, h_dest): get_cmp_data(e, addr, sizeof(addr), &inv); for (i = 0; i < ETH_ALEN; i++) @@ -217,13 +254,11 @@ static void nft_bridge_parse_payload(struct nft_xt_ctx *ctx, if (inv) fw->invflags |= EBT_IDEST; - if (ctx->flags & NFT_XT_CTX_BITWISE) { - memcpy(fw->destmsk, ctx->bitwise.mask, ETH_ALEN); - ctx->flags &= ~NFT_XT_CTX_BITWISE; - } else { + if (reg->bitwise.set) + memcpy(fw->destmsk, reg->bitwise.mask, ETH_ALEN); + else memset(&fw->destmsk, 0xff, - min(ctx->payload.len, ETH_ALEN)); - } + min(reg->payload.len, ETH_ALEN)); fw->bitmask |= EBT_IDEST; break; case offsetof(struct ethhdr, h_source): @@ -232,33 +267,33 @@ static void nft_bridge_parse_payload(struct nft_xt_ctx *ctx, fw->sourcemac[i] = addr[i]; if (inv) fw->invflags |= EBT_ISOURCE; - if (ctx->flags & NFT_XT_CTX_BITWISE) { - memcpy(fw->sourcemsk, ctx->bitwise.mask, ETH_ALEN); - ctx->flags &= ~NFT_XT_CTX_BITWISE; - } else { + if (reg->bitwise.set) + memcpy(fw->sourcemsk, reg->bitwise.mask, ETH_ALEN); + else memset(&fw->sourcemsk, 0xff, - min(ctx->payload.len, ETH_ALEN)); - } + min(reg->payload.len, ETH_ALEN)); fw->bitmask |= EBT_ISOURCE; break; case offsetof(struct ethhdr, h_proto): - get_cmp_data(e, ðproto, sizeof(ethproto), &inv); - fw->ethproto = ethproto; + __get_cmp_data(e, ðproto, sizeof(ethproto), &op); + if (ethproto == htons(0x0600)) { + fw->bitmask |= EBT_802_3; + inv = (op == NFT_CMP_GTE); + } else { + fw->ethproto = ethproto; + inv = (op == NFT_CMP_NEQ); + } if (inv) fw->invflags |= EBT_IPROTO; fw->bitmask &= ~EBT_NOPROTO; break; + default: + DEBUGP("unknown payload offset %d\n", reg->payload.offset); + ctx->errmsg = "unknown payload offset"; + break; } } -static void nft_bridge_parse_immediate(const char *jumpto, bool nft_goto, - void *data) -{ - struct iptables_command_state *cs = data; - - cs->jumpto = jumpto; -} - /* return 0 if saddr, 1 if daddr, -1 on error */ static int lookup_check_ether_payload(uint32_t base, uint32_t offset, uint32_t len) @@ -296,49 +331,74 @@ lookup_check_iphdr_payload(uint32_t base, uint32_t offset, uint32_t len) /* Make sure previous payload expression(s) is/are consistent and extract if * matching on source or destination address and if matching on MAC and IP or * only MAC address. */ -static int lookup_analyze_payloads(const struct nft_xt_ctx *ctx, +static int lookup_analyze_payloads(struct nft_xt_ctx *ctx, + enum nft_registers sreg, + uint32_t key_len, bool *dst, bool *ip) { + const struct nft_xt_ctx_reg *reg; int val, val2 = -1; - if (ctx->flags & NFT_XT_CTX_PREV_PAYLOAD) { - val = lookup_check_ether_payload(ctx->prev_payload.base, - ctx->prev_payload.offset, - ctx->prev_payload.len); + reg = nft_xt_ctx_get_sreg(ctx, sreg); + if (!reg) + return -1; + + if (reg->type != NFT_XT_REG_PAYLOAD) { + ctx->errmsg = "lookup reg is not payload type"; + return -1; + } + + switch (key_len) { + case 12: /* ether + ipv4addr */ + val = lookup_check_ether_payload(reg->payload.base, + reg->payload.offset, + reg->payload.len); if (val < 0) { DEBUGP("unknown payload base/offset/len %d/%d/%d\n", - ctx->prev_payload.base, ctx->prev_payload.offset, - ctx->prev_payload.len); + reg->payload.base, reg->payload.offset, + reg->payload.len); return -1; } - if (!(ctx->flags & NFT_XT_CTX_PAYLOAD)) { - DEBUGP("Previous but no current payload?\n"); + + sreg = nft_get_next_reg(sreg, ETH_ALEN); + + reg = nft_xt_ctx_get_sreg(ctx, sreg); + if (!reg) { + ctx->errmsg = "next lookup register is invalid"; return -1; } - val2 = lookup_check_iphdr_payload(ctx->payload.base, - ctx->payload.offset, - ctx->payload.len); + + if (reg->type != NFT_XT_REG_PAYLOAD) { + ctx->errmsg = "next lookup reg is not payload type"; + return -1; + } + + val2 = lookup_check_iphdr_payload(reg->payload.base, + reg->payload.offset, + reg->payload.len); if (val2 < 0) { DEBUGP("unknown payload base/offset/len %d/%d/%d\n", - ctx->payload.base, ctx->payload.offset, - ctx->payload.len); + reg->payload.base, reg->payload.offset, + reg->payload.len); return -1; } else if (val != val2) { DEBUGP("mismatching payload match offsets\n"); return -1; } - } else if (ctx->flags & NFT_XT_CTX_PAYLOAD) { - val = lookup_check_ether_payload(ctx->payload.base, - ctx->payload.offset, - ctx->payload.len); + break; + case 6: /* ether */ + val = lookup_check_ether_payload(reg->payload.base, + reg->payload.offset, + reg->payload.len); if (val < 0) { DEBUGP("unknown payload base/offset/len %d/%d/%d\n", - ctx->payload.base, ctx->payload.offset, - ctx->payload.len); + reg->payload.base, reg->payload.offset, + reg->payload.len); return -1; } - } else { - DEBUGP("unknown LHS of lookup expression\n"); + break; + default: + ctx->errmsg = "unsupported lookup key length"; return -1; } @@ -405,7 +465,7 @@ static struct nftnl_set *set_from_lookup_expr(struct nft_xt_ctx *ctx, } static void nft_bridge_parse_lookup(struct nft_xt_ctx *ctx, - struct nftnl_expr *e, void *data) + struct nftnl_expr *e) { struct xtables_match *match = NULL; struct nft_among_data *among_data; @@ -415,14 +475,17 @@ static void nft_bridge_parse_lookup(struct nft_xt_ctx *ctx, size_t poff, size; uint32_t cnt; - if (lookup_analyze_payloads(ctx, &is_dst, &have_ip)) - return; - s = set_from_lookup_expr(ctx, e); if (!s) xtables_error(OTHER_PROBLEM, "BUG: lookup expression references unknown set"); + if (lookup_analyze_payloads(ctx, + nftnl_expr_get_u32(e, NFTNL_EXPR_LOOKUP_SREG), + nftnl_set_get_u32(s, NFTNL_SET_KEY_LEN), + &is_dst, &have_ip)) + return; + cnt = nftnl_set_get_u32(s, NFTNL_SET_DESC_SIZE); for (ematch = ctx->cs->match_list; ematch; ematch = ematch->next) { @@ -470,8 +533,6 @@ static void nft_bridge_parse_lookup(struct nft_xt_ctx *ctx, if (set_elems_to_among_pairs(among_data->pairs + poff, s, cnt)) xtables_error(OTHER_PROBLEM, "ebtables among pair parsing failed"); - - ctx->flags &= ~(NFT_XT_CTX_PAYLOAD | NFT_XT_CTX_PREV_PAYLOAD); } static void parse_watcher(void *object, struct ebt_match **match_list, @@ -491,17 +552,15 @@ static void parse_watcher(void *object, struct ebt_match **match_list, (*match_list)->next = m; } -static void nft_bridge_parse_match(struct xtables_match *m, void *data) +static void nft_bridge_parse_match(struct xtables_match *m, + struct iptables_command_state *cs) { - struct iptables_command_state *cs = data; - parse_watcher(m, &cs->match_list, true); } -static void nft_bridge_parse_target(struct xtables_target *t, void *data) +static void nft_bridge_parse_target(struct xtables_target *t, + struct iptables_command_state *cs) { - struct iptables_command_state *cs = data; - /* harcoded names :-( */ if (strcmp(t->name, "log") == 0 || strcmp(t->name, "nflog") == 0) { @@ -510,14 +569,15 @@ static void nft_bridge_parse_target(struct xtables_target *t, void *data) } cs->target = t; + cs->jumpto = t->name; } -static void nft_rule_to_ebtables_command_state(struct nft_handle *h, +static bool nft_rule_to_ebtables_command_state(struct nft_handle *h, const struct nftnl_rule *r, struct iptables_command_state *cs) { cs->eb.bitmask = EBT_NOPROTO; - nft_rule_to_iptables_command_state(h, r, cs); + return nft_rule_to_iptables_command_state(h, r, cs); } static void print_iface(const char *option, const char *name, bool invert) @@ -534,7 +594,7 @@ static void nft_bridge_print_table_header(const char *tablename) static void nft_bridge_print_header(unsigned int format, const char *chain, const char *pol, const struct xt_counters *counters, - bool basechain, uint32_t refs, uint32_t entries) + int refs, uint32_t entries) { printf("Bridge chain: %s, entries: %u, policy: %s\n", chain, entries, pol ?: "RETURN"); @@ -590,7 +650,7 @@ static void print_protocol(uint16_t ethproto, bool invert, unsigned int bitmask) printf("! "); if (bitmask & EBT_802_3) { - printf("length "); + printf("Length "); return; } @@ -601,11 +661,10 @@ static void print_protocol(uint16_t ethproto, bool invert, unsigned int bitmask) printf("%s ", ent->e_name); } -static void nft_bridge_save_rule(const void *data, unsigned int format) +static void __nft_bridge_save_rule(const struct iptables_command_state *cs, + unsigned int format) { - const struct iptables_command_state *cs = data; - - if (cs->eb.ethproto) + if (!(cs->eb.bitmask & EBT_NOPROTO)) print_protocol(cs->eb.ethproto, cs->eb.invflags & EBT_IPROTO, cs->eb.bitmask); if (cs->eb.bitmask & EBT_ISOURCE) @@ -652,6 +711,13 @@ static void nft_bridge_save_rule(const void *data, unsigned int format) fputc('\n', stdout); } +static void nft_bridge_save_rule(const struct iptables_command_state *cs, + unsigned int format) +{ + printf(" "); + __nft_bridge_save_rule(cs, format); +} + static void nft_bridge_print_rule(struct nft_handle *h, struct nftnl_rule *r, unsigned int num, unsigned int format) { @@ -661,7 +727,7 @@ static void nft_bridge_print_rule(struct nft_handle *h, struct nftnl_rule *r, printf("%d ", num); nft_rule_to_ebtables_command_state(h, r, &cs); - nft_bridge_save_rule(&cs, format); + __nft_bridge_save_rule(&cs, format); ebt_cs_clean(&cs); } @@ -673,10 +739,11 @@ static void nft_bridge_save_chain(const struct nftnl_chain *c, printf(":%s %s\n", chain, policy ?: "ACCEPT"); } -static bool nft_bridge_is_same(const void *data_a, const void *data_b) +static bool nft_bridge_is_same(const struct iptables_command_state *cs_a, + const struct iptables_command_state *cs_b) { - const struct ebt_entry *a = data_a; - const struct ebt_entry *b = data_b; + const struct ebt_entry *a = &cs_a->eb; + const struct ebt_entry *b = &cs_b->eb; int i; if (a->ethproto != b->ethproto || @@ -728,7 +795,6 @@ static int xlate_ebmatches(const struct iptables_command_state *cs, struct xt_xl struct xt_xlate_mt_params mt_params = { .ip = (const void *)&cs->eb, .numeric = numeric, - .escape_quotes = false, .match = matchp->m, }; @@ -741,7 +807,6 @@ static int xlate_ebmatches(const struct iptables_command_state *cs, struct xt_xl struct xt_xlate_tg_params wt_params = { .ip = (const void *)&cs->eb, .numeric = numeric, - .escape_quotes = false, .target = watcherp->t, }; @@ -772,7 +837,6 @@ static int xlate_ebaction(const struct iptables_command_state *cs, struct xt_xla else if (strcmp(cs->jumpto, XTC_LABEL_RETURN) == 0) xt_xlate_add(xl, " return"); else if (cs->target->xlate) { - xt_xlate_add(xl, " "); struct xt_xlate_tg_params params = { .ip = (const void *)&cs->eb, .target = cs->target->t, @@ -806,25 +870,23 @@ static void nft_bridge_xlate_mac(struct xt_xlate *xl, const char *type, bool inv xt_xlate_add(xl, "ether %s %s", type, invert ? "!= " : ""); - xlate_mac(xl, mac); - if (memcmp(mask, one_msk, ETH_ALEN)) { int i; - xt_xlate_add(xl, " and "); + xt_xlate_add(xl, "and"); xlate_mac(xl, mask); xt_xlate_add(xl, " == %02x", mac[0] & mask[0]); for (i=1; i < ETH_ALEN; i++) xt_xlate_add(xl, ":%02x", mac[i] & mask[i]); + } else { + xlate_mac(xl, mac); } - - xt_xlate_add(xl, " "); } -static int nft_bridge_xlate(const void *data, struct xt_xlate *xl) +static int nft_bridge_xlate(const struct iptables_command_state *cs, + struct xt_xlate *xl) { - const struct iptables_command_state *cs = data; int ret; xlate_ifname(xl, "iifname", cs->eb.in, @@ -836,7 +898,10 @@ static int nft_bridge_xlate(const void *data, struct xt_xlate *xl) xlate_ifname(xl, "meta obrname", cs->eb.logical_out, cs->eb.invflags & EBT_ILOGICALOUT); - if ((cs->eb.bitmask & EBT_NOPROTO) == 0) { + if (cs->eb.bitmask & EBT_802_3) { + xt_xlate_add(xl, "ether type %s 0x0600 ", + cs->eb.invflags & EBT_IPROTO ? ">=" : "<"); + } else if ((cs->eb.bitmask & EBT_NOPROTO) == 0) { const char *implicit = NULL; switch (ntohs(cs->eb.ethproto)) { @@ -859,9 +924,6 @@ static int nft_bridge_xlate(const void *data, struct xt_xlate *xl) ntohs(cs->eb.ethproto)); } - if (cs->eb.bitmask & EBT_802_3) - return 0; - if (cs->eb.bitmask & EBT_ISOURCE) nft_bridge_xlate_mac(xl, "saddr", cs->eb.invflags & EBT_ISOURCE, cs->eb.sourcemac, cs->eb.sourcemsk); @@ -885,7 +947,6 @@ struct nft_family_ops nft_family_ops_bridge = { .print_payload = NULL, .parse_meta = nft_bridge_parse_meta, .parse_payload = nft_bridge_parse_payload, - .parse_immediate = nft_bridge_parse_immediate, .parse_lookup = nft_bridge_parse_lookup, .parse_match = nft_bridge_parse_match, .parse_target = nft_bridge_parse_target, @@ -894,7 +955,6 @@ struct nft_family_ops nft_family_ops_bridge = { .print_rule = nft_bridge_print_rule, .save_rule = nft_bridge_save_rule, .save_chain = nft_bridge_save_chain, - .post_parse = NULL, .rule_to_cs = nft_rule_to_ebtables_command_state, .clear_cs = ebt_cs_clean, .xlate = nft_bridge_xlate, diff --git a/iptables/nft-cache.c b/iptables/nft-cache.c index 2c88301c..76e99adc 100644 --- a/iptables/nft-cache.c +++ b/iptables/nft-cache.c @@ -105,7 +105,8 @@ static void mnl_genid_get(struct nft_handle *h, uint32_t *genid) return; xtables_error(RESOURCE_PROBLEM, - "Could not fetch rule set generation id: %s\n", nft_strerror(errno)); + "Could not fetch rule set generation id: %s", + nft_strerror(errno)); } static int nftnl_table_list_cb(const struct nlmsghdr *nlh, void *data) @@ -141,8 +142,8 @@ static int fetch_table_cache(struct nft_handle *h) char buf[16536]; int i, ret; - nlh = nftnl_rule_nlmsg_build_hdr(buf, NFT_MSG_GETTABLE, h->family, - NLM_F_DUMP, h->seq); + nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETTABLE, h->family, + NLM_F_DUMP, h->seq); ret = mnl_talk(h, nlh, nftnl_table_list_cb, h); if (ret < 0 && errno == EINTR) @@ -202,26 +203,52 @@ nft_chain_find(struct nft_handle *h, const char *table, const char *chain) return NULL; } +static int +nft_cache_add_base_chain(struct nft_handle *h, const struct builtin_table *t, + struct nft_chain *nc) +{ + uint32_t hooknum = nftnl_chain_get_u32(nc->nftnl, NFTNL_CHAIN_HOOKNUM); + const char *name = nftnl_chain_get_str(nc->nftnl, NFTNL_CHAIN_NAME); + const char *type = nftnl_chain_get_str(nc->nftnl, NFTNL_CHAIN_TYPE); + uint32_t prio = nftnl_chain_get_u32(nc->nftnl, NFTNL_CHAIN_PRIO); + const struct builtin_chain *bc = NULL; + int i; + + for (i = 0; i < NF_IP_NUMHOOKS && t->chains[i].name != NULL; i++) { + if (hooknum == t->chains[i].hook) { + bc = &t->chains[i]; + break; + } + } + + if (!bc || + prio != bc->prio || + strcmp(name, bc->name) || + strcmp(type, bc->type)) + return -EINVAL; + + nc->base_slot = &h->cache->table[t->type].base_chains[hooknum]; + if (*nc->base_slot) + return -EEXIST; + + *nc->base_slot = nc; + return 0; +} + int nft_cache_add_chain(struct nft_handle *h, const struct builtin_table *t, struct nftnl_chain *c) { const char *cname = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME); struct nft_chain *nc = nft_chain_alloc(c); + int ret; if (nftnl_chain_is_set(c, NFTNL_CHAIN_HOOKNUM)) { - uint32_t hooknum = nftnl_chain_get_u32(c, NFTNL_CHAIN_HOOKNUM); - - if (hooknum >= NF_INET_NUMHOOKS) { + ret = nft_cache_add_base_chain(h, t, nc); + if (ret) { + h->cache->table[t->type].tainted = true; nft_chain_free(nc); - return -EINVAL; + return ret; } - - if (h->cache->table[t->type].base_chains[hooknum]) { - nft_chain_free(nc); - return -EEXIST; - } - - h->cache->table[t->type].base_chains[hooknum] = nc; } else { list_add_tail(&nc->head, &h->cache->table[t->type].chains->list); @@ -314,9 +341,7 @@ static int nftnl_chain_list_cb(const struct nlmsghdr *nlh, void *data) goto out; } - if (nft_cache_add_chain(h, t, c)) - goto out; - + nft_cache_add_chain(h, t, c); return MNL_CB_OK; out: nftnl_chain_free(c); @@ -429,8 +454,8 @@ static int fetch_set_cache(struct nft_handle *h, } } - nlh = nftnl_set_nlmsg_build_hdr(buf, NFT_MSG_GETSET, - h->family, flags, h->seq); + nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETSET, + h->family, flags, h->seq); if (s) { nftnl_set_nlmsg_build_payload(nlh, s); @@ -472,8 +497,8 @@ static int __fetch_chain_cache(struct nft_handle *h, struct nlmsghdr *nlh; int ret; - nlh = nftnl_chain_nlmsg_build_hdr(buf, NFT_MSG_GETCHAIN, h->family, - c ? NLM_F_ACK : NLM_F_DUMP, h->seq); + nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETCHAIN, h->family, + c ? NLM_F_ACK : NLM_F_DUMP, h->seq); if (c) nftnl_chain_nlmsg_build_payload(nlh, c); @@ -514,9 +539,15 @@ static int fetch_chain_cache(struct nft_handle *h, return ret; } +struct rule_list_cb_data { + struct nftnl_chain *chain; + int verbose; +}; + static int nftnl_rule_list_cb(const struct nlmsghdr *nlh, void *data) { - struct nftnl_chain *c = data; + struct rule_list_cb_data *rld = data; + struct nftnl_chain *c = rld->chain; struct nftnl_rule *r; r = nftnl_rule_alloc(); @@ -528,6 +559,10 @@ static int nftnl_rule_list_cb(const struct nlmsghdr *nlh, void *data) return MNL_CB_OK; } + if (rld->verbose > 1) { + nftnl_rule_fprintf(stdout, r, 0, 0); + fprintf(stdout, "\n"); + } nftnl_chain_rule_add_tail(r, c); return MNL_CB_OK; } @@ -536,6 +571,10 @@ static int nft_rule_list_update(struct nft_chain *nc, void *data) { struct nftnl_chain *c = nc->nftnl; struct nft_handle *h = data; + struct rule_list_cb_data rld = { + .chain = c, + .verbose = h->verbose, + }; char buf[16536]; struct nlmsghdr *nlh; struct nftnl_rule *rule; @@ -553,11 +592,11 @@ static int nft_rule_list_update(struct nft_chain *nc, void *data) nftnl_rule_set_str(rule, NFTNL_RULE_CHAIN, nftnl_chain_get_str(c, NFTNL_CHAIN_NAME)); - nlh = nftnl_rule_nlmsg_build_hdr(buf, NFT_MSG_GETRULE, h->family, - NLM_F_DUMP, h->seq); + nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETRULE, h->family, + NLM_F_DUMP, h->seq); nftnl_rule_nlmsg_build_payload(nlh, rule); - ret = mnl_talk(h, nlh, nftnl_rule_list_cb, c); + ret = mnl_talk(h, nlh, nftnl_rule_list_cb, &rld); if (ret < 0 && errno == EINTR) assert(nft_restart(h) >= 0); diff --git a/iptables/nft-chain.h b/iptables/nft-chain.h index 137f4b7f..9adf1738 100644 --- a/iptables/nft-chain.h +++ b/iptables/nft-chain.h @@ -9,6 +9,7 @@ struct nft_handle; struct nft_chain { struct list_head head; struct hlist_node hnode; + struct nft_chain **base_slot; struct nftnl_chain *nftnl; }; diff --git a/iptables/nft-cmd.c b/iptables/nft-cmd.c index 2d874bd4..f16ea0e6 100644 --- a/iptables/nft-cmd.c +++ b/iptables/nft-cmd.c @@ -24,6 +24,7 @@ struct nft_cmd *nft_cmd_new(struct nft_handle *h, int command, struct nft_cmd *cmd; cmd = xtables_calloc(1, sizeof(struct nft_cmd)); + cmd->error.lineno = h->error.lineno; cmd->command = command; |