summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore12
-rw-r--r--INCOMPATIBILITIES14
-rw-r--r--Makefile.am8
-rw-r--r--configure.ac15
-rw-r--r--etc/xtables.conf74
-rw-r--r--extensions/GNUmakefile.in134
-rw-r--r--extensions/dscp_helper.c4
-rw-r--r--extensions/generic.txlate68
-rw-r--r--extensions/libarpt_standard.t2
-rw-r--r--extensions/libebt_802_3.t6
-rw-r--r--extensions/libebt_among.c23
-rw-r--r--extensions/libebt_arp.c89
-rw-r--r--extensions/libebt_arp.t3
-rw-r--r--extensions/libebt_dnat.txlate12
-rw-r--r--extensions/libebt_ip.c287
-rw-r--r--extensions/libebt_ip.txlate20
-rw-r--r--extensions/libebt_ip6.c111
-rw-r--r--extensions/libebt_ip6.txlate20
-rw-r--r--extensions/libebt_limit.txlate6
-rw-r--r--extensions/libebt_log.c18
-rw-r--r--extensions/libebt_log.t6
-rw-r--r--extensions/libebt_log.txlate10
-rw-r--r--extensions/libebt_mark.c2
-rw-r--r--extensions/libebt_mark.txlate11
-rw-r--r--extensions/libebt_mark.xlate11
-rw-r--r--extensions/libebt_mark_m.txlate10
-rw-r--r--extensions/libebt_nflog.c9
-rw-r--r--extensions/libebt_nflog.t2
-rw-r--r--extensions/libebt_nflog.txlate8
-rw-r--r--extensions/libebt_pkttype.txlate14
-rw-r--r--extensions/libebt_redirect.c6
-rw-r--r--extensions/libebt_redirect.t2
-rw-r--r--extensions/libebt_redirect.txlate8
-rw-r--r--extensions/libebt_snat.txlate8
-rw-r--r--extensions/libebt_stp.c4
-rw-r--r--extensions/libebt_stp.t2
-rw-r--r--extensions/libebt_vlan.t4
-rw-r--r--extensions/libebt_vlan.txlate8
-rw-r--r--extensions/libip6t_LOG.c250
-rw-r--r--extensions/libip6t_LOG.txlate6
-rw-r--r--extensions/libip6t_MASQUERADE.c188
-rw-r--r--extensions/libip6t_MASQUERADE.txlate15
-rw-r--r--extensions/libip6t_NETMAP.t2
-rw-r--r--extensions/libip6t_REJECT.t2
-rw-r--r--extensions/libip6t_REJECT.txlate6
-rw-r--r--extensions/libip6t_SNAT.c308
-rw-r--r--extensions/libip6t_SNAT.t6
-rw-r--r--extensions/libip6t_SNAT.txlate8
-rw-r--r--extensions/libip6t_ah.txlate12
-rw-r--r--extensions/libip6t_dst.c6
-rw-r--r--extensions/libip6t_frag.c30
-rw-r--r--extensions/libip6t_frag.txlate12
-rw-r--r--extensions/libip6t_hbh.txlate4
-rw-r--r--extensions/libip6t_hl.txlate4
-rw-r--r--extensions/libip6t_icmp6.c97
-rw-r--r--extensions/libip6t_icmp6.txlate6
-rw-r--r--extensions/libip6t_mh.c2
-rw-r--r--extensions/libip6t_mh.txlate4
-rw-r--r--extensions/libip6t_rt.c7
-rw-r--r--extensions/libip6t_rt.txlate10
-rw-r--r--extensions/libipt_CLUSTERIP.c10
-rw-r--r--extensions/libipt_CLUSTERIP.t4
-rw-r--r--extensions/libipt_LOG.c250
-rw-r--r--extensions/libipt_LOG.txlate4
-rw-r--r--extensions/libipt_MASQUERADE.c190
-rw-r--r--extensions/libipt_MASQUERADE.txlate15
-rw-r--r--extensions/libipt_NETMAP.t2
-rw-r--r--extensions/libipt_REJECT.t2
-rw-r--r--extensions/libipt_REJECT.txlate6
-rw-r--r--extensions/libipt_SNAT.c280
-rw-r--r--extensions/libipt_SNAT.t6
-rw-r--r--extensions/libipt_SNAT.txlate10
-rw-r--r--extensions/libipt_ah.txlate6
-rw-r--r--extensions/libipt_icmp.c110
-rw-r--r--extensions/libipt_icmp.txlate8
-rw-r--r--extensions/libipt_realm.txlate8
-rw-r--r--extensions/libipt_ttl.c4
-rw-r--r--extensions/libipt_ttl.txlate4
-rw-r--r--extensions/libxt_AUDIT.txlate6
-rw-r--r--extensions/libxt_CLASSIFY.txlate6
-rw-r--r--extensions/libxt_CONNMARK.c15
-rw-r--r--extensions/libxt_CONNMARK.t8
-rw-r--r--extensions/libxt_CONNMARK.txlate17
-rw-r--r--extensions/libxt_CONNSECMARK.c3
-rw-r--r--extensions/libxt_CT.c2
-rw-r--r--extensions/libxt_DNAT.txlate24
-rw-r--r--extensions/libxt_DSCP.t2
-rw-r--r--extensions/libxt_DSCP.txlate4
-rw-r--r--extensions/libxt_IDLETIMER.t2
-rw-r--r--extensions/libxt_LOG.c204
-rw-r--r--extensions/libxt_MARK.c2
-rw-r--r--extensions/libxt_MARK.t4
-rw-r--r--extensions/libxt_MARK.txlate18
-rw-r--r--extensions/libxt_NAT.c (renamed from extensions/libxt_DNAT.c)440
-rw-r--r--extensions/libxt_NFLOG.c12
-rw-r--r--extensions/libxt_NFLOG.txlate10
-rw-r--r--extensions/libxt_NFQUEUE.c2
-rw-r--r--extensions/libxt_NFQUEUE.man2
-rw-r--r--extensions/libxt_NFQUEUE.t7
-rw-r--r--extensions/libxt_NFQUEUE.txlate6
-rw-r--r--extensions/libxt_NOTRACK.txlate2
-rw-r--r--extensions/libxt_REDIRECT.t1
-rw-r--r--extensions/libxt_REDIRECT.txlate21
-rw-r--r--extensions/libxt_SECMARK.c2
-rw-r--r--extensions/libxt_SYNPROXY.txlate2
-rw-r--r--extensions/libxt_TCPMSS.c1
-rw-r--r--extensions/libxt_TCPMSS.txlate4
-rw-r--r--extensions/libxt_TCPOPTSTRIP.c13
-rw-r--r--extensions/libxt_TEE.txlate8
-rw-r--r--extensions/libxt_TOS.c33
-rw-r--r--extensions/libxt_TOS.t12
-rw-r--r--extensions/libxt_TOS.txlate19
-rw-r--r--extensions/libxt_TRACE.txlate2
-rw-r--r--extensions/libxt_addrtype.txlate8
-rw-r--r--extensions/libxt_bpf.c3
-rw-r--r--extensions/libxt_cgroup.txlate4
-rw-r--r--extensions/libxt_cluster.txlate18
-rw-r--r--extensions/libxt_comment.c7
-rw-r--r--extensions/libxt_comment.txlate6
-rw-r--r--extensions/libxt_connbytes.txlate10
-rw-r--r--extensions/libxt_connlabel.txlate4
-rw-r--r--extensions/libxt_connlimit.t12
-rw-r--r--extensions/libxt_connlimit.txlate16
-rw-r--r--extensions/libxt_connmark.t4
-rw-r--r--extensions/libxt_connmark.txlate10
-rw-r--r--extensions/libxt_conntrack.c13
-rw-r--r--extensions/libxt_conntrack.txlate40
-rw-r--r--extensions/libxt_cpu.txlate4
-rw-r--r--extensions/libxt_dccp.c11
-rw-r--r--extensions/libxt_dccp.txlate14
-rw-r--r--extensions/libxt_devgroup.c4
-rw-r--r--extensions/libxt_devgroup.txlate12
-rw-r--r--extensions/libxt_dscp.t2
-rw-r--r--extensions/libxt_dscp.txlate4
-rw-r--r--extensions/libxt_ecn.c2
-rw-r--r--extensions/libxt_ecn.txlate20
-rw-r--r--extensions/libxt_esp.txlate8
-rw-r--r--extensions/libxt_hashlimit.c10
-rw-r--r--extensions/libxt_hashlimit.txlate4
-rw-r--r--extensions/libxt_helper.c8
-rw-r--r--extensions/libxt_helper.txlate4
-rw-r--r--extensions/libxt_icmp.h242
-rw-r--r--extensions/libxt_ipcomp.c2
-rw-r--r--extensions/libxt_ipcomp.c.man3
-rw-r--r--extensions/libxt_ipcomp.txlate4
-rw-r--r--extensions/libxt_iprange.c12
-rw-r--r--extensions/libxt_iprange.txlate10
-rw-r--r--extensions/libxt_length.t2
-rw-r--r--extensions/libxt_length.txlate8
-rw-r--r--extensions/libxt_limit.c4
-rw-r--r--extensions/libxt_limit.txlate6
-rw-r--r--extensions/libxt_mac.txlate4
-rw-r--r--extensions/libxt_mark.t3
-rw-r--r--extensions/libxt_mark.txlate4
-rw-r--r--extensions/libxt_multiport.c4
-rw-r--r--extensions/libxt_multiport.txlate10
-rw-r--r--extensions/libxt_owner.txlate6
-rw-r--r--extensions/libxt_pkttype.c2
-rw-r--r--extensions/libxt_pkttype.txlate6
-rw-r--r--extensions/libxt_policy.txlate4
-rw-r--r--extensions/libxt_quota.txlate4
-rw-r--r--extensions/libxt_recent.t4
-rw-r--r--extensions/libxt_rpfilter.txlate6
-rw-r--r--extensions/libxt_sctp.c47
-rw-r--r--extensions/libxt_sctp.man4
-rw-r--r--extensions/libxt_sctp.t4
-rw-r--r--extensions/libxt_sctp.txlate30
-rw-r--r--extensions/libxt_set.c59
-rw-r--r--extensions/libxt_standard.t3
-rw-r--r--extensions/libxt_statistic.c8
-rw-r--r--extensions/libxt_statistic.txlate6
-rw-r--r--extensions/libxt_tcp.c23
-rw-r--r--extensions/libxt_tcp.t3
-rw-r--r--extensions/libxt_tcp.txlate24
-rw-r--r--extensions/libxt_tcpmss.txlate8
-rw-r--r--extensions/libxt_time.c12
-rw-r--r--extensions/libxt_time.txlate18
-rw-r--r--extensions/libxt_tos.t8
-rw-r--r--extensions/libxt_udp.c6
-rw-r--r--extensions/libxt_udp.t3
-rw-r--r--extensions/libxt_udp.txlate8
-rw-r--r--include/Makefile.am8
-rw-r--r--include/linux/netfilter/nf_log.h15
-rw-r--r--include/linux/netfilter/nf_tables.h542
-rw-r--r--include/linux/netfilter/xt_LOG.h20
-rw-r--r--include/linux/netfilter_bridge/ebt_ip.h15
-rw-r--r--include/linux/netfilter_ipv4/ipt_LOG.h19
-rw-r--r--include/linux/netfilter_ipv6/ip6t_LOG.h19
-rw-r--r--include/xtables.h8
-rwxr-xr-xiptables-test.py302
-rw-r--r--iptables/.gitignore5
-rw-r--r--iptables/Makefile.am91
-rw-r--r--iptables/ebtables-nft.842
-rw-r--r--iptables/ip6tables-apply.81
-rw-r--r--iptables/ip6tables-restore.81
-rw-r--r--iptables/ip6tables-save.81
-rw-r--r--iptables/ip6tables.81
-rw-r--r--iptables/ip6tables.c51
-rw-r--r--iptables/iptables-restore.c42
-rw-r--r--iptables/iptables-save.c5
-rw-r--r--iptables/iptables-xml.c26
-rw-r--r--iptables/iptables.c51
-rw-r--r--iptables/nft-arp.c144
-rw-r--r--iptables/nft-bridge.c467
-rw-r--r--iptables/nft-cache.c19
-rw-r--r--iptables/nft-cache.h2
-rw-r--r--iptables/nft-cmd.c3
-rw-r--r--iptables/nft-cmd.h5
-rw-r--r--iptables/nft-ipv4.c137
-rw-r--r--iptables/nft-ipv6.c113
-rw-r--r--iptables/nft-ruleparse-arp.c168
-rw-r--r--iptables/nft-ruleparse-bridge.c422
-rw-r--r--iptables/nft-ruleparse-ipv4.c135
-rw-r--r--iptables/nft-ruleparse-ipv6.c112
-rw-r--r--iptables/nft-ruleparse.c1208
-rw-r--r--iptables/nft-ruleparse.h138
-rw-r--r--iptables/nft-shared.c1003
-rw-r--r--iptables/nft-shared.h69
-rw-r--r--iptables/nft.c85
-rw-r--r--iptables/nft.h9
-rwxr-xr-xiptables/tests/shell/run-tests.sh7
-rwxr-xr-xiptables/tests/shell/testcases/chain/0006rename-segfault_019
-rwxr-xr-xiptables/tests/shell/testcases/ebtables/0001-ebtables-basic_04
-rwxr-xr-xiptables/tests/shell/testcases/ebtables/0002-ebtables-save-restore_020
-rwxr-xr-xiptables/tests/shell/testcases/ebtables/0003-ebtables-restore-defaults_02
-rwxr-xr-xiptables/tests/shell/testcases/ebtables/0006-flush_047
-rwxr-xr-xiptables/tests/shell/testcases/ebtables/0008-ebtables-among_098
-rwxr-xr-xiptables/tests/shell/testcases/ip6tables/0002-verbose-output_020
-rwxr-xr-xiptables/tests/shell/testcases/ip6tables/0005-rule-check_017
-rwxr-xr-xiptables/tests/shell/testcases/ipt-restore/0003-restore-ordering_016
-rwxr-xr-xiptables/tests/shell/testcases/ipt-restore/0011-noflush-empty-line_02
-rwxr-xr-xiptables/tests/shell/testcases/ipt-restore/0014-verbose-restore_02
-rwxr-xr-xiptables/tests/shell/testcases/iptables/0002-verbose-output_04
-rwxr-xr-xiptables/tests/shell/testcases/iptables/0009-unknown-arg_031
-rw-r--r--iptables/tests/shell/testcases/nft-only/0010-iptables-nft-save.txt26
-rwxr-xr-xiptables/tests/shell/testcases/nft-only/0010-native-delinearize_09
-rw-r--r--iptables/tests/shell/testcases/nft-only/0010-nft-native.txt41
-rw-r--r--iptables/xshared.c162
-rw-r--r--iptables/xshared.h11
-rw-r--r--iptables/xtables-eb-translate.c73
-rw-r--r--iptables/xtables-eb.c93
-rw-r--r--iptables/xtables-monitor.c2
-rw-r--r--iptables/xtables-multi.h1
-rw-r--r--iptables/xtables-restore.c33
-rw-r--r--iptables/xtables-translate.813
-rw-r--r--iptables/xtables-translate.c35
-rw-r--r--iptables/xtables.c2
-rw-r--r--libipq/Makefile.am2
-rw-r--r--libiptc/Makefile.am2
-rw-r--r--libiptc/libiptc.c13
-rw-r--r--libiptc/linux_stddef.h39
-rw-r--r--libxtables/xtables.c72
-rw-r--r--libxtables/xtoptions.c4
-rw-r--r--utils/.gitignore1
-rw-r--r--utils/Makefile.am10
-rw-r--r--utils/nfbpf_compile.c10
-rwxr-xr-xxlate-test.py227
257 files changed, 5775 insertions, 5656 deletions
diff --git a/.gitignore b/.gitignore
index a206fb48..ec4e44ca 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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, &reg);
- 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, &ethproto, 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, &ethproto, 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);
+ 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