diff options
257 files changed, 5775 insertions, 5656 deletions
@@ -20,6 +20,7 @@ Makefile.in /build-aux/ /config.* /configure +/configure~ /libtool /stamp-h1 /iptables/iptables-apply.8 @@ -29,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 ea5d2d49..488c01eb 100644 --- a/configure.ac +++ b/configure.ac @@ -1,9 +1,9 @@ -AC_INIT([iptables], [1.8.8]) +AC_INIT([iptables], [1.8.9]) # See libtool.info "Libtool's versioning system" -libxtables_vcurrent=18 -libxtables_vage=6 +libxtables_vcurrent=19 +libxtables_vage=7 AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_HEADERS([config.h]) @@ -113,14 +113,15 @@ AM_CONDITIONAL([ENABLE_SYNCONF], [test "$enable_nfsynproxy" = "yes"]) AM_CONDITIONAL([ENABLE_NFTABLES], [test "$enable_nftables" = "yes"]) AM_CONDITIONAL([ENABLE_CONNLABEL], [test "$enable_connlabel" = "yes"]) -if test "x$enable_bpfc" = "xyes" || test "x$enable_nfsynproxy" = "xyes"; then - AC_CHECK_LIB(pcap, pcap_compile,, AC_MSG_ERROR(missing libpcap library required by bpf compiler or nfsynproxy tool)) -fi - PKG_CHECK_MODULES([libnfnetlink], [libnfnetlink >= 1.0], [nfnetlink=1], [nfnetlink=0]) AM_CONDITIONAL([HAVE_LIBNFNETLINK], [test "$nfnetlink" = 1]) +if test "x$enable_bpfc" = "xyes" || test "x$enable_nfsynproxy" = "xyes"; then + PKG_CHECK_MODULES([libpcap], [libpcap], [], [ + AC_MSG_ERROR(missing libpcap library required by bpf compiler or nfsynproxy tool)]) +fi + if test "x$enable_nftables" = "xyes"; then PKG_CHECK_MODULES([libmnl], [libmnl >= 1.0], [mnl=1], [mnl=0]) 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 3c68f8de..e289adf0 100644 --- a/extensions/GNUmakefile.in +++ b/extensions/GNUmakefile.in @@ -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 REDIRECT +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,7 +131,13 @@ libxt_NOTRACK.so: libxt_CT.so ln -fs $< $@ libxt_state.so: libxt_conntrack.so ln -fs $< $@ -libxt_REDIRECT.so: libxt_DNAT.so +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 @@ -169,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; +initexts := ext exta extb ext4 ext6 +initext_depfiles = $(patsubst %,.init%.dd,${initexts}) +initext_sources = $(patsubst %,init%.c,${initexts}) -.initexta.dd: FORCE - @echo "${initexta_func}" >$@.tmp; \ +${initext_depfiles}: FORCE + @echo "$(value $(patsubst .%.dd,%,$@)_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; - -.initext6.dd: FORCE - @echo "${initext6_func}" >$@.tmp; \ - cmp -s $@ $@.tmp || mv $@.tmp $@; \ - rm -f $@.tmp; - -initext.c: .initext.dd - ${AM_VERBOSE_GEN} - @( \ - echo "" >$@; \ - for i in ${initext_func}; do \ - echo "extern void lib$${i}_init(void);" >>$@; \ - done; \ - echo "void init_extensions(void);" >>$@; \ - echo "void init_extensions(void)" >>$@; \ - echo "{" >>$@; \ - for i in ${initext_func}; do \ - echo " ""lib$${i}_init();" >>$@; \ - done; \ - echo "}" >>$@; \ - ); - -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 +${initext_sources}: %.c: .%.dd ${AM_VERBOSE_GEN} @( \ + initext_func="$(value $(basename $@)_func)"; \ + funcname="init_extensions$(patsubst initext%.c,%,$@)"; \ echo "" >$@; \ - for i in ${initext4_func}; do \ + for i in $${initext_func}; do \ echo "extern void lib$${i}_init(void);" >>$@; \ done; \ - echo "void init_extensions4(void);" >>$@; \ - echo "void init_extensions4(void)" >>$@; \ + echo "void $${funcname}(void);" >>$@; \ + echo "void $${funcname}(void)" >>$@; \ echo "{" >>$@; \ - for i in ${initext4_func}; do \ + for i in $${initext_func}; do \ echo " ""lib$${i}_init();" >>$@; \ done; \ echo "}" >>$@; \ ); -initext6.c: .initext6.dd - ${AM_VERBOSE_GEN} - @( \ - echo "" >$@; \ - for i in ${initext6_func}; do \ - echo "extern void lib$${i}_init(void);" >>$@; \ - done; \ - echo "void init_extensions6(void);" >>$@; \ - echo "void init_extensions6(void)" >>$@; \ - echo "{" >>$@; \ - for i in ${initext6_func}; do \ - echo " ""lib$${i}_init();" >>$@; \ - done; \ - echo "}" >>$@; \ - ); - # # Manual pages # @@ -302,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_standard.t b/extensions/libarpt_standard.t index e84a00b7..007fa2b8 100644 --- a/extensions/libarpt_standard.t +++ b/extensions/libarpt_standard.t @@ -12,3 +12,5 @@ -i lo --destination-mac 11:22:33:44:55:66;-i lo --dst-mac 11:22:33:44:55:66;OK --source-mac Unicast;--src-mac 00:00:00:00:00:00/01:00:00:00:00:00;OK ! --src-mac Multicast;! --src-mac 01:00:00:00:00:00/01:00:00:00:00:00;OK +--src-mac=01:02:03:04:05:06 --dst-mac=07:08:09:0A:0B:0C --h-length=6 --opcode=Request --h-type=Ethernet --proto-type=ipv4;--src-mac 01:02:03:04:05:06 --dst-mac 07:08:09:0a:0b:0c --opcode 1 --proto-type 0x800;OK +--src-mac ! 01:02:03:04:05:06 --dst-mac ! 07:08:09:0A:0B:0C --h-length ! 6 --opcode ! Request --h-type ! Ethernet --proto-type ! ipv4;! --src-mac 01:02:03:04:05:06 ! --dst-mac 07:08:09:0a:0b:0c ! --h-length 6 ! --opcode 1 ! --h-type 1 ! --proto-type 0x800;OK 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..68f34bff 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: { @@ -668,6 +432,24 @@ static void brip_xlate_nh(struct xt_xlate *xl, xtables_ipmask_to_numeric(maskp)); } +static bool may_skip_ether_type_dep(uint8_t flags) +{ + /* these convert to "ip (s|d)addr" matches */ + if (flags & (EBT_IP_SOURCE | EBT_IP_DEST)) + return true; + + /* icmp match triggers implicit ether type dependency in nft */ + if (flags & EBT_IP_ICMP) + return true; + + /* allow if "ip protocol" match is created by brip_xlate() */ + if (flags & EBT_IP_PROTO && + !(flags & (EBT_IP_SPORT | EBT_IP_DPORT | EBT_IP_ICMP))) + return true; + + return false; +} + static int brip_xlate(struct xt_xlate *xl, const struct xt_xlate_mt_params *params) { @@ -677,11 +459,14 @@ static int brip_xlate(struct xt_xlate *xl, brip_xlate_nh(xl, info, EBT_IP_SOURCE); brip_xlate_nh(xl, info, EBT_IP_DEST); + if (!may_skip_ether_type_dep(info->bitmask)) + xt_xlate_add(xl, "ether type ip "); + if (info->bitmask & EBT_IP_TOS) { - xt_xlate_add(xl, "ip dscp "); + xt_xlate_add(xl, "@nh,8,8 "); if (info->invflags & EBT_IP_TOS) xt_xlate_add(xl, "!= "); - xt_xlate_add(xl, "0x%02x ", info->tos & 0x3f); /* remove ECN bits */ + xt_xlate_add(xl, "0x%02x ", info->tos); } if (info->bitmask & EBT_IP_PROTO) { struct protoent *pe; diff --git a/extensions/libebt_ip.txlate b/extensions/libebt_ip.txlate index b5882c34..44ce9276 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 +ebtables-translate -I OUTPUT -p ip -o eth0 --ip-tos 0xff +nft 'insert rule bridge filter OUTPUT oifname "eth0" ether type ip @nh,8,8 0xff 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 ether type ip 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 ether type ip 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..7821935e 100644 --- a/extensions/libebt_redirect.c +++ b/extensions/libebt_redirect.c @@ -83,10 +83,10 @@ static int brredir_xlate(struct xt_xlate *xl, { const struct ebt_redirect_info *red = (const void*)params->target->data; - xt_xlate_add(xl, "meta set pkttype host"); - if (red->target != EBT_ACCEPT) + xt_xlate_add(xl, "meta pkttype set host"); + if (red->target != EBT_CONTINUE) 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_redirect.txlate b/extensions/libebt_redirect.txlate new file mode 100644 index 00000000..d073ec77 --- /dev/null +++ b/extensions/libebt_redirect.txlate @@ -0,0 +1,8 @@ +ebtables-translate -t nat -A PREROUTING -d de:ad:00:00:be:ef -j redirect +nft 'add rule bridge nat PREROUTING ether daddr de:ad:00:00:be:ef counter meta pkttype set host accept' + +ebtables-translate -t nat -A PREROUTING -d de:ad:00:00:be:ef -j redirect --redirect-target RETURN +nft 'add rule bridge nat PREROUTING ether daddr de:ad:00:00:be:ef counter meta pkttype set host return' + +ebtables-translate -t nat -A PREROUTING -d de:ad:00:00:be:ef -j redirect --redirect-target CONTINUE +nft 'add rule bridge nat PREROUTING ether daddr de:ad:00:00:be:ef counter meta pkttype set host' 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_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_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_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 4fe272b2..00000000 --- a/extensions/libip6t_SNAT.c +++ /dev/null @@ -1,308 +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, - F_TO_SRC = 1 << O_TO_SRC, - F_RANDOM = 1 << O_RANDOM, - F_RANDOM_FULLY = 1 << O_RANDOM_FULLY, -}; - -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}, - {.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: - parse_to(cb->arg, portok, range); - 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 deleted file mode 100644 index 30b80167..00000000 --- a/extensions/libipt_CLUSTERIP.t +++ /dev/null @@ -1,4 +0,0 @@ -: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;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_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_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 211a20bc..00000000 --- a/extensions/libipt_SNAT.c +++ /dev/null @@ -1,280 +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, - F_TO_SRC = 1 << O_TO_SRC, - F_RANDOM = 1 << O_RANDOM, - F_RANDOM_FULLY = 1 << O_RANDOM_FULLY, -}; - -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}, - {.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_ipv4_range *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.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; - } - *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; -} - -static void SNAT_parse(struct xt_option_call *cb) -{ - struct nf_nat_ipv4_multi_range_compat *mr = cb->data; - const struct ipt_entry *entry = cb->xt_entry; - 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: - parse_to(cb->arg, portok, mr->range); - break; - case O_PERSISTENT: - mr->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_ipv4_multi_range_compat *mr = cb->data; - - if ((cb->xflags & f) == f) - mr->range->flags |= NF_NAT_RANGE_PROTO_RANDOM; - if ((cb->xflags & r) == r) - mr->range->flags |= NF_NAT_RANGE_PROTO_RANDOM_FULLY; - - mr->rangesize = 1; -} - -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 nf_nat_ipv4_multi_range_compat *mr = - (const void *)target->data; - - printf(" to:"); - print_range(mr->range); - if (mr->range->flags & NF_NAT_RANGE_PROTO_RANDOM) - printf(" random"); - if (mr->range->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) - printf(" random-fully"); - if (mr->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_ipv4_multi_range_compat *mr = - (const void *)target->data; - - printf(" --to-source "); - print_range(mr->range); - if (mr->range->flags & NF_NAT_RANGE_PROTO_RANDOM) - printf(" --random"); - if (mr->range->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) - printf(" --random-fully"); - if (mr->range->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 nf_nat_ipv4_multi_range_compat *mr = - (const void *)params->target->data; - bool sep_need = false; - const char *sep = " "; - - xt_xlate_add(xl, "snat to "); - print_range_xlate(mr->range, xl); - if (mr->range->flags & NF_NAT_RANGE_PROTO_RANDOM) { - xt_xlate_add(xl, " random"); - sep_need = true; - } - if (mr->range->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) { - if (sep_need) - sep = ","; - xt_xlate_add(xl, "%sfully-random", sep); - sep_need = true; - } - if (mr->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_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.txlate b/extensions/libxt_DNAT.txlate index a6597656..e005245d 100644 --- a/extensions/libxt_DNAT.txlate +++ b/extensions/libxt_DNAT.txlate @@ -1,35 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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_MARK.c b/extensions/libxt_MARK.c index 1536563d..100f6a38 100644 --- a/extensions/libxt_MARK.c +++ b/extensions/libxt_MARK.c @@ -366,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_DNAT.c b/extensions/libxt_NAT.c index 5696d31f..2a634398 100644 --- a/extensions/libxt_DNAT.c +++ b/extensions/libxt_NAT.c @@ -25,17 +25,45 @@ .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, - F_TO_DEST = 1 << O_TO_DEST, - F_TO_PORTS = 1 << O_TO_PORTS, - F_RANDOM = 1 << O_RANDOM, }; +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( @@ -63,6 +91,22 @@ static void REDIRECT_help(void) " [--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}, @@ -197,7 +241,7 @@ parse_to(const char *orig_arg, bool portok, if (!inet_pton(family, start, &range->min_addr)) xtables_error(PARAMETER_PROBLEM, - "Bad IP address \"%s\"", arg); + "Bad IP address \"%s\"", start); if (dash) { if (!inet_pton(family, dash + 1, &range->max_addr)) xtables_error(PARAMETER_PROBLEM, @@ -209,8 +253,8 @@ parse_to(const char *orig_arg, bool portok, return; } -static void __DNAT_parse(struct xt_option_call *cb, __u16 proto, - struct nf_nat_range2 *range, int family) +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 || @@ -221,6 +265,7 @@ static void __DNAT_parse(struct xt_option_call *cb, __u16 proto, 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: @@ -229,19 +274,26 @@ static void __DNAT_parse(struct xt_option_call *cb, __u16 proto, 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 DNAT_parse(struct xt_option_call *cb) +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 = {}; - __DNAT_parse(cb, entry->ip.proto, &range, AF_INET); + __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 */ @@ -250,19 +302,42 @@ static void DNAT_parse(struct xt_option_call *cb) 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 __DNAT_fcheck(struct xt_fcheck_call *cb, unsigned int *flags) +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) { - static const unsigned int redir_f = F_TO_PORTS | F_RANDOM; - static const unsigned int dnat_f = F_TO_DEST | F_RANDOM; + const struct ipt_entry *entry = cb->xt_entry; - if ((cb->xflags & redir_f) == redir_f || - (cb->xflags & dnat_f) == dnat_f) - *flags |= NF_NAT_RANGE_PROTO_RANDOM; + __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) @@ -274,8 +349,15 @@ static void DNAT_fcheck(struct xt_fcheck_call *cb) if (mr->range[0].flags & NF_NAT_RANGE_PROTO_OFFSET) xtables_error(PARAMETER_PROBLEM, "Shifted portmap ranges not supported with this kernel"); +} - __DNAT_fcheck(cb, &mr->range[0].flags); +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) @@ -325,31 +407,15 @@ static void __NAT_print(const struct nf_nat_range2 *r, int family, } 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); } -#define __DNAT_print(r, family) __NAT_print(r, family, "to:", "", false) -#define __DNAT_save(r, family) __NAT_print(r, family, "--to-destination ", "--", false) -#define __REDIRECT_print(r) __NAT_print(r, AF_INET, "redir ports ", "", true) -#define __REDIRECT_save(r) __NAT_print(r, AF_INET, "--to-ports ", "--", true) - -static void DNAT_print(const void *ip, const struct xt_entry_target *target, - int numeric) -{ - struct nf_nat_range2 range = RANGE2_INIT_FROM_IPV4_MRC(target->data); - - __DNAT_print(&range, AF_INET); -} - -static void DNAT_save(const void *ip, const struct xt_entry_target *target) -{ - struct nf_nat_range2 range = RANGE2_INIT_FROM_IPV4_MRC(target->data); - - __DNAT_save(&range, AF_INET); -} static int -__DNAT_xlate(struct xt_xlate *xl, const struct nf_nat_range2 *r, int family) +__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 = " "; @@ -358,13 +424,17 @@ __DNAT_xlate(struct xt_xlate *xl, const struct nf_nat_range2 *r, int family) if (r->flags & NF_NAT_RANGE_PROTO_OFFSET) return 0; - xt_xlate_add(xl, "dnat"); + 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 = ","; @@ -372,183 +442,74 @@ __DNAT_xlate(struct xt_xlate *xl, const struct nf_nat_range2 *r, int family) return 1; } -static int DNAT_xlate(struct xt_xlate *xl, - const struct xt_xlate_tg_params *params) -{ - struct nf_nat_range2 range = - RANGE2_INIT_FROM_IPV4_MRC(params->target->data); - - return __DNAT_xlate(xl, &range, AF_INET); +#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); \ } -static void DNAT_parse_v2(struct xt_option_call *cb) -{ - const struct ipt_entry *entry = cb->xt_entry; +PSX_GEN(DNAT, RANGE2_INIT_FROM_IPV4_MRC, \ + AF_INET, "to:", "--to-destination ", false, "dnat") - __DNAT_parse(cb, entry->ip.proto, cb->data, AF_INET); -} +PSX_GEN(DNATv2, *(struct nf_nat_range2 *), \ + AF_INET, "to:", "--to-destination ", false, "dnat") -static void DNAT_fcheck_v2(struct xt_fcheck_call *cb) -{ - __DNAT_fcheck(cb, &((struct nf_nat_range2 *)cb->data)->flags); -} +PSX_GEN(DNAT6, RANGE2_INIT_FROM_RANGE, \ + AF_INET6, "to:", "--to-destination ", false, "dnat") -static void DNAT_print_v2(const void *ip, const struct xt_entry_target *target, - int numeric) -{ - __DNAT_print((const void *)target->data, AF_INET); -} +PSX_GEN(DNAT6v2, *(struct nf_nat_range2 *), \ + AF_INET6, "to:", "--to-destination ", false, "dnat") -static void DNAT_save_v2(const void *ip, const struct xt_entry_target *target) -{ - __DNAT_save((const void *)target->data, AF_INET); -} +PSX_GEN(REDIRECT, RANGE2_INIT_FROM_IPV4_MRC, \ + AF_INET, "redir ports ", "--to-ports ", true, "redirect") -static int DNAT_xlate_v2(struct xt_xlate *xl, - const struct xt_xlate_tg_params *params) -{ - return __DNAT_xlate(xl, (const void *)params->target->data, AF_INET); -} - -static void DNAT_parse6(struct xt_option_call *cb) -{ - const struct ip6t_entry *entry = cb->xt_entry; - struct nf_nat_range *range_v1 = (void *)cb->data; - struct nf_nat_range2 range = {}; +PSX_GEN(REDIRECT6, RANGE2_INIT_FROM_RANGE, \ + AF_INET6, "redir ports ", "--to-ports ", true, "redirect") - memcpy(&range, range_v1, sizeof(*range_v1)); - __DNAT_parse(cb, entry->ipv6.proto, &range, AF_INET6); - memcpy(range_v1, &range, sizeof(*range_v1)); -} +PSX_GEN(SNAT, RANGE2_INIT_FROM_IPV4_MRC, \ + AF_INET, "to:", "--to-source ", false, "snat") -static void DNAT_fcheck6(struct xt_fcheck_call *cb) -{ - struct nf_nat_range *range = (void *)cb->data; +PSX_GEN(SNAT6, RANGE2_INIT_FROM_RANGE, \ + AF_INET6, "to:", "--to-source ", false, "snat") - if (range->flags & NF_NAT_RANGE_PROTO_OFFSET) - xtables_error(PARAMETER_PROBLEM, - "Shifted portmap ranges not supported with this kernel"); +PSX_GEN(MASQUERADE, RANGE2_INIT_FROM_IPV4_MRC, \ + AF_INET, "masq ports: ", "--to-ports ", true, "masquerade") - __DNAT_fcheck(cb, &range->flags); -} +PSX_GEN(MASQUERADE6, RANGE2_INIT_FROM_RANGE, \ + AF_INET6, "masq ports: ", "--to-ports ", true, "masquerade") -static void DNAT_print6(const void *ip, const struct xt_entry_target *target, - int numeric) -{ - struct nf_nat_range2 range = {}; - - memcpy(&range, (const void *)target->data, sizeof(struct nf_nat_range)); - __DNAT_print(&range, AF_INET6); -} - -static void DNAT_save6(const void *ip, const struct xt_entry_target *target) -{ - struct nf_nat_range2 range = {}; - - memcpy(&range, (const void *)target->data, sizeof(struct nf_nat_range)); - __DNAT_save(&range, AF_INET6); -} - -static int DNAT_xlate6(struct xt_xlate *xl, - const struct xt_xlate_tg_params *params) -{ - struct nf_nat_range2 range = {}; - - memcpy(&range, (const void *)params->target->data, - sizeof(struct nf_nat_range)); - return __DNAT_xlate(xl, &range, AF_INET6); -} - -static void DNAT_parse6_v2(struct xt_option_call *cb) -{ - const struct ip6t_entry *entry = cb->xt_entry; - - __DNAT_parse(cb, entry->ipv6.proto, cb->data, AF_INET6); -} - -static void DNAT_print6_v2(const void *ip, const struct xt_entry_target *target, - int numeric) -{ - __DNAT_print((const void *)target->data, AF_INET6); -} - -static void DNAT_save6_v2(const void *ip, const struct xt_entry_target *target) -{ - __DNAT_save((const void *)target->data, AF_INET6); -} - -static int DNAT_xlate6_v2(struct xt_xlate *xl, - const struct xt_xlate_tg_params *params) -{ - return __DNAT_xlate(xl, (const void *)params->target->data, AF_INET6); -} - -static int __REDIRECT_xlate(struct xt_xlate *xl, - const struct nf_nat_range2 *range) -{ - char *range_str = sprint_range(range, AF_INET); - - xt_xlate_add(xl, "redirect"); - if (strlen(range_str)) - xt_xlate_add(xl, " to %s", range_str); - if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) - xt_xlate_add(xl, " random"); - - return 1; -} - -static void REDIRECT_print(const void *ip, const struct xt_entry_target *target, - int numeric) -{ - struct nf_nat_range2 range = RANGE2_INIT_FROM_IPV4_MRC(target->data); - - __REDIRECT_print(&range); -} - -static void REDIRECT_save(const void *ip, const struct xt_entry_target *target) -{ - struct nf_nat_range2 range = RANGE2_INIT_FROM_IPV4_MRC(target->data); - - __REDIRECT_save(&range); -} - -static int REDIRECT_xlate(struct xt_xlate *xl, - const struct xt_xlate_tg_params *params) -{ - struct nf_nat_range2 range = - RANGE2_INIT_FROM_IPV4_MRC(params->target->data); - - return __REDIRECT_xlate(xl, &range); -} - -static void REDIRECT_print6(const void *ip, const struct xt_entry_target *target, - int numeric) -{ - struct nf_nat_range2 range = {}; - - memcpy(&range, (const void *)target->data, sizeof(struct nf_nat_range)); - __REDIRECT_print(&range); -} - -static void REDIRECT_save6(const void *ip, const struct xt_entry_target *target) -{ - struct nf_nat_range2 range = {}; - - memcpy(&range, (const void *)target->data, sizeof(struct nf_nat_range)); - __REDIRECT_save(&range); -} - -static int REDIRECT_xlate6(struct xt_xlate *xl, - const struct xt_xlate_tg_params *params) -{ - struct nf_nat_range2 range = {}; - - memcpy(&range, (const void *)params->target->data, - sizeof(struct nf_nat_range)); - return __REDIRECT_xlate(xl, &range); -} - -static struct xtables_target dnat_tg_reg[] = { +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, @@ -559,12 +520,39 @@ static struct xtables_target dnat_tg_reg[] = { .help = DNAT_help, .print = DNAT_print, .save = DNAT_save, - .x6_parse = DNAT_parse, + .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, @@ -574,12 +562,26 @@ static struct xtables_target dnat_tg_reg[] = { .help = REDIRECT_help, .print = REDIRECT_print, .save = REDIRECT_save, - .x6_parse = DNAT_parse, + .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, @@ -587,12 +589,12 @@ static struct xtables_target dnat_tg_reg[] = { .size = XT_ALIGN(sizeof(struct nf_nat_range)), .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)), .help = DNAT_help, - .print = DNAT_print6, - .save = DNAT_save6, - .x6_parse = DNAT_parse6, + .print = DNAT6_print, + .save = DNAT6_save, + .x6_parse = NAT_parse6, .x6_fcheck = DNAT_fcheck6, .x6_options = DNAT_opts, - .xlate = DNAT_xlate6, + .xlate = DNAT6_xlate, }, { .name = "REDIRECT", @@ -601,12 +603,12 @@ static struct xtables_target dnat_tg_reg[] = { .size = XT_ALIGN(sizeof(struct nf_nat_range)), .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)), .help = REDIRECT_help, - .print = REDIRECT_print6, - .save = REDIRECT_save6, - .x6_parse = DNAT_parse6, + .print = REDIRECT6_print, + .save = REDIRECT6_save, + .x6_parse = NAT_parse6, .x6_fcheck = DNAT_fcheck6, .x6_options = REDIRECT_opts, - .xlate = REDIRECT_xlate6, + .xlate = REDIRECT6_xlate, }, { .name = "DNAT", @@ -616,12 +618,11 @@ static struct xtables_target dnat_tg_reg[] = { .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, + .print = DNATv2_print, + .save = DNATv2_save, .x6_parse = DNAT_parse_v2, - .x6_fcheck = DNAT_fcheck_v2, .x6_options = DNAT_opts, - .xlate = DNAT_xlate_v2, + .xlate = DNATv2_xlate, }, { .name = "DNAT", @@ -631,16 +632,15 @@ static struct xtables_target dnat_tg_reg[] = { .size = XT_ALIGN(sizeof(struct nf_nat_range2)), .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range2)), .help = DNAT_help_v2, - .print = DNAT_print6_v2, - .save = DNAT_save6_v2, + .print = DNAT6v2_print, + .save = DNAT6v2_save, .x6_parse = DNAT_parse6_v2, - .x6_fcheck = DNAT_fcheck_v2, .x6_options = DNAT_opts, - .xlate = DNAT_xlate6_v2, + .xlate = DNAT6v2_xlate, }, }; void _init(void) { - xtables_register_targets(dnat_tg_reg, ARRAY_SIZE(dnat_tg_reg)); + xtables_register_targets(nat_tg_reg, ARRAY_SIZE(nat_tg_reg)); } diff --git a/extensions/libxt_NFLOG.c b/extensions/libxt_NFLOG.c index 7a12e5ac..d12ef044 100644 --- a/extensions/libxt_NFLOG.c +++ b/extensions/libxt_NFLOG.c @@ -112,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) @@ -135,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; } 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.t b/extensions/libxt_REDIRECT.t index f607dd0a..362efa84 100644 --- a/extensions/libxt_REDIRECT.t +++ b/extensions/libxt_REDIRECT.t @@ -14,3 +14,4 @@ -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 index 2c536495..dc473340 100644 --- a/extensions/libxt_REDIRECT.txlate +++ b/extensions/libxt_REDIRECT.txlate @@ -1,26 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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_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.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 234085c5..09548c29 100644 --- a/extensions/libxt_conntrack.c +++ b/extensions/libxt_conntrack.c @@ -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.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..6e2b2745 100644 --- a/extensions/libxt_sctp.c +++ b/extensions/libxt_sctp.c @@ -50,7 +50,7 @@ static void sctp_help(void) " --dport ...\n" "[!] --chunk-types (all|any|none) (chunktype[:flags])+ match if all, any or none of\n" " chunktypes are present\n" -"chunktypes - DATA INIT INIT_ACK SACK HEARTBEAT HEARTBEAT_ACK ABORT SHUTDOWN SHUTDOWN_ACK ERROR COOKIE_ECHO COOKIE_ACK ECN_ECNE ECN_CWR SHUTDOWN_COMPLETE ASCONF ASCONF_ACK FORWARD_TSN ALL NONE\n"); +"chunktypes - DATA INIT INIT_ACK SACK HEARTBEAT HEARTBEAT_ACK ABORT SHUTDOWN SHUTDOWN_ACK ERROR COOKIE_ECHO COOKIE_ACK ECN_ECNE ECN_CWR SHUTDOWN_COMPLETE I_DATA RE_CONFIG PAD ASCONF ASCONF_ACK FORWARD_TSN I_FORWARD_TSN ALL NONE\n"); } static const struct option sctp_opts[] = { @@ -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 a2137ab1..471bde8a 100644 --- a/extensions/libxt_set.c +++ b/extensions/libxt_set.c @@ -334,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; } @@ -354,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; @@ -418,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': @@ -523,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; @@ -587,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_standard.t b/extensions/libxt_standard.t index 56d6da2e..6ed978e4 100644 --- a/extensions/libxt_standard.t +++ b/extensions/libxt_standard.t @@ -21,3 +21,6 @@ -s 10.11.12.13/255.128.0.0;-s 10.0.0.0/9;OK -s 10.11.12.13/255.0.255.0;-s 10.0.12.0/255.0.255.0;OK -s 10.11.12.13/255.0.12.0;-s 10.0.12.0/255.0.12.0;OK +:FORWARD +--protocol=tcp --source=1.2.3.4 --destination=5.6.7.8/32 --in-interface=eth0 --out-interface=eth1 --jump=ACCEPT;-s 1.2.3.4/32 -d 5.6.7.8/32 -i eth0 -o eth1 -p tcp -j ACCEPT;OK +-ptcp -s1.2.3.4 -d5.6.7.8/32 -ieth0 -oeth1 -jACCEPT;-s 1.2.3.4/32 -d 5.6.7.8/32 -i eth0 -o eth1 -p tcp -j ACCEPT;OK 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_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.txlate b/extensions/libxt_tcpmss.txlate index d3f1b27d..82475e67 100644 --- a/extensions/libxt_tcpmss.txlate +++ b/extensions/libxt_tcpmss.txlate @@ -1,11 +1,11 @@ iptables-translate -A INPUT -m tcpmss --mss 42 -nft add rule ip filter INPUT tcp option maxseg size 42 counter +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 +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 +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 +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/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..c4d4d8e4 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 @@ -95,6 +97,14 @@ enum nft_verdicts { * @NFT_MSG_NEWFLOWTABLE: add new flow table (enum nft_flowtable_attributes) * @NFT_MSG_GETFLOWTABLE: get flow table (enum nft_flowtable_attributes) * @NFT_MSG_DELFLOWTABLE: delete flow table (enum nft_flowtable_attributes) + * @NFT_MSG_GETRULE_RESET: get rules and reset stateful expressions (enum nft_obj_attributes) + * @NFT_MSG_DESTROYTABLE: destroy a table (enum nft_table_attributes) + * @NFT_MSG_DESTROYCHAIN: destroy a chain (enum nft_chain_attributes) + * @NFT_MSG_DESTROYRULE: destroy a rule (enum nft_rule_attributes) + * @NFT_MSG_DESTROYSET: destroy a set (enum nft_set_attributes) + * @NFT_MSG_DESTROYSETELEM: destroy a set element (enum nft_set_elem_attributes) + * @NFT_MSG_DESTROYOBJ: destroy a stateful object (enum nft_object_attributes) + * @NFT_MSG_DESTROYFLOWTABLE: destroy flow table (enum nft_flowtable_attributes) */ enum nf_tables_msg_types { NFT_MSG_NEWTABLE, @@ -122,6 +132,14 @@ enum nf_tables_msg_types { NFT_MSG_NEWFLOWTABLE, NFT_MSG_GETFLOWTABLE, NFT_MSG_DELFLOWTABLE, + NFT_MSG_GETRULE_RESET, + NFT_MSG_DESTROYTABLE, + NFT_MSG_DESTROYCHAIN, + NFT_MSG_DESTROYRULE, + NFT_MSG_DESTROYSET, + NFT_MSG_DESTROYSETELEM, + NFT_MSG_DESTROYOBJ, + NFT_MSG_DESTROYFLOWTABLE, NFT_MSG_MAX, }; @@ -131,7 +149,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 +161,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 +180,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 +191,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 +201,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 +227,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 +242,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 +260,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 +273,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 +311,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 +324,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 +343,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 +383,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 +404,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 +414,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 +432,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 +446,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 +513,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 +553,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 +574,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 +598,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) @@ -590,7 +685,7 @@ enum nft_range_ops { * enum nft_range_attributes - nf_tables range expression netlink attributes * * @NFTA_RANGE_SREG: source register of data to compare (NLA_U32: nft_registers) - * @NFTA_RANGE_OP: cmp operation (NLA_U32: nft_cmp_ops) + * @NFTA_RANGE_OP: cmp operation (NLA_U32: nft_range_ops) * @NFTA_RANGE_FROM_DATA: data range from (NLA_NESTED: nft_data_attributes) * @NFTA_RANGE_TO_DATA: data range to (NLA_NESTED: nft_data_attributes) */ @@ -631,10 +726,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 +745,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 +758,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) @@ -670,11 +769,14 @@ enum nft_dynset_attributes { * @NFT_PAYLOAD_LL_HEADER: link layer header * @NFT_PAYLOAD_NETWORK_HEADER: network header * @NFT_PAYLOAD_TRANSPORT_HEADER: transport header + * @NFT_PAYLOAD_INNER_HEADER: inner header / payload */ enum nft_payload_bases { NFT_PAYLOAD_LL_HEADER, NFT_PAYLOAD_NETWORK_HEADER, NFT_PAYLOAD_TRANSPORT_HEADER, + NFT_PAYLOAD_INNER_HEADER, + NFT_PAYLOAD_TUN_HEADER, }; /** @@ -682,16 +784,44 @@ 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 { NFT_PAYLOAD_L4CSUM_PSEUDOHDR = (1 << 0), }; +enum nft_inner_type { + NFT_INNER_UNSPEC = 0, + NFT_INNER_VXLAN, + NFT_INNER_GENEVE, +}; + +enum nft_inner_flags { + NFT_INNER_HDRSIZE = (1 << 0), + NFT_INNER_LL = (1 << 1), + NFT_INNER_NH = (1 << 2), + NFT_INNER_TH = (1 << 3), +}; +#define NFT_INNER_MASK (NFT_INNER_HDRSIZE | NFT_INNER_LL | \ + NFT_INNER_NH | NFT_INNER_TH) + +enum nft_inner_attributes { + NFTA_INNER_UNSPEC, + NFTA_INNER_NUM, + NFTA_INNER_TYPE, + NFTA_INNER_FLAGS, + NFTA_INNER_HDRSIZE, + NFTA_INNER_EXPR, + __NFTA_INNER_MAX +}; +#define NFTA_INNER_MAX (__NFTA_INNER_MAX - 1) + /** * enum nft_payload_attributes - nf_tables payload expression netlink attributes * @@ -727,10 +857,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) @@ -744,7 +878,7 @@ enum nft_exthdr_op { * @NFTA_EXTHDR_LEN: extension header length (NLA_U32) * @NFTA_EXTHDR_FLAGS: extension header flags (NLA_U32) * @NFTA_EXTHDR_OP: option match type (NLA_U32) - * @NFTA_EXTHDR_SREG: option match type (NLA_U32) + * @NFTA_EXTHDR_SREG: source register (NLA_U32: nft_registers) */ enum nft_exthdr_attributes { NFTA_EXTHDR_UNSPEC, @@ -788,6 +922,16 @@ 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 + * @NFT_META_BRI_BROUTE: packet br_netfilter_broute bit */ enum nft_meta_keys { NFT_META_LEN, @@ -798,7 +942,8 @@ enum nft_meta_keys { NFT_META_OIF, NFT_META_IIFNAME, NFT_META_OIFNAME, - NFT_META_IIFTYPE, + NFT_META_IFTYPE, +#define NFT_META_IIFTYPE NFT_META_IFTYPE NFT_META_OIFTYPE, NFT_META_SKUID, NFT_META_SKGID, @@ -816,6 +961,17 @@ 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, + NFT_META_BRI_BROUTE, + __NFT_META_IIFTYPE, }; /** @@ -825,13 +981,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 +1014,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 +1026,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 +1063,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 +1106,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 +1117,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 +1143,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 +1211,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,12 +1245,27 @@ 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) + * @NFTA_LOG_GROUP: netlink group to send messages to (NLA_U16) * @NFTA_LOG_PREFIX: prefix to prepend to log messages (NLA_STRING) * @NFTA_LOG_SNAPLEN: length of payload to include in netlink message (NLA_U32) - * @NFTA_LOG_QTHRESHOLD: queue threshold (NLA_U32) + * @NFTA_LOG_QTHRESHOLD: queue threshold (NLA_U16) * @NFTA_LOG_LEVEL: log level (NLA_U32) * @NFTA_LOG_FLAGS: logging flags (NLA_U32) */ @@ -1040,6 +1282,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 +1353,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 +1449,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 +1514,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 +1606,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 +1649,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 +1660,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 +1686,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 +1696,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 +1718,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 +1765,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 +1854,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 +1863,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 +1876,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/xt_LOG.h b/include/linux/netfilter/xt_LOG.h new file mode 100644 index 00000000..167d4ddd --- /dev/null +++ b/include/linux/netfilter/xt_LOG.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _XT_LOG_H +#define _XT_LOG_H + +/* make sure not to change this without changing nf_log.h:NF_LOG_* (!) */ +#define XT_LOG_TCPSEQ 0x01 /* Log TCP sequence numbers */ +#define XT_LOG_TCPOPT 0x02 /* Log TCP options */ +#define XT_LOG_IPOPT 0x04 /* Log IP options */ +#define XT_LOG_UID 0x08 /* Log UID owning local socket */ +#define XT_LOG_NFLOG 0x10 /* Unsupported, don't reuse */ +#define XT_LOG_MACDECODE 0x20 /* Decode MAC header */ +#define XT_LOG_MASK 0x2f + +struct xt_log_info { + unsigned char level; + unsigned char logflags; + char prefix[30]; +}; + +#endif /* _XT_LOG_H */ 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/linux/netfilter_ipv4/ipt_LOG.h b/include/linux/netfilter_ipv4/ipt_LOG.h deleted file mode 100644 index dcdbadf9..00000000 --- a/include/linux/netfilter_ipv4/ipt_LOG.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef _IPT_LOG_H -#define _IPT_LOG_H - -/* make sure not to change this without changing netfilter.h:NF_LOG_* (!) */ -#define IPT_LOG_TCPSEQ 0x01 /* Log TCP sequence numbers */ -#define IPT_LOG_TCPOPT 0x02 /* Log TCP options */ -#define IPT_LOG_IPOPT 0x04 /* Log IP options */ -#define IPT_LOG_UID 0x08 /* Log UID owning local socket */ -#define IPT_LOG_NFLOG 0x10 /* Unsupported, don't reuse */ -#define IPT_LOG_MACDECODE 0x20 /* Decode MAC header */ -#define IPT_LOG_MASK 0x2f - -struct ipt_log_info { - unsigned char level; - unsigned char logflags; - char prefix[30]; -}; - -#endif /*_IPT_LOG_H*/ diff --git a/include/linux/netfilter_ipv6/ip6t_LOG.h b/include/linux/netfilter_ipv6/ip6t_LOG.h deleted file mode 100644 index 9dd5579e..00000000 --- a/include/linux/netfilter_ipv6/ip6t_LOG.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef _IP6T_LOG_H -#define _IP6T_LOG_H - -/* make sure not to change this without changing netfilter.h:NF_LOG_* (!) */ -#define IP6T_LOG_TCPSEQ 0x01 /* Log TCP sequence numbers */ -#define IP6T_LOG_TCPOPT 0x02 /* Log TCP options */ -#define IP6T_LOG_IPOPT 0x04 /* Log IP options */ -#define IP6T_LOG_UID 0x08 /* Log UID owning local socket */ -#define IP6T_LOG_NFLOG 0x10 /* Unsupported, don't use */ -#define IP6T_LOG_MACDECODE 0x20 /* Decode MAC header */ -#define IP6T_LOG_MASK 0x2f - -struct ip6t_log_info { - unsigned char level; - unsigned char logflags; - char prefix[30]; -}; - -#endif /*_IPT_LOG_H*/ diff --git a/include/xtables.h b/include/xtables.h index 9eba4f61..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. */ @@ -621,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); diff --git a/iptables-test.py b/iptables-test.py index 6acaa822..ef0a35d3 100755 --- a/iptables-test.py +++ b/iptables-test.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # # (C) 2012-2013 by Pablo Neira Ayuso <pablo@netfilter.org> # @@ -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) @@ -79,14 +79,12 @@ def run_test(iptables, rule, rule_save, res, filename, lineno, netns): :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 " + EXECUTABLE + " " + cmd - - ret = execute_cmd(cmd, filename, lineno) + ret = execute_cmd(cmd, filename, lineno, netns) # # report failed test @@ -103,7 +101,7 @@ 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 @@ -126,7 +124,7 @@ def run_test(iptables, rule, rule_save, res, filename, lineno, netns): command = EXECUTABLE + " " + command if netns: - command = "ip netns exec ____iptables-container-test " + command + command = "ip netns exec " + netns + " " + command args = tokens[1:] proc = subprocess.Popen(command, shell=True, @@ -140,7 +138,7 @@ 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 @@ -149,7 +147,7 @@ def run_test(iptables, rule, rule_save, res, filename, lineno, netns): if res == "OK": reason = "cannot find: " + iptables + " -I " + rule print_error(reason, filename, lineno) - delete_rule(iptables, rule, filename, lineno) + delete_rule(iptables, rule, filename, lineno, netns) return -1 else: # do not report this error @@ -158,7 +156,7 @@ def run_test(iptables, rule, rule_save, res, filename, lineno, netns): if res != "OK": reason = "should not match: " + cmd print_error(reason, filename, lineno) - delete_rule(iptables, rule, filename, lineno) + delete_rule(iptables, rule, filename, lineno, netns) return -1 # Test "ip netns del NETNS" path with rules in place @@ -167,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. @@ -175,11 +173,15 @@ 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 = 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, stderr=subprocess.STDOUT, stdout=log_file) @@ -220,12 +222,163 @@ def variant_res(res, variant, alt_res=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. @@ -253,6 +406,14 @@ def run_test_file(filename, netns): # 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 @@ -262,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: @@ -272,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 " + EXECUTABLE + " " + external_cmd - execute_cmd(external_cmd, filename, lineno) + execute_cmd(external_cmd, filename, lineno, netns) continue if line[0] == "*": @@ -334,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 @@ -400,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') @@ -413,14 +569,17 @@ def main(): show_missing() return - global EXECUTABLE - EXECUTABLE = "xtables-legacy-multi" + variants = [] + if args.legacy: + variants.append("legacy") if args.nftables: - EXECUTABLE = "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", @@ -431,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 23f8352d..8a722702 100644 --- a/iptables/Makefile.am +++ b/iptables/Makefile.am @@ -6,46 +6,55 @@ 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.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-ruleparse.c nft-ruleparse.h \ + nft-ruleparse-arp.c nft-ruleparse-bridge.c \ + nft-ruleparse-ipv4.c nft-ruleparse-ipv6.c \ + 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 @@ -57,22 +66,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 @@ -86,7 +92,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 \ @@ -102,9 +108,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 :) @@ -139,3 +148,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 d75aae24..0304b508 100644 --- a/iptables/ebtables-nft.8 +++ b/iptables/ebtables-nft.8 @@ -55,7 +55,7 @@ It is analogous to the application, but less complicated, due to the fact that the Ethernet protocol is much simpler than the IP protocol. .SS CHAINS -There are two ebtables tables with built-in chains in the +There are three ebtables tables with built-in chains in the Linux kernel. These tables are used to divide functionality into different sets of rules. Each set of rules is called a chain. Each chain is an ordered list of rules that can match Ethernet frames. If a @@ -81,7 +81,10 @@ an 'extension' (see below) or a jump to a user-defined chain. .B ACCEPT means to let the frame through. .B DROP -means the frame has to be dropped. +means the frame has to be dropped. In the +.BR BROUTING " chain however, the " ACCEPT " and " DROP " target have different" +meanings (see the info provided for the +.BR -t " option)." .B CONTINUE means the next rule has to be checked. This can be handy, f.e., to know how many frames pass a certain point in the chain, to log those frames or to apply multiple @@ -93,17 +96,13 @@ For the extension targets please refer to the .B "TARGET EXTENSIONS" section of this man page. .SS TABLES -As stated earlier, there are two ebtables tables in the Linux -kernel. The table names are -.BR filter " and " nat . -Of these two tables, +As stated earlier, the table names are +.BR filter ", " nat " and " broute . +Of these tables, the filter table is the default table that the command operates on. -If you are working with the filter table, then you can drop the '-t filter' -argument to the ebtables command. However, you will need to provide -the -t argument for -.B nat -table. Moreover, the -t argument must be the -first argument on the ebtables command line, if used. +If you are working with a table other than filter, you will need to provide +the -t argument. Moreover, the -t argument must be the +first argument on the ebtables command line, if used. .TP .B "-t, --table" .br @@ -131,6 +130,23 @@ iptables world to ebtables it is easier to have the same names. Note that you can change the name .BR "" ( -E ) if you don't like the default. +.br +.br +.B broute +is used to make a brouter, it has one built-in chain: +.BR BROUTING . +The targets +.BR DROP " and " ACCEPT +have a special meaning in the broute table (these names are used for +compatibility reasons with ebtables-legacy). +.B DROP +actually means the frame has to be routed, while +.B ACCEPT +means the frame has to be bridged. The +.B BROUTING +chain is traversed very early. +Normally those frames +would be bridged, but you can decide otherwise here. .SH EBTABLES COMMAND LINE ARGUMENTS After the initial ebtables '-t table' command line argument, the remaining arguments can be divided into several groups. These groups @@ -1059,8 +1075,6 @@ arp message and the hardware address length in the arp header is 6 bytes. .BR "" "See " http://netfilter.org/mailinglists.html .SH BUGS The version of ebtables this man page ships with does not support the -.B broute -table. Also there is no support for .B string match. Further, support for atomic-options .RB ( --atomic-file ", " --atomic-init ", " --atomic-save ", " --atomic-commit ) 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.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 75984cc1..9afc32c1 100644 --- a/iptables/ip6tables.c +++ b/iptables/ip6tables.c @@ -122,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); @@ -179,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))); @@ -277,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, @@ -329,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]; @@ -359,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]; @@ -800,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); } } @@ -908,7 +879,7 @@ int do_command6(int argc, char *argv[], char **table, 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.c b/iptables/iptables-restore.c index 4410a587..6f7ddf93 100644 --- a/iptables/iptables-restore.c +++ b/iptables/iptables-restore.c @@ -78,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; } @@ -184,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) { @@ -209,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'; @@ -249,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, @@ -263,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)); } } @@ -280,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 = {}; @@ -292,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", @@ -302,10 +301,9 @@ 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); diff --git a/iptables/iptables-save.c b/iptables/iptables-save.c index a8dded63..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); 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.c b/iptables/iptables.c index e5207ba1..6f7b3476 100644 --- a/iptables/iptables.c +++ b/iptables/iptables.c @@ -122,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); @@ -178,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))); @@ -276,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, @@ -328,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; @@ -358,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; @@ -795,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); } } @@ -903,7 +874,7 @@ int do_command4(int argc, char *argv[], char **table, 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 e6e4d2d8..265de5f8 100644 --- a/iptables/nft-arp.c +++ b/iptables/nft-arp.c @@ -160,134 +160,6 @@ static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, return ret; } -static void nft_arp_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e, - struct iptables_command_state *cs) -{ - struct arpt_entry *fw = &cs->arp; - uint8_t flags = 0; - - parse_meta(ctx, e, ctx->meta.key, fw->arp.iniface, fw->arp.iniface_mask, - fw->arp.outiface, fw->arp.outiface_mask, - &flags); - - fw->arp.invflags |= flags; -} - -static void parse_mask_ipv4(struct nft_xt_ctx *ctx, struct in_addr *mask) -{ - mask->s_addr = ctx->bitwise.mask[0]; -} - -static bool nft_arp_parse_devaddr(struct nft_xt_ctx *ctx, - struct nftnl_expr *e, - struct arpt_devaddr_info *info) -{ - uint32_t hlen; - bool inv; - - nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &hlen); - - if (hlen != ETH_ALEN) - return false; - - 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 { - memset(info->mask, 0xff, - min(ctx->payload.len, ETH_ALEN)); - } - - return inv; -} - -static void nft_arp_parse_payload(struct nft_xt_ctx *ctx, - struct nftnl_expr *e, - struct iptables_command_state *cs) -{ - struct arpt_entry *fw = &cs->arp; - struct in_addr addr; - uint16_t ar_hrd, ar_pro, ar_op; - uint8_t ar_hln; - bool inv; - - switch (ctx->payload.offset) { - case offsetof(struct arphdr, ar_hrd): - get_cmp_data(e, &ar_hrd, sizeof(ar_hrd), &inv); - fw->arp.arhrd = ar_hrd; - fw->arp.arhrd_mask = 0xffff; - if (inv) - fw->arp.invflags |= IPT_INV_ARPHRD; - break; - case offsetof(struct arphdr, ar_pro): - get_cmp_data(e, &ar_pro, sizeof(ar_pro), &inv); - fw->arp.arpro = ar_pro; - fw->arp.arpro_mask = 0xffff; - if (inv) - fw->arp.invflags |= IPT_INV_PROTO; - break; - case offsetof(struct arphdr, ar_op): - get_cmp_data(e, &ar_op, sizeof(ar_op), &inv); - fw->arp.arpop = ar_op; - fw->arp.arpop_mask = 0xffff; - if (inv) - fw->arp.invflags |= IPT_INV_ARPOP; - break; - case offsetof(struct arphdr, ar_hln): - get_cmp_data(e, &ar_hln, sizeof(ar_hln), &inv); - fw->arp.arhln = ar_hln; - fw->arp.arhln_mask = 0xff; - if (inv) - fw->arp.invflags |= IPT_INV_ARPOP; - break; - default: - if (ctx->payload.offset == sizeof(struct arphdr)) { - if (nft_arp_parse_devaddr(ctx, e, &fw->arp.src_devaddr)) - fw->arp.invflags |= IPT_INV_SRCDEVADDR; - } else if (ctx->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 { - memset(&fw->arp.smsk, 0xff, - min(ctx->payload.len, - sizeof(struct in_addr))); - } - - if (inv) - fw->arp.invflags |= IPT_INV_SRCIP; - } else if (ctx->payload.offset == sizeof(struct arphdr) + - fw->arp.arhln + - sizeof(struct in_addr)) { - if (nft_arp_parse_devaddr(ctx, e, &fw->arp.tgt_devaddr)) - fw->arp.invflags |= IPT_INV_TGTDEVADDR; - } else if (ctx->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 { - memset(&fw->arp.tmsk, 0xff, - min(ctx->payload.len, - sizeof(struct in_addr))); - } - - if (inv) - fw->arp.invflags |= IPT_INV_DSTIP; - } - break; - } -} - static void nft_arp_print_header(unsigned int format, const char *chain, const char *pol, const struct xt_counters *counters, @@ -401,7 +273,8 @@ after_devsrc: after_devdst: - if (fw->arp.arhln_mask != 255 || fw->arp.arhln != 6) { + if (fw->arp.arhln_mask != 255 || fw->arp.arhln != 6 || + fw->arp.invflags & IPT_INV_ARPHLN) { printf("%s%s", sep, fw->arp.invflags & IPT_INV_ARPHLN ? "! " : ""); printf("--h-length %d", fw->arp.arhln); @@ -425,7 +298,8 @@ after_devdst: sep = " "; } - if (fw->arp.arhrd_mask != 65535 || fw->arp.arhrd != htons(1)) { + if (fw->arp.arhrd_mask != 65535 || fw->arp.arhrd != htons(1) || + fw->arp.invflags & IPT_INV_ARPHRD) { uint16_t tmp = ntohs(fw->arp.arhrd); printf("%s%s", sep, fw->arp.invflags & IPT_INV_ARPHRD @@ -490,7 +364,7 @@ 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 struct iptables_command_state *cs_a, @@ -701,7 +575,7 @@ nft_arp_add_entry(struct nft_handle *h, 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, + ret = nft_cmd_rule_append(h, chain, table, cs, verbose); } else { ret = nft_cmd_rule_insert(h, chain, table, cs, @@ -776,19 +650,17 @@ 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, .print_header = nft_arp_print_header, .print_rule = nft_arp_print_rule, .save_rule = nft_arp_save_rule, .save_chain = nft_arp_save_chain, + .rule_parse = &nft_ruleparse_ops_arp, .cmd_parse = { .post_parse = nft_arp_post_parse, }, .rule_to_cs = nft_rule_to_iptables_command_state, .init_cs = nft_arp_init_cs, - .clear_cs = nft_clear_iptables_command_state, - .parse_target = nft_ipv46_parse_target, + .clear_cs = xtables_clear_iptables_command_state, .add_entry = nft_arp_add_entry, .delete_entry = nft_arp_delete_entry, .check_entry = nft_arp_check_entry, diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index 106bcc72..6e509507 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -95,11 +95,66 @@ static void add_logical_outiface(struct nft_handle *h, struct nftnl_rule *r, add_cmp_ptr(r, op, iface, iface_len + 1, reg); } +static int add_meta_broute(struct nftnl_rule *r) +{ + struct nftnl_expr *expr; + + expr = nftnl_expr_alloc("immediate"); + if (expr == NULL) + return -1; + + nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_DREG, NFT_REG32_01); + nftnl_expr_set_u8(expr, NFTNL_EXPR_IMM_DATA, 1); + nftnl_rule_add_expr(r, expr); + + expr = nftnl_expr_alloc("meta"); + if (expr == NULL) + return -1; + nftnl_expr_set_u32(expr, NFTNL_EXPR_META_KEY, NFT_META_BRI_BROUTE); + nftnl_expr_set_u32(expr, NFTNL_EXPR_META_SREG, NFT_REG32_01); + + nftnl_rule_add_expr(r, expr); + return 0; +} + static int _add_action(struct nftnl_rule *r, struct iptables_command_state *cs) { + const char *table = nftnl_rule_get_str(r, NFTNL_RULE_TABLE); + + if (cs->target && + table && strcmp(table, "broute") == 0) { + if (strcmp(cs->jumpto, XTC_LABEL_DROP) == 0) { + int ret = add_meta_broute(r); + + if (ret) + return ret; + + cs->jumpto = "ACCEPT"; + } + } + 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"); + + if (!strcmp(m->u.user.name, "ip") && fw->ethproto != htons(ETH_P_IP)) + xtables_error(PARAMETER_PROBLEM, + "For IP filtering the protocol must be specified as IPv4."); + + if (!strcmp(m->u.user.name, "ip6") && fw->ethproto != htons(ETH_P_IPV6)) + xtables_error(PARAMETER_PROBLEM, + "For IPv6 filtering the protocol must be specified as IPv6."); + + return add_match(h, r, m); +} + static int nft_bridge_add(struct nft_handle *h, struct nftnl_rule *r, struct iptables_command_state *cs) @@ -108,6 +163,20 @@ static int nft_bridge_add(struct nft_handle *h, struct ebt_entry *fw = &cs->eb; uint32_t op; + if (fw->bitmask & EBT_ISOURCE) { + op = nft_invflags2cmp(fw->invflags, EBT_ISOURCE); + 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(h, r, NFT_PAYLOAD_LL_HEADER, + offsetof(struct ethhdr, h_dest), + fw->destmac, fw->destmsk, ETH_ALEN, op); + } + if (fw->in[0] != '\0') { op = nft_invflags2cmp(fw->invflags, EBT_IIN); add_iniface(h, r, fw->in, op); @@ -128,34 +197,27 @@ static int nft_bridge_add(struct nft_handle *h, add_logical_outiface(h, r, fw->logical_out, op); } - if (fw->bitmask & EBT_ISOURCE) { - op = nft_invflags2cmp(fw->invflags, EBT_ISOURCE); - 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(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(h, r, offsetof(struct ethhdr, h_proto), 2, NFT_PAYLOAD_LL_HEADER, ®); - add_cmp_u16(r, fw->ethproto, op, reg); + + 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)) @@ -169,352 +231,12 @@ static int nft_bridge_add(struct nft_handle *h, return _add_action(r, cs); } -static void nft_bridge_parse_meta(struct nft_xt_ctx *ctx, - struct nftnl_expr *e, - struct iptables_command_state *cs) -{ - struct ebt_entry *fw = &cs->eb; - uint8_t invflags = 0; - char iifname[IFNAMSIZ] = {}, oifname[IFNAMSIZ] = {}; - - parse_meta(ctx, e, ctx->meta.key, iifname, NULL, oifname, NULL, &invflags); - - switch (ctx->meta.key) { - case NFT_META_BRI_IIFNAME: - if (invflags & IPT_INV_VIA_IN) - cs->eb.invflags |= EBT_ILOGICALIN; - snprintf(fw->logical_in, sizeof(fw->logical_in), "%s", iifname); - break; - case NFT_META_IIFNAME: - if (invflags & IPT_INV_VIA_IN) - cs->eb.invflags |= EBT_IIN; - snprintf(fw->in, sizeof(fw->in), "%s", iifname); - break; - case NFT_META_BRI_OIFNAME: - if (invflags & IPT_INV_VIA_OUT) - cs->eb.invflags |= EBT_ILOGICALOUT; - snprintf(fw->logical_out, sizeof(fw->logical_out), "%s", oifname); - break; - case NFT_META_OIFNAME: - if (invflags & IPT_INV_VIA_OUT) - cs->eb.invflags |= EBT_IOUT; - snprintf(fw->out, sizeof(fw->out), "%s", oifname); - break; - default: - break; - } -} - -static void nft_bridge_parse_payload(struct nft_xt_ctx *ctx, - struct nftnl_expr *e, - struct iptables_command_state *cs) -{ - struct ebt_entry *fw = &cs->eb; - unsigned char addr[ETH_ALEN]; - unsigned short int ethproto; - bool inv; - int i; - - switch (ctx->payload.offset) { - case offsetof(struct ethhdr, h_dest): - get_cmp_data(e, addr, sizeof(addr), &inv); - for (i = 0; i < ETH_ALEN; i++) - fw->destmac[i] = addr[i]; - 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 { - memset(&fw->destmsk, 0xff, - min(ctx->payload.len, ETH_ALEN)); - } - fw->bitmask |= EBT_IDEST; - break; - case offsetof(struct ethhdr, h_source): - get_cmp_data(e, addr, sizeof(addr), &inv); - for (i = 0; i < ETH_ALEN; i++) - 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 { - memset(&fw->sourcemsk, 0xff, - min(ctx->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; - if (inv) - fw->invflags |= EBT_IPROTO; - fw->bitmask &= ~EBT_NOPROTO; - break; - } -} - -/* 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) -{ - if (base != 0 || len != ETH_ALEN) - return -1; - - switch (offset) { - case offsetof(struct ether_header, ether_dhost): - return 1; - case offsetof(struct ether_header, ether_shost): - return 0; - default: - return -1; - } -} - -/* return 0 if saddr, 1 if daddr, -1 on error */ -static int -lookup_check_iphdr_payload(uint32_t base, uint32_t offset, uint32_t len) -{ - if (base != 1 || len != 4) - return -1; - - switch (offset) { - case offsetof(struct iphdr, daddr): - return 1; - case offsetof(struct iphdr, saddr): - return 0; - default: - return -1; - } -} - -/* 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, - bool *dst, bool *ip) -{ - 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); - 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); - return -1; - } - if (!(ctx->flags & NFT_XT_CTX_PAYLOAD)) { - DEBUGP("Previous but no current payload?\n"); - return -1; - } - val2 = lookup_check_iphdr_payload(ctx->payload.base, - ctx->payload.offset, - ctx->payload.len); - if (val2 < 0) { - DEBUGP("unknown payload base/offset/len %d/%d/%d\n", - ctx->payload.base, ctx->payload.offset, - ctx->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); - if (val < 0) { - DEBUGP("unknown payload base/offset/len %d/%d/%d\n", - ctx->payload.base, ctx->payload.offset, - ctx->payload.len); - return -1; - } - } else { - DEBUGP("unknown LHS of lookup expression\n"); - return -1; - } - - if (dst) - *dst = (val == 1); - if (ip) - *ip = (val2 != -1); - return 0; -} - -static int set_elems_to_among_pairs(struct nft_among_pair *pairs, - const struct nftnl_set *s, int cnt) -{ - struct nftnl_set_elems_iter *iter = nftnl_set_elems_iter_create(s); - struct nftnl_set_elem *elem; - size_t tmpcnt = 0; - const void *data; - uint32_t datalen; - int ret = -1; - - if (!iter) { - fprintf(stderr, "BUG: set elems iter allocation failed\n"); - return ret; - } - - while ((elem = nftnl_set_elems_iter_next(iter))) { - data = nftnl_set_elem_get(elem, NFTNL_SET_ELEM_KEY, &datalen); - if (!data) { - fprintf(stderr, "BUG: set elem without key\n"); - goto err; - } - if (datalen > sizeof(*pairs)) { - fprintf(stderr, "BUG: overlong set elem\n"); - goto err; - } - nft_among_insert_pair(pairs, &tmpcnt, data); - } - ret = 0; -err: - nftnl_set_elems_iter_destroy(iter); - return ret; -} - -static struct nftnl_set *set_from_lookup_expr(struct nft_xt_ctx *ctx, - const struct nftnl_expr *e) -{ - const char *set_name = nftnl_expr_get_str(e, NFTNL_EXPR_LOOKUP_SET); - uint32_t set_id = nftnl_expr_get_u32(e, NFTNL_EXPR_LOOKUP_SET_ID); - struct nftnl_set_list *slist; - struct nftnl_set *set; - - slist = nft_set_list_get(ctx->h, ctx->table, set_name); - if (slist) { - set = nftnl_set_list_lookup_byname(slist, set_name); - if (set) - return set; - - set = nft_set_batch_lookup_byid(ctx->h, set_id); - if (set) - return set; - } - - return NULL; -} - -static void nft_bridge_parse_lookup(struct nft_xt_ctx *ctx, - struct nftnl_expr *e) -{ - struct xtables_match *match = NULL; - struct nft_among_data *among_data; - bool is_dst, have_ip, inv; - struct ebt_match *ematch; - struct nftnl_set *s; - 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"); - - cnt = nftnl_set_get_u32(s, NFTNL_SET_DESC_SIZE); - - for (ematch = ctx->cs->match_list; ematch; ematch = ematch->next) { - if (!ematch->ismatch || strcmp(ematch->u.match->name, "among")) - continue; - - match = ematch->u.match; - among_data = (struct nft_among_data *)match->m->data; - - size = cnt + among_data->src.cnt + among_data->dst.cnt; - size *= sizeof(struct nft_among_pair); - - size += XT_ALIGN(sizeof(struct xt_entry_match)) + - sizeof(struct nft_among_data); - - match->m = xtables_realloc(match->m, size); - break; - } - if (!match) { - match = xtables_find_match("among", XTF_TRY_LOAD, - &ctx->cs->matches); - - size = cnt * sizeof(struct nft_among_pair); - size += XT_ALIGN(sizeof(struct xt_entry_match)) + - sizeof(struct nft_among_data); - - match->m = xtables_calloc(1, size); - strcpy(match->m->u.user.name, match->name); - match->m->u.user.revision = match->revision; - xs_init_match(match); - - if (ctx->h->ops->parse_match != NULL) - ctx->h->ops->parse_match(match, ctx->cs); - } - if (!match) - return; - - match->m->u.match_size = size; - - inv = !!(nftnl_expr_get_u32(e, NFTNL_EXPR_LOOKUP_FLAGS) & - NFT_LOOKUP_F_INV); - - among_data = (struct nft_among_data *)match->m->data; - poff = nft_among_prepare_data(among_data, is_dst, cnt, inv, have_ip); - 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, - bool ismatch) -{ - struct ebt_match *m = xtables_calloc(1, sizeof(struct ebt_match)); - - if (ismatch) - m->u.match = object; - else - m->u.watcher = object; - - m->ismatch = ismatch; - if (*match_list == NULL) - *match_list = m; - else - (*match_list)->next = m; -} - -static void nft_bridge_parse_match(struct xtables_match *m, - struct iptables_command_state *cs) -{ - parse_watcher(m, &cs->match_list, true); -} - -static void nft_bridge_parse_target(struct xtables_target *t, - struct iptables_command_state *cs) -{ - /* harcoded names :-( */ - if (strcmp(t->name, "log") == 0 || - strcmp(t->name, "nflog") == 0) { - parse_watcher(t, &cs->match_list, false); - return; - } - - 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) @@ -587,7 +309,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,7 +323,7 @@ static void print_protocol(uint16_t ethproto, bool invert, unsigned int bitmask) static void __nft_bridge_save_rule(const struct iptables_command_state *cs, unsigned int format) { - 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) @@ -732,7 +454,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, }; @@ -745,7 +466,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, }; @@ -776,7 +496,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, @@ -810,20 +529,18 @@ 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 struct iptables_command_state *cs, @@ -840,7 +557,10 @@ static int nft_bridge_xlate(const struct iptables_command_state *cs, 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)) { @@ -863,9 +583,6 @@ static int nft_bridge_xlate(const struct iptables_command_state *cs, 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); @@ -887,11 +604,7 @@ struct nft_family_ops nft_family_ops_bridge = { .add = nft_bridge_add, .is_same = nft_bridge_is_same, .print_payload = NULL, - .parse_meta = nft_bridge_parse_meta, - .parse_payload = nft_bridge_parse_payload, - .parse_lookup = nft_bridge_parse_lookup, - .parse_match = nft_bridge_parse_match, - .parse_target = nft_bridge_parse_target, + .rule_parse = &nft_ruleparse_ops_bridge, .print_table_header = nft_bridge_print_table_header, .print_header = nft_bridge_print_header, .print_rule = nft_bridge_print_rule, diff --git a/iptables/nft-cache.c b/iptables/nft-cache.c index 608e42a7..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) @@ -453,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); @@ -496,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); @@ -591,8 +592,8 @@ 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, &rld); diff --git a/iptables/nft-cache.h b/iptables/nft-cache.h index 58a01526..29ec6b5c 100644 --- a/iptables/nft-cache.h +++ b/iptables/nft-cache.h @@ -1,6 +1,8 @@ #ifndef _NFT_CACHE_H_ #define _NFT_CACHE_H_ +#include <libnftnl/chain.h> + struct nft_handle; struct nft_chain; struct nft_cmd; diff --git a/iptables/nft-cmd.c b/iptables/nft-cmd.c index fcd01bd0..7b2fc3a5 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; cmd->table = xtables_strdup(table); if (chain) @@ -91,7 +92,7 @@ static void nft_cmd_rule_bridge(struct nft_handle *h, const struct nft_cmd *cmd) int nft_cmd_rule_append(struct nft_handle *h, const char *chain, const char *table, struct iptables_command_state *state, - void *ref, bool verbose) + bool verbose) { struct nft_cmd *cmd; diff --git a/iptables/nft-cmd.h b/iptables/nft-cmd.h index b5a99ef7..ae5908d8 100644 --- a/iptables/nft-cmd.h +++ b/iptables/nft-cmd.h @@ -24,6 +24,9 @@ struct nft_cmd { struct xt_counters counters; const char *rename; int counters_save; + struct { + unsigned int lineno; + } error; }; struct nft_cmd *nft_cmd_new(struct nft_handle *h, int command, @@ -34,7 +37,7 @@ void nft_cmd_free(struct nft_cmd *cmd); int nft_cmd_rule_append(struct nft_handle *h, const char *chain, const char *table, struct iptables_command_state *state, - void *ref, bool verbose); + bool verbose); int nft_cmd_rule_insert(struct nft_handle *h, const char *chain, const char *table, struct iptables_command_state *state, int rulenum, bool verbose); diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c index 59c4a41f..d67d8198 100644 --- a/iptables/nft-ipv4.c +++ b/iptables/nft-ipv4.c @@ -33,6 +33,22 @@ static int nft_ipv4_add(struct nft_handle *h, struct nftnl_rule *r, uint32_t op; int ret; + if (cs->fw.ip.src.s_addr || cs->fw.ip.smsk.s_addr || cs->fw.ip.invflags & IPT_INV_SRCIP) { + op = nft_invflags2cmp(cs->fw.ip.invflags, IPT_INV_SRCIP); + add_addr(h, r, NFT_PAYLOAD_NETWORK_HEADER, + offsetof(struct iphdr, saddr), + &cs->fw.ip.src.s_addr, &cs->fw.ip.smsk.s_addr, + sizeof(struct in_addr), op); + } + + if (cs->fw.ip.dst.s_addr || cs->fw.ip.dmsk.s_addr || cs->fw.ip.invflags & IPT_INV_DSTIP) { + op = nft_invflags2cmp(cs->fw.ip.invflags, IPT_INV_DSTIP); + add_addr(h, r, NFT_PAYLOAD_NETWORK_HEADER, + offsetof(struct iphdr, daddr), + &cs->fw.ip.dst.s_addr, &cs->fw.ip.dmsk.s_addr, + sizeof(struct in_addr), op); + } + if (cs->fw.ip.iniface[0] != '\0') { op = nft_invflags2cmp(cs->fw.ip.invflags, IPT_INV_VIA_IN); add_iniface(h, r, cs->fw.ip.iniface, op); @@ -48,20 +64,6 @@ static int nft_ipv4_add(struct nft_handle *h, struct nftnl_rule *r, add_l4proto(h, r, cs->fw.ip.proto, op); } - if (cs->fw.ip.src.s_addr || cs->fw.ip.smsk.s_addr || cs->fw.ip.invflags & IPT_INV_SRCIP) { - op = nft_invflags2cmp(cs->fw.ip.invflags, IPT_INV_SRCIP); - add_addr(h, r, NFT_PAYLOAD_NETWORK_HEADER, - offsetof(struct iphdr, saddr), - &cs->fw.ip.src.s_addr, &cs->fw.ip.smsk.s_addr, - sizeof(struct in_addr), op); - } - if (cs->fw.ip.dst.s_addr || cs->fw.ip.dmsk.s_addr || cs->fw.ip.invflags & IPT_INV_DSTIP) { - op = nft_invflags2cmp(cs->fw.ip.invflags, IPT_INV_DSTIP); - add_addr(h, r, NFT_PAYLOAD_NETWORK_HEADER, - offsetof(struct iphdr, daddr), - &cs->fw.ip.dst.s_addr, &cs->fw.ip.dmsk.s_addr, - sizeof(struct in_addr), op); - } if (cs->fw.ip.flags & IPT_F_FRAG) { uint8_t reg; @@ -115,103 +117,6 @@ static bool nft_ipv4_is_same(const struct iptables_command_state *a, b->fw.ip.iniface_mask, b->fw.ip.outiface_mask); } -static void get_frag(struct nft_xt_ctx *ctx, struct nftnl_expr *e, bool *inv) -{ - uint8_t op; - - /* we assume correct mask and xor */ - if (!(ctx->flags & NFT_XT_CTX_BITWISE)) - return; - - /* we assume correct data */ - op = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP); - if (op == NFT_CMP_EQ) - *inv = true; - else - *inv = false; - - ctx->flags &= ~NFT_XT_CTX_BITWISE; -} - -static void nft_ipv4_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e, - struct iptables_command_state *cs) -{ - switch (ctx->meta.key) { - case NFT_META_L4PROTO: - cs->fw.ip.proto = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA); - if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ) - cs->fw.ip.invflags |= XT_INV_PROTO; - return; - default: - break; - } - - parse_meta(ctx, e, ctx->meta.key, cs->fw.ip.iniface, cs->fw.ip.iniface_mask, - cs->fw.ip.outiface, cs->fw.ip.outiface_mask, - &cs->fw.ip.invflags); -} - -static void parse_mask_ipv4(struct nft_xt_ctx *ctx, struct in_addr *mask) -{ - mask->s_addr = ctx->bitwise.mask[0]; -} - -static void nft_ipv4_parse_payload(struct nft_xt_ctx *ctx, - struct nftnl_expr *e, - struct iptables_command_state *cs) -{ - struct in_addr addr; - uint8_t proto; - bool inv; - - switch(ctx->payload.offset) { - case offsetof(struct iphdr, saddr): - get_cmp_data(e, &addr, sizeof(addr), &inv); - cs->fw.ip.src.s_addr = addr.s_addr; - if (ctx->flags & NFT_XT_CTX_BITWISE) { - parse_mask_ipv4(ctx, &cs->fw.ip.smsk); - ctx->flags &= ~NFT_XT_CTX_BITWISE; - } else { - memset(&cs->fw.ip.smsk, 0xff, - min(ctx->payload.len, sizeof(struct in_addr))); - } - - if (inv) - cs->fw.ip.invflags |= IPT_INV_SRCIP; - break; - case offsetof(struct iphdr, daddr): - get_cmp_data(e, &addr, sizeof(addr), &inv); - cs->fw.ip.dst.s_addr = addr.s_addr; - if (ctx->flags & NFT_XT_CTX_BITWISE) { - parse_mask_ipv4(ctx, &cs->fw.ip.dmsk); - ctx->flags &= ~NFT_XT_CTX_BITWISE; - } else { - memset(&cs->fw.ip.dmsk, 0xff, - min(ctx->payload.len, sizeof(struct in_addr))); - } - - if (inv) - cs->fw.ip.invflags |= IPT_INV_DSTIP; - break; - case offsetof(struct iphdr, protocol): - get_cmp_data(e, &proto, sizeof(proto), &inv); - cs->fw.ip.proto = proto; - if (inv) - cs->fw.ip.invflags |= IPT_INV_PROTO; - break; - case offsetof(struct iphdr, frag_off): - cs->fw.ip.flags |= IPT_F_FRAG; - inv = false; - get_frag(ctx, e, &inv); - if (inv) - cs->fw.ip.invflags |= IPT_INV_FRAG; - break; - default: - DEBUGP("unknown payload offset %d\n", ctx->payload.offset); - break; - } -} - static void nft_ipv4_set_goto_flag(struct iptables_command_state *cs) { cs->fw.ip.flags |= IPT_F_GOTO; @@ -244,7 +149,7 @@ static void nft_ipv4_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 void nft_ipv4_save_rule(const struct iptables_command_state *cs, @@ -365,7 +270,7 @@ nft_ipv4_add_entry(struct nft_handle *h, if (append) { ret = nft_cmd_rule_append(h, chain, table, - cs, NULL, verbose); + cs, verbose); } else { ret = nft_cmd_rule_insert(h, chain, table, cs, rulenum, verbose); @@ -438,20 +343,18 @@ nft_ipv4_replace_entry(struct nft_handle *h, struct nft_family_ops nft_family_ops_ipv4 = { .add = nft_ipv4_add, .is_same = nft_ipv4_is_same, - .parse_meta = nft_ipv4_parse_meta, - .parse_payload = nft_ipv4_parse_payload, .set_goto_flag = nft_ipv4_set_goto_flag, .print_header = print_header, .print_rule = nft_ipv4_print_rule, .save_rule = nft_ipv4_save_rule, .save_chain = nft_ipv46_save_chain, + .rule_parse = &nft_ruleparse_ops_ipv4, .cmd_parse = { .proto_parse = ipv4_proto_parse, .post_parse = ipv4_post_parse, }, - .parse_target = nft_ipv46_parse_target, .rule_to_cs = nft_rule_to_iptables_command_state, - .clear_cs = nft_clear_iptables_command_state, + .clear_cs = xtables_clear_iptables_command_state, .xlate = nft_ipv4_xlate, .add_entry = nft_ipv4_add_entry, .delete_entry = nft_ipv4_delete_entry, diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c index 9a29d18b..658a4f20 100644 --- a/iptables/nft-ipv6.c +++ b/iptables/nft-ipv6.c @@ -32,21 +32,6 @@ static int nft_ipv6_add(struct nft_handle *h, struct nftnl_rule *r, uint32_t op; int ret; - if (cs->fw6.ipv6.iniface[0] != '\0') { - op = nft_invflags2cmp(cs->fw6.ipv6.invflags, IPT_INV_VIA_IN); - add_iniface(h, r, cs->fw6.ipv6.iniface, op); - } - - if (cs->fw6.ipv6.outiface[0] != '\0') { - op = nft_invflags2cmp(cs->fw6.ipv6.invflags, IPT_INV_VIA_OUT); - add_outiface(h, r, cs->fw6.ipv6.outiface, op); - } - - if (cs->fw6.ipv6.proto != 0) { - op = nft_invflags2cmp(cs->fw6.ipv6.invflags, XT_INV_PROTO); - add_l4proto(h, r, cs->fw6.ipv6.proto, op); - } - if (!IN6_IS_ADDR_UNSPECIFIED(&cs->fw6.ipv6.src) || !IN6_IS_ADDR_UNSPECIFIED(&cs->fw6.ipv6.smsk) || (cs->fw6.ipv6.invflags & IPT_INV_SRCIP)) { @@ -56,6 +41,7 @@ static int nft_ipv6_add(struct nft_handle *h, struct nftnl_rule *r, &cs->fw6.ipv6.src, &cs->fw6.ipv6.smsk, sizeof(struct in6_addr), op); } + if (!IN6_IS_ADDR_UNSPECIFIED(&cs->fw6.ipv6.dst) || !IN6_IS_ADDR_UNSPECIFIED(&cs->fw6.ipv6.dmsk) || (cs->fw6.ipv6.invflags & IPT_INV_DSTIP)) { @@ -65,6 +51,22 @@ static int nft_ipv6_add(struct nft_handle *h, struct nftnl_rule *r, &cs->fw6.ipv6.dst, &cs->fw6.ipv6.dmsk, sizeof(struct in6_addr), op); } + + if (cs->fw6.ipv6.iniface[0] != '\0') { + op = nft_invflags2cmp(cs->fw6.ipv6.invflags, IPT_INV_VIA_IN); + add_iniface(h, r, cs->fw6.ipv6.iniface, op); + } + + if (cs->fw6.ipv6.outiface[0] != '\0') { + op = nft_invflags2cmp(cs->fw6.ipv6.invflags, IPT_INV_VIA_OUT); + add_outiface(h, r, cs->fw6.ipv6.outiface, op); + } + + if (cs->fw6.ipv6.proto != 0) { + op = nft_invflags2cmp(cs->fw6.ipv6.invflags, XT_INV_PROTO); + add_l4proto(h, r, cs->fw6.ipv6.proto, op); + } + add_compat(r, cs->fw6.ipv6.proto, cs->fw6.ipv6.invflags & XT_INV_PROTO); for (matchp = cs->matches; matchp; matchp = matchp->next) { @@ -104,77 +106,6 @@ static bool nft_ipv6_is_same(const struct iptables_command_state *a, b->fw6.ipv6.outiface_mask); } -static void nft_ipv6_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e, - struct iptables_command_state *cs) -{ - switch (ctx->meta.key) { - case NFT_META_L4PROTO: - cs->fw6.ipv6.proto = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA); - if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ) - cs->fw6.ipv6.invflags |= XT_INV_PROTO; - return; - default: - break; - } - - parse_meta(ctx, e, ctx->meta.key, cs->fw6.ipv6.iniface, - cs->fw6.ipv6.iniface_mask, cs->fw6.ipv6.outiface, - cs->fw6.ipv6.outiface_mask, &cs->fw6.ipv6.invflags); -} - -static void parse_mask_ipv6(struct nft_xt_ctx *ctx, struct in6_addr *mask) -{ - memcpy(mask, ctx->bitwise.mask, sizeof(struct in6_addr)); -} - -static void nft_ipv6_parse_payload(struct nft_xt_ctx *ctx, - struct nftnl_expr *e, - struct iptables_command_state *cs) -{ - struct in6_addr addr; - uint8_t proto; - bool inv; - - switch (ctx->payload.offset) { - case offsetof(struct ip6_hdr, ip6_src): - get_cmp_data(e, &addr, sizeof(addr), &inv); - memcpy(cs->fw6.ipv6.src.s6_addr, &addr, sizeof(addr)); - if (ctx->flags & NFT_XT_CTX_BITWISE) { - parse_mask_ipv6(ctx, &cs->fw6.ipv6.smsk); - ctx->flags &= ~NFT_XT_CTX_BITWISE; - } else { - memset(&cs->fw6.ipv6.smsk, 0xff, - min(ctx->payload.len, sizeof(struct in6_addr))); - } - - if (inv) - cs->fw6.ipv6.invflags |= IP6T_INV_SRCIP; - break; - case offsetof(struct ip6_hdr, ip6_dst): - get_cmp_data(e, &addr, sizeof(addr), &inv); - memcpy(cs->fw6.ipv6.dst.s6_addr, &addr, sizeof(addr)); - if (ctx->flags & NFT_XT_CTX_BITWISE) { - parse_mask_ipv6(ctx, &cs->fw6.ipv6.dmsk); - ctx->flags &= ~NFT_XT_CTX_BITWISE; - } else { - memset(&cs->fw6.ipv6.dmsk, 0xff, - min(ctx->payload.len, sizeof(struct in6_addr))); - } - - if (inv) - cs->fw6.ipv6.invflags |= IP6T_INV_DSTIP; - break; - case offsetof(struct ip6_hdr, ip6_nxt): - get_cmp_data(e, &proto, sizeof(proto), &inv); - cs->fw6.ipv6.proto = proto; - if (inv) - cs->fw6.ipv6.invflags |= IP6T_INV_PROTO; - default: - DEBUGP("unknown payload offset %d\n", ctx->payload.offset); - break; - } -} - static void nft_ipv6_set_goto_flag(struct iptables_command_state *cs) { cs->fw6.ipv6.flags |= IP6T_F_GOTO; @@ -205,7 +136,7 @@ static void nft_ipv6_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 void nft_ipv6_save_rule(const struct iptables_command_state *cs, @@ -323,7 +254,7 @@ nft_ipv6_add_entry(struct nft_handle *h, &args->d.mask.v6[j], sizeof(struct in6_addr)); if (append) { ret = nft_cmd_rule_append(h, chain, table, - cs, NULL, verbose); + cs, verbose); } else { ret = nft_cmd_rule_insert(h, chain, table, cs, rulenum, verbose); @@ -404,20 +335,18 @@ nft_ipv6_replace_entry(struct nft_handle *h, struct nft_family_ops nft_family_ops_ipv6 = { .add = nft_ipv6_add, .is_same = nft_ipv6_is_same, - .parse_meta = nft_ipv6_parse_meta, - .parse_payload = nft_ipv6_parse_payload, .set_goto_flag = nft_ipv6_set_goto_flag, .print_header = print_header, .print_rule = nft_ipv6_print_rule, .save_rule = nft_ipv6_save_rule, .save_chain = nft_ipv46_save_chain, + .rule_parse = &nft_ruleparse_ops_ipv6, .cmd_parse = { .proto_parse = ipv6_proto_parse, .post_parse = ipv6_post_parse, }, - .parse_target = nft_ipv46_parse_target, .rule_to_cs = nft_rule_to_iptables_command_state, - .clear_cs = nft_clear_iptables_command_state, + .clear_cs = xtables_clear_iptables_command_state, .xlate = nft_ipv6_xlate, .add_entry = nft_ipv6_add_entry, .delete_entry = nft_ipv6_delete_entry, diff --git a/iptables/nft-ruleparse-arp.c b/iptables/nft-ruleparse-arp.c new file mode 100644 index 00000000..b68fb06d --- /dev/null +++ b/iptables/nft-ruleparse-arp.c @@ -0,0 +1,168 @@ +/* + * (C) 2013 by Pablo Neira Ayuso <pablo@netfilter.org> + * (C) 2013 by Giuseppe Longo <giuseppelng@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This code has been sponsored by Sophos Astaro <http://www.sophos.com> + */ + +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <netdb.h> +#include <net/if.h> +#include <net/if_arp.h> +#include <netinet/if_ether.h> + +#include <libnftnl/rule.h> +#include <libnftnl/expr.h> + +#include "nft-shared.h" +#include "nft-ruleparse.h" +#include "xshared.h" + +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 arpt_entry *fw = &cs->arp; + uint8_t flags = 0; + + if (parse_meta(ctx, e, reg->meta_dreg.key, fw->arp.iniface, fw->arp.iniface_mask, + fw->arp.outiface, fw->arp.outiface_mask, + &flags) == 0) { + fw->arp.invflags |= flags; + return; + } + + ctx->errmsg = "Unknown arp meta key"; +} + +static void parse_mask_ipv4(const struct nft_xt_ctx_reg *reg, struct in_addr *mask) +{ + mask->s_addr = reg->bitwise.mask[0]; +} + +static bool nft_arp_parse_devaddr(const struct nft_xt_ctx_reg *reg, + struct nftnl_expr *e, + struct arpt_devaddr_info *info) +{ + uint32_t hlen; + bool inv; + + nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &hlen); + + if (hlen != ETH_ALEN) + return false; + + get_cmp_data(e, info->addr, ETH_ALEN, &inv); + + if (reg->bitwise.set) + memcpy(info->mask, reg->bitwise.mask, ETH_ALEN); + else + memset(info->mask, 0xff, + min(reg->payload.len, ETH_ALEN)); + + return inv; +} + +static void nft_arp_parse_payload(struct nft_xt_ctx *ctx, + const struct nft_xt_ctx_reg *reg, + struct nftnl_expr *e, + struct iptables_command_state *cs) +{ + struct arpt_entry *fw = &cs->arp; + struct in_addr addr; + uint16_t ar_hrd, ar_pro, ar_op; + uint8_t ar_hln, ar_pln; + bool inv; + + 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; + fw->arp.arhrd_mask = 0xffff; + if (inv) + fw->arp.invflags |= IPT_INV_ARPHRD; + break; + case offsetof(struct arphdr, ar_pro): + get_cmp_data(e, &ar_pro, sizeof(ar_pro), &inv); + fw->arp.arpro = ar_pro; + fw->arp.arpro_mask = 0xffff; + if (inv) + fw->arp.invflags |= IPT_INV_PROTO; + break; + case offsetof(struct arphdr, ar_op): + get_cmp_data(e, &ar_op, sizeof(ar_op), &inv); + fw->arp.arpop = ar_op; + fw->arp.arpop_mask = 0xffff; + if (inv) + fw->arp.invflags |= IPT_INV_ARPOP; + break; + case offsetof(struct arphdr, ar_hln): + get_cmp_data(e, &ar_hln, sizeof(ar_hln), &inv); + fw->arp.arhln = ar_hln; + fw->arp.arhln_mask = 0xff; + if (inv) + fw->arp.invflags |= IPT_INV_ARPHLN; + 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 (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 (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 (reg->bitwise.set) + parse_mask_ipv4(reg, &fw->arp.smsk); + else + memset(&fw->arp.smsk, 0xff, + min(reg->payload.len, + sizeof(struct in_addr))); + + if (inv) + fw->arp.invflags |= IPT_INV_SRCIP; + } else if (reg->payload.offset == sizeof(struct arphdr) + + fw->arp.arhln + + sizeof(struct in_addr)) { + if (nft_arp_parse_devaddr(reg, e, &fw->arp.tgt_devaddr)) + fw->arp.invflags |= IPT_INV_TGTDEVADDR; + } 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 (reg->bitwise.set) + parse_mask_ipv4(reg, &fw->arp.tmsk); + else + memset(&fw->arp.tmsk, 0xff, + min(reg->payload.len, + sizeof(struct in_addr))); + + if (inv) + fw->arp.invflags |= IPT_INV_DSTIP; + } else { + ctx->errmsg = "unknown payload offset"; + } + break; + } +} + +struct nft_ruleparse_ops nft_ruleparse_ops_arp = { + .meta = nft_arp_parse_meta, + .payload = nft_arp_parse_payload, + .target = nft_ipv46_parse_target, +}; diff --git a/iptables/nft-ruleparse-bridge.c b/iptables/nft-ruleparse-bridge.c new file mode 100644 index 00000000..50fb9283 --- /dev/null +++ b/iptables/nft-ruleparse-bridge.c @@ -0,0 +1,422 @@ +/* + * (C) 2014 by Giuseppe Longo <giuseppelng@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <netdb.h> +#include <net/if.h> +//#include <net/if_arp.h> +#include <netinet/if_ether.h> + +#include <libnftnl/rule.h> +#include <libnftnl/expr.h> +#include <libnftnl/set.h> + +#include <xtables.h> + +#include "nft.h" /* just for nft_set_batch_lookup_byid? */ +#include "nft-bridge.h" +#include "nft-cache.h" +#include "nft-shared.h" +#include "nft-ruleparse.h" +#include "xshared.h" + +static void nft_bridge_parse_meta(struct nft_xt_ctx *ctx, + const struct nft_xt_ctx_reg *reg, + struct nftnl_expr *e, + struct iptables_command_state *cs) +{ + struct ebt_entry *fw = &cs->eb; + uint8_t invflags = 0; + char iifname[IFNAMSIZ] = {}, oifname[IFNAMSIZ] = {}; + + 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 (reg->meta_dreg.key) { + case NFT_META_BRI_IIFNAME: + if (invflags & IPT_INV_VIA_IN) + cs->eb.invflags |= EBT_ILOGICALIN; + snprintf(fw->logical_in, sizeof(fw->logical_in), "%s", iifname); + break; + case NFT_META_IIFNAME: + if (invflags & IPT_INV_VIA_IN) + cs->eb.invflags |= EBT_IIN; + snprintf(fw->in, sizeof(fw->in), "%s", iifname); + break; + case NFT_META_BRI_OIFNAME: + if (invflags & IPT_INV_VIA_OUT) + cs->eb.invflags |= EBT_ILOGICALOUT; + snprintf(fw->logical_out, sizeof(fw->logical_out), "%s", oifname); + break; + case NFT_META_OIFNAME: + if (invflags & IPT_INV_VIA_OUT) + cs->eb.invflags |= EBT_IOUT; + 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, + const struct nft_xt_ctx_reg *reg, + struct nftnl_expr *e, + struct iptables_command_state *cs) +{ + struct ebt_entry *fw = &cs->eb; + unsigned char addr[ETH_ALEN]; + unsigned short int ethproto; + uint8_t op; + bool inv; + int i; + + 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++) + fw->destmac[i] = addr[i]; + if (inv) + fw->invflags |= EBT_IDEST; + + if (reg->bitwise.set) + memcpy(fw->destmsk, reg->bitwise.mask, ETH_ALEN); + else + memset(&fw->destmsk, 0xff, + min(reg->payload.len, ETH_ALEN)); + fw->bitmask |= EBT_IDEST; + break; + case offsetof(struct ethhdr, h_source): + get_cmp_data(e, addr, sizeof(addr), &inv); + for (i = 0; i < ETH_ALEN; i++) + fw->sourcemac[i] = addr[i]; + if (inv) + fw->invflags |= EBT_ISOURCE; + if (reg->bitwise.set) + memcpy(fw->sourcemsk, reg->bitwise.mask, ETH_ALEN); + else + memset(&fw->sourcemsk, 0xff, + min(reg->payload.len, ETH_ALEN)); + fw->bitmask |= EBT_ISOURCE; + break; + case offsetof(struct ethhdr, h_proto): + __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; + } +} + +/* 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) +{ + if (base != 0 || len != ETH_ALEN) + return -1; + + switch (offset) { + case offsetof(struct ether_header, ether_dhost): + return 1; + case offsetof(struct ether_header, ether_shost): + return 0; + default: + return -1; + } +} + +/* return 0 if saddr, 1 if daddr, -1 on error */ +static int +lookup_check_iphdr_payload(uint32_t base, uint32_t offset, uint32_t len) +{ + if (base != 1 || len != 4) + return -1; + + switch (offset) { + case offsetof(struct iphdr, daddr): + return 1; + case offsetof(struct iphdr, saddr): + return 0; + default: + return -1; + } +} + +/* 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(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; + + 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", + reg->payload.base, reg->payload.offset, + reg->payload.len); + return -1; + } + + 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; + } + + 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", + reg->payload.base, reg->payload.offset, + reg->payload.len); + return -1; + } else if (val != val2) { + DEBUGP("mismatching payload match offsets\n"); + return -1; + } + 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", + reg->payload.base, reg->payload.offset, + reg->payload.len); + return -1; + } + break; + default: + ctx->errmsg = "unsupported lookup key length"; + return -1; + } + + if (dst) + *dst = (val == 1); + if (ip) + *ip = (val2 != -1); + return 0; +} + +static int set_elems_to_among_pairs(struct nft_among_pair *pairs, + const struct nftnl_set *s, int cnt) +{ + struct nftnl_set_elems_iter *iter = nftnl_set_elems_iter_create(s); + struct nftnl_set_elem *elem; + size_t tmpcnt = 0; + const void *data; + uint32_t datalen; + int ret = -1; + + if (!iter) { + fprintf(stderr, "BUG: set elems iter allocation failed\n"); + return ret; + } + + while ((elem = nftnl_set_elems_iter_next(iter))) { + data = nftnl_set_elem_get(elem, NFTNL_SET_ELEM_KEY, &datalen); + if (!data) { + fprintf(stderr, "BUG: set elem without key\n"); + goto err; + } + if (datalen > sizeof(*pairs)) { + fprintf(stderr, "BUG: overlong set elem\n"); + goto err; + } + nft_among_insert_pair(pairs, &tmpcnt, data); + } + ret = 0; +err: + nftnl_set_elems_iter_destroy(iter); + return ret; +} + +static struct nftnl_set *set_from_lookup_expr(struct nft_xt_ctx *ctx, + const struct nftnl_expr *e) +{ + const char *set_name = nftnl_expr_get_str(e, NFTNL_EXPR_LOOKUP_SET); + uint32_t set_id = nftnl_expr_get_u32(e, NFTNL_EXPR_LOOKUP_SET_ID); + struct nftnl_set_list *slist; + struct nftnl_set *set; + + slist = nft_set_list_get(ctx->h, ctx->table, set_name); + if (slist) { + set = nftnl_set_list_lookup_byname(slist, set_name); + if (set) + return set; + + set = nft_set_batch_lookup_byid(ctx->h, set_id); + if (set) + return set; + } + + return NULL; +} + +static void nft_bridge_parse_lookup(struct nft_xt_ctx *ctx, + struct nftnl_expr *e) +{ + struct xtables_match *match = NULL; + struct nft_among_data *among_data; + bool is_dst, have_ip, inv; + struct ebt_match *ematch; + struct nftnl_set *s; + size_t poff, size; + uint32_t cnt; + + 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) { + if (!ematch->ismatch || strcmp(ematch->u.match->name, "among")) + continue; + + match = ematch->u.match; + among_data = (struct nft_among_data *)match->m->data; + + size = cnt + among_data->src.cnt + among_data->dst.cnt; + size *= sizeof(struct nft_among_pair); + + size += XT_ALIGN(sizeof(struct xt_entry_match)) + + sizeof(struct nft_among_data); + + match->m = xtables_realloc(match->m, size); + break; + } + if (!match) { + match = xtables_find_match("among", XTF_TRY_LOAD, + &ctx->cs->matches); + + size = cnt * sizeof(struct nft_among_pair); + size += XT_ALIGN(sizeof(struct xt_entry_match)) + + sizeof(struct nft_among_data); + + match->m = xtables_calloc(1, size); + strcpy(match->m->u.user.name, match->name); + match->m->u.user.revision = match->revision; + xs_init_match(match); + + if (ctx->h->ops->rule_parse->match != NULL) + ctx->h->ops->rule_parse->match(match, ctx->cs); + } + if (!match) + return; + + match->m->u.match_size = size; + + inv = !!(nftnl_expr_get_u32(e, NFTNL_EXPR_LOOKUP_FLAGS) & + NFT_LOOKUP_F_INV); + + among_data = (struct nft_among_data *)match->m->data; + poff = nft_among_prepare_data(among_data, is_dst, cnt, inv, have_ip); + if (set_elems_to_among_pairs(among_data->pairs + poff, s, cnt)) + xtables_error(OTHER_PROBLEM, + "ebtables among pair parsing failed"); +} + +static void parse_watcher(void *object, struct ebt_match **match_list, + bool ismatch) +{ + struct ebt_match *m = xtables_calloc(1, sizeof(struct ebt_match)); + + if (ismatch) + m->u.match = object; + else + m->u.watcher = object; + + m->ismatch = ismatch; + if (*match_list == NULL) + *match_list = m; + else + (*match_list)->next = m; +} + +static void nft_bridge_parse_match(struct xtables_match *m, + struct iptables_command_state *cs) +{ + parse_watcher(m, &cs->match_list, true); +} + +static void nft_bridge_parse_target(struct xtables_target *t, + struct iptables_command_state *cs) +{ + /* harcoded names :-( */ + if (strcmp(t->name, "log") == 0 || + strcmp(t->name, "nflog") == 0) { + parse_watcher(t, &cs->match_list, false); + return; + } + + cs->target = t; + cs->jumpto = t->name; +} + +struct nft_ruleparse_ops nft_ruleparse_ops_bridge = { + .meta = nft_bridge_parse_meta, + .payload = nft_bridge_parse_payload, + .lookup = nft_bridge_parse_lookup, + .match = nft_bridge_parse_match, + .target = nft_bridge_parse_target, +}; diff --git a/iptables/nft-ruleparse-ipv4.c b/iptables/nft-ruleparse-ipv4.c new file mode 100644 index 00000000..c87e159c --- /dev/null +++ b/iptables/nft-ruleparse-ipv4.c @@ -0,0 +1,135 @@ +/* + * (C) 2012-2014 by Pablo Neira Ayuso <pablo@netfilter.org> + * (C) 2013 by Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This code has been sponsored by Sophos Astaro <http://www.sophos.com> + */ + +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <netdb.h> +#include <net/if.h> +#include <netinet/if_ether.h> +#include <netinet/ip.h> + +#include <libnftnl/rule.h> +#include <libnftnl/expr.h> + +#include "nft-shared.h" +#include "nft-ruleparse.h" +#include "xshared.h" + +static void nft_ipv4_parse_meta(struct nft_xt_ctx *ctx, + const struct nft_xt_ctx_reg *reg, + struct nftnl_expr *e, + struct iptables_command_state *cs) +{ + switch (reg->meta_dreg.key) { + case NFT_META_L4PROTO: + cs->fw.ip.proto = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA); + if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ) + cs->fw.ip.invflags |= XT_INV_PROTO; + return; + default: + break; + } + + if (parse_meta(ctx, e, reg->meta_dreg.key, cs->fw.ip.iniface, cs->fw.ip.iniface_mask, + cs->fw.ip.outiface, cs->fw.ip.outiface_mask, + &cs->fw.ip.invflags) == 0) + return; + + ctx->errmsg = "unknown ipv4 meta key"; +} + +static void parse_mask_ipv4(const struct nft_xt_ctx_reg *sreg, struct in_addr *mask) +{ + mask->s_addr = sreg->bitwise.mask[0]; +} + +static bool get_frag(const struct nft_xt_ctx_reg *reg, struct nftnl_expr *e) +{ + uint8_t op; + + /* we assume correct mask and xor */ + if (!reg->bitwise.set) + return false; + + /* we assume correct data */ + op = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP); + if (op == NFT_CMP_EQ) + return true; + + return false; +} + +static void nft_ipv4_parse_payload(struct nft_xt_ctx *ctx, + const struct nft_xt_ctx_reg *sreg, + struct nftnl_expr *e, + struct iptables_command_state *cs) +{ + struct in_addr addr; + uint8_t proto; + bool inv; + + switch (sreg->payload.offset) { + case offsetof(struct iphdr, saddr): + get_cmp_data(e, &addr, sizeof(addr), &inv); + cs->fw.ip.src.s_addr = addr.s_addr; + if (sreg->bitwise.set) { + parse_mask_ipv4(sreg, &cs->fw.ip.smsk); + } else { + memset(&cs->fw.ip.smsk, 0xff, + min(sreg->payload.len, sizeof(struct in_addr))); + } + + if (inv) + cs->fw.ip.invflags |= IPT_INV_SRCIP; + break; + case offsetof(struct iphdr, daddr): + get_cmp_data(e, &addr, sizeof(addr), &inv); + cs->fw.ip.dst.s_addr = addr.s_addr; + if (sreg->bitwise.set) + parse_mask_ipv4(sreg, &cs->fw.ip.dmsk); + else + memset(&cs->fw.ip.dmsk, 0xff, + min(sreg->payload.len, sizeof(struct in_addr))); + + if (inv) + cs->fw.ip.invflags |= IPT_INV_DSTIP; + break; + case offsetof(struct iphdr, protocol): + get_cmp_data(e, &proto, sizeof(proto), &inv); + cs->fw.ip.proto = proto; + if (inv) + cs->fw.ip.invflags |= IPT_INV_PROTO; + break; + case offsetof(struct iphdr, frag_off): + cs->fw.ip.flags |= IPT_F_FRAG; + inv = get_frag(sreg, e); + if (inv) + cs->fw.ip.invflags |= IPT_INV_FRAG; + break; + case offsetof(struct iphdr, ttl): + if (nft_parse_hl(ctx, e, cs) < 0) + ctx->errmsg = "invalid ttl field match"; + break; + default: + DEBUGP("unknown payload offset %d\n", sreg->payload.offset); + ctx->errmsg = "unknown payload offset"; + break; + } +} + +struct nft_ruleparse_ops nft_ruleparse_ops_ipv4 = { + .meta = nft_ipv4_parse_meta, + .payload = nft_ipv4_parse_payload, + .target = nft_ipv46_parse_target, +}; diff --git a/iptables/nft-ruleparse-ipv6.c b/iptables/nft-ruleparse-ipv6.c new file mode 100644 index 00000000..af55420b --- /dev/null +++ b/iptables/nft-ruleparse-ipv6.c @@ -0,0 +1,112 @@ +/* + * (C) 2012-2014 by Pablo Neira Ayuso <pablo@netfilter.org> + * (C) 2013 by Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This code has been sponsored by Sophos Astaro <http://www.sophos.com> + */ + +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <netdb.h> +#include <net/if.h> +#include <netinet/if_ether.h> +#include <netinet/ip6.h> + +#include <libnftnl/rule.h> +#include <libnftnl/expr.h> + +#include "nft-shared.h" +#include "nft-ruleparse.h" +#include "xshared.h" + +static void nft_ipv6_parse_meta(struct nft_xt_ctx *ctx, + const struct nft_xt_ctx_reg *reg, + struct nftnl_expr *e, + struct iptables_command_state *cs) +{ + switch (reg->meta_dreg.key) { + case NFT_META_L4PROTO: + cs->fw6.ipv6.proto = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA); + if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ) + cs->fw6.ipv6.invflags |= XT_INV_PROTO; + return; + default: + break; + } + + if (parse_meta(ctx, e, reg->meta_dreg.key, cs->fw6.ipv6.iniface, + cs->fw6.ipv6.iniface_mask, cs->fw6.ipv6.outiface, + cs->fw6.ipv6.outiface_mask, &cs->fw6.ipv6.invflags) == 0) + return; + + ctx->errmsg = "unknown ipv6 meta key"; +} + +static void parse_mask_ipv6(const struct nft_xt_ctx_reg *reg, + struct in6_addr *mask) +{ + memcpy(mask, reg->bitwise.mask, sizeof(struct in6_addr)); +} + +static void nft_ipv6_parse_payload(struct nft_xt_ctx *ctx, + const struct nft_xt_ctx_reg *reg, + struct nftnl_expr *e, + struct iptables_command_state *cs) +{ + struct in6_addr addr; + uint8_t proto; + bool inv; + + switch (reg->payload.offset) { + case offsetof(struct ip6_hdr, ip6_src): + get_cmp_data(e, &addr, sizeof(addr), &inv); + memcpy(cs->fw6.ipv6.src.s6_addr, &addr, sizeof(addr)); + if (reg->bitwise.set) + parse_mask_ipv6(reg, &cs->fw6.ipv6.smsk); + else + memset(&cs->fw6.ipv6.smsk, 0xff, + min(reg->payload.len, sizeof(struct in6_addr))); + + if (inv) + cs->fw6.ipv6.invflags |= IP6T_INV_SRCIP; + break; + case offsetof(struct ip6_hdr, ip6_dst): + get_cmp_data(e, &addr, sizeof(addr), &inv); + memcpy(cs->fw6.ipv6.dst.s6_addr, &addr, sizeof(addr)); + if (reg->bitwise.set) + parse_mask_ipv6(reg, &cs->fw6.ipv6.dmsk); + else + memset(&cs->fw6.ipv6.dmsk, 0xff, + min(reg->payload.len, sizeof(struct in6_addr))); + + if (inv) + cs->fw6.ipv6.invflags |= IP6T_INV_DSTIP; + break; + case offsetof(struct ip6_hdr, ip6_nxt): + get_cmp_data(e, &proto, sizeof(proto), &inv); + cs->fw6.ipv6.proto = proto; + if (inv) + cs->fw6.ipv6.invflags |= IP6T_INV_PROTO; + case offsetof(struct ip6_hdr, ip6_hlim): + if (nft_parse_hl(ctx, e, cs) < 0) + ctx->errmsg = "invalid ttl field match"; + break; + default: + DEBUGP("unknown payload offset %d\n", reg->payload.offset); + ctx->errmsg = "unknown payload offset"; + break; + } +} + +struct nft_ruleparse_ops nft_ruleparse_ops_ipv6 = { + .meta = nft_ipv6_parse_meta, + .payload = nft_ipv6_parse_payload, + .target = nft_ipv46_parse_target, +}; diff --git a/iptables/nft-ruleparse.c b/iptables/nft-ruleparse.c new file mode 100644 index 00000000..edbbfa40 --- /dev/null +++ b/iptables/nft-ruleparse.c @@ -0,0 +1,1208 @@ +/* + * (C) 2012-2013 by Pablo Neira Ayuso <pablo@netfilter.org> + * (C) 2013 by Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This code has been sponsored by Sophos Astaro <http://www.sophos.com> + */ + +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> + +#include <linux/netfilter/nf_log.h> +#include <linux/netfilter/xt_limit.h> +#include <linux/netfilter/xt_mark.h> +#include <linux/netfilter/xt_NFLOG.h> +#include <linux/netfilter/xt_pkttype.h> + +#include <linux/netfilter_ipv6/ip6t_hl.h> + +#include <libnftnl/rule.h> +#include <libnftnl/expr.h> + +#include <xtables.h> + +#include "nft-ruleparse.h" +#include "nft.h" + +static struct xtables_match * +nft_find_match_in_cs(struct iptables_command_state *cs, const char *name) +{ + struct xtables_rule_match *rm; + struct ebt_match *ebm; + + for (ebm = cs->match_list; ebm; ebm = ebm->next) { + if (ebm->ismatch && + !strcmp(ebm->u.match->m->u.user.name, name)) + return ebm->u.match; + } + for (rm = cs->matches; rm; rm = rm->next) { + if (!strcmp(rm->match->m->u.user.name, name)) + return rm->match; + } + return NULL; +} + +void * +nft_create_match(struct nft_xt_ctx *ctx, + struct iptables_command_state *cs, + const char *name, bool reuse) +{ + struct xtables_match *match; + struct xt_entry_match *m; + unsigned int size; + + if (reuse) { + match = nft_find_match_in_cs(cs, name); + if (match) + return match->m->data; + } + + match = xtables_find_match(name, XTF_TRY_LOAD, + &cs->matches); + if (!match) + return NULL; + + size = XT_ALIGN(sizeof(struct xt_entry_match)) + match->size; + m = xtables_calloc(1, size); + m->u.match_size = size; + m->u.user.revision = match->revision; + + strcpy(m->u.user.name, match->name); + match->m = m; + + xs_init_match(match); + + if (ctx->h->ops->rule_parse->match) + ctx->h->ops->rule_parse->match(match, cs); + + return match->m->data; +} + +static void nft_parse_counter(struct nftnl_expr *e, struct xt_counters *counters) +{ + counters->pcnt = nftnl_expr_get_u64(e, NFTNL_EXPR_CTR_PACKETS); + counters->bcnt = nftnl_expr_get_u64(e, NFTNL_EXPR_CTR_BYTES); +} + +static void nft_parse_payload(struct nft_xt_ctx *ctx, struct nftnl_expr *e) +{ + enum nft_registers regnum = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_DREG); + struct nft_xt_ctx_reg *reg = nft_xt_ctx_get_dreg(ctx, regnum); + + if (!reg) + return; + + reg->type = NFT_XT_REG_PAYLOAD; + reg->payload.base = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_BASE); + reg->payload.offset = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_OFFSET); + reg->payload.len = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_LEN); +} + +static bool nft_parse_meta_set_common(struct nft_xt_ctx* ctx, + struct nft_xt_ctx_reg *sreg) +{ + if ((sreg->type != NFT_XT_REG_IMMEDIATE)) { + ctx->errmsg = "meta sreg is not an immediate"; + return false; + } + + if (sreg->immediate.data[0] == 0) { + ctx->errmsg = "meta sreg immediate is 0"; + return false; + } + + return true; +} + +static void nft_parse_meta_set(struct nft_xt_ctx *ctx, + struct nftnl_expr *e) +{ + struct xtables_target *target; + struct nft_xt_ctx_reg *sreg; + enum nft_registers sregnum; + struct xt_entry_target *t; + unsigned int size; + const char *targname; + + sregnum = nftnl_expr_get_u32(e, NFTNL_EXPR_META_SREG); + sreg = nft_xt_ctx_get_sreg(ctx, sregnum); + if (!sreg) + return; + + switch (nftnl_expr_get_u32(e, NFTNL_EXPR_META_KEY)) { + case NFT_META_NFTRACE: + if (!nft_parse_meta_set_common(ctx, sreg)) + return; + + targname = "TRACE"; + break; + case NFT_META_BRI_BROUTE: + if (!nft_parse_meta_set_common(ctx, sreg)) + return; + + ctx->cs->jumpto = "DROP"; + return; + default: + ctx->errmsg = "meta sreg key not supported"; + return; + } + + target = xtables_find_target(targname, XTF_TRY_LOAD); + if (target == NULL) { + ctx->errmsg = "target TRACE not found"; + return; + } + + size = XT_ALIGN(sizeof(struct xt_entry_target)) + target->size; + + t = xtables_calloc(1, size); + t->u.target_size = size; + t->u.user.revision = target->revision; + strcpy(t->u.user.name, targname); + + target->t = t; + + ctx->h->ops->rule_parse->target(target, ctx->cs); +} + +static void nft_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e) +{ + struct nft_xt_ctx_reg *reg; + + if (nftnl_expr_is_set(e, NFTNL_EXPR_META_SREG)) { + nft_parse_meta_set(ctx, e); + return; + } + + reg = nft_xt_ctx_get_dreg(ctx, nftnl_expr_get_u32(e, NFTNL_EXPR_META_DREG)); + if (!reg) + return; + + reg->meta_dreg.key = nftnl_expr_get_u32(e, NFTNL_EXPR_META_KEY); + reg->type = NFT_XT_REG_META_DREG; +} + +static void nft_parse_bitwise(struct nft_xt_ctx *ctx, struct nftnl_expr *e) +{ + enum nft_registers sregnum = nftnl_expr_get_u32(e, NFTNL_EXPR_BITWISE_SREG); + enum nft_registers dregnum = nftnl_expr_get_u32(e, NFTNL_EXPR_BITWISE_DREG); + struct nft_xt_ctx_reg *sreg = nft_xt_ctx_get_sreg(ctx, sregnum); + struct nft_xt_ctx_reg *dreg = sreg; + const void *data; + uint32_t len; + + if (!sreg) + return; + + if (sregnum != dregnum) { + dreg = nft_xt_ctx_get_sreg(ctx, dregnum); /* sreg, do NOT clear ... */ + if (!dreg) + return; + + *dreg = *sreg; /* .. and copy content instead */ + } + + data = nftnl_expr_get(e, NFTNL_EXPR_BITWISE_XOR, &len); + + if (len > sizeof(dreg->bitwise.xor)) { + ctx->errmsg = "bitwise xor too large"; + return; + } + + memcpy(dreg->bitwise.xor, data, len); + + data = nftnl_expr_get(e, NFTNL_EXPR_BITWISE_MASK, &len); + + if (len > sizeof(dreg->bitwise.mask)) { + ctx->errmsg = "bitwise mask too large"; + return; + } + + memcpy(dreg->bitwise.mask, data, len); + + dreg->bitwise.set = true; +} + +static void nft_parse_icmp(struct nft_xt_ctx *ctx, + struct iptables_command_state *cs, + struct nft_xt_ctx_reg *sreg, + uint8_t op, const char *data, size_t dlen) +{ + struct ipt_icmp icmp = { + .type = UINT8_MAX, + .code = { 0, UINT8_MAX }, + }, *icmpp; + + if (dlen < 1) + goto out_err_len; + + switch (sreg->payload.offset) { + case 0: + icmp.type = data[0]; + if (dlen == 1) + break; + dlen--; + data++; + /* fall through */ + case 1: + if (dlen > 1) + goto out_err_len; + icmp.code[0] = icmp.code[1] = data[0]; + break; + default: + ctx->errmsg = "unexpected payload offset"; + return; + } + + switch (ctx->h->family) { + case NFPROTO_IPV4: + icmpp = nft_create_match(ctx, cs, "icmp", false); + break; + case NFPROTO_IPV6: + if (icmp.type == UINT8_MAX) { + ctx->errmsg = "icmp6 code with any type match not supported"; + return; + } + icmpp = nft_create_match(ctx, cs, "icmp6", false); + break; + default: + ctx->errmsg = "unexpected family for icmp match"; + return; + } + + if (!icmpp) { + ctx->errmsg = "icmp match extension not found"; + return; + } + memcpy(icmpp, &icmp, sizeof(icmp)); + return; + +out_err_len: + ctx->errmsg = "unexpected RHS data length"; +} + +static void port_match_single_to_range(__u16 *ports, __u8 *invflags, + uint8_t op, int port, __u8 invflag) +{ + if (port < 0) + return; + + switch (op) { + case NFT_CMP_NEQ: + *invflags |= invflag; + /* fallthrough */ + case NFT_CMP_EQ: + ports[0] = port; + ports[1] = port; + break; + case NFT_CMP_LT: + ports[1] = max(port - 1, 1); + break; + case NFT_CMP_LTE: + ports[1] = port; + break; + case NFT_CMP_GT: + ports[0] = min(port + 1, UINT16_MAX); + break; + case NFT_CMP_GTE: + ports[0] = port; + break; + } +} + +static void nft_parse_udp(struct nft_xt_ctx *ctx, + struct iptables_command_state *cs, + int sport, int dport, + uint8_t op) +{ + struct xt_udp *udp = nft_create_match(ctx, cs, "udp", true); + + if (!udp) { + ctx->errmsg = "udp match extension not found"; + return; + } + + port_match_single_to_range(udp->spts, &udp->invflags, + op, sport, XT_UDP_INV_SRCPT); + port_match_single_to_range(udp->dpts, &udp->invflags, + op, dport, XT_UDP_INV_DSTPT); +} + +static void nft_parse_tcp(struct nft_xt_ctx *ctx, + struct iptables_command_state *cs, + int sport, int dport, + uint8_t op) +{ + struct xt_tcp *tcp = nft_create_match(ctx, cs, "tcp", true); + + if (!tcp) { + ctx->errmsg = "tcp match extension not found"; + return; + } + + port_match_single_to_range(tcp->spts, &tcp->invflags, + op, sport, XT_TCP_INV_SRCPT); + port_match_single_to_range(tcp->dpts, &tcp->invflags, + op, dport, XT_TCP_INV_DSTPT); +} + +static void nft_parse_th_port(struct nft_xt_ctx *ctx, + struct iptables_command_state *cs, + uint8_t proto, + int sport, int dport, uint8_t op) +{ + switch (proto) { + case IPPROTO_UDP: + nft_parse_udp(ctx, cs, sport, dport, op); + break; + case IPPROTO_TCP: + nft_parse_tcp(ctx, cs, sport, dport, op); + break; + default: + ctx->errmsg = "unknown layer 4 protocol for TH match"; + } +} + +static void nft_parse_tcp_flags(struct nft_xt_ctx *ctx, + struct iptables_command_state *cs, + uint8_t op, uint8_t flags, uint8_t mask) +{ + struct xt_tcp *tcp = nft_create_match(ctx, cs, "tcp", true); + + if (!tcp) { + ctx->errmsg = "tcp match extension not found"; + return; + } + + if (op == NFT_CMP_NEQ) + tcp->invflags |= XT_TCP_INV_FLAGS; + tcp->flg_cmp = flags; + tcp->flg_mask = mask; +} + +static void nft_parse_transport(struct nft_xt_ctx *ctx, + struct nftnl_expr *e, + struct iptables_command_state *cs) +{ + struct nft_xt_ctx_reg *sreg; + enum nft_registers reg; + uint32_t sdport; + uint16_t port; + uint8_t proto, op; + unsigned int len; + + switch (ctx->h->family) { + case NFPROTO_IPV4: + proto = ctx->cs->fw.ip.proto; + break; + case NFPROTO_IPV6: + proto = ctx->cs->fw6.ipv6.proto; + break; + default: + ctx->errmsg = "invalid family for TH match"; + return; + } + + nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &len); + op = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP); + + reg = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_SREG); + sreg = nft_xt_ctx_get_sreg(ctx, reg); + if (!sreg) + return; + + if (sreg->type != NFT_XT_REG_PAYLOAD) { + ctx->errmsg = "sgreg not payload"; + return; + } + + switch (proto) { + case IPPROTO_UDP: + case IPPROTO_TCP: + break; + case IPPROTO_ICMP: + case IPPROTO_ICMPV6: + nft_parse_icmp(ctx, cs, sreg, op, + nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &len), + len); + return; + default: + ctx->errmsg = "unsupported layer 4 protocol value"; + return; + } + + switch(sreg->payload.offset) { + case 0: /* th->sport */ + switch (len) { + case 2: /* load sport only */ + port = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_CMP_DATA)); + nft_parse_th_port(ctx, cs, proto, port, -1, op); + return; + case 4: /* load both src and dst port */ + sdport = ntohl(nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_DATA)); + nft_parse_th_port(ctx, cs, proto, sdport >> 16, sdport & 0xffff, op); + return; + } + break; + case 2: /* th->dport */ + switch (len) { + case 2: + port = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_CMP_DATA)); + nft_parse_th_port(ctx, cs, proto, -1, port, op); + return; + } + break; + case 13: /* th->flags */ + if (len == 1 && proto == IPPROTO_TCP) { + uint8_t flags = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA); + uint8_t mask = ~0; + + if (sreg->bitwise.set) + memcpy(&mask, &sreg->bitwise.mask, sizeof(mask)); + + nft_parse_tcp_flags(ctx, cs, op, flags, mask); + } + return; + } +} + +static void nft_parse_cmp(struct nft_xt_ctx *ctx, struct nftnl_expr *e) +{ + struct nft_xt_ctx_reg *sreg; + uint32_t reg; + + reg = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_SREG); + + sreg = nft_xt_ctx_get_sreg(ctx, reg); + if (!sreg) + return; + + switch (sreg->type) { + case NFT_XT_REG_UNDEF: + ctx->errmsg = "cmp sreg undef"; + break; + case NFT_XT_REG_META_DREG: + ctx->h->ops->rule_parse->meta(ctx, sreg, e, ctx->cs); + break; + case NFT_XT_REG_PAYLOAD: + switch (sreg->payload.base) { + case NFT_PAYLOAD_LL_HEADER: + if (ctx->h->family == NFPROTO_BRIDGE) + ctx->h->ops->rule_parse->payload(ctx, sreg, e, ctx->cs); + break; + case NFT_PAYLOAD_NETWORK_HEADER: + ctx->h->ops->rule_parse->payload(ctx, sreg, e, ctx->cs); + break; + case NFT_PAYLOAD_TRANSPORT_HEADER: + nft_parse_transport(ctx, e, ctx->cs); + break; + } + + break; + default: + ctx->errmsg = "cmp sreg has unknown type"; + break; + } +} + +static void nft_parse_immediate(struct nft_xt_ctx *ctx, struct nftnl_expr *e) +{ + const char *chain = nftnl_expr_get_str(e, NFTNL_EXPR_IMM_CHAIN); + struct iptables_command_state *cs = ctx->cs; + struct xt_entry_target *t; + uint32_t size; + int verdict; + + if (nftnl_expr_is_set(e, NFTNL_EXPR_IMM_DATA)) { + struct nft_xt_ctx_reg *dreg; + const void *imm_data; + uint32_t len; + + imm_data = nftnl_expr_get(e, NFTNL_EXPR_IMM_DATA, &len); + dreg = nft_xt_ctx_get_dreg(ctx, nftnl_expr_get_u32(e, NFTNL_EXPR_IMM_DREG)); + if (!dreg) + return; + + if (len > sizeof(dreg->immediate.data)) { + ctx->errmsg = "oversized immediate data"; + return; + } + + memcpy(dreg->immediate.data, imm_data, len); + dreg->immediate.len = len; + dreg->type = NFT_XT_REG_IMMEDIATE; + + return; + } + + verdict = nftnl_expr_get_u32(e, NFTNL_EXPR_IMM_VERDICT); + /* Standard target? */ + switch(verdict) { + case NF_ACCEPT: + if (cs->jumpto && strcmp(ctx->table, "broute") == 0) + break; + cs->jumpto = "ACCEPT"; + break; + case NF_DROP: + cs->jumpto = "DROP"; + break; + case NFT_RETURN: + cs->jumpto = "RETURN"; + break;; + case NFT_GOTO: + if (ctx->h->ops->set_goto_flag) + ctx->h->ops->set_goto_flag(cs); + /* fall through */ + case NFT_JUMP: + cs->jumpto = chain; + /* fall through */ + default: + return; + } + + cs->target = xtables_find_target(cs->jumpto, XTF_TRY_LOAD); + if (!cs->target) { + ctx->errmsg = "verdict extension not found"; + return; + } + + size = XT_ALIGN(sizeof(struct xt_entry_target)) + cs->target->size; + t = xtables_calloc(1, size); + t->u.target_size = size; + t->u.user.revision = cs->target->revision; + strcpy(t->u.user.name, cs->jumpto); + cs->target->t = t; +} + +static void nft_parse_match(struct nft_xt_ctx *ctx, struct nftnl_expr *e) +{ + uint32_t mt_len; + const char *mt_name = nftnl_expr_get_str(e, NFTNL_EXPR_MT_NAME); + const void *mt_info = nftnl_expr_get(e, NFTNL_EXPR_MT_INFO, &mt_len); + struct xtables_match *match; + struct xtables_rule_match **matches; + struct xt_entry_match *m; + + switch (ctx->h->family) { + case NFPROTO_IPV4: + case NFPROTO_IPV6: + case NFPROTO_BRIDGE: + matches = &ctx->cs->matches; + break; + default: + fprintf(stderr, "BUG: nft_parse_match() unknown family %d\n", + ctx->h->family); + exit(EXIT_FAILURE); + } + + match = xtables_find_match(mt_name, XTF_TRY_LOAD, matches); + if (match == NULL) { + ctx->errmsg = "match extension not found"; + return; + } + + m = xtables_calloc(1, sizeof(struct xt_entry_match) + mt_len); + memcpy(&m->data, mt_info, mt_len); + m->u.match_size = mt_len + XT_ALIGN(sizeof(struct xt_entry_match)); + m->u.user.revision = nftnl_expr_get_u32(e, NFTNL_EXPR_TG_REV); + strcpy(m->u.user.name, match->name); + + match->m = m; + + if (ctx->h->ops->rule_parse->match != NULL) + ctx->h->ops->rule_parse->match(match, ctx->cs); +} + +static void nft_parse_target(struct nft_xt_ctx *ctx, struct nftnl_expr *e) +{ + uint32_t tg_len; + const char *targname = nftnl_expr_get_str(e, NFTNL_EXPR_TG_NAME); + const void *targinfo = nftnl_expr_get(e, NFTNL_EXPR_TG_INFO, &tg_len); + struct xtables_target *target; + struct xt_entry_target *t; + size_t size; + + target = xtables_find_target(targname, XTF_TRY_LOAD); + if (target == NULL) { + ctx->errmsg = "target extension not found"; + return; + } + + size = XT_ALIGN(sizeof(struct xt_entry_target)) + tg_len; + + t = xtables_calloc(1, size); + memcpy(&t->data, targinfo, tg_len); + t->u.target_size = size; + t->u.user.revision = nftnl_expr_get_u32(e, NFTNL_EXPR_TG_REV); + strcpy(t->u.user.name, target->name); + + target->t = t; + + ctx->h->ops->rule_parse->target(target, ctx->cs); +} + +static void nft_parse_limit(struct nft_xt_ctx *ctx, struct nftnl_expr *e) +{ + __u32 burst = nftnl_expr_get_u32(e, NFTNL_EXPR_LIMIT_BURST); + __u64 unit = nftnl_expr_get_u64(e, NFTNL_EXPR_LIMIT_UNIT); + __u64 rate = nftnl_expr_get_u64(e, NFTNL_EXPR_LIMIT_RATE); + struct xt_rateinfo *rinfo; + + switch (ctx->h->family) { + case NFPROTO_IPV4: + case NFPROTO_IPV6: + case NFPROTO_BRIDGE: + break; + default: + fprintf(stderr, "BUG: nft_parse_limit() unknown family %d\n", + ctx->h->family); + exit(EXIT_FAILURE); + } + + rinfo = nft_create_match(ctx, ctx->cs, "limit", false); + if (!rinfo) { + ctx->errmsg = "limit match extension not found"; + return; + } + + rinfo->avg = XT_LIMIT_SCALE * unit / rate; + rinfo->burst = burst; +} + +static void nft_parse_lookup(struct nft_xt_ctx *ctx, struct nft_handle *h, + struct nftnl_expr *e) +{ + if (ctx->h->ops->rule_parse->lookup) + ctx->h->ops->rule_parse->lookup(ctx, e); +} + +static void nft_parse_log(struct nft_xt_ctx *ctx, struct nftnl_expr *e) +{ + struct xtables_target *target; + struct xt_entry_target *t; + size_t target_size; + /* + * In order to handle the longer log-prefix supported by nft, instead of + * using struct xt_nflog_info, we use a struct with a compatible layout, but + * a larger buffer for the prefix. + */ + struct xt_nflog_info_nft { + __u32 len; + __u16 group; + __u16 threshold; + __u16 flags; + __u16 pad; + char prefix[NF_LOG_PREFIXLEN]; + } info = { + .group = nftnl_expr_get_u16(e, NFTNL_EXPR_LOG_GROUP), + .threshold = nftnl_expr_get_u16(e, NFTNL_EXPR_LOG_QTHRESHOLD), + }; + if (nftnl_expr_is_set(e, NFTNL_EXPR_LOG_SNAPLEN)) { + info.len = nftnl_expr_get_u32(e, NFTNL_EXPR_LOG_SNAPLEN); + info.flags = XT_NFLOG_F_COPY_LEN; + } + if (nftnl_expr_is_set(e, NFTNL_EXPR_LOG_PREFIX)) + snprintf(info.prefix, sizeof(info.prefix), "%s", + nftnl_expr_get_str(e, NFTNL_EXPR_LOG_PREFIX)); + + target = xtables_find_target("NFLOG", XTF_TRY_LOAD); + if (target == NULL) { + ctx->errmsg = "NFLOG target extension not found"; + return; + } + + target_size = XT_ALIGN(sizeof(struct xt_entry_target)) + + XT_ALIGN(sizeof(struct xt_nflog_info_nft)); + + t = xtables_calloc(1, target_size); + t->u.target_size = target_size; + strcpy(t->u.user.name, target->name); + t->u.user.revision = target->revision; + + target->t = t; + + memcpy(&target->t->data, &info, sizeof(info)); + + ctx->h->ops->rule_parse->target(target, ctx->cs); +} + +static void nft_parse_udp_range(struct nft_xt_ctx *ctx, + struct iptables_command_state *cs, + int sport_from, int sport_to, + int dport_from, int dport_to, + uint8_t op) +{ + struct xt_udp *udp = nft_create_match(ctx, cs, "udp", true); + + if (!udp) { + ctx->errmsg = "udp match extension not found"; + return; + } + + if (sport_from >= 0) { + switch (op) { + case NFT_RANGE_NEQ: + udp->invflags |= XT_UDP_INV_SRCPT; + /* fallthrough */ + case NFT_RANGE_EQ: + udp->spts[0] = sport_from; + udp->spts[1] = sport_to; + break; + } + } + + if (dport_to >= 0) { + switch (op) { + case NFT_CMP_NEQ: + udp->invflags |= XT_UDP_INV_DSTPT; + /* fallthrough */ + case NFT_CMP_EQ: + udp->dpts[0] = dport_from; + udp->dpts[1] = dport_to; + break; + } + } +} + +static void nft_parse_tcp_range(struct nft_xt_ctx *ctx, + struct iptables_command_state *cs, + int sport_from, int sport_to, + int dport_from, int dport_to, + uint8_t op) +{ + struct xt_tcp *tcp = nft_create_match(ctx, cs, "tcp", true); + + if (!tcp) { + ctx->errmsg = "tcp match extension not found"; + return; + } + + if (sport_from >= 0) { + switch (op) { + case NFT_RANGE_NEQ: + tcp->invflags |= XT_TCP_INV_SRCPT; + /* fallthrough */ + case NFT_RANGE_EQ: + tcp->spts[0] = sport_from; + tcp->spts[1] = sport_to; + break; + } + } + + if (dport_to >= 0) { + switch (op) { + case NFT_CMP_NEQ: + tcp->invflags |= XT_TCP_INV_DSTPT; + /* fallthrough */ + case NFT_CMP_EQ: + tcp->dpts[0] = dport_from; + tcp->dpts[1] = dport_to; + break; + } + } +} + +static void nft_parse_th_port_range(struct nft_xt_ctx *ctx, + struct iptables_command_state *cs, + uint8_t proto, + int sport_from, int sport_to, + int dport_from, int dport_to, uint8_t op) +{ + switch (proto) { + case IPPROTO_UDP: + nft_parse_udp_range(ctx, cs, sport_from, sport_to, dport_from, dport_to, op); + break; + case IPPROTO_TCP: + nft_parse_tcp_range(ctx, cs, sport_from, sport_to, dport_from, dport_to, op); + break; + } +} + +static void nft_parse_transport_range(struct nft_xt_ctx *ctx, + const struct nft_xt_ctx_reg *sreg, + struct nftnl_expr *e, + struct iptables_command_state *cs) +{ + unsigned int len_from, len_to; + uint8_t proto, op; + uint16_t from, to; + + switch (ctx->h->family) { + case NFPROTO_IPV4: + proto = ctx->cs->fw.ip.proto; + break; + case NFPROTO_IPV6: + proto = ctx->cs->fw6.ipv6.proto; + break; + default: + proto = 0; + break; + } + + nftnl_expr_get(e, NFTNL_EXPR_RANGE_FROM_DATA, &len_from); + nftnl_expr_get(e, NFTNL_EXPR_RANGE_FROM_DATA, &len_to); + if (len_to != len_from || len_to != 2) + return; + + op = nftnl_expr_get_u32(e, NFTNL_EXPR_RANGE_OP); + + from = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_RANGE_FROM_DATA)); + to = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_RANGE_TO_DATA)); + + switch (sreg->payload.offset) { + case 0: + nft_parse_th_port_range(ctx, cs, proto, from, to, -1, -1, op); + return; + case 2: + to = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_RANGE_TO_DATA)); + nft_parse_th_port_range(ctx, cs, proto, -1, -1, from, to, op); + return; + } +} + +static void nft_parse_range(struct nft_xt_ctx *ctx, struct nftnl_expr *e) +{ + struct nft_xt_ctx_reg *sreg; + uint32_t reg; + + reg = nftnl_expr_get_u32(e, NFTNL_EXPR_RANGE_SREG); + sreg = nft_xt_ctx_get_sreg(ctx, reg); + + switch (sreg->type) { + case NFT_XT_REG_UNDEF: + ctx->errmsg = "range sreg undef"; + break; + case NFT_XT_REG_PAYLOAD: + switch (sreg->payload.base) { + case NFT_PAYLOAD_TRANSPORT_HEADER: + nft_parse_transport_range(ctx, sreg, e, ctx->cs); + break; + default: + ctx->errmsg = "range with unknown payload base"; + break; + } + break; + default: + ctx->errmsg = "range sreg type unsupported"; + break; + } +} + +bool nft_rule_to_iptables_command_state(struct nft_handle *h, + const struct nftnl_rule *r, + struct iptables_command_state *cs) +{ + struct nftnl_expr_iter *iter; + struct nftnl_expr *expr; + struct nft_xt_ctx ctx = { + .cs = cs, + .h = h, + .table = nftnl_rule_get_str(r, NFTNL_RULE_TABLE), + }; + bool ret = true; + + iter = nftnl_expr_iter_create(r); + if (iter == NULL) + return false; + + ctx.iter = iter; + expr = nftnl_expr_iter_next(iter); + while (expr != NULL) { + const char *name = + nftnl_expr_get_str(expr, NFTNL_EXPR_NAME); + + if (strcmp(name, "counter") == 0) + nft_parse_counter(expr, &ctx.cs->counters); + else if (strcmp(name, "payload") == 0) + nft_parse_payload(&ctx, expr); + else if (strcmp(name, "meta") == 0) + nft_parse_meta(&ctx, expr); + else if (strcmp(name, "bitwise") == 0) + nft_parse_bitwise(&ctx, expr); + else if (strcmp(name, "cmp") == 0) + nft_parse_cmp(&ctx, expr); + else if (strcmp(name, "immediate") == 0) + nft_parse_immediate(&ctx, expr); + else if (strcmp(name, "match") == 0) + nft_parse_match(&ctx, expr); + else if (strcmp(name, "target") == 0) + nft_parse_target(&ctx, expr); + else if (strcmp(name, "limit") == 0) + nft_parse_limit(&ctx, expr); + else if (strcmp(name, "lookup") == 0) + nft_parse_lookup(&ctx, h, expr); + else if (strcmp(name, "log") == 0) + nft_parse_log(&ctx, expr); + else if (strcmp(name, "range") == 0) + nft_parse_range(&ctx, expr); + + if (ctx.errmsg) { + fprintf(stderr, "Error: %s\n", ctx.errmsg); + ctx.errmsg = NULL; + ret = false; + } + + expr = nftnl_expr_iter_next(iter); + } + + nftnl_expr_iter_destroy(iter); + + if (nftnl_rule_is_set(r, NFTNL_RULE_USERDATA)) { + const void *data; + uint32_t len, size; + const char *comment; + + data = nftnl_rule_get_data(r, NFTNL_RULE_USERDATA, &len); + comment = get_comment(data, len); + if (comment) { + struct xtables_match *match; + struct xt_entry_match *m; + + match = xtables_find_match("comment", XTF_TRY_LOAD, + &cs->matches); + if (match == NULL) + return false; + + size = XT_ALIGN(sizeof(struct xt_entry_match)) + + match->size; + m = xtables_calloc(1, size); + + strncpy((char *)m->data, comment, match->size - 1); + m->u.match_size = size; + m->u.user.revision = 0; + strcpy(m->u.user.name, match->name); + + match->m = m; + } + } + + if (!cs->jumpto) + cs->jumpto = ""; + + if (!ret) + xtables_error(VERSION_PROBLEM, "Parsing nftables rule failed"); + return ret; +} + +static void parse_ifname(const char *name, unsigned int len, + char *dst, unsigned char *mask) +{ + if (len == 0) + return; + + memcpy(dst, name, len); + if (name[len - 1] == '\0') { + if (mask) + memset(mask, 0xff, strlen(name) + 1); + return; + } + + if (len >= IFNAMSIZ) + return; + + /* wildcard */ + dst[len++] = '+'; + if (len >= IFNAMSIZ) + return; + dst[len++] = 0; + if (mask) + memset(mask, 0xff, len - 2); +} + +static void parse_invalid_iface(char *iface, unsigned char *mask, + uint8_t *invflags, uint8_t invbit) +{ + if (*invflags & invbit || strcmp(iface, "INVAL/D")) + return; + + /* nft's poor "! -o +" excuse */ + *invflags |= invbit; + iface[0] = '+'; + iface[1] = '\0'; + mask[0] = 0xff; + mask[1] = 0xff; + memset(mask + 2, 0, IFNAMSIZ - 2); +} + +static uint32_t get_meta_mask(struct nft_xt_ctx *ctx, enum nft_registers sreg) +{ + struct nft_xt_ctx_reg *reg = nft_xt_ctx_get_sreg(ctx, sreg); + + if (reg->bitwise.set) + return reg->bitwise.mask[0]; + + return ~0u; +} + +static int parse_meta_mark(struct nft_xt_ctx *ctx, struct nftnl_expr *e) +{ + struct xt_mark_mtinfo1 *mark; + uint32_t value; + + mark = nft_create_match(ctx, ctx->cs, "mark", false); + if (!mark) + return -1; + + if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ) + mark->invert = 1; + + value = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_DATA); + mark->mark = value; + mark->mask = get_meta_mask(ctx, nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_SREG)); + + return 0; +} + +static int parse_meta_pkttype(struct nft_xt_ctx *ctx, struct nftnl_expr *e) +{ + struct xt_pkttype_info *pkttype; + uint8_t value; + + pkttype = nft_create_match(ctx, ctx->cs, "pkttype", false); + if (!pkttype) + return -1; + + if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ) + pkttype->invert = 1; + + value = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA); + pkttype->pkttype = value; + + return 0; +} + +int parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e, uint8_t key, + char *iniface, unsigned char *iniface_mask, + char *outiface, unsigned char *outiface_mask, uint8_t *invflags) +{ + uint32_t value; + const void *ifname; + uint32_t len; + + switch(key) { + case NFT_META_IIF: + value = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_DATA); + if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ) + *invflags |= IPT_INV_VIA_IN; + + if_indextoname(value, iniface); + + memset(iniface_mask, 0xff, strlen(iniface)+1); + break; + case NFT_META_OIF: + value = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_DATA); + if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ) + *invflags |= IPT_INV_VIA_OUT; + + if_indextoname(value, outiface); + + memset(outiface_mask, 0xff, strlen(outiface)+1); + break; + case NFT_META_BRI_IIFNAME: + case NFT_META_IIFNAME: + ifname = nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &len); + if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ) + *invflags |= IPT_INV_VIA_IN; + + parse_ifname(ifname, len, iniface, iniface_mask); + parse_invalid_iface(iniface, iniface_mask, + invflags, IPT_INV_VIA_IN); + break; + case NFT_META_BRI_OIFNAME: + case NFT_META_OIFNAME: + ifname = nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &len); + if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ) + *invflags |= IPT_INV_VIA_OUT; + + parse_ifname(ifname, len, outiface, outiface_mask); + parse_invalid_iface(outiface, outiface_mask, + invflags, IPT_INV_VIA_OUT); + break; + case NFT_META_MARK: + parse_meta_mark(ctx, e); + break; + case NFT_META_PKTTYPE: + parse_meta_pkttype(ctx, e); + break; + default: + return -1; + } + + return 0; +} + +void nft_ipv46_parse_target(struct xtables_target *t, + struct iptables_command_state *cs) +{ + cs->target = t; + cs->jumpto = t->name; +} + +int nft_parse_hl(struct nft_xt_ctx *ctx, struct nftnl_expr *e, + struct iptables_command_state *cs) +{ + struct ip6t_hl_info *info; + uint8_t hl, mode; + int op; + + hl = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA); + op = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP); + + switch (op) { + case NFT_CMP_NEQ: + mode = IP6T_HL_NE; + break; + case NFT_CMP_EQ: + mode = IP6T_HL_EQ; + break; + case NFT_CMP_LT: + mode = IP6T_HL_LT; + break; + case NFT_CMP_GT: + mode = IP6T_HL_GT; + break; + case NFT_CMP_LTE: + mode = IP6T_HL_LT; + if (hl == 255) + return -1; + hl++; + break; + case NFT_CMP_GTE: + mode = IP6T_HL_GT; + if (hl == 0) + return -1; + hl--; + break; + default: + return -1; + } + + /* ipt_ttl_info and ip6t_hl_info have same layout, + * IPT_TTL_x and IP6T_HL_x are aliases as well, so + * just use HL for both ipv4 and ipv6. + */ + switch (ctx->h->family) { + case NFPROTO_IPV4: + info = nft_create_match(ctx, ctx->cs, "ttl", false); + break; + case NFPROTO_IPV6: + info = nft_create_match(ctx, ctx->cs, "hl", false); + break; + default: + return -1; + } + + if (!info) + return -1; + + info->hop_limit = hl; + info->mode = mode; + + return 0; +} diff --git a/iptables/nft-ruleparse.h b/iptables/nft-ruleparse.h new file mode 100644 index 00000000..fd083c08 --- /dev/null +++ b/iptables/nft-ruleparse.h @@ -0,0 +1,138 @@ +#ifndef _NFT_RULEPARSE_H_ +#define _NFT_RULEPARSE_H_ + +#include <linux/netfilter/nf_tables.h> + +#include <libnftnl/expr.h> + +#include "xshared.h" + +enum nft_ctx_reg_type { + NFT_XT_REG_UNDEF, + NFT_XT_REG_PAYLOAD, + NFT_XT_REG_IMMEDIATE, + NFT_XT_REG_META_DREG, +}; + +struct nft_xt_ctx_reg { + enum nft_ctx_reg_type type:8; + + union { + struct { + uint32_t base; + uint32_t offset; + uint32_t len; + } payload; + struct { + uint32_t data[4]; + uint8_t len; + } immediate; + struct { + uint32_t key; + } meta_dreg; + struct { + uint32_t key; + } meta_sreg; + }; + + struct { + uint32_t mask[4]; + uint32_t xor[4]; + bool set; + } bitwise; +}; + +struct nft_xt_ctx { + struct iptables_command_state *cs; + struct nftnl_expr_iter *iter; + struct nft_handle *h; + uint32_t flags; + const char *table; + + struct nft_xt_ctx_reg regs[1 + 16]; + + const char *errmsg; +}; + +static inline struct nft_xt_ctx_reg *nft_xt_ctx_get_sreg(struct nft_xt_ctx *ctx, enum nft_registers reg) +{ + switch (reg) { + case NFT_REG_VERDICT: + return &ctx->regs[0]; + case NFT_REG_1: + return &ctx->regs[1]; + case NFT_REG_2: + return &ctx->regs[5]; + case NFT_REG_3: + return &ctx->regs[9]; + case NFT_REG_4: + return &ctx->regs[13]; + case NFT_REG32_00...NFT_REG32_15: + return &ctx->regs[reg - NFT_REG32_00]; + default: + ctx->errmsg = "Unknown register requested"; + break; + } + + return NULL; +} + +static inline void nft_xt_reg_clear(struct nft_xt_ctx_reg *r) +{ + r->type = 0; + r->bitwise.set = false; +} + +static inline struct nft_xt_ctx_reg *nft_xt_ctx_get_dreg(struct nft_xt_ctx *ctx, enum nft_registers reg) +{ + struct nft_xt_ctx_reg *r = nft_xt_ctx_get_sreg(ctx, reg); + + if (r) + nft_xt_reg_clear(r); + + return r; +} + +struct nft_ruleparse_ops { + void (*meta)(struct nft_xt_ctx *ctx, + const struct nft_xt_ctx_reg *sreg, + struct nftnl_expr *e, + struct iptables_command_state *cs); + void (*payload)(struct nft_xt_ctx *ctx, + const struct nft_xt_ctx_reg *sreg, + struct nftnl_expr *e, + struct iptables_command_state *cs); + void (*lookup)(struct nft_xt_ctx *ctx, struct nftnl_expr *e); + void (*match)(struct xtables_match *m, + struct iptables_command_state *cs); + void (*target)(struct xtables_target *t, + struct iptables_command_state *cs); +}; + +extern struct nft_ruleparse_ops nft_ruleparse_ops_arp; +extern struct nft_ruleparse_ops nft_ruleparse_ops_bridge; +extern struct nft_ruleparse_ops nft_ruleparse_ops_ipv4; +extern struct nft_ruleparse_ops nft_ruleparse_ops_ipv6; + +void *nft_create_match(struct nft_xt_ctx *ctx, + struct iptables_command_state *cs, + const char *name, bool reuse); + +bool nft_rule_to_iptables_command_state(struct nft_handle *h, + const struct nftnl_rule *r, + struct iptables_command_state *cs); + +#define min(x, y) ((x) < (y) ? (x) : (y)) +#define max(x, y) ((x) > (y) ? (x) : (y)) + +int parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e, uint8_t key, + char *iniface, unsigned char *iniface_mask, char *outiface, + unsigned char *outiface_mask, uint8_t *invflags); + +void nft_ipv46_parse_target(struct xtables_target *t, + struct iptables_command_state *cs); + +int nft_parse_hl(struct nft_xt_ctx *ctx, struct nftnl_expr *e, + struct iptables_command_state *cs); + +#endif /* _NFT_RULEPARSE_H_ */ diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index 74e19cca..12860fbf 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -10,6 +10,7 @@ * This code has been sponsored by Sophos Astaro <http://www.sophos.com> */ +#include <assert.h> #include <string.h> #include <stdio.h> #include <stdlib.h> @@ -20,12 +21,6 @@ #include <xtables.h> -#include <linux/netfilter/nf_log.h> -#include <linux/netfilter/xt_comment.h> -#include <linux/netfilter/xt_limit.h> -#include <linux/netfilter/xt_NFLOG.h> -#include <linux/netfilter/xt_mark.h> - #include <libmnl/libmnl.h> #include <libnftnl/rule.h> #include <libnftnl/expr.h> @@ -164,6 +159,9 @@ void add_iniface(struct nft_handle *h, struct nftnl_rule *r, if (iface[iface_len - 1] == '+') { if (iface_len > 1) add_cmp_ptr(r, op, iface, iface_len - 1, reg); + else if (op != NFT_CMP_EQ) + add_cmp_ptr(r, NFT_CMP_EQ, "INVAL/D", + strlen("INVAL/D") + 1, reg); } else { add_cmp_ptr(r, op, iface, iface_len + 1, reg); } @@ -181,6 +179,9 @@ void add_outiface(struct nft_handle *h, struct nftnl_rule *r, if (iface[iface_len - 1] == '+') { if (iface_len > 1) add_cmp_ptr(r, op, iface, iface_len - 1, reg); + else if (op != NFT_CMP_EQ) + add_cmp_ptr(r, NFT_CMP_EQ, "INVAL/D", + strlen("INVAL/D") + 1, reg); } else { add_cmp_ptr(r, op, iface, iface_len + 1, reg); } @@ -267,978 +268,20 @@ bool is_same_interfaces(const char *a_iniface, const char *a_outiface, return true; } -static void parse_ifname(const char *name, unsigned int len, char *dst, unsigned char *mask) -{ - if (len == 0) - return; - - memcpy(dst, name, len); - if (name[len - 1] == '\0') { - if (mask) - memset(mask, 0xff, len); - return; - } - - if (len >= IFNAMSIZ) - return; - - /* wildcard */ - dst[len++] = '+'; - if (len >= IFNAMSIZ) - return; - dst[len++] = 0; - if (mask) - memset(mask, 0xff, len - 2); -} - -static struct xtables_match * -nft_create_match(struct nft_xt_ctx *ctx, - struct iptables_command_state *cs, - const char *name); - -static int parse_meta_mark(struct nft_xt_ctx *ctx, struct nftnl_expr *e) +void __get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, uint8_t *op) { - struct xt_mark_mtinfo1 *mark; - struct xtables_match *match; - uint32_t value; - - match = nft_create_match(ctx, ctx->cs, "mark"); - if (!match) - return -1; - - mark = (void*)match->m->data; - - if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ) - mark->invert = 1; - - value = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_DATA); - mark->mark = value; - if (ctx->flags & NFT_XT_CTX_BITWISE) { - memcpy(&mark->mask, &ctx->bitwise.mask, sizeof(mark->mask)); - ctx->flags &= ~NFT_XT_CTX_BITWISE; - } else { - mark->mask = 0xffffffff; - } - - return 0; -} - -int parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e, uint8_t key, - char *iniface, unsigned char *iniface_mask, - char *outiface, unsigned char *outiface_mask, uint8_t *invflags) -{ - uint32_t value; - const void *ifname; uint32_t len; - switch(key) { - case NFT_META_IIF: - value = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_DATA); - if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ) - *invflags |= IPT_INV_VIA_IN; - - if_indextoname(value, iniface); - - memset(iniface_mask, 0xff, strlen(iniface)+1); - break; - case NFT_META_OIF: - value = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_DATA); - if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ) - *invflags |= IPT_INV_VIA_OUT; - - if_indextoname(value, outiface); - - memset(outiface_mask, 0xff, strlen(outiface)+1); - break; - case NFT_META_BRI_IIFNAME: - case NFT_META_IIFNAME: - ifname = nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &len); - if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ) - *invflags |= IPT_INV_VIA_IN; - - parse_ifname(ifname, len, iniface, iniface_mask); - break; - case NFT_META_BRI_OIFNAME: - case NFT_META_OIFNAME: - ifname = nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &len); - if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ) - *invflags |= IPT_INV_VIA_OUT; - - parse_ifname(ifname, len, outiface, outiface_mask); - break; - case NFT_META_MARK: - parse_meta_mark(ctx, e); - break; - default: - return -1; - } - - return 0; -} - -static void nft_parse_target(struct nft_xt_ctx *ctx, struct nftnl_expr *e) -{ - uint32_t tg_len; - const char *targname = nftnl_expr_get_str(e, NFTNL_EXPR_TG_NAME); - const void *targinfo = nftnl_expr_get(e, NFTNL_EXPR_TG_INFO, &tg_len); - struct xtables_target *target; - struct xt_entry_target *t; - size_t size; - - target = xtables_find_target(targname, XTF_TRY_LOAD); - if (target == NULL) - return; - - size = XT_ALIGN(sizeof(struct xt_entry_target)) + tg_len; - - t = xtables_calloc(1, size); - memcpy(&t->data, targinfo, tg_len); - t->u.target_size = size; - t->u.user.revision = nftnl_expr_get_u32(e, NFTNL_EXPR_TG_REV); - strcpy(t->u.user.name, target->name); - - target->t = t; - - ctx->h->ops->parse_target(target, ctx->cs); -} - -static void nft_parse_match(struct nft_xt_ctx *ctx, struct nftnl_expr *e) -{ - uint32_t mt_len; - const char *mt_name = nftnl_expr_get_str(e, NFTNL_EXPR_MT_NAME); - const void *mt_info = nftnl_expr_get(e, NFTNL_EXPR_MT_INFO, &mt_len); - struct xtables_match *match; - struct xtables_rule_match **matches; - struct xt_entry_match *m; - - switch (ctx->h->family) { - case NFPROTO_IPV4: - case NFPROTO_IPV6: - case NFPROTO_BRIDGE: - matches = &ctx->cs->matches; - break; - default: - fprintf(stderr, "BUG: nft_parse_match() unknown family %d\n", - ctx->h->family); - exit(EXIT_FAILURE); - } - - match = xtables_find_match(mt_name, XTF_TRY_LOAD, matches); - if (match == NULL) - return; - - m = xtables_calloc(1, sizeof(struct xt_entry_match) + mt_len); - memcpy(&m->data, mt_info, mt_len); - m->u.match_size = mt_len + XT_ALIGN(sizeof(struct xt_entry_match)); - m->u.user.revision = nftnl_expr_get_u32(e, NFTNL_EXPR_TG_REV); - strcpy(m->u.user.name, match->name); - - match->m = m; - - if (ctx->h->ops->parse_match != NULL) - ctx->h->ops->parse_match(match, ctx->cs); + memcpy(data, nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &len), dlen); + *op = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP); } void get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, bool *inv) { - uint32_t len; uint8_t op; - memcpy(data, nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &len), dlen); - op = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP); - if (op == NFT_CMP_NEQ) - *inv = true; - else - *inv = false; -} - -static void nft_meta_set_to_target(struct nft_xt_ctx *ctx) -{ - struct xtables_target *target; - struct xt_entry_target *t; - unsigned int size; - const char *targname; - - switch (ctx->meta.key) { - case NFT_META_NFTRACE: - if (ctx->immediate.data[0] == 0) - return; - targname = "TRACE"; - break; - default: - return; - } - - target = xtables_find_target(targname, XTF_TRY_LOAD); - if (target == NULL) - return; - - size = XT_ALIGN(sizeof(struct xt_entry_target)) + target->size; - - t = xtables_calloc(1, size); - t->u.target_size = size; - t->u.user.revision = target->revision; - strcpy(t->u.user.name, targname); - - target->t = t; - - ctx->h->ops->parse_target(target, ctx->cs); -} - -static void nft_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e) -{ - ctx->meta.key = nftnl_expr_get_u32(e, NFTNL_EXPR_META_KEY); - - if (nftnl_expr_is_set(e, NFTNL_EXPR_META_SREG) && - (ctx->flags & NFT_XT_CTX_IMMEDIATE) && - nftnl_expr_get_u32(e, NFTNL_EXPR_META_SREG) == ctx->immediate.reg) { - ctx->flags &= ~NFT_XT_CTX_IMMEDIATE; - nft_meta_set_to_target(ctx); - return; - } - - ctx->reg = nftnl_expr_get_u32(e, NFTNL_EXPR_META_DREG); - ctx->flags |= NFT_XT_CTX_META; -} - -static void nft_parse_payload(struct nft_xt_ctx *ctx, struct nftnl_expr *e) -{ - if (ctx->flags & NFT_XT_CTX_PAYLOAD) { - memcpy(&ctx->prev_payload, &ctx->payload, - sizeof(ctx->prev_payload)); - ctx->flags |= NFT_XT_CTX_PREV_PAYLOAD; - } - - ctx->reg = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_DREG); - ctx->payload.base = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_BASE); - ctx->payload.offset = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_OFFSET); - ctx->payload.len = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_LEN); - ctx->flags |= NFT_XT_CTX_PAYLOAD; -} - -static void nft_parse_bitwise(struct nft_xt_ctx *ctx, struct nftnl_expr *e) -{ - uint32_t reg, len; - const void *data; - - reg = nftnl_expr_get_u32(e, NFTNL_EXPR_BITWISE_SREG); - if (ctx->reg && reg != ctx->reg) - return; - - reg = nftnl_expr_get_u32(e, NFTNL_EXPR_BITWISE_DREG); - ctx->reg = reg; - data = nftnl_expr_get(e, NFTNL_EXPR_BITWISE_XOR, &len); - memcpy(ctx->bitwise.xor, data, len); - data = nftnl_expr_get(e, NFTNL_EXPR_BITWISE_MASK, &len); - memcpy(ctx->bitwise.mask, data, len); - ctx->flags |= NFT_XT_CTX_BITWISE; -} - -static struct xtables_match * -nft_create_match(struct nft_xt_ctx *ctx, - struct iptables_command_state *cs, - const char *name) -{ - struct xtables_match *match; - struct xt_entry_match *m; - unsigned int size; - - match = xtables_find_match(name, XTF_TRY_LOAD, - &cs->matches); - if (!match) - return NULL; - - size = XT_ALIGN(sizeof(struct xt_entry_match)) + match->size; - m = xtables_calloc(1, size); - m->u.match_size = size; - m->u.user.revision = match->revision; - - strcpy(m->u.user.name, match->name); - match->m = m; - - xs_init_match(match); - - return match; -} - -static struct xt_udp *nft_udp_match(struct nft_xt_ctx *ctx, - struct iptables_command_state *cs) -{ - struct xt_udp *udp = ctx->tcpudp.udp; - struct xtables_match *match; - - if (!udp) { - match = nft_create_match(ctx, cs, "udp"); - if (!match) - return NULL; - - udp = (void*)match->m->data; - ctx->tcpudp.udp = udp; - } - - return udp; -} - -static struct xt_tcp *nft_tcp_match(struct nft_xt_ctx *ctx, - struct iptables_command_state *cs) -{ - struct xt_tcp *tcp = ctx->tcpudp.tcp; - struct xtables_match *match; - - if (!tcp) { - match = nft_create_match(ctx, cs, "tcp"); - if (!match) - return NULL; - - tcp = (void*)match->m->data; - ctx->tcpudp.tcp = tcp; - } - - return tcp; -} - -static void nft_parse_udp_range(struct nft_xt_ctx *ctx, - struct iptables_command_state *cs, - int sport_from, int sport_to, - int dport_from, int dport_to, - uint8_t op) -{ - struct xt_udp *udp = nft_udp_match(ctx, cs); - - if (!udp) - return; - - if (sport_from >= 0) { - switch (op) { - case NFT_RANGE_NEQ: - udp->invflags |= XT_UDP_INV_SRCPT; - /* fallthrough */ - case NFT_RANGE_EQ: - udp->spts[0] = sport_from; - udp->spts[1] = sport_to; - break; - } - } - - if (dport_to >= 0) { - switch (op) { - case NFT_CMP_NEQ: - udp->invflags |= XT_UDP_INV_DSTPT; - /* fallthrough */ - case NFT_CMP_EQ: - udp->dpts[0] = dport_from; - udp->dpts[1] = dport_to; - break; - } - } -} - -static void nft_parse_tcp_range(struct nft_xt_ctx *ctx, - struct iptables_command_state *cs, - int sport_from, int sport_to, - int dport_from, int dport_to, - uint8_t op) -{ - struct xt_tcp *tcp = nft_tcp_match(ctx, cs); - - if (!tcp) - return; - - if (sport_from >= 0) { - switch (op) { - case NFT_RANGE_NEQ: - tcp->invflags |= XT_TCP_INV_SRCPT; - /* fallthrough */ - case NFT_RANGE_EQ: - tcp->spts[0] = sport_from; - tcp->spts[1] = sport_to; - break; - } - } - - if (dport_to >= 0) { - switch (op) { - case NFT_CMP_NEQ: - tcp->invflags |= XT_TCP_INV_DSTPT; - /* fallthrough */ - case NFT_CMP_EQ: - tcp->dpts[0] = dport_from; - tcp->dpts[1] = dport_to; - break; - } - } -} - -static void nft_parse_udp(struct nft_xt_ctx *ctx, - struct iptables_command_state *cs, - int sport, int dport, - uint8_t op) -{ - struct xt_udp *udp = nft_udp_match(ctx, cs); - - if (!udp) - return; - - if (sport >= 0) { - switch (op) { - case NFT_CMP_NEQ: - udp->invflags |= XT_UDP_INV_SRCPT; - /* fallthrough */ - case NFT_CMP_EQ: - udp->spts[0] = sport; - udp->spts[1] = sport; - break; - case NFT_CMP_LT: - udp->spts[1] = sport > 1 ? sport - 1 : 1; - break; - case NFT_CMP_LTE: - udp->spts[1] = sport; - break; - case NFT_CMP_GT: - udp->spts[0] = sport < 0xffff ? sport + 1 : 0xffff; - break; - case NFT_CMP_GTE: - udp->spts[0] = sport; - break; - } - } - if (dport >= 0) { - switch (op) { - case NFT_CMP_NEQ: - udp->invflags |= XT_UDP_INV_DSTPT; - /* fallthrough */ - case NFT_CMP_EQ: - udp->dpts[0] = dport; - udp->dpts[1] = dport; - break; - case NFT_CMP_LT: - udp->dpts[1] = dport > 1 ? dport - 1 : 1; - break; - case NFT_CMP_LTE: - udp->dpts[1] = dport; - break; - case NFT_CMP_GT: - udp->dpts[0] = dport < 0xffff ? dport + 1 : 0xffff; - break; - case NFT_CMP_GTE: - udp->dpts[0] = dport; - break; - } - } -} - -static void nft_parse_tcp(struct nft_xt_ctx *ctx, - struct iptables_command_state *cs, - int sport, int dport, - uint8_t op) -{ - struct xt_tcp *tcp = nft_tcp_match(ctx, cs); - - if (!tcp) - return; - - if (sport >= 0) { - switch (op) { - case NFT_CMP_NEQ: - tcp->invflags |= XT_TCP_INV_SRCPT; - /* fallthrough */ - case NFT_CMP_EQ: - tcp->spts[0] = sport; - tcp->spts[1] = sport; - break; - case NFT_CMP_LT: - tcp->spts[1] = sport > 1 ? sport - 1 : 1; - break; - case NFT_CMP_LTE: - tcp->spts[1] = sport; - break; - case NFT_CMP_GT: - tcp->spts[0] = sport < 0xffff ? sport + 1 : 0xffff; - break; - case NFT_CMP_GTE: - tcp->spts[0] = sport; - break; - } - } - - if (dport >= 0) { - switch (op) { - case NFT_CMP_NEQ: - tcp->invflags |= XT_TCP_INV_DSTPT; - /* fallthrough */ - case NFT_CMP_EQ: - tcp->dpts[0] = dport; - tcp->dpts[1] = dport; - break; - case NFT_CMP_LT: - tcp->dpts[1] = dport > 1 ? dport - 1 : 1; - break; - case NFT_CMP_LTE: - tcp->dpts[1] = dport; - break; - case NFT_CMP_GT: - tcp->dpts[0] = dport < 0xffff ? dport + 1 : 0xffff; - break; - case NFT_CMP_GTE: - tcp->dpts[0] = dport; - break; - } - } -} - -static void nft_parse_th_port(struct nft_xt_ctx *ctx, - struct iptables_command_state *cs, - uint8_t proto, - int sport, int dport, uint8_t op) -{ - switch (proto) { - case IPPROTO_UDP: - nft_parse_udp(ctx, cs, sport, dport, op); - break; - case IPPROTO_TCP: - nft_parse_tcp(ctx, cs, sport, dport, op); - break; - } -} - -static void nft_parse_th_port_range(struct nft_xt_ctx *ctx, - struct iptables_command_state *cs, - uint8_t proto, - int sport_from, int sport_to, - int dport_from, int dport_to, uint8_t op) -{ - switch (proto) { - case IPPROTO_UDP: - nft_parse_udp_range(ctx, cs, sport_from, sport_to, dport_from, dport_to, op); - break; - case IPPROTO_TCP: - nft_parse_tcp_range(ctx, cs, sport_from, sport_to, dport_from, dport_to, op); - break; - } -} - -static void nft_parse_tcp_flags(struct nft_xt_ctx *ctx, - struct iptables_command_state *cs, - uint8_t op, uint8_t flags, uint8_t mask) -{ - struct xt_tcp *tcp = nft_tcp_match(ctx, cs); - - if (!tcp) - return; - - if (op == NFT_CMP_NEQ) - tcp->invflags |= XT_TCP_INV_FLAGS; - tcp->flg_cmp = flags; - tcp->flg_mask = mask; -} - -static void nft_parse_transport(struct nft_xt_ctx *ctx, - struct nftnl_expr *e, - struct iptables_command_state *cs) -{ - uint32_t sdport; - uint16_t port; - uint8_t proto, op; - unsigned int len; - - switch (ctx->h->family) { - case NFPROTO_IPV4: - proto = ctx->cs->fw.ip.proto; - break; - case NFPROTO_IPV6: - proto = ctx->cs->fw6.ipv6.proto; - break; - default: - proto = 0; - break; - } - - nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &len); - op = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP); - - switch(ctx->payload.offset) { - case 0: /* th->sport */ - switch (len) { - case 2: /* load sport only */ - port = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_CMP_DATA)); - nft_parse_th_port(ctx, cs, proto, port, -1, op); - return; - case 4: /* load both src and dst port */ - sdport = ntohl(nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_DATA)); - nft_parse_th_port(ctx, cs, proto, sdport >> 16, sdport & 0xffff, op); - return; - } - break; - case 2: /* th->dport */ - switch (len) { - case 2: - port = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_CMP_DATA)); - nft_parse_th_port(ctx, cs, proto, -1, port, op); - return; - } - break; - case 13: /* th->flags */ - if (len == 1 && proto == IPPROTO_TCP) { - uint8_t flags = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA); - uint8_t mask = ~0; - - if (ctx->flags & NFT_XT_CTX_BITWISE) { - memcpy(&mask, &ctx->bitwise.mask, sizeof(mask)); - ctx->flags &= ~NFT_XT_CTX_BITWISE; - } - nft_parse_tcp_flags(ctx, cs, op, flags, mask); - } - return; - } -} - -static void nft_parse_transport_range(struct nft_xt_ctx *ctx, - struct nftnl_expr *e, - struct iptables_command_state *cs) -{ - unsigned int len_from, len_to; - uint8_t proto, op; - uint16_t from, to; - - switch (ctx->h->family) { - case NFPROTO_IPV4: - proto = ctx->cs->fw.ip.proto; - break; - case NFPROTO_IPV6: - proto = ctx->cs->fw6.ipv6.proto; - break; - default: - proto = 0; - break; - } - - nftnl_expr_get(e, NFTNL_EXPR_RANGE_FROM_DATA, &len_from); - nftnl_expr_get(e, NFTNL_EXPR_RANGE_FROM_DATA, &len_to); - if (len_to != len_from || len_to != 2) - return; - - op = nftnl_expr_get_u32(e, NFTNL_EXPR_RANGE_OP); - - from = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_RANGE_FROM_DATA)); - to = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_RANGE_TO_DATA)); - - switch(ctx->payload.offset) { - case 0: - nft_parse_th_port_range(ctx, cs, proto, from, to, -1, -1, op); - return; - case 2: - to = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_RANGE_TO_DATA)); - nft_parse_th_port_range(ctx, cs, proto, -1, -1, from, to, op); - return; - } -} - -static void nft_parse_cmp(struct nft_xt_ctx *ctx, struct nftnl_expr *e) -{ - uint32_t reg; - - reg = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_SREG); - if (ctx->reg && reg != ctx->reg) - return; - - if (ctx->flags & NFT_XT_CTX_META) { - ctx->h->ops->parse_meta(ctx, e, ctx->cs); - ctx->flags &= ~NFT_XT_CTX_META; - } - /* bitwise context is interpreted from payload */ - if (ctx->flags & NFT_XT_CTX_PAYLOAD) { - switch (ctx->payload.base) { - case NFT_PAYLOAD_LL_HEADER: - if (ctx->h->family == NFPROTO_BRIDGE) - ctx->h->ops->parse_payload(ctx, e, ctx->cs); - break; - case NFT_PAYLOAD_NETWORK_HEADER: - ctx->h->ops->parse_payload(ctx, e, ctx->cs); - break; - case NFT_PAYLOAD_TRANSPORT_HEADER: - nft_parse_transport(ctx, e, ctx->cs); - break; - } - } -} - -static void nft_parse_counter(struct nftnl_expr *e, struct xt_counters *counters) -{ - counters->pcnt = nftnl_expr_get_u64(e, NFTNL_EXPR_CTR_PACKETS); - counters->bcnt = nftnl_expr_get_u64(e, NFTNL_EXPR_CTR_BYTES); -} - -static void nft_parse_immediate(struct nft_xt_ctx *ctx, struct nftnl_expr *e) -{ - const char *chain = nftnl_expr_get_str(e, NFTNL_EXPR_IMM_CHAIN); - struct iptables_command_state *cs = ctx->cs; - struct xt_entry_target *t; - uint32_t size; - int verdict; - - if (nftnl_expr_is_set(e, NFTNL_EXPR_IMM_DATA)) { - const void *imm_data; - uint32_t len; - - imm_data = nftnl_expr_get_data(e, NFTNL_EXPR_IMM_DATA, &len); - - if (len > sizeof(ctx->immediate.data)) - return; - - memcpy(ctx->immediate.data, imm_data, len); - ctx->immediate.len = len; - ctx->immediate.reg = nftnl_expr_get_u32(e, NFTNL_EXPR_IMM_DREG); - ctx->flags |= NFT_XT_CTX_IMMEDIATE; - return; - } - - verdict = nftnl_expr_get_u32(e, NFTNL_EXPR_IMM_VERDICT); - /* Standard target? */ - switch(verdict) { - case NF_ACCEPT: - cs->jumpto = "ACCEPT"; - break; - case NF_DROP: - cs->jumpto = "DROP"; - break; - case NFT_RETURN: - cs->jumpto = "RETURN"; - break;; - case NFT_GOTO: - if (ctx->h->ops->set_goto_flag) - ctx->h->ops->set_goto_flag(cs); - /* fall through */ - case NFT_JUMP: - cs->jumpto = chain; - /* fall through */ - default: - return; - } - - cs->target = xtables_find_target(cs->jumpto, XTF_TRY_LOAD); - if (!cs->target) - return; - - size = XT_ALIGN(sizeof(struct xt_entry_target)) + cs->target->size; - t = xtables_calloc(1, size); - t->u.target_size = size; - t->u.user.revision = cs->target->revision; - strcpy(t->u.user.name, cs->jumpto); - cs->target->t = t; -} - -static void nft_parse_limit(struct nft_xt_ctx *ctx, struct nftnl_expr *e) -{ - __u32 burst = nftnl_expr_get_u32(e, NFTNL_EXPR_LIMIT_BURST); - __u64 unit = nftnl_expr_get_u64(e, NFTNL_EXPR_LIMIT_UNIT); - __u64 rate = nftnl_expr_get_u64(e, NFTNL_EXPR_LIMIT_RATE); - struct xtables_rule_match **matches; - struct xtables_match *match; - struct xt_rateinfo *rinfo; - size_t size; - - switch (ctx->h->family) { - case NFPROTO_IPV4: - case NFPROTO_IPV6: - case NFPROTO_BRIDGE: - matches = &ctx->cs->matches; - break; - default: - fprintf(stderr, "BUG: nft_parse_limit() unknown family %d\n", - ctx->h->family); - exit(EXIT_FAILURE); - } - - match = xtables_find_match("limit", XTF_TRY_LOAD, matches); - if (match == NULL) - return; - - size = XT_ALIGN(sizeof(struct xt_entry_match)) + match->size; - match->m = xtables_calloc(1, size); - match->m->u.match_size = size; - strcpy(match->m->u.user.name, match->name); - match->m->u.user.revision = match->revision; - xs_init_match(match); - - rinfo = (void *)match->m->data; - rinfo->avg = XT_LIMIT_SCALE * unit / rate; - rinfo->burst = burst; - - if (ctx->h->ops->parse_match != NULL) - ctx->h->ops->parse_match(match, ctx->cs); -} - -static void nft_parse_log(struct nft_xt_ctx *ctx, struct nftnl_expr *e) -{ - struct xtables_target *target; - struct xt_entry_target *t; - size_t target_size; - /* - * In order to handle the longer log-prefix supported by nft, instead of - * using struct xt_nflog_info, we use a struct with a compatible layout, but - * a larger buffer for the prefix. - */ - struct xt_nflog_info_nft { - __u32 len; - __u16 group; - __u16 threshold; - __u16 flags; - __u16 pad; - char prefix[NF_LOG_PREFIXLEN]; - } info = { - .group = nftnl_expr_get_u16(e, NFTNL_EXPR_LOG_GROUP), - .threshold = nftnl_expr_get_u16(e, NFTNL_EXPR_LOG_QTHRESHOLD), - }; - if (nftnl_expr_is_set(e, NFTNL_EXPR_LOG_SNAPLEN)) { - info.len = nftnl_expr_get_u32(e, NFTNL_EXPR_LOG_SNAPLEN); - info.flags = XT_NFLOG_F_COPY_LEN; - } - if (nftnl_expr_is_set(e, NFTNL_EXPR_LOG_PREFIX)) - snprintf(info.prefix, sizeof(info.prefix), "%s", - nftnl_expr_get_str(e, NFTNL_EXPR_LOG_PREFIX)); - - target = xtables_find_target("NFLOG", XTF_TRY_LOAD); - if (target == NULL) - return; - - target_size = XT_ALIGN(sizeof(struct xt_entry_target)) + - XT_ALIGN(sizeof(struct xt_nflog_info_nft)); - - t = xtables_calloc(1, target_size); - t->u.target_size = target_size; - strcpy(t->u.user.name, target->name); - t->u.user.revision = target->revision; - - target->t = t; - - memcpy(&target->t->data, &info, sizeof(info)); - - ctx->h->ops->parse_target(target, ctx->cs); -} - -static void nft_parse_lookup(struct nft_xt_ctx *ctx, struct nft_handle *h, - struct nftnl_expr *e) -{ - if (ctx->h->ops->parse_lookup) - ctx->h->ops->parse_lookup(ctx, e); -} - -static void nft_parse_range(struct nft_xt_ctx *ctx, struct nftnl_expr *e) -{ - uint32_t reg; - - reg = nftnl_expr_get_u32(e, NFTNL_EXPR_RANGE_SREG); - if (reg != ctx->reg) - return; - - if (ctx->flags & NFT_XT_CTX_PAYLOAD) { - switch (ctx->payload.base) { - case NFT_PAYLOAD_TRANSPORT_HEADER: - nft_parse_transport_range(ctx, e, ctx->cs); - break; - default: - break; - } - } -} - -void nft_rule_to_iptables_command_state(struct nft_handle *h, - const struct nftnl_rule *r, - struct iptables_command_state *cs) -{ - struct nftnl_expr_iter *iter; - struct nftnl_expr *expr; - struct nft_xt_ctx ctx = { - .cs = cs, - .h = h, - .table = nftnl_rule_get_str(r, NFTNL_RULE_TABLE), - }; - - iter = nftnl_expr_iter_create(r); - if (iter == NULL) - return; - - ctx.iter = iter; - expr = nftnl_expr_iter_next(iter); - while (expr != NULL) { - const char *name = - nftnl_expr_get_str(expr, NFTNL_EXPR_NAME); - - if (strcmp(name, "counter") == 0) - nft_parse_counter(expr, &ctx.cs->counters); - else if (strcmp(name, "payload") == 0) - nft_parse_payload(&ctx, expr); - else if (strcmp(name, "meta") == 0) - nft_parse_meta(&ctx, expr); - else if (strcmp(name, "bitwise") == 0) - nft_parse_bitwise(&ctx, expr); - else if (strcmp(name, "cmp") == 0) - nft_parse_cmp(&ctx, expr); - else if (strcmp(name, "immediate") == 0) - nft_parse_immediate(&ctx, expr); - else if (strcmp(name, "match") == 0) - nft_parse_match(&ctx, expr); - else if (strcmp(name, "target") == 0) - nft_parse_target(&ctx, expr); - else if (strcmp(name, "limit") == 0) - nft_parse_limit(&ctx, expr); - else if (strcmp(name, "lookup") == 0) - nft_parse_lookup(&ctx, h, expr); - else if (strcmp(name, "log") == 0) - nft_parse_log(&ctx, expr); - else if (strcmp(name, "range") == 0) - nft_parse_range(&ctx, expr); - - expr = nftnl_expr_iter_next(iter); - } - - nftnl_expr_iter_destroy(iter); - - if (nftnl_rule_is_set(r, NFTNL_RULE_USERDATA)) { - const void *data; - uint32_t len, size; - const char *comment; - - data = nftnl_rule_get_data(r, NFTNL_RULE_USERDATA, &len); - comment = get_comment(data, len); - if (comment) { - struct xtables_match *match; - struct xt_entry_match *m; - - match = xtables_find_match("comment", XTF_TRY_LOAD, - &cs->matches); - if (match == NULL) - return; - - size = XT_ALIGN(sizeof(struct xt_entry_match)) - + match->size; - m = xtables_calloc(1, size); - - strncpy((char *)m->data, comment, match->size - 1); - m->u.match_size = size; - m->u.user.revision = 0; - strcpy(m->u.user.name, match->name); - - match->m = m; - } - } - - if (!cs->jumpto) - cs->jumpto = ""; -} - -void nft_clear_iptables_command_state(struct iptables_command_state *cs) -{ - xtables_rule_matches_free(&cs->matches); - if (cs->target) { - free(cs->target->t); - cs->target->t = NULL; - - if (cs->target == cs->target->next) { - free(cs->target); - cs->target = NULL; - } - } + __get_cmp_data(e, data, dlen, &op); + *inv = (op == NFT_CMP_NEQ); } void nft_ipv46_save_chain(const struct nftnl_chain *c, const char *policy) @@ -1384,13 +427,6 @@ bool compare_targets(struct xtables_target *tg1, struct xtables_target *tg2) return true; } -void nft_ipv46_parse_target(struct xtables_target *t, - struct iptables_command_state *cs) -{ - cs->target = t; - cs->jumpto = t->name; -} - void nft_check_xt_legacy(int family, bool is_ipt_save) { static const char tables6[] = "/proc/net/ip6_tables_names"; @@ -1424,3 +460,18 @@ void nft_check_xt_legacy(int family, bool is_ipt_save) prefix, prefix, is_ipt_save ? "-save" : ""); fclose(fp); } + +enum nft_registers nft_get_next_reg(enum nft_registers reg, size_t size) +{ + /* convert size to NETLINK_ALIGN-sized chunks */ + size = (size + NETLINK_ALIGN - 1) / NETLINK_ALIGN; + + /* map 16byte reg to 4byte one */ + if (reg < __NFT_REG_MAX) + reg = NFT_REG32_00 + (reg - 1) * NFT_REG_SIZE / NFT_REG32_SIZE; + + reg += size; + assert(reg <= NFT_REG32_15); + + return reg; +} diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index b0404904..a06b263d 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -11,6 +11,7 @@ #include <linux/netfilter/nf_tables.h> #include "xshared.h" +#include "nft-ruleparse.h" #ifdef DEBUG #define DEBUG_DEL @@ -38,45 +39,6 @@ struct xtables_args; struct nft_handle; struct xt_xlate; -enum { - NFT_XT_CTX_PAYLOAD = (1 << 0), - NFT_XT_CTX_META = (1 << 1), - NFT_XT_CTX_BITWISE = (1 << 2), - NFT_XT_CTX_IMMEDIATE = (1 << 3), - NFT_XT_CTX_PREV_PAYLOAD = (1 << 4), - NFT_XT_CTX_RANGE = (1 << 5), -}; - -struct nft_xt_ctx { - struct iptables_command_state *cs; - struct nftnl_expr_iter *iter; - struct nft_handle *h; - uint32_t flags; - const char *table; - union { - struct xt_tcp *tcp; - struct xt_udp *udp; - } tcpudp; - - uint32_t reg; - struct { - uint32_t base; - uint32_t offset; - uint32_t len; - } payload, prev_payload; - struct { - uint32_t key; - } meta; - struct { - uint32_t data[4]; - uint32_t len, reg; - } immediate; - struct { - uint32_t mask[4]; - uint32_t xor[4]; - } bitwise; -}; - struct nft_family_ops { int (*add)(struct nft_handle *h, struct nftnl_rule *r, struct iptables_command_state *cs); @@ -84,11 +46,6 @@ struct nft_family_ops { const struct iptables_command_state *cs_b); void (*print_payload)(struct nftnl_expr *e, struct nftnl_expr_iter *iter); - void (*parse_meta)(struct nft_xt_ctx *ctx, struct nftnl_expr *e, - struct iptables_command_state *cs); - void (*parse_payload)(struct nft_xt_ctx *ctx, struct nftnl_expr *e, - struct iptables_command_state *cs); - void (*parse_lookup)(struct nft_xt_ctx *ctx, struct nftnl_expr *e); void (*set_goto_flag)(struct iptables_command_state *cs); void (*print_table_header)(const char *tablename); @@ -101,13 +58,10 @@ struct nft_family_ops { void (*save_rule)(const struct iptables_command_state *cs, unsigned int format); void (*save_chain)(const struct nftnl_chain *c, const char *policy); + struct nft_ruleparse_ops *rule_parse; struct xt_cmd_parse_ops cmd_parse; - void (*parse_match)(struct xtables_match *m, - struct iptables_command_state *cs); - void (*parse_target)(struct xtables_target *t, - struct iptables_command_state *cs); void (*init_cs)(struct iptables_command_state *cs); - void (*rule_to_cs)(struct nft_handle *h, const struct nftnl_rule *r, + bool (*rule_to_cs)(struct nft_handle *h, const struct nftnl_rule *r, struct iptables_command_state *cs); void (*clear_cs)(struct iptables_command_state *cs); int (*xlate)(const struct iptables_command_state *cs, @@ -156,14 +110,8 @@ bool is_same_interfaces(const char *a_iniface, const char *a_outiface, unsigned const char *b_iniface_mask, unsigned const char *b_outiface_mask); -int parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e, uint8_t key, - char *iniface, unsigned char *iniface_mask, char *outiface, - unsigned char *outiface_mask, uint8_t *invflags); +void __get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, uint8_t *op); void get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, bool *inv); -void nft_rule_to_iptables_command_state(struct nft_handle *h, - const struct nftnl_rule *r, - struct iptables_command_state *cs); -void nft_clear_iptables_command_state(struct iptables_command_state *cs); void print_matches_and_target(struct iptables_command_state *cs, unsigned int format); void nft_ipv46_save_chain(const struct nftnl_chain *c, const char *policy); @@ -173,9 +121,6 @@ void save_matches_and_target(const struct iptables_command_state *cs, struct nft_family_ops *nft_family_ops_lookup(int family); -void nft_ipv46_parse_target(struct xtables_target *t, - struct iptables_command_state *cs); - bool compare_matches(struct xtables_rule_match *mt1, struct xtables_rule_match *mt2); bool compare_targets(struct xtables_target *tg1, struct xtables_target *tg2); @@ -212,7 +157,9 @@ void xtables_restore_parse(struct nft_handle *h, void nft_check_xt_legacy(int family, bool is_ipt_save); -#define min(x, y) ((x) < (y) ? (x) : (y)) -#define max(x, y) ((x) > (y) ? (x) : (y)) +/* simplified nftables:include/netlink.h, netlink_padded_len() */ +#define NETLINK_ALIGN 4 + +enum nft_registers nft_get_next_reg(enum nft_registers reg, size_t size); #endif diff --git a/iptables/nft.c b/iptables/nft.c index ec79f2bc..1cb104e7 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -434,7 +434,7 @@ static void batch_chain_flush(struct nft_handle *h, } } -const struct builtin_table xtables_ipv4[NFT_TABLE_MAX] = { +static const struct builtin_table xtables_ipv4[NFT_TABLE_MAX] = { [NFT_TABLE_RAW] = { .name = "raw", .type = NFT_TABLE_RAW, @@ -571,7 +571,7 @@ const struct builtin_table xtables_ipv4[NFT_TABLE_MAX] = { #include <linux/netfilter_arp.h> -const struct builtin_table xtables_arp[NFT_TABLE_MAX] = { +static const struct builtin_table xtables_arp[NFT_TABLE_MAX] = { [NFT_TABLE_FILTER] = { .name = "filter", .type = NFT_TABLE_FILTER, @@ -594,7 +594,7 @@ const struct builtin_table xtables_arp[NFT_TABLE_MAX] = { #include <linux/netfilter_bridge.h> -const struct builtin_table xtables_bridge[NFT_TABLE_MAX] = { +static const struct builtin_table xtables_bridge[NFT_TABLE_MAX] = { [NFT_TABLE_FILTER] = { .name = "filter", .type = NFT_TABLE_FILTER, @@ -643,6 +643,19 @@ const struct builtin_table xtables_bridge[NFT_TABLE_MAX] = { }, }, }, + [NFT_TABLE_BROUTE] = { + .name = "broute", + .type = NFT_TABLE_BROUTE, + .chains = { + { + .name = "BROUTING", + .type = "filter", + .prio = NF_BR_PRI_FIRST, + .hook = NF_BR_PRE_ROUTING, + }, + }, + }, + }; static int nft_table_builtin_add(struct nft_handle *h, @@ -1133,9 +1146,6 @@ gen_lookup(uint32_t sreg, const char *set_name, uint32_t set_id, uint32_t flags) return e; } -/* simplified nftables:include/netlink.h, netlink_padded_len() */ -#define NETLINK_ALIGN 4 - /* from nftables:include/datatype.h, TYPE_BITS */ #define CONCAT_TYPE_BITS 6 @@ -1167,7 +1177,7 @@ static int __add_nft_among(struct nft_handle *h, const char *table, type = type << CONCAT_TYPE_BITS | NFT_DATATYPE_IPADDR; len += sizeof(struct in_addr) + NETLINK_ALIGN - 1; len &= ~(NETLINK_ALIGN - 1); - flags = NFT_SET_INTERVAL; + flags = NFT_SET_INTERVAL | NFT_SET_CONCAT; } s = add_anon_set(h, table, flags, type, len, cnt); @@ -1208,8 +1218,9 @@ static int __add_nft_among(struct nft_handle *h, const char *table, nftnl_rule_add_expr(r, e); if (ip) { - e = gen_payload(h, NFT_PAYLOAD_NETWORK_HEADER, ip_addr_off[dst], - sizeof(struct in_addr), ®); + reg = nft_get_next_reg(reg, ETH_ALEN); + e = __gen_payload(NFT_PAYLOAD_NETWORK_HEADER, ip_addr_off[dst], + sizeof(struct in_addr), reg); if (!e) return -ENOMEM; nftnl_rule_add_expr(r, e); @@ -1362,6 +1373,9 @@ static int add_nft_udp(struct nft_handle *h, struct nftnl_rule *r, return ret; } + if (nftnl_rule_get_u32(r, NFTNL_RULE_COMPAT_PROTO) != IPPROTO_UDP) + xtables_error(PARAMETER_PROBLEM, "UDP match requires '-p udp'"); + return add_nft_tcpudp(h, r, udp->spts, udp->invflags & XT_UDP_INV_SRCPT, udp->dpts, udp->invflags & XT_UDP_INV_DSTPT); } @@ -1412,6 +1426,9 @@ static int add_nft_tcp(struct nft_handle *h, struct nftnl_rule *r, return ret; } + if (nftnl_rule_get_u32(r, NFTNL_RULE_COMPAT_PROTO) != IPPROTO_TCP) + xtables_error(PARAMETER_PROBLEM, "TCP match requires '-p tcp'"); + if (tcp->flg_mask) { int ret = add_nft_tcpflags(h, r, tcp->flg_cmp, tcp->flg_mask, tcp->invflags & XT_TCP_INV_FLAGS); @@ -1750,15 +1767,16 @@ nft_rule_append(struct nft_handle *h, const char *chain, const char *table, return 1; } -void +bool nft_rule_print_save(struct nft_handle *h, const struct nftnl_rule *r, enum nft_rule_print type, unsigned int format) { const char *chain = nftnl_rule_get_str(r, NFTNL_RULE_CHAIN); struct iptables_command_state cs = {}; struct nft_family_ops *ops = h->ops; + bool ret; - ops->rule_to_cs(h, r, &cs); + ret = ops->rule_to_cs(h, r, &cs); if (!(format & (FMT_NOCOUNTS | FMT_C_COUNTS))) printf("[%llu:%llu] ", (unsigned long long)cs.counters.pcnt, @@ -1779,6 +1797,8 @@ nft_rule_print_save(struct nft_handle *h, const struct nftnl_rule *r, if (ops->clear_cs) ops->clear_cs(&cs); + + return ret; } static bool nft_rule_is_policy_rule(struct nftnl_rule *r) @@ -1889,6 +1909,7 @@ int nft_chain_save(struct nft_chain *nc, void *data) struct nft_rule_save_data { struct nft_handle *h; unsigned int format; + unsigned int errors; }; static int nft_rule_save_cb(struct nft_chain *c, void *data) @@ -1903,7 +1924,11 @@ static int nft_rule_save_cb(struct nft_chain *c, void *data) r = nftnl_rule_iter_next(iter); while (r != NULL) { - nft_rule_print_save(d->h, r, NFT_RULE_APPEND, d->format); + bool ret = nft_rule_print_save(d->h, r, NFT_RULE_APPEND, d->format); + + if (!ret) + d->errors++; + r = nftnl_rule_iter_next(iter); } @@ -1921,6 +1946,9 @@ int nft_rule_save(struct nft_handle *h, const char *table, unsigned int format) ret = nft_chain_foreach(h, table, nft_rule_save_cb, &d); + if (ret == 0 && d.errors) + xtables_error(VERSION_PROBLEM, "Cannot decode all rules provided by kernel"); + /* the core expects 1 for success and 0 for error */ return ret == 0 ? 1 : 0; } @@ -2328,7 +2356,8 @@ static int __nft_rule_del(struct nft_handle *h, struct nftnl_rule *r) nftnl_rule_list_del(r); - if (!nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE)) + if (!nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE) && + !nftnl_rule_get_u32(r, NFTNL_RULE_ID)) nftnl_rule_set_u32(r, NFTNL_RULE_ID, ++h->rule_id); obj = batch_rule_add(h, NFT_COMPAT_RULE_DELETE, r); @@ -2343,15 +2372,18 @@ static bool nft_rule_cmp(struct nft_handle *h, struct nftnl_rule *r, struct nftnl_rule *rule) { struct iptables_command_state _cs = {}, this = {}, *cs = &_cs; - bool ret = false; + bool ret = false, ret_this, ret_that; - h->ops->rule_to_cs(h, r, &this); - h->ops->rule_to_cs(h, rule, cs); + ret_this = h->ops->rule_to_cs(h, r, &this); + ret_that = h->ops->rule_to_cs(h, rule, cs); DEBUGP("comparing with... "); #ifdef DEBUG_DEL nft_rule_print_save(h, r, NFT_RULE_APPEND, 0); #endif + if (!ret_this || !ret_that) + DEBUGP("Cannot convert rules: %d %d\n", ret_this, ret_that); + if (!h->ops->is_same(cs, &this)) goto out; @@ -2862,10 +2894,11 @@ int nft_rule_zero_counters(struct nft_handle *h, const char *chain, goto error; } - nft_rule_to_iptables_command_state(h, r, &cs); - + h->ops->rule_to_cs(h, r, &cs); cs.counters.pcnt = cs.counters.bcnt = 0; new_rule = nft_rule_new(h, chain, table, &cs); + h->ops->clear_cs(&cs); + if (!new_rule) return 1; @@ -2893,8 +2926,8 @@ static void nft_compat_table_batch_add(struct nft_handle *h, uint16_t type, { struct nlmsghdr *nlh; - nlh = nftnl_table_nlmsg_build_hdr(nftnl_batch_buffer(h->batch), - type, h->family, flags, seq); + nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(h->batch), + type, h->family, flags, seq); nftnl_table_nlmsg_build_payload(nlh, table); nft_table_print_debug(h, table, nlh); } @@ -2938,8 +2971,8 @@ static void nft_compat_chain_batch_add(struct nft_handle *h, uint16_t type, { struct nlmsghdr *nlh; - nlh = nftnl_chain_nlmsg_build_hdr(nftnl_batch_buffer(h->batch), - type, h->family, flags, seq); + nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(h->batch), + type, h->family, flags, seq); nftnl_chain_nlmsg_build_payload(nlh, chain); nft_chain_print_debug(h, chain, nlh); } @@ -2950,8 +2983,8 @@ static void nft_compat_rule_batch_add(struct nft_handle *h, uint16_t type, { struct nlmsghdr *nlh; - nlh = nftnl_rule_nlmsg_build_hdr(nftnl_batch_buffer(h->batch), - type, h->family, flags, seq); + nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(h->batch), + type, h->family, flags, seq); nftnl_rule_nlmsg_build_payload(nlh, rule); nft_rule_print_debug(h, rule, nlh); } @@ -3360,6 +3393,8 @@ static int nft_prepare(struct nft_handle *h) nft_cache_build(h); list_for_each_entry_safe(cmd, next, &h->cmd_list, head) { + h->error.lineno = cmd->error.lineno; + switch (cmd->command) { case NFT_COMPAT_TABLE_FLUSH: ret = nft_table_flush(h, cmd->table); @@ -3857,6 +3892,6 @@ void nft_assert_table_compatible(struct nft_handle *h, chain = ""; } xtables_error(OTHER_PROBLEM, - "%s%s%stable `%s' is incompatible, use 'nft' tool.\n", + "%s%s%stable `%s' is incompatible, use 'nft' tool.", pfx, chain, sfx, table); } diff --git a/iptables/nft.h b/iptables/nft.h index 68b0910c..1d18982d 100644 --- a/iptables/nft.h +++ b/iptables/nft.h @@ -14,8 +14,9 @@ enum nft_table_type { NFT_TABLE_RAW, NFT_TABLE_FILTER, NFT_TABLE_NAT, + NFT_TABLE_BROUTE, }; -#define NFT_TABLE_MAX (NFT_TABLE_NAT + 1) +#define NFT_TABLE_MAX (NFT_TABLE_BROUTE + 1) struct builtin_chain { const char *name; @@ -117,10 +118,6 @@ struct nft_handle { } error; }; -extern const struct builtin_table xtables_ipv4[NFT_TABLE_MAX]; -extern const struct builtin_table xtables_arp[NFT_TABLE_MAX]; -extern const struct builtin_table xtables_bridge[NFT_TABLE_MAX]; - int mnl_talk(struct nft_handle *h, struct nlmsghdr *nlh, int (*cb)(const struct nlmsghdr *nlh, void *data), void *data); @@ -203,7 +200,7 @@ enum nft_rule_print { NFT_RULE_DEL, }; -void nft_rule_print_save(struct nft_handle *h, const struct nftnl_rule *r, +bool nft_rule_print_save(struct nft_handle *h, const struct nftnl_rule *r, enum nft_rule_print type, unsigned int format); uint32_t nft_invflags2cmp(uint32_t invflags, uint32_t flag); diff --git a/iptables/tests/shell/run-tests.sh b/iptables/tests/shell/run-tests.sh index 7878760f..11256905 100755 --- a/iptables/tests/shell/run-tests.sh +++ b/iptables/tests/shell/run-tests.sh @@ -21,7 +21,6 @@ EOF msg_error() { echo "E: $1 ..." >&2 - exit 1 } msg_warn() { @@ -34,10 +33,12 @@ msg_info() { if [ "$(id -u)" != "0" ] ; then msg_error "this requires root!" + exit 77 fi if [ ! -d "$TESTDIR" ] ; then msg_error "missing testdir $TESTDIR" + exit 99 fi # support matching repeated pattern in SINGLE check below @@ -76,6 +77,7 @@ while [ -n "$1" ]; do ;; *) msg_error "unknown parameter '$1'" + exit 99 ;; esac done @@ -122,7 +124,8 @@ EOF if [ "$VALGRIND" == "y" ]; then tmpd=$(mktemp -d) msg_info "writing valgrind logs to $tmpd" - chmod a+rx $tmpd + # let nobody write logs, too (././testcases/iptables/0008-unprivileged_0) + chmod 777 $tmpd printscript "$XTABLES_NFT_MULTI" "$tmpd" >${tmpd}/xtables-nft-multi printscript "$XTABLES_LEGACY_MULTI" "$tmpd" >${tmpd}/xtables-legacy-multi trap "rm ${tmpd}/xtables-*-multi" EXIT diff --git a/iptables/tests/shell/testcases/chain/0006rename-segfault_0 b/iptables/tests/shell/testcases/chain/0006rename-segfault_0 new file mode 100755 index 00000000..c10a8006 --- /dev/null +++ b/iptables/tests/shell/testcases/chain/0006rename-segfault_0 @@ -0,0 +1,19 @@ +#!/bin/bash +# +# Cover for a bug in libiptc: +# - the chain 'node-98-tmp' is the last in the list sorted by name +# - there are 81 chains in total, so three chain index buckets +# - the last index bucket contains only the 'node-98-tmp' chain +# => rename temporarily removes it from the bucket, leaving a NULL bucket +# behind which is dereferenced later when inserting the chain again with new +# name again + +( + echo "*filter" + for chain in node-1 node-10 node-101 node-102 node-104 node-107 node-11 node-12 node-13 node-14 node-15 node-16 node-17 node-18 node-19 node-2 node-20 node-21 node-22 node-23 node-25 node-26 node-27 node-28 node-29 node-3 node-30 node-31 node-32 node-33 node-34 node-36 node-37 node-39 node-4 node-40 node-41 node-42 node-43 node-44 node-45 node-46 node-47 node-48 node-49 node-5 node-50 node-51 node-53 node-54 node-55 node-56 node-57 node-58 node-59 node-6 node-60 node-61 node-62 node-63 node-64 node-65 node-66 node-68 node-69 node-7 node-70 node-71 node-74 node-75 node-76 node-8 node-80 node-81 node-86 node-89 node-9 node-92 node-93 node-95 node-98-tmp; do + echo ":$chain - [0:0]" + done + echo "COMMIT" +) | $XT_MULTI iptables-restore +$XT_MULTI iptables -E node-98-tmp node-98 +exit $? diff --git a/iptables/tests/shell/testcases/ebtables/0001-ebtables-basic_0 b/iptables/tests/shell/testcases/ebtables/0001-ebtables-basic_0 index 6f11bd12..bae0de7d 100755 --- a/iptables/tests/shell/testcases/ebtables/0001-ebtables-basic_0 +++ b/iptables/tests/shell/testcases/ebtables/0001-ebtables-basic_0 @@ -15,13 +15,13 @@ get_entries_count() { # (chain) set -x -for t in filter nat;do +for t in filter nat broute; do $XT_MULTI ebtables -t $t -L || exit 1 $XT_MULTI ebtables -t $t -X || exit 1 $XT_MULTI ebtables -t $t -F || exit 1 done -for t in broute foobar ;do +for t in foobar; do $XT_MULTI ebtables -t $t -L && $XT_MULTI ebtables -t $t -X && $XT_MULTI ebtables -t $t -F diff --git a/iptables/tests/shell/testcases/ebtables/0002-ebtables-save-restore_0 b/iptables/tests/shell/testcases/ebtables/0002-ebtables-save-restore_0 index ccdef19c..b4f9728b 100755 --- a/iptables/tests/shell/testcases/ebtables/0002-ebtables-save-restore_0 +++ b/iptables/tests/shell/testcases/ebtables/0002-ebtables-save-restore_0 @@ -13,8 +13,8 @@ $XT_MULTI ebtables -A INPUT -p IPv4 -i lo -j ACCEPT $XT_MULTI ebtables -P FORWARD DROP $XT_MULTI ebtables -A OUTPUT -s ff:ff:ff:ff:ff:ff/ff:ff:ff:ff:ff:ff -j DROP $XT_MULTI ebtables -N foo -$XT_MULTI ebtables -A foo --802_3-sap 0x23 -j ACCEPT -$XT_MULTI ebtables -A foo --802_3-sap 0xaa --802_3-type 0x1337 -j ACCEPT +$XT_MULTI ebtables -A foo -p length --802_3-sap 0x23 -j ACCEPT +$XT_MULTI ebtables -A foo -p length --802_3-sap 0xaa --802_3-type 0x1337 -j ACCEPT #$XT_MULTI ebtables -A foo --among-dst fe:ed:ba:be:00:01,fe:ed:ba:be:00:02,fe:ed:ba:be:00:03 -j ACCEPT $XT_MULTI ebtables -A foo -p ARP --arp-gratuitous -j ACCEPT $XT_MULTI ebtables -A foo -p ARP --arp-opcode Request -j ACCEPT @@ -38,13 +38,13 @@ $XT_MULTI ebtables -A foo -p IPv6 --ip6-proto tcp -j ACCEPT $XT_MULTI ebtables -A foo --limit 100 --limit-burst 42 -j ACCEPT $XT_MULTI ebtables -A foo --log -$XT_MULTI ebtables -A foo --mark-set 0x23 --mark-target ACCEPT +$XT_MULTI ebtables -A foo -j mark --mark-set 0x23 --mark-target ACCEPT $XT_MULTI ebtables -A foo --nflog $XT_MULTI ebtables -A foo --pkttype-type multicast -j ACCEPT $XT_MULTI ebtables -A foo --stp-type config -j ACCEPT #$XT_MULTI ebtables -A foo --vlan-id 42 -j ACCEPT -$XT_MULTI ebtables -A foo --802_3-sap 0x23 --limit 100 -j ACCEPT +$XT_MULTI ebtables -A foo -p length --802_3-sap 0x23 --limit 100 -j ACCEPT $XT_MULTI ebtables -A foo --pkttype-type multicast --log $XT_MULTI ebtables -A foo --pkttype-type multicast --limit 100 -j ACCEPT @@ -53,7 +53,7 @@ $XT_MULTI ebtables -A FORWARD -j foo $XT_MULTI ebtables -N bar $XT_MULTI ebtables -P bar RETURN -$XT_MULTI ebtables -t nat -A PREROUTING --redirect-target ACCEPT +$XT_MULTI ebtables -t nat -A PREROUTING -j redirect --redirect-target ACCEPT #$XT_MULTI ebtables -t nat -A PREROUTING --to-src fe:ed:ba:be:00:01 $XT_MULTI ebtables -t nat -A OUTPUT -j ACCEPT @@ -75,8 +75,8 @@ DUMP='*filter -A INPUT -p IPv4 -i lo -j ACCEPT -A FORWARD -j foo -A OUTPUT -s Broadcast -j DROP --A foo --802_3-sap 0x23 -j ACCEPT --A foo --802_3-sap 0xaa --802_3-type 0x1337 -j ACCEPT +-A foo -p Length --802_3-sap 0x23 -j ACCEPT +-A foo -p Length --802_3-sap 0xaa --802_3-type 0x1337 -j ACCEPT -A foo -p ARP --arp-gratuitous -j ACCEPT -A foo -p ARP --arp-op Request -j ACCEPT -A foo -p ARP --arp-ip-src 10.0.0.1 -j ACCEPT @@ -91,13 +91,13 @@ DUMP='*filter -A foo -p IPv6 --ip6-dst feed:babe::/64 -j ACCEPT -A foo -p IPv6 --ip6-proto tcp -j ACCEPT -A foo --limit 100/sec --limit-burst 42 -j ACCEPT --A foo --log-level notice --log-prefix "" -j CONTINUE +-A foo --log-level notice -j CONTINUE -A foo -j mark --mark-set 0x23 --mark-target ACCEPT -A foo --nflog-group 1 -j CONTINUE -A foo --pkttype-type multicast -j ACCEPT -A foo --stp-type config -j ACCEPT --A foo --802_3-sap 0x23 --limit 100/sec --limit-burst 5 -j ACCEPT --A foo --pkttype-type multicast --log-level notice --log-prefix "" -j CONTINUE +-A foo -p Length --802_3-sap 0x23 --limit 100/sec --limit-burst 5 -j ACCEPT +-A foo --pkttype-type multicast --log-level notice -j CONTINUE -A foo --pkttype-type multicast --limit 100/sec --limit-burst 5 -j ACCEPT *nat :PREROUTING ACCEPT diff --git a/iptables/tests/shell/testcases/ebtables/0003-ebtables-restore-defaults_0 b/iptables/tests/shell/testcases/ebtables/0003-ebtables-restore-defaults_0 index 63891c1b..7554ef85 100755 --- a/iptables/tests/shell/testcases/ebtables/0003-ebtables-restore-defaults_0 +++ b/iptables/tests/shell/testcases/ebtables/0003-ebtables-restore-defaults_0 @@ -24,7 +24,7 @@ EXPECT='*filter -A FORWARD --limit 100/sec --limit-burst 42 -j ACCEPT -A FORWARD --limit 1000/sec --limit-burst 5 -j ACCEPT -A FORWARD --log-level notice --log-prefix "foobar" -j CONTINUE --A FORWARD --log-level notice --log-prefix "" -j CONTINUE' +-A FORWARD --log-level notice -j CONTINUE' $XT_MULTI ebtables --init-table $XT_MULTI ebtables-restore <<<$DUMP diff --git a/iptables/tests/shell/testcases/ebtables/0006-flush_0 b/iptables/tests/shell/testcases/ebtables/0006-flush_0 new file mode 100755 index 00000000..5d714529 --- /dev/null +++ b/iptables/tests/shell/testcases/ebtables/0006-flush_0 @@ -0,0 +1,47 @@ +#!/bin/bash + +set -e + +# there is no legacy backend to test +[[ $XT_MULTI == *xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; } + +RULESET='*filter +:INPUT ACCEPT +:FORWARD ACCEPT +:OUTPUT ACCEPT +-A FORWARD --among-dst fe:ed:ba:be:13:37=10.0.0.1 -j ACCEPT +-A OUTPUT --among-src c0:ff:ee:90:0:0=192.168.0.1 -j DROP +*nat +:PREROUTING ACCEPT +:OUTPUT ACCEPT +:POSTROUTING ACCEPT +-A OUTPUT --among-src c0:ff:ee:90:90:90=192.168.0.1 -j DROP' + +$XT_MULTI ebtables-restore <<<$RULESET +diff -u <(echo -e "$RULESET") <($XT_MULTI ebtables-save | grep -v '^#') + +RULESET='*filter +:INPUT ACCEPT +:FORWARD ACCEPT +:OUTPUT ACCEPT +-A FORWARD --among-dst fe:ed:ba:be:13:37=10.0.0.1 -j ACCEPT +-A OUTPUT --among-src c0:ff:ee:90:0:0=192.168.0.1 -j DROP +*nat +:PREROUTING ACCEPT +:OUTPUT ACCEPT +:POSTROUTING ACCEPT' + +$XT_MULTI ebtables -t nat -F +diff -u <(echo -e "$RULESET") <($XT_MULTI ebtables-save | grep -v '^#') + +RULESET='*filter +:INPUT ACCEPT +:FORWARD ACCEPT +:OUTPUT ACCEPT +*nat +:PREROUTING ACCEPT +:OUTPUT ACCEPT +:POSTROUTING ACCEPT' + +$XT_MULTI ebtables -t filter -F +diff -u <(echo -e "$RULESET") <($XT_MULTI ebtables-save | grep -v '^#') diff --git a/iptables/tests/shell/testcases/ebtables/0008-ebtables-among_0 b/iptables/tests/shell/testcases/ebtables/0008-ebtables-among_0 new file mode 100755 index 00000000..b5df9725 --- /dev/null +++ b/iptables/tests/shell/testcases/ebtables/0008-ebtables-among_0 @@ -0,0 +1,98 @@ +#!/bin/sh + +case "$XT_MULTI" in +*xtables-nft-multi) + ;; +*) + echo "skip $XT_MULTI" + exit 0 + ;; +esac + +sfx=$(mktemp -u "XXXXXXXX") +nsa="nsa-$sfx" +nsb="nsb-$sfx" +nsc="nsc-$sfx" + +cleanup() +{ + ip netns del "$nsa" + ip netns del "$nsb" + ip netns del "$nsc" +} + +trap cleanup EXIT + +assert_fail() +{ + if [ $1 -eq 0 ]; then + echo "FAILED: $2" + exit 1 + fi +} + +assert_pass() +{ + if [ $1 -ne 0 ]; then + echo "FAILED: $2" + exit 2 + fi +} + +ip netns add "$nsa" +ip netns add "$nsb" +ip netns add "$nsc" + +ip link add name c_b netns "$nsc" type veth peer name b_c netns "$nsb" +ip link add name s_b netns "$nsa" type veth peer name b_s netns "$nsb" +ip netns exec "$nsb" ip link add name br0 type bridge + +ip -net "$nsb" link set b_c up +ip netns exec "$nsb" ip link set b_s up +ip netns exec "$nsb" ip addr add 10.167.11.254/24 dev br0 +ip netns exec "$nsb" ip link set br0 up +ip netns exec "$nsb" ip link set b_c master br0 +ip netns exec "$nsb" ip link set b_s master br0 +ip netns exec "$nsc" ip addr add 10.167.11.2/24 dev c_b +ip netns exec "$nsc" ip link set c_b up +ip -net "$nsa" addr add 10.167.11.1/24 dev s_b +ip -net "$nsa" link set s_b up + +ip netns exec "$nsc" ping -q 10.167.11.1 -c1 >/dev/null || exit 1 + +bf_bridge_mac1=`ip netns exec "$nsb" cat /sys/class/net/b_s/address` +bf_bridge_mac0=`ip netns exec "$nsb" cat /sys/class/net/b_c/address` +bf_client_mac1=`ip netns exec "$nsc" cat /sys/class/net/c_b/address` +bf_server_mac1=`ip netns exec "$nsa" cat /sys/class/net/s_b/address` + +bf_server_ip1="10.167.11.1" +bf_bridge_ip0="10.167.11.254" +bf_client_ip1="10.167.11.2" +pktsize=64 + +# --among-src [mac,IP] +ip netns exec "$nsb" $XT_MULTI ebtables -F +ip netns exec "$nsb" $XT_MULTI ebtables -A FORWARD -p ip --ip-dst $bf_server_ip1 --among-src $bf_bridge_mac0=$bf_bridge_ip0,$bf_client_mac1=$bf_client_ip1 -j DROP > /dev/null +ip netns exec "$nsc" ping -q $bf_server_ip1 -c 1 -s $pktsize -W 1 >/dev/null +assert_fail $? "--among-src [match]" + +# ip netns exec "$nsb" $XT_MULTI ebtables -L --Ln --Lc + +ip netns exec "$nsb" $XT_MULTI ebtables -F +ip netns exec "$nsb" $XT_MULTI ebtables -A FORWARD -p ip --ip-dst $bf_server_ip1 --among-src ! $bf_bridge_mac0=$bf_bridge_ip0,$bf_client_mac1=$bf_client_ip1 -j DROP > /dev/null +ip netns exec "$nsc" ping $bf_server_ip1 -c 1 -s $pktsize -W 1 >/dev/null +assert_pass $? "--among-src [not match]" + +# --among-dst [mac,IP] +ip netns exec "$nsb" $XT_MULTI ebtables -F +ip netns exec "$nsb" $XT_MULTI ebtables -A FORWARD -p ip --ip-src $bf_client_ip1 --among-dst $bf_client_mac1=$bf_client_ip1,$bf_server_mac1=$bf_server_ip1 -j DROP > /dev/null +ip netns exec "$nsc" ping -q $bf_server_ip1 -c 1 -s $pktsize -W 1 > /dev/null +assert_fail $? "--among-dst [match]" + +# --among-dst ! [mac,IP] +ip netns exec "$nsb" $XT_MULTI ebtables -F +ip netns exec "$nsb" $XT_MULTI ebtables -A FORWARD -p ip --ip-src $bf_client_ip1 --among-dst ! $bf_client_mac1=$bf_client_ip1,$bf_server_mac1=$bf_server_ip1 -j DROP > /dev/null +ip netns exec "$nsc" ping -q $bf_server_ip1 -c 1 -s $pktsize -W 1 > /dev/null +assert_pass $? "--among-dst [not match]" + +exit 0 diff --git a/iptables/tests/shell/testcases/ip6tables/0002-verbose-output_0 b/iptables/tests/shell/testcases/ip6tables/0002-verbose-output_0 index 7624cbab..cc18a94b 100755 --- a/iptables/tests/shell/testcases/ip6tables/0002-verbose-output_0 +++ b/iptables/tests/shell/testcases/ip6tables/0002-verbose-output_0 @@ -6,15 +6,15 @@ set -e # ensure verbose output is identical between legacy and nft tools RULE1='-i eth2 -o eth3 -s feed:babe::1 -d feed:babe::2 -j ACCEPT' -VOUT1='ACCEPT all opt in eth2 out eth3 feed:babe::1 -> feed:babe::2' +VOUT1='ACCEPT all opt -- in eth2 out eth3 feed:babe::1 -> feed:babe::2' RULE2='-i eth2 -o eth3 -s feed:babe::4 -d feed:babe::5 -j ACCEPT' -VOUT2='ACCEPT all opt in eth2 out eth3 feed:babe::4 -> feed:babe::5' +VOUT2='ACCEPT all opt -- in eth2 out eth3 feed:babe::4 -> feed:babe::5' RULE3='-p icmpv6 -m icmp6 --icmpv6-type no-route' -VOUT3=' ipv6-icmp opt in * out * ::/0 -> ::/0 ipv6-icmptype 1 code 0' +VOUT3=' ipv6-icmp opt -- in * out * ::/0 -> ::/0 ipv6-icmptype 1 code 0' RULE4='-m dst --dst-len 42 -m rt --rt-type 23' -VOUT4=' all opt in * out * ::/0 -> ::/0 dst length:42 rt type:23' +VOUT4=' all opt -- in * out * ::/0 -> ::/0 dst length:42 rt type:23' RULE5='-m frag --fragid 1337 -j LOG' -VOUT5='LOG all opt in * out * ::/0 -> ::/0 frag id:1337 LOG flags 0 level 4' +VOUT5='LOG all opt -- in * out * ::/0 -> ::/0 frag id:1337 LOG flags 0 level 4' diff -u -Z <(echo -e "$VOUT1") <($XT_MULTI ip6tables -v -A FORWARD $RULE1) diff -u -Z <(echo -e "$VOUT2") <($XT_MULTI ip6tables -v -I FORWARD 2 $RULE2) @@ -33,11 +33,11 @@ EXPECT='Chain INPUT (policy ACCEPT 0 packets, 0 bytes) Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination - 0 0 ACCEPT all eth2 eth3 feed:babe::1 feed:babe::2 - 0 0 ACCEPT all eth2 eth3 feed:babe::4 feed:babe::5 - 0 0 ipv6-icmp * * ::/0 ::/0 ipv6-icmptype 1 code 0 - 0 0 all * * ::/0 ::/0 dst length:42 rt type:23 - 0 0 LOG all * * ::/0 ::/0 frag id:1337 LOG flags 0 level 4 + 0 0 ACCEPT 0 -- eth2 eth3 feed:babe::1 feed:babe::2 + 0 0 ACCEPT 0 -- eth2 eth3 feed:babe::4 feed:babe::5 + 0 0 58 -- * * ::/0 ::/0 ipv6-icmptype 1 code 0 + 0 0 0 -- * * ::/0 ::/0 dst length:42 rt type:23 + 0 0 LOG 0 -- * * ::/0 ::/0 frag id:1337 LOG flags 0 level 4 Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination' diff --git a/iptables/tests/shell/testcases/ip6tables/0005-rule-check_0 b/iptables/tests/shell/testcases/ip6tables/0005-rule-check_0 new file mode 100755 index 00000000..cc8215bf --- /dev/null +++ b/iptables/tests/shell/testcases/ip6tables/0005-rule-check_0 @@ -0,0 +1,17 @@ +#!/bin/bash +# +# Test the fix in commit 78850e7dba64a ("ip6tables: Fix checking existence of +# rule"). Happens with legacy ip6tables only, but testing ip6tables-nft doesn't +# hurt. +# +# Code taken from https://bugzilla.netfilter.org/show_bug.cgi?id=1667 +# Thanks to Jonathan Caicedo <jonathan@jcaicedo.com> for providing it. + +RULE='-p tcp --dport 81 -j DNAT --to-destination [::1]:81' + +$XT_MULTI ip6tables -t nat -N testchain || exit 1 +$XT_MULTI ip6tables -t nat -A testchain $RULE || exit 1 +$XT_MULTI ip6tables -t nat -C testchain $RULE || exit 1 + +$XT_MULTI ip6tables -t nat -C testchain ${RULE//81/82} 2>/dev/null && exit 1 +exit 0 diff --git a/iptables/tests/shell/testcases/ipt-restore/0003-restore-ordering_0 b/iptables/tests/shell/testcases/ipt-restore/0003-restore-ordering_0 index 3f1d229e..5482b7ea 100755 --- a/iptables/tests/shell/testcases/ipt-restore/0003-restore-ordering_0 +++ b/iptables/tests/shell/testcases/ipt-restore/0003-restore-ordering_0 @@ -123,3 +123,19 @@ EXPECT='-A FORWARD -m comment --comment "rule 1" -j ACCEPT -A FORWARD -m comment --comment "rule 3" -j ACCEPT' diff -u -Z <(echo -e "$EXPECT") <(ipt_show) + +# test adding, referencing and deleting the same rule in a batch + +$XT_MULTI iptables-restore <<EOF +*filter +-A FORWARD -m comment --comment "first rule" -j ACCEPT +-A FORWARD -m comment --comment "referenced rule" -j ACCEPT +-I FORWARD 2 -m comment --comment "referencing rule" -j ACCEPT +-D FORWARD -m comment --comment "referenced rule" -j ACCEPT +COMMIT +EOF + +EXPECT='-A FORWARD -m comment --comment "first rule" -j ACCEPT +-A FORWARD -m comment --comment "referencing rule" -j ACCEPT' + +diff -u -Z <(echo -e "$EXPECT") <(ipt_show) diff --git a/iptables/tests/shell/testcases/ipt-restore/0011-noflush-empty-line_0 b/iptables/tests/shell/testcases/ipt-restore/0011-noflush-empty-line_0 index bea1a690..1a3af46f 100755 --- a/iptables/tests/shell/testcases/ipt-restore/0011-noflush-empty-line_0 +++ b/iptables/tests/shell/testcases/ipt-restore/0011-noflush-empty-line_0 @@ -12,5 +12,5 @@ EOF EXPECT='Chain FORWARD (policy ACCEPT) target prot opt source destination -ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 ' +ACCEPT 0 -- 0.0.0.0/0 0.0.0.0/0 ' diff -u <(echo "$EXPECT") <($XT_MULTI iptables -n -L FORWARD) diff --git a/iptables/tests/shell/testcases/ipt-restore/0014-verbose-restore_0 b/iptables/tests/shell/testcases/ipt-restore/0014-verbose-restore_0 index 5daf7a78..087156b1 100755 --- a/iptables/tests/shell/testcases/ipt-restore/0014-verbose-restore_0 +++ b/iptables/tests/shell/testcases/ipt-restore/0014-verbose-restore_0 @@ -60,7 +60,7 @@ Flushing chain \`OUTPUT' Flushing chain \`secfoo' Deleting chain \`secfoo'" -EXPECT6=$(sed -e 's/0\.0\.0\.0/::/g' -e 's/opt --/opt /' <<< "$EXPECT") +EXPECT6=$(sed -e 's/0\.0\.0\.0/::/g' <<< "$EXPECT") diff -u -Z <(echo "$EXPECT") <($XT_MULTI iptables-restore -v <<< "$DUMP") diff -u -Z <(echo "$EXPECT6") <($XT_MULTI ip6tables-restore -v <<< "$DUMP") diff --git a/iptables/tests/shell/testcases/iptables/0002-verbose-output_0 b/iptables/tests/shell/testcases/iptables/0002-verbose-output_0 index 5d2af4c8..15c72af3 100755 --- a/iptables/tests/shell/testcases/iptables/0002-verbose-output_0 +++ b/iptables/tests/shell/testcases/iptables/0002-verbose-output_0 @@ -21,8 +21,8 @@ EXPECT='Chain INPUT (policy ACCEPT 0 packets, 0 bytes) Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination - 0 0 ACCEPT all -- eth2 eth3 10.0.0.1 10.0.0.2 - 0 0 ACCEPT all -- eth2 eth3 10.0.0.4 10.0.0.5 + 0 0 ACCEPT 0 -- eth2 eth3 10.0.0.1 10.0.0.2 + 0 0 ACCEPT 0 -- eth2 eth3 10.0.0.4 10.0.0.5 Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination' diff --git a/iptables/tests/shell/testcases/iptables/0009-unknown-arg_0 b/iptables/tests/shell/testcases/iptables/0009-unknown-arg_0 new file mode 100755 index 00000000..ac6e7439 --- /dev/null +++ b/iptables/tests/shell/testcases/iptables/0009-unknown-arg_0 @@ -0,0 +1,31 @@ +#!/bin/bash + +rc=0 + +check() { + local cmd="$1" + local msg="$2" + + $XT_MULTI $cmd 2>&1 | grep -q "$msg" || { + echo "cmd: $XT_MULTI $1" + echo "exp: $msg" + echo "res: $($XT_MULTI $cmd 2>&1)" + rc=1 + } +} + +cmds="iptables ip6tables" +[[ $XT_MULTI == *xtables-nft-multi ]] && { + cmds+=" ebtables" + cmds+=" iptables-translate" + cmds+=" ip6tables-translate" + cmds+=" ebtables-translate" +} + +for cmd in $cmds; do + check "${cmd} --foo" 'unknown option "--foo"' + check "${cmd} -A" 'option "-A" requires an argument' + check "${cmd} -aL" 'unknown option "-a"' +done + +exit $rc diff --git a/iptables/tests/shell/testcases/nft-only/0010-iptables-nft-save.txt b/iptables/tests/shell/testcases/nft-only/0010-iptables-nft-save.txt new file mode 100644 index 00000000..5ee4c231 --- /dev/null +++ b/iptables/tests/shell/testcases/nft-only/0010-iptables-nft-save.txt @@ -0,0 +1,26 @@ +*filter +:INPUT ACCEPT [0:0] +:FORWARD ACCEPT [0:0] +:OUTPUT ACCEPT [0:0] +-A INPUT -s 1.2.3.4/32 -p tcp -m tcp --dport 23 -j ACCEPT +-A INPUT -s 1.2.3.0/24 -d 0.0.0.0/32 -p udp -m udp --dport 67:69 -j DROP +-A INPUT -s 1.0.0.0/8 -d 0.0.0.0/32 -p tcp -m tcp --sport 1024:65535 --dport 443 --tcp-flags SYN,ACK SYN -j ACCEPT +-A INPUT -p tcp -m tcp --dport 443 ! --tcp-flags SYN NONE -m comment --comment "checks if SYN bit is set" +-A INPUT -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -m comment --comment "same as iptables --syn" +-A INPUT -p tcp -m tcp --tcp-flags SYN SYN +-A INPUT -p tcp -m tcp ! --tcp-flags SYN,ACK SYN,ACK +-A INPUT -d 0.0.0.0/1 -m ttl --ttl-eq 1 -j DROP +-A INPUT -d 0.0.0.0/2 -m ttl --ttl-gt 2 -j ACCEPT +-A INPUT -d 0.0.0.0/3 -m ttl --ttl-lt 254 -j ACCEPT +-A INPUT -d 0.0.0.0/4 -m ttl ! --ttl-eq 255 -j DROP +-A INPUT -d 8.0.0.0/5 -p icmp -m icmp --icmp-type 1 -j ACCEPT +-A INPUT -d 8.0.0.0/6 -p icmp -m icmp --icmp-type 2/3 -j ACCEPT +-A INPUT -d 10.0.0.0/7 -p icmp -m icmp --icmp-type 8 -j ACCEPT +-A INPUT -m pkttype --pkt-type broadcast -j ACCEPT +-A INPUT -m pkttype ! --pkt-type unicast -j DROP +-A INPUT -p tcp +-A INPUT -d 0.0.0.0/1 -p udp +-A FORWARD -m limit --limit 10/day +-A FORWARD -p udp -m udp --dport 42 +-A FORWARD -i lo -o lo+ -j NFLOG --nflog-prefix "should use NFLOG" --nflog-group 1 --nflog-size 123 --nflog-threshold 42 +COMMIT diff --git a/iptables/tests/shell/testcases/nft-only/0010-native-delinearize_0 b/iptables/tests/shell/testcases/nft-only/0010-native-delinearize_0 new file mode 100755 index 00000000..7859e76c --- /dev/null +++ b/iptables/tests/shell/testcases/nft-only/0010-native-delinearize_0 @@ -0,0 +1,9 @@ +#!/bin/bash + +[[ $XT_MULTI == *xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; } +nft -v >/dev/null || exit 0 + +set -e + +unshare -n bash -c "nft -f $(dirname $0)/0010-nft-native.txt; + diff -u -Z $(dirname $0)/0010-iptables-nft-save.txt <($XT_MULTI iptables-save | grep -v '^#')" diff --git a/iptables/tests/shell/testcases/nft-only/0010-nft-native.txt b/iptables/tests/shell/testcases/nft-only/0010-nft-native.txt new file mode 100644 index 00000000..d37ce873 --- /dev/null +++ b/iptables/tests/shell/testcases/nft-only/0010-nft-native.txt @@ -0,0 +1,41 @@ +table ip filter { + chain INPUT { + type filter hook input priority filter; policy accept; + + ip saddr 1.2.3.4 tcp dport 23 accept + ip saddr 1.2.3.0/24 ip daddr 0.0.0.0 udp dport 67-69 drop + + ip saddr 1.0.0.0/8 ip daddr 0.0.0.0 tcp sport 1024-65535 tcp dport 443 tcp flags syn / syn,ack accept + tcp dport 443 tcp flags syn comment "checks if SYN bit is set" + tcp flags syn / syn,rst,ack,fin comment "same as iptables --syn" + tcp flags & syn == syn + tcp flags & (syn | ack) != (syn | ack ) + + ip daddr 0.0.0.0/1 ip ttl 1 drop + ip daddr 0.0.0.0/2 ip ttl > 2 accept + ip daddr 0.0.0.0/3 ip ttl < 254 accept + ip daddr 0.0.0.0/4 ip ttl != 255 drop + + ip daddr 8.0.0.0/5 icmp type 1 accept + ip daddr 8.0.0.0/6 icmp type 2 icmp code port-unreachable accept + ip daddr 10.0.0.0/7 icmp type echo-request accept + + meta pkttype broadcast accept + meta pkttype != host drop + + ip saddr 0.0.0.0/0 ip protocol tcp + ip daddr 0.0.0.0/1 ip protocol udp + } + + chain FORWARD { + type filter hook forward priority filter; + limit rate 10/day counter + udp dport 42 counter + + # FIXME: can't dissect plain syslog + # meta iif "lo" log prefix "just doing a log" level alert flags tcp sequence,options + + # iif, not iifname, and wildcard + meta iif "lo" oifname "lo*" log group 1 prefix "should use NFLOG" queue-threshold 42 snaplen 123 + } +} diff --git a/iptables/xshared.c b/iptables/xshared.c index bd4e1022..17aed04e 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -192,9 +192,12 @@ static int command_default(struct iptables_command_state *cs, if (cs->c == ':') xtables_error(PARAMETER_PROBLEM, "option \"%s\" " "requires an argument", cs->argv[optind-1]); - if (cs->c == '?') - xtables_error(PARAMETER_PROBLEM, "unknown option " - "\"%s\"", cs->argv[optind-1]); + if (cs->c == '?') { + char optoptstr[3] = {'-', optopt, '\0'}; + + xtables_error(PARAMETER_PROBLEM, "unknown option \"%s\"", + optopt ? optoptstr : cs->argv[optind - 1]); + } xtables_error(PARAMETER_PROBLEM, "Unknown arg \"%s\"", optarg); } @@ -400,15 +403,15 @@ bool tokenize_rule_counters(char **bufferp, char **pcntp, char **bcntp, int line ptr = strchr(buffer, ']'); if (!ptr) - xtables_error(PARAMETER_PROBLEM, "Bad line %u: need ]\n", line); + xtables_error(PARAMETER_PROBLEM, "Bad line %u: need ]", line); pcnt = strtok(buffer+1, ":"); if (!pcnt) - xtables_error(PARAMETER_PROBLEM, "Bad line %u: need :\n", line); + xtables_error(PARAMETER_PROBLEM, "Bad line %u: need :", line); bcnt = strtok(NULL, "]"); if (!bcnt) - xtables_error(PARAMETER_PROBLEM, "Bad line %u: need ]\n", line); + xtables_error(PARAMETER_PROBLEM, "Bad line %u: need ]", line); *pcntp = pcnt; *bcntp = bcnt; @@ -433,10 +436,10 @@ void add_argv(struct argv_store *store, const char *what, int quoted) if (store->argc + 1 >= MAX_ARGC) xtables_error(PARAMETER_PROBLEM, - "Parser cannot handle more arguments\n"); + "Parser cannot handle more arguments"); if (!what) xtables_error(PARAMETER_PROBLEM, - "Trying to store NULL argument\n"); + "Trying to store NULL argument"); store->argv[store->argc] = xtables_strdup(what); store->argvattr[store->argc] = quoted; @@ -731,7 +734,7 @@ void print_fragment(unsigned int flags, unsigned int invflags, fputs("opt ", stdout); if (fake) { - fputs(" ", stdout); + fputs("--", stdout); } else { fputc(invflags & IPT_INV_FRAG ? '!' : '-', stdout); fputc(flags & IPT_F_FRAG ? 'f' : '-', stdout); @@ -900,8 +903,7 @@ static char cmd2char(int option) ; if (i >= ARRAY_SIZE(cmdflags)) xtables_error(OTHER_PROBLEM, - "cmd2char(): Invalid command number %u.\n", - 1 << i); + "cmd2char(): Invalid command number %u.", 1 << i); return cmdflags[i]; } @@ -911,8 +913,8 @@ static void add_command(unsigned int *cmd, const int newcmd, if (invert) xtables_error(PARAMETER_PROBLEM, "unexpected '!' flag"); if (*cmd & (~othercmds)) - xtables_error(PARAMETER_PROBLEM, "Cannot use -%c with -%c\n", - cmd2char(newcmd), cmd2char(*cmd & (~othercmds))); + xtables_error(PARAMETER_PROBLEM, "Cannot use -%c with -%c", + cmd2char(newcmd), cmd2char(*cmd & (~othercmds))); *cmd |= newcmd; } @@ -979,9 +981,8 @@ static void generic_opt_check(int command, int options) if (!(options & (1<<i))) { if (commands_v_options[j][i] == '+') xtables_error(PARAMETER_PROBLEM, - "You need to supply the `-%c' " - "option for this command\n", - optflags[i]); + "You need to supply the `-%c' option for this command", + optflags[i]); } else { if (commands_v_options[j][i] != 'x') legal = 1; @@ -991,8 +992,8 @@ static void generic_opt_check(int command, int options) } if (legal == -1) xtables_error(PARAMETER_PROBLEM, - "Illegal option `-%c' with this command\n", - optflags[i]); + "Illegal option `-%c' with this command", + optflags[i]); } } @@ -1060,12 +1061,12 @@ void assert_valid_chain_name(const char *chainname) if (*chainname == '-' || *chainname == '!') xtables_error(PARAMETER_PROBLEM, - "chain name not allowed to start with `%c'\n", + "chain name not allowed to start with `%c'", *chainname); if (xtables_find_target(chainname, XTF_TRY_LOAD)) xtables_error(PARAMETER_PROBLEM, - "chain name may not clash with target name\n"); + "chain name may not clash with target name"); for (ptr = chainname; *ptr; ptr++) if (isspace(*ptr)) @@ -1092,10 +1093,10 @@ void print_rule_details(unsigned int linenum, const struct xt_counters *ctrs, fputc(invflags & XT_INV_PROTO ? '!' : ' ', stdout); - if (pname) - printf(FMT("%-5s", "%s "), pname); + if (((format & (FMT_NUMERIC | FMT_NOTABLE)) == FMT_NUMERIC) || !pname) + printf(FMT("%-4hu ", "%hu "), proto); else - printf(FMT("%-5hu", "%hu "), proto); + printf(FMT("%-4s ", "%s "), pname); } void save_rule_details(const char *iniface, unsigned const char *iniface_mask, @@ -1317,7 +1318,7 @@ static void check_empty_interface(struct xtables_args *args, const char *arg) } static void check_inverse(struct xtables_args *args, const char option[], - bool *invert, int *optidx, int argc) + bool *invert, int argc, char **argv) { switch (args->family) { case NFPROTO_ARP: @@ -1336,12 +1337,11 @@ static void check_inverse(struct xtables_args *args, const char option[], xtables_error(PARAMETER_PROBLEM, "Multiple `!' flags not allowed"); *invert = true; - if (optidx) { - *optidx = *optidx + 1; - if (argc && *optidx > argc) - xtables_error(PARAMETER_PROBLEM, - "no argument following `!'"); - } + optind++; + if (optind > argc) + xtables_error(PARAMETER_PROBLEM, "no argument following `!'"); + + optarg = argv[optind - 1]; } static const char *optstring_lookup(int family) @@ -1358,6 +1358,23 @@ static const char *optstring_lookup(int family) return ""; } +void xtables_clear_iptables_command_state(struct iptables_command_state *cs) +{ + xtables_rule_matches_free(&cs->matches); + if (cs->target) { + free(cs->target->t); + cs->target->t = NULL; + + free(cs->target->udata); + cs->target->udata = NULL; + + if (cs->target == cs->target->next) { + free(cs->target); + cs->target = NULL; + } + } +} + void do_parse(int argc, char *argv[], struct xt_cmd_parse *p, struct iptables_command_state *cs |