diff --git a/Makefile.am b/Makefile.am index 044f6461abf5ad100313225ecaad8495c676fb2a..b1ba015ffe8e626143bc6d05fff70384494596c5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -26,7 +26,7 @@ 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 --exclude=*.t --exclude=iptables-test.py -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.bz2 --owner=root --group=root ${PACKAGE_TARNAME}-${PACKAGE_VERSION}/; rm -Rf /tmp/${PACKAGE_TARNAME}-${PACKAGE_VERSION}; config.status: extensions/GNUmakefile.in \ diff --git a/Makefile.in b/Makefile.in index 47391e086d79876a98b59069a170ccc3bf688835..1d8a0e1ec85d85e03acda2c22204fb24aea01dba 100644 --- a/Makefile.in +++ b/Makefile.in @@ -926,7 +926,7 @@ 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 --exclude=*.t --exclude=iptables-test.py -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.bz2 --owner=root --group=root ${PACKAGE_TARNAME}-${PACKAGE_VERSION}/; rm -Rf /tmp/${PACKAGE_TARNAME}-${PACKAGE_VERSION}; config.status: extensions/GNUmakefile.in \ diff --git a/configure b/configure index 79e4fa679fd28c6e351d7847fdbe30a7cac7b228..da51d51a357c03366051212867cab3f80fb5763d 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for iptables 1.8.2. +# Generated by GNU Autoconf 2.69 for iptables 1.8.3. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. @@ -587,8 +587,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='iptables' PACKAGE_TARNAME='iptables' -PACKAGE_VERSION='1.8.2' -PACKAGE_STRING='iptables 1.8.2' +PACKAGE_VERSION='1.8.3' +PACKAGE_STRING='iptables 1.8.3' PACKAGE_BUGREPORT='' PACKAGE_URL='' @@ -1413,7 +1413,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures iptables 1.8.2 to adapt to many kinds of systems. +\`configure' configures iptables 1.8.3 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1484,7 +1484,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of iptables 1.8.2:";; + short | recursive ) echo "Configuration of iptables 1.8.3:";; esac cat <<\_ACEOF @@ -1641,7 +1641,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -iptables configure 1.8.2 +iptables configure 1.8.3 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2189,7 +2189,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by iptables $as_me 1.8.2, which was +It was created by iptables $as_me 1.8.3, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -3060,7 +3060,7 @@ fi # Define the identity of the package. PACKAGE='iptables' - VERSION='1.8.2' + VERSION='1.8.3' cat >>confdefs.h <<_ACEOF @@ -13114,12 +13114,12 @@ if test -n "$libnftnl_CFLAGS"; then pkg_cv_libnftnl_CFLAGS="$libnftnl_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libnftnl >= 1.1.1\""; } >&5 - ($PKG_CONFIG --exists --print-errors "libnftnl >= 1.1.1") 2>&5 + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libnftnl >= 1.1.3\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libnftnl >= 1.1.3") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then - pkg_cv_libnftnl_CFLAGS=`$PKG_CONFIG --cflags "libnftnl >= 1.1.1" 2>/dev/null` + pkg_cv_libnftnl_CFLAGS=`$PKG_CONFIG --cflags "libnftnl >= 1.1.3" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes @@ -13131,12 +13131,12 @@ if test -n "$libnftnl_LIBS"; then pkg_cv_libnftnl_LIBS="$libnftnl_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libnftnl >= 1.1.1\""; } >&5 - ($PKG_CONFIG --exists --print-errors "libnftnl >= 1.1.1") 2>&5 + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libnftnl >= 1.1.3\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libnftnl >= 1.1.3") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then - pkg_cv_libnftnl_LIBS=`$PKG_CONFIG --libs "libnftnl >= 1.1.1" 2>/dev/null` + pkg_cv_libnftnl_LIBS=`$PKG_CONFIG --libs "libnftnl >= 1.1.3" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes @@ -13157,9 +13157,9 @@ else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then - libnftnl_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libnftnl >= 1.1.1" 2>&1` + libnftnl_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libnftnl >= 1.1.3" 2>&1` else - libnftnl_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libnftnl >= 1.1.1" 2>&1` + libnftnl_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libnftnl >= 1.1.3" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$libnftnl_PKG_ERRORS" >&5 @@ -13562,7 +13562,7 @@ cat >>confdefs.h <<_ACEOF _ACEOF -ac_config_files="$ac_config_files Makefile extensions/GNUmakefile include/Makefile iptables/Makefile iptables/xtables.pc iptables/iptables.8 iptables/iptables-extensions.8.tmpl iptables/iptables-save.8 iptables/iptables-restore.8 iptables/iptables-apply.8 iptables/iptables-xml.1 libipq/Makefile libipq/libipq.pc libiptc/Makefile libiptc/libiptc.pc libiptc/libip4tc.pc libiptc/libip6tc.pc libxtables/Makefile utils/Makefile include/xtables-version.h include/iptables/internal.h iptables/xtables-monitor.8 utils/nfnl_osf.8" +ac_config_files="$ac_config_files Makefile extensions/GNUmakefile include/Makefile iptables/Makefile iptables/xtables.pc iptables/iptables.8 iptables/iptables-extensions.8.tmpl iptables/iptables-save.8 iptables/iptables-restore.8 iptables/iptables-apply.8 iptables/iptables-xml.1 libipq/Makefile libipq/libipq.pc libiptc/Makefile libiptc/libiptc.pc libiptc/libip4tc.pc libiptc/libip6tc.pc libxtables/Makefile utils/Makefile include/xtables-version.h include/iptables/internal.h iptables/xtables-monitor.8 utils/nfnl_osf.8 utils/nfbpf_compile.8" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure @@ -14154,7 +14154,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by iptables $as_me 1.8.2, which was +This file was extended by iptables $as_me 1.8.3, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -14220,7 +14220,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -iptables config.status 1.8.2 +iptables config.status 1.8.3 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" @@ -14658,6 +14658,7 @@ do "include/iptables/internal.h") CONFIG_FILES="$CONFIG_FILES include/iptables/internal.h" ;; "iptables/xtables-monitor.8") CONFIG_FILES="$CONFIG_FILES iptables/xtables-monitor.8" ;; "utils/nfnl_osf.8") CONFIG_FILES="$CONFIG_FILES utils/nfnl_osf.8" ;; + "utils/nfbpf_compile.8") CONFIG_FILES="$CONFIG_FILES utils/nfbpf_compile.8" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac diff --git a/configure.ac b/configure.ac index 448ec918fd89b1e6a0469c9fa8f4d0a2f51ca4a9..b94512d79442de4c9ccd2ffbea24014884a69c1c 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ -AC_INIT([iptables], [1.8.2]) +AC_INIT([iptables], [1.8.3]) # See libtool.info "Libtool's versioning system" libxtables_vcurrent=14 @@ -136,7 +136,7 @@ if test "x$enable_nftables" = "xyes"; then exit 1 fi - PKG_CHECK_MODULES([libnftnl], [libnftnl >= 1.1.1], [nftables=1], [nftables=0]) + PKG_CHECK_MODULES([libnftnl], [libnftnl >= 1.1.3], [nftables=1], [nftables=0]) if test "$nftables" = 0; then @@ -252,7 +252,8 @@ AC_CONFIG_FILES([Makefile extensions/GNUmakefile include/Makefile libxtables/Makefile utils/Makefile include/xtables-version.h include/iptables/internal.h iptables/xtables-monitor.8 - utils/nfnl_osf.8]) + utils/nfnl_osf.8 + utils/nfbpf_compile.8]) AC_OUTPUT diff --git a/extensions/GNUmakefile.in b/extensions/GNUmakefile.in index c0d73cd28c038d05cb0c0bd90234ec99214980a5..0842a55354e4bfc63b83b6fc2bd731dfc317afc7 100644 --- a/extensions/GNUmakefile.in +++ b/extensions/GNUmakefile.in @@ -55,11 +55,12 @@ pfb_objs := $(patsubst %,libebt_%.o,${pfb_build_mod}) pfa_objs := $(patsubst %,libarpt_%.o,${pfa_build_mod}) pf4_objs := $(patsubst %,libipt_%.o,${pf4_build_mod}) pf6_objs := $(patsubst %,libip6t_%.o,${pf6_build_mod}) -pfx_solibs := $(patsubst %,libxt_%.so,${pfx_build_mod} ${pfx_symlinks}) +pfx_solibs := $(patsubst %,libxt_%.so,${pfx_build_mod}) pfb_solibs := $(patsubst %,libebt_%.so,${pfb_build_mod}) pfa_solibs := $(patsubst %,libarpt_%.so,${pfa_build_mod}) pf4_solibs := $(patsubst %,libipt_%.so,${pf4_build_mod}) pf6_solibs := $(patsubst %,libip6t_%.so,${pf6_build_mod}) +pfx_symlink_files := $(patsubst %,libxt_%.so,${pfx_symlinks}) # @@ -72,8 +73,9 @@ targets_install := @ENABLE_STATIC_TRUE@ libext_arpt_objs := ${pfa_objs} @ENABLE_STATIC_TRUE@ libext4_objs := ${pf4_objs} @ENABLE_STATIC_TRUE@ libext6_objs := ${pf6_objs} -@ENABLE_STATIC_FALSE@ targets += ${pfx_solibs} ${pfb_solibs} ${pf4_solibs} ${pf6_solibs} ${pfa_solibs} +@ENABLE_STATIC_FALSE@ targets += ${pfx_solibs} ${pfb_solibs} ${pf4_solibs} ${pf6_solibs} ${pfa_solibs} ${pfx_symlink_files} @ENABLE_STATIC_FALSE@ targets_install += ${pfx_solibs} ${pfb_solibs} ${pf4_solibs} ${pf6_solibs} ${pfa_solibs} +@ENABLE_STATIC_FALSE@ symlinks_install := ${pfx_symlink_files} .SECONDARY: @@ -81,9 +83,14 @@ targets_install := all: ${targets} -install: ${targets_install} +install: ${targets_install} ${symlinks_install} @mkdir -p "${DESTDIR}${xtlibdir}"; - if test -n "${targets_install}"; then install -pm0755 $^ "${DESTDIR}${xtlibdir}/"; fi; + if test -n "${targets_install}"; then \ + install -pm0755 ${targets_install} "${DESTDIR}${xtlibdir}/"; \ + fi; + if test -n "${symlinks_install}"; then \ + cp -P ${symlinks_install} "${DESTDIR}${xtlibdir}/"; \ + fi; clean: rm -f *.o *.oo *.so *.a {matches,targets}.man initext.c initext4.c initext6.c initextb.c initexta.c; diff --git a/extensions/iptables.t b/extensions/iptables.t new file mode 100644 index 0000000000000000000000000000000000000000..b4b6d677abab14af4097225d140c7eb5ec074cf4 --- /dev/null +++ b/extensions/iptables.t @@ -0,0 +1,6 @@ +:FORWARD +-i alongifacename0;=;OK +-i thisinterfaceistoolong0;;FAIL +-i eth+ -o alongifacename+;=;OK +! -i eth0;=;OK +! -o eth+;=;OK diff --git a/extensions/libarpt_CLASSIFY.t b/extensions/libarpt_CLASSIFY.t new file mode 100644 index 0000000000000000000000000000000000000000..0cf0f2ce8e736e61d44f2bb7d46a0f798f326651 --- /dev/null +++ b/extensions/libarpt_CLASSIFY.t @@ -0,0 +1,4 @@ +:OUTPUT +-o lo --destination-mac 11:22:33:44:55:66;-o lo --dst-mac 11:22:33:44:55:66;OK +--dst-mac Broadcast ;--dst-mac ff:ff:ff:ff:ff:ff;OK +! -o eth+ -d 1.2.3.4/24 -j CLASSIFY --set-class 0:0;-j CLASSIFY ! -o eth+ -d 1.2.3.0/24 --set-class 0:0;OK diff --git a/extensions/libarpt_MARK.t b/extensions/libarpt_MARK.t new file mode 100644 index 0000000000000000000000000000000000000000..3b13d44fd2c4bed45869e241d0979fa2d1ce953c --- /dev/null +++ b/extensions/libarpt_MARK.t @@ -0,0 +1,4 @@ +:INPUT,OUTPUT +-j MARK -d 0.0.0.0/8 --set-mark 1;=;OK +-s ! 0.0.0.0 -j MARK --and-mark 0x17;-j MARK ! -s 0.0.0.0 --and-mark 17;OK +-j MARK -s 0.0.0.0 --or-mark 17;=;OK diff --git a/extensions/libarpt_mangle.t b/extensions/libarpt_mangle.t new file mode 100644 index 0000000000000000000000000000000000000000..da9669489d291395ac8191169791809c9835520d --- /dev/null +++ b/extensions/libarpt_mangle.t @@ -0,0 +1,5 @@ +:OUTPUT +-j mangle -s 1.2.3.4 --mangle-ip-s 1.2.3.5;=;OK +-j mangle -d 1.2.3.4 --mangle-ip-d 1.2.3.5;=;OK +-j mangle -d 1.2.3.4 --mangle-mac-d 00:01:02:03:04:05;=;OK +-d 1.2.3.4 --h-length 5 -j mangle --mangle-mac-s 00:01:02:03:04:05;=;FAIL diff --git a/extensions/libarpt_standard.t b/extensions/libarpt_standard.t new file mode 100644 index 0000000000000000000000000000000000000000..e84a00b780488df06ee2143ec9c2420cf35ffe73 --- /dev/null +++ b/extensions/libarpt_standard.t @@ -0,0 +1,14 @@ +:INPUT +-s 192.168.0.1;=;OK +-s 0.0.0.0/8;=;OK +-s ! 0.0.0.0;! -s 0.0.0.0;OK +-d 192.168.0.1;=;OK +! -d 0.0.0.0;=;OK +-d 0.0.0.0/24;=;OK +-j DROP -i lo;=;OK +-j ACCEPT ! -i lo;=;OK +-i ppp+;=;OK +! -i ppp+;=;OK +-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 diff --git a/extensions/libebt_802_3.c b/extensions/libebt_802_3.c index 9e91d0526259100868c37960c69b35c63b89b09d..f05d02ead5a4a6d8046e8719af28ce11924fdbe3 100644 --- a/extensions/libebt_802_3.c +++ b/extensions/libebt_802_3.c @@ -98,15 +98,15 @@ static void br802_3_print(const void *ip, const struct xt_entry_match *match, struct ebt_802_3_info *info = (struct ebt_802_3_info *)match->data; if (info->bitmask & EBT_802_3_SAP) { + printf("--802_3-sap "); if (info->invflags & EBT_802_3_SAP) printf("! "); - printf("--802_3-sap "); printf("0x%.2x ", info->sap); } if (info->bitmask & EBT_802_3_TYPE) { + printf("--802_3-type "); if (info->invflags & EBT_802_3_TYPE) printf("! "); - printf("--802_3-type "); printf("0x%.4x ", ntohs(info->type)); } } diff --git a/extensions/libebt_802_3.t b/extensions/libebt_802_3.t new file mode 100644 index 0000000000000000000000000000000000000000..ddfb2f0a72baf46ca9f35c9042059cc6a32b9858 --- /dev/null +++ b/extensions/libebt_802_3.t @@ -0,0 +1,3 @@ +:INPUT,FORWARD,OUTPUT +--802_3-sap ! 0x0a -j CONTINUE;=;OK +--802_3-type 0x000a -j RETURN;=;OK diff --git a/extensions/libebt_arp.c b/extensions/libebt_arp.c index c1b0ab1db0cf151b66806de8b1f7c5c6727a088e..a062b7e7e586440fce9b995b5f9e84a4ed1598fc 100644 --- a/extensions/libebt_arp.c +++ b/extensions/libebt_arp.c @@ -338,51 +338,51 @@ static void brarp_print(const void *ip, const struct xt_entry_match *match, int if (arpinfo->bitmask & EBT_ARP_OPCODE) { int opcode = ntohs(arpinfo->opcode); + printf("--arp-op "); if (arpinfo->invflags & EBT_ARP_OPCODE) printf("! "); - printf("--arp-op "); if (opcode > 0 && opcode <= ARRAY_SIZE(opcodes)) printf("%s ", opcodes[opcode - 1]); else printf("%d ", opcode); } if (arpinfo->bitmask & EBT_ARP_HTYPE) { + printf("--arp-htype "); if (arpinfo->invflags & EBT_ARP_HTYPE) printf("! "); - printf("--arp-htype "); printf("%d ", ntohs(arpinfo->htype)); } if (arpinfo->bitmask & EBT_ARP_PTYPE) { + printf("--arp-ptype "); if (arpinfo->invflags & EBT_ARP_PTYPE) printf("! "); - printf("--arp-ptype "); printf("0x%x ", ntohs(arpinfo->ptype)); } if (arpinfo->bitmask & EBT_ARP_SRC_IP) { + printf("--arp-ip-src "); if (arpinfo->invflags & EBT_ARP_SRC_IP) printf("! "); - printf("--arp-ip-src "); printf("%s%s ", xtables_ipaddr_to_numeric((const struct in_addr*) &arpinfo->saddr), xtables_ipmask_to_numeric((const struct in_addr*)&arpinfo->smsk)); } if (arpinfo->bitmask & EBT_ARP_DST_IP) { + printf("--arp-ip-dst "); if (arpinfo->invflags & EBT_ARP_DST_IP) printf("! "); - printf("--arp-ip-dst "); printf("%s%s ", xtables_ipaddr_to_numeric((const struct in_addr*) &arpinfo->daddr), xtables_ipmask_to_numeric((const struct in_addr*)&arpinfo->dmsk)); } if (arpinfo->bitmask & EBT_ARP_SRC_MAC) { + printf("--arp-mac-src "); if (arpinfo->invflags & EBT_ARP_SRC_MAC) printf("! "); - printf("--arp-mac-src "); xtables_print_mac_and_mask(arpinfo->smaddr, arpinfo->smmsk); printf(" "); } if (arpinfo->bitmask & EBT_ARP_DST_MAC) { + printf("--arp-mac-dst "); if (arpinfo->invflags & EBT_ARP_DST_MAC) printf("! "); - printf("--arp-mac-dst "); xtables_print_mac_and_mask(arpinfo->dmaddr, arpinfo->dmmsk); printf(" "); } diff --git a/extensions/libebt_arp.t b/extensions/libebt_arp.t new file mode 100644 index 0000000000000000000000000000000000000000..14ff0f097cfd8cc68171966cb3c4b1996c0701d4 --- /dev/null +++ b/extensions/libebt_arp.t @@ -0,0 +1,12 @@ +:INPUT,FORWARD,OUTPUT +-p ARP --arp-op Request;=;OK +-p ARP --arp-htype ! 1;=;OK +-p ARP --arp-ptype 0x2;=;OK +-p ARP --arp-ip-src 1.2.3.4;=;OK +-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-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 +--arp-htype 1;=;FAIL diff --git a/extensions/libebt_arpreply.t b/extensions/libebt_arpreply.t new file mode 100644 index 0000000000000000000000000000000000000000..6734501a106b58ce16f04013eeec244a375ac4bd --- /dev/null +++ b/extensions/libebt_arpreply.t @@ -0,0 +1,4 @@ +:PREROUTING +*nat +-p ARP -i foo -j arpreply --arpreply-mac de:ad:00:be:ee:ff --arpreply-target ACCEPT;=;OK +-p ARP -i foo -j arpreply --arpreply-mac de:ad:00:be:ee:ff;=;OK diff --git a/extensions/libebt_dnat.t b/extensions/libebt_dnat.t new file mode 100644 index 0000000000000000000000000000000000000000..9428d237850fb356e60908f0cf7ec5b511ec932a --- /dev/null +++ b/extensions/libebt_dnat.t @@ -0,0 +1,5 @@ +:PREROUTING +*nat +-i someport -j dnat --to-dst de:ad:0:be:ee:ff;-i someport -j dnat --to-dst de:ad:00:be:ee:ff --dnat-target ACCEPT;OK +-j dnat --to-dst de:ad:00:be:ee:ff --dnat-target ACCEPT;=;OK +-j dnat --to-dst de:ad:00:be:ee:ff --dnat-target CONTINUE;=;OK diff --git a/extensions/libebt_ip.c b/extensions/libebt_ip.c index d48704fe1c8026fdeb9eda2c6b40fd1deb3c39cd..acb9bfcdbbd9fb56e5dd1e527bcb217fd4cf3ffc 100644 --- a/extensions/libebt_ip.c +++ b/extensions/libebt_ip.c @@ -472,35 +472,35 @@ static void brip_print(const void *ip, const struct xt_entry_match *match, struct in_addr *addrp, *maskp; if (info->bitmask & EBT_IP_SOURCE) { + printf("--ip-src "); if (info->invflags & EBT_IP_SOURCE) printf("! "); - printf("--ip-src "); addrp = (struct in_addr *)&info->saddr; maskp = (struct in_addr *)&info->smsk; printf("%s%s ", xtables_ipaddr_to_numeric(addrp), xtables_ipmask_to_numeric(maskp)); } if (info->bitmask & EBT_IP_DEST) { + printf("--ip-dst "); if (info->invflags & EBT_IP_DEST) printf("! "); - printf("--ip-dst "); addrp = (struct in_addr *)&info->daddr; maskp = (struct in_addr *)&info->dmsk; printf("%s%s ", xtables_ipaddr_to_numeric(addrp), xtables_ipmask_to_numeric(maskp)); } if (info->bitmask & EBT_IP_TOS) { + printf("--ip-tos "); if (info->invflags & EBT_IP_TOS) printf("! "); - printf("--ip-tos "); printf("0x%02X ", info->tos); } if (info->bitmask & EBT_IP_PROTO) { struct protoent *pe; + printf("--ip-proto "); if (info->invflags & EBT_IP_PROTO) printf("! "); - printf("--ip-proto "); pe = getprotobynumber(info->protocol); if (pe == NULL) { printf("%d ", info->protocol); @@ -509,28 +509,28 @@ static void brip_print(const void *ip, const struct xt_entry_match *match, } } if (info->bitmask & EBT_IP_SPORT) { + printf("--ip-sport "); if (info->invflags & EBT_IP_SPORT) printf("! "); - printf("--ip-sport "); print_port_range(info->sport); } if (info->bitmask & EBT_IP_DPORT) { + printf("--ip-dport "); if (info->invflags & EBT_IP_DPORT) printf("! "); - printf("--ip-dport "); print_port_range(info->dport); } if (info->bitmask & EBT_IP_ICMP) { + printf("--ip-icmp-type "); if (info->invflags & EBT_IP_ICMP) printf("! "); - printf("--ip-icmp-type "); ebt_print_icmp_type(icmp_codes, ARRAY_SIZE(icmp_codes), info->icmp_type, info->icmp_code); } if (info->bitmask & EBT_IP_IGMP) { + printf("--ip-igmp-type "); if (info->invflags & EBT_IP_IGMP) printf("! "); - printf("--ip-igmp-type "); ebt_print_icmp_type(igmp_types, ARRAY_SIZE(igmp_types), info->igmp_type, NULL); } diff --git a/extensions/libebt_ip.t b/extensions/libebt_ip.t new file mode 100644 index 0000000000000000000000000000000000000000..8be5dfbb22309f61bb5a77ecc4fb2e4bc854dbfd --- /dev/null +++ b/extensions/libebt_ip.t @@ -0,0 +1,13 @@ +:INPUT,FORWARD,OUTPUT +-p ip --ip-src ! 192.168.0.0/24 -j ACCEPT;-p IPv4 --ip-src ! 192.168.0.0/24 -j ACCEPT;OK +-p IPv4 --ip-dst 10.0.0.1;=;OK +-p IPv4 --ip-tos 0xFF;=;OK +-p IPv4 --ip-tos ! 0xFF;=;OK +-p IPv4 --ip-proto tcp --ip-dport 22;=;OK +-p IPv4 --ip-proto udp --ip-sport 1024:65535;=;OK +-p IPv4 --ip-proto 253;=;OK +-p IPv4 --ip-proto icmp --ip-icmp-type echo-request;=;OK +-p IPv4 --ip-proto icmp --ip-icmp-type 1/1;=;OK +-p ip --ip-protocol icmp --ip-icmp-type ! 1:10;-p IPv4 --ip-proto icmp --ip-icmp-type ! 1:10/0:255 -j CONTINUE;OK +--ip-proto icmp --ip-icmp-type 1/1;=;FAIL +! -p ip --ip-proto icmp --ip-icmp-type 1/1;=;FAIL diff --git a/extensions/libebt_ip6.c b/extensions/libebt_ip6.c index b727764903ffab6bf7bc663be0a2ab53901568c1..b8a5a5d8c3a923213146c15fee3da1f65e8e0d36 100644 --- a/extensions/libebt_ip6.c +++ b/extensions/libebt_ip6.c @@ -399,31 +399,31 @@ static void brip6_print(const void *ip, const struct xt_entry_match *match, struct ebt_ip6_info *ipinfo = (struct ebt_ip6_info *)match->data; if (ipinfo->bitmask & EBT_IP6_SOURCE) { + printf("--ip6-src "); if (ipinfo->invflags & EBT_IP6_SOURCE) printf("! "); - printf("--ip6-src "); printf("%s", xtables_ip6addr_to_numeric(&ipinfo->saddr)); printf("%s ", xtables_ip6mask_to_numeric(&ipinfo->smsk)); } if (ipinfo->bitmask & EBT_IP6_DEST) { + printf("--ip6-dst "); if (ipinfo->invflags & EBT_IP6_DEST) printf("! "); - printf("--ip6-dst "); printf("%s", xtables_ip6addr_to_numeric(&ipinfo->daddr)); printf("%s ", xtables_ip6mask_to_numeric(&ipinfo->dmsk)); } if (ipinfo->bitmask & EBT_IP6_TCLASS) { + printf("--ip6-tclass "); if (ipinfo->invflags & EBT_IP6_TCLASS) printf("! "); - printf("--ip6-tclass "); printf("0x%02X ", ipinfo->tclass); } if (ipinfo->bitmask & EBT_IP6_PROTO) { struct protoent *pe; + printf("--ip6-proto "); if (ipinfo->invflags & EBT_IP6_PROTO) printf("! "); - printf("--ip6-proto "); pe = getprotobynumber(ipinfo->protocol); if (pe == NULL) { printf("%d ", ipinfo->protocol); @@ -432,21 +432,21 @@ static void brip6_print(const void *ip, const struct xt_entry_match *match, } } if (ipinfo->bitmask & EBT_IP6_SPORT) { + printf("--ip6-sport "); if (ipinfo->invflags & EBT_IP6_SPORT) printf("! "); - printf("--ip6-sport "); print_port_range(ipinfo->sport); } if (ipinfo->bitmask & EBT_IP6_DPORT) { + printf("--ip6-dport "); if (ipinfo->invflags & EBT_IP6_DPORT) printf("! "); - printf("--ip6-dport "); print_port_range(ipinfo->dport); } if (ipinfo->bitmask & EBT_IP6_ICMP6) { + printf("--ip6-icmp-type "); if (ipinfo->invflags & EBT_IP6_ICMP6) printf("! "); - printf("--ip6-icmp-type "); print_icmp_type(ipinfo->icmpv6_type, ipinfo->icmpv6_code); } } diff --git a/extensions/libebt_ip6.t b/extensions/libebt_ip6.t new file mode 100644 index 0000000000000000000000000000000000000000..fa1038af256494227aadc98655e338ce99c1315e --- /dev/null +++ b/extensions/libebt_ip6.t @@ -0,0 +1,15 @@ +:INPUT,FORWARD,OUTPUT +-p ip6 --ip6-src ! dead::beef/64 -j ACCEPT;-p IPv6 --ip6-src ! dead::/64 -j ACCEPT;OK +-p IPv6 --ip6-dst dead:beef::/64 -j ACCEPT;=;OK +-p IPv6 --ip6-dst f00:ba::;=;OK +-p IPv6 --ip6-tclass 0xFF;=;OK +-p IPv6 --ip6-proto tcp --ip6-dport 22;=;OK +-p IPv6 --ip6-proto tcp --ip6-dport ! 22;=;OK +-p IPv6 --ip6-proto udp --ip6-sport 1024:65535;=;OK +-p IPv6 --ip6-proto 253;=;OK +-p IPv6 --ip6-proto ipv6-icmp --ip6-icmp-type echo-request -j CONTINUE;=;OK +-p IPv6 --ip6-proto ipv6-icmp --ip6-icmp-type echo-request;=;OK +-p ip6 --ip6-protocol icmpv6 --ip6-icmp-type 1/1;-p IPv6 --ip6-proto ipv6-icmp --ip6-icmp-type communication-prohibited -j CONTINUE;OK +-p IPv6 --ip6-proto ipv6-icmp --ip6-icmp-type ! 1:10/0:255;=;OK +--ip6-proto ipv6-icmp ! --ip6-icmp-type 1:10/0:255;=;FAIL +! -p IPv6 --ip6-proto ipv6-icmp ! --ip6-icmp-type 1:10/0:255;=;FAIL diff --git a/extensions/libebt_log.t b/extensions/libebt_log.t new file mode 100644 index 0000000000000000000000000000000000000000..a0df6169112a05352895b550dc0ae6f272f814de --- /dev/null +++ b/extensions/libebt_log.t @@ -0,0 +1,6 @@ +:INPUT,FORWARD,OUTPUT +--log;=;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 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_mark.t b/extensions/libebt_mark.t new file mode 100644 index 0000000000000000000000000000000000000000..2d8f9d7a972ad4a7f4b21724c63fe856bbce7f70 --- /dev/null +++ b/extensions/libebt_mark.t @@ -0,0 +1,5 @@ +:INPUT,FORWARD,OUTPUT +-j mark --mark-set 1;-j mark --mark-set 0x1 --mark-target ACCEPT;OK +-j mark --mark-or 0xa --mark-target CONTINUE;=;OK +-j mark --mark-and 0x1 --mark-target RETURN;=;OK +-j mark --mark-xor 0x1 --mark-target CONTINUE;=;OK diff --git a/extensions/libebt_mark_m.c b/extensions/libebt_mark_m.c index 64ad926f19959a3b1cc6d3f396332acdeee47e82..2462d0af7d0bc4adae7fbd9220d0e7c2211b8e2c 100644 --- a/extensions/libebt_mark_m.c +++ b/extensions/libebt_mark_m.c @@ -86,9 +86,9 @@ static void brmark_m_print(const void *ip, const struct xt_entry_match *match, { struct ebt_mark_m_info *info = (struct ebt_mark_m_info *)match->data; + printf("--mark "); if (info->invert) printf("! "); - printf("--mark "); if (info->bitmask == EBT_MARK_OR) printf("/0x%lx ", info->mask); else if (info->mask != 0xffffffff) diff --git a/extensions/libebt_mark_m.t b/extensions/libebt_mark_m.t new file mode 100644 index 0000000000000000000000000000000000000000..00035427f8b6ed8f941fc9d5f9f08dae5fc20c1c --- /dev/null +++ b/extensions/libebt_mark_m.t @@ -0,0 +1,6 @@ +:INPUT,FORWARD,OUTPUT +--mark 42;--mark 0x2a;OK +--mark ! 42;--mark ! 0x2a;OK +--mark 42/0xff;--mark 0x2a/0xff;OK +--mark ! 0x1/0xff;=;OK +--mark /0x2;=;OK diff --git a/extensions/libebt_nflog.t b/extensions/libebt_nflog.t new file mode 100644 index 0000000000000000000000000000000000000000..f867df303fa955a76c51decda57586adf209e654 --- /dev/null +++ b/extensions/libebt_nflog.t @@ -0,0 +1,5 @@ +:INPUT,FORWARD,OUTPUT +--nflog;=;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_pkttype.c b/extensions/libebt_pkttype.c index 265674d19bde67cc3168be3e160e9d6b57121401..4e2d19de7983b3bfb43d074dd80f5933ea166dcc 100644 --- a/extensions/libebt_pkttype.c +++ b/extensions/libebt_pkttype.c @@ -75,10 +75,7 @@ static void brpkttype_print(const void *ip, const struct xt_entry_match *match, { struct ebt_pkttype_info *pt = (struct ebt_pkttype_info *)match->data; - if (pt->invert) - printf("! "); - - printf("--pkttype-type "); + printf("--pkttype-type %s", pt->invert ? "! " : ""); if (pt->pkt_type < ARRAY_SIZE(classes)) printf("%s ", classes[pt->pkt_type]); diff --git a/extensions/libebt_pkttype.t b/extensions/libebt_pkttype.t new file mode 100644 index 0000000000000000000000000000000000000000..e3b95ded4903ec195d25cbd0ad32e76492f0eb25 --- /dev/null +++ b/extensions/libebt_pkttype.t @@ -0,0 +1,14 @@ +:INPUT,FORWARD,OUTPUT +! --pkttype-type host;--pkttype-type ! host -j CONTINUE;OK +--pkttype-type host;=;OK +--pkttype-type ! host;=;OK +--pkttype-type broadcast;=;OK +--pkttype-type ! broadcast;=;OK +--pkttype-type multicast;=;OK +--pkttype-type ! multicast;=;OK +--pkttype-type otherhost;=;OK +--pkttype-type ! otherhost;=;OK +--pkttype-type outgoing;=;OK +--pkttype-type ! outgoing;=;OK +--pkttype-type loopback;=;OK +--pkttype-type ! loopback;=;OK diff --git a/extensions/libebt_redirect.t b/extensions/libebt_redirect.t new file mode 100644 index 0000000000000000000000000000000000000000..23858afa3b58837c55e017866ef06a73125cfbe7 --- /dev/null +++ b/extensions/libebt_redirect.t @@ -0,0 +1,4 @@ +:PREROUTING +*nat +-j redirect;=;OK +-j redirect --redirect-target RETURN;=;OK diff --git a/extensions/libebt_snat.t b/extensions/libebt_snat.t new file mode 100644 index 0000000000000000000000000000000000000000..639b13f300c9dcddce68da26e1b6bcabe1cb2917 --- /dev/null +++ b/extensions/libebt_snat.t @@ -0,0 +1,4 @@ +:POSTROUTING +*nat +-o someport -j snat --to-source a:b:c:d:e:f;-o someport -j snat --to-src 0a:0b:0c:0d:0e:0f --snat-target ACCEPT;OK +-o someport+ -j snat --to-src de:ad:00:be:ee:ff --snat-target CONTINUE;=;OK diff --git a/extensions/libebt_standard.t b/extensions/libebt_standard.t new file mode 100644 index 0000000000000000000000000000000000000000..0d678fb23c439a1a9bb9cd6c07189b0d3c36c0cd --- /dev/null +++ b/extensions/libebt_standard.t @@ -0,0 +1,11 @@ +:INPUT,FORWARD,OUTPUT +-d de:ad:be:ef:00:00;=;OK +-s 0:0:0:0:0:0;-s 00:00:00:00:00:00;OK +-d 00:00:00:00:00:00;=;OK +-s de:ad:be:ef:0:00 -j RETURN;-s de:ad:be:ef:00:00 -j RETURN;OK +-d de:ad:be:ef:00:00 -j CONTINUE;=;OK +-d de:ad:be:ef:0:00/ff:ff:ff:ff:0:0 -j DROP;-d de:ad:be:ef:00:00/ff:ff:ff:ff:00:00 -j DROP;OK +-p ARP -j ACCEPT;=;OK +-p ! ARP -j ACCEPT;=;OK +-p 0 -j ACCEPT;=;FAIL +-p ! 0 -j ACCEPT;=;FAIL diff --git a/extensions/libebt_stp.c b/extensions/libebt_stp.c index 33e4c8d9c615dcf6cf1cbd92f0ffc4b5b9809bd1..06cf93b8d84498de77fc3549145e0f9d2fce3bb3 100644 --- a/extensions/libebt_stp.c +++ b/extensions/libebt_stp.c @@ -307,9 +307,8 @@ static void brstp_print(const void *ip, const struct xt_entry_match *match, for (i = 0; i < STP_NUMOPS; i++) { if (!(stpinfo->bitmask & (1 << i))) continue; - if (stpinfo->invflags & (1 << i)) - printf("! "); - printf("--%s ", brstp_opts[i].name); + printf("--%s %s", brstp_opts[i].name, + (stpinfo->invflags & (1 << i)) ? "! " : ""); if (EBT_STP_TYPE == (1 << i)) { if (stpinfo->type == BPDU_TYPE_CONFIG) printf("%s", BPDU_TYPE_CONFIG_STRING); diff --git a/extensions/libebt_stp.t b/extensions/libebt_stp.t new file mode 100644 index 0000000000000000000000000000000000000000..0c6b77b91454bf42c056b6485fa7cab8d26cb9ed --- /dev/null +++ b/extensions/libebt_stp.t @@ -0,0 +1,13 @@ +: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-addr 0d:ea:d0:0b:ee:f0;=;OK +--stp-root-cost 1;=;OK +--stp-sender-prio 1;=;OK +--stp-sender-addr de:ad:be:ef:00:00;=;OK +--stp-port 1;=;OK +--stp-msg-age 1;=;OK +--stp-max-age 1;=;OK +--stp-hello-time 1;=;OK +--stp-forward-delay 1;=;OK diff --git a/extensions/libebt_vlan.c b/extensions/libebt_vlan.c index 4a2eb7126895eb63e12fe22e268f6b9eb1a8a20e..fa697921068dc150712da8274460e218cc153ff5 100644 --- a/extensions/libebt_vlan.c +++ b/extensions/libebt_vlan.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include "iptables/nft.h" @@ -108,19 +109,14 @@ static void brvlan_print(const void *ip, const struct xt_entry_match *match, struct ebt_vlan_info *vlaninfo = (struct ebt_vlan_info *) match->data; if (vlaninfo->bitmask & EBT_VLAN_ID) { - if (vlaninfo->invflags & EBT_VLAN_ID) - printf("! "); - printf("--vlan-id %d ", vlaninfo->id); + printf("--vlan-id %s%d ", (vlaninfo->invflags & EBT_VLAN_ID) ? "! " : "", vlaninfo->id); } if (vlaninfo->bitmask & EBT_VLAN_PRIO) { - if (vlaninfo->invflags & EBT_VLAN_PRIO) - printf("! "); - printf("--vlan-prio %d ", vlaninfo->prio); + printf("--vlan-prio %s%d ", (vlaninfo->invflags & EBT_VLAN_PRIO) ? "! " : "", vlaninfo->prio); } if (vlaninfo->bitmask & EBT_VLAN_ENCAP) { - if (vlaninfo->invflags & EBT_VLAN_ENCAP) - printf("! "); - printf("--vlan-encap %4.4X ", ntohs(vlaninfo->encap)); + printf("--vlan-encap %s", (vlaninfo->invflags & EBT_VLAN_ENCAP) ? "! " : ""); + printf("%4.4X ", ntohs(vlaninfo->encap)); } } diff --git a/extensions/libebt_vlan.t b/extensions/libebt_vlan.t new file mode 100644 index 0000000000000000000000000000000000000000..81c795854fca077d868f3fa6a160ab1e4728a8a1 --- /dev/null +++ b/extensions/libebt_vlan.t @@ -0,0 +1,13 @@ +:INPUT,FORWARD,OUTPUT +-p 802_1Q --vlan-id 42;=;OK +-p 802_1Q --vlan-id ! 42;=;OK +-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 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 +--vlan-id 2;=;FAIL +--vlan-prio 1;=;FAIL diff --git a/extensions/libip6t_DNAT.t b/extensions/libip6t_DNAT.t new file mode 100644 index 0000000000000000000000000000000000000000..ec7d61f418cfe74736d593b268b7de6b6c4c5e33 --- /dev/null +++ b/extensions/libip6t_DNAT.t @@ -0,0 +1,16 @@ +:PREROUTING +*nat +-j DNAT --to-destination dead::beef;=;OK +-j DNAT --to-destination dead::beef-dead::fee7;=;OK +-j DNAT --to-destination [dead::beef]:1025-65535;;FAIL +-j DNAT --to-destination [dead::beef] --to-destination [dead::fee7];;FAIL +-p tcp -j DNAT --to-destination [dead::beef]:1025-65535;=;OK +-p tcp -j DNAT --to-destination [dead::beef-dead::fee7]:1025-65535;=;OK +-p tcp -j DNAT --to-destination [dead::beef-dead::fee7]:1025-65536;;FAIL +-p tcp -j DNAT --to-destination [dead::beef-dead::fee7]:1025-65535 --to-destination [dead::beef-dead::fee8]:1025-65535;;FAIL +-p tcp -j DNAT --to-destination [dead::beef-dead::fee7]:1000-2000/1000;=;OK +-p tcp -j DNAT --to-destination [dead::beef-dead::fee7]:1000-2000/3000;=;OK +-p tcp -j DNAT --to-destination [dead::beef-dead::fee7]:1000-2000/65535;=;OK +-p tcp -j DNAT --to-destination [dead::beef-dead::fee7]:1000-2000/0;;FAIL +-p tcp -j DNAT --to-destination [dead::beef-dead::fee7]:1000-2000/65536;;FAIL +-j DNAT;;FAIL diff --git a/extensions/libip6t_DNPT.t b/extensions/libip6t_DNPT.t new file mode 100644 index 0000000000000000000000000000000000000000..0406dc90d2c6e34841a93072fc36c883de0e6ec4 --- /dev/null +++ b/extensions/libip6t_DNPT.t @@ -0,0 +1,7 @@ +:PREROUTING +*mangle +-j DNPT --src-pfx dead::/64 --dst-pfx 1c3::/64;=;OK +-j DNPT --src-pfx dead::beef --dst-pfx 1c3::/64;;FAIL +-j DNPT --src-pfx dead::/64;;FAIL +-j DNPT --dst-pfx dead::/64;;FAIL +-j DNPT;;FAIL diff --git a/extensions/libip6t_HL.t b/extensions/libip6t_HL.t new file mode 100644 index 0000000000000000000000000000000000000000..4e529f883b2c5d97850f1c55fa6daf560df8c231 --- /dev/null +++ b/extensions/libip6t_HL.t @@ -0,0 +1,10 @@ +:PREROUTING,INPUT,FORWARD,OUTPUT,POSTROUTING +*mangle +-j HL --hl-set 42;=;OK +-j HL --hl-inc 1;=;OK +-j HL --hl-dec 1;=;OK +-j HL --hl-set 256;;FAIL +-j HL --hl-inc 0;;FAIL +-j HL --hl-dec 0;;FAIL +-j HL --hl-dec 1 --hl-inc 1;;FAIL +-j HL --hl-set --hl-inc 1;;FAIL diff --git a/extensions/libip6t_LOG.t b/extensions/libip6t_LOG.t new file mode 100644 index 0000000000000000000000000000000000000000..fbf5118b2382a34fcebb3eac7902777cdd25e0b9 --- /dev/null +++ b/extensions/libip6t_LOG.t @@ -0,0 +1,12 @@ +:INPUT,FORWARD,OUTPUT +-j LOG;-j LOG;OK +-j LOG --log-prefix "test: ";=;OK +-j LOG --log-prefix "test: " --log-level 1;=;OK +# iptables displays the log-level output using the number; not the string +-j LOG --log-prefix "test: " --log-level alert;-j LOG --log-prefix "test: " --log-level 1;OK +-j LOG --log-prefix "test: " --log-tcp-sequence;=;OK +-j LOG --log-prefix "test: " --log-tcp-options;=;OK +-j LOG --log-prefix "test: " --log-ip-options;=;OK +-j LOG --log-prefix "test: " --log-uid;=;OK +-j LOG --log-prefix "test: " --log-level bad;;FAIL +-j LOG --log-prefix;;FAIL diff --git a/extensions/libip6t_MASQUERADE.t b/extensions/libip6t_MASQUERADE.t new file mode 100644 index 0000000000000000000000000000000000000000..e25d2a04ab7b06b25eab3d34e7e73854c42ab4de --- /dev/null +++ b/extensions/libip6t_MASQUERADE.t @@ -0,0 +1,9 @@ +:POSTROUTING +*nat +-j MASQUERADE;=;OK +-j MASQUERADE --random;=;OK +-j MASQUERADE --random-fully;=;OK +-p tcp -j MASQUERADE --to-ports 1024;=;OK +-p udp -j MASQUERADE --to-ports 1024-65535;=;OK +-p udp -j MASQUERADE --to-ports 1024-65536;;FAIL +-p udp -j MASQUERADE --to-ports -1;;FAIL diff --git a/extensions/libip6t_NETMAP.t b/extensions/libip6t_NETMAP.t new file mode 100644 index 0000000000000000000000000000000000000000..043562d2612433b04fb7ca1b72f92cd74b56912f --- /dev/null +++ b/extensions/libip6t_NETMAP.t @@ -0,0 +1,4 @@ +:PREROUTING,INPUT,OUTPUT,POSTROUTING +*nat +-j NETMAP --to dead::/64;=;OK +-j NETMAP --to dead::beef;=;OK diff --git a/extensions/libip6t_REDIRECT.t b/extensions/libip6t_REDIRECT.t new file mode 100644 index 0000000000000000000000000000000000000000..a0fb0ed19a5ea89f2cead940d4e469612417f015 --- /dev/null +++ b/extensions/libip6t_REDIRECT.t @@ -0,0 +1,6 @@ +:PREROUTING,OUTPUT +*nat +-p tcp -j REDIRECT --to-ports 42;=;OK +-p udp -j REDIRECT --to-ports 42-1234;=;OK +-p tcp -j REDIRECT --to-ports 42-1234 --random;=;OK +-j REDIRECT --to-ports 42;;FAIL diff --git a/extensions/libip6t_REJECT.t b/extensions/libip6t_REJECT.t new file mode 100644 index 0000000000000000000000000000000000000000..d2b337d7ebdeb87ee8f879967e473a27d0a7b165 --- /dev/null +++ b/extensions/libip6t_REJECT.t @@ -0,0 +1,11 @@ +:INPUT,FORWARD,OUTPUT +-j REJECT;=;OK +# manpage for IPv6 variant of REJECT does not show up for some reason? +-j REJECT --reject-with icmp6-no-route;=;OK +-j REJECT --reject-with icmp6-adm-prohibited;=;OK +-j REJECT --reject-with icmp6-addr-unreachable;=;OK +-j REJECT --reject-with icmp6-port-unreachable;=;OK +-j REJECT --reject-with icmp6-policy-fail;=;OK +-j REJECT --reject-with icmp6-reject-route;=;OK +-p tcp -j REJECT --reject-with tcp-reset;=;OK +-j REJECT --reject-with tcp-reset;;FAIL diff --git a/extensions/libip6t_SNAT.t b/extensions/libip6t_SNAT.t new file mode 100644 index 0000000000000000000000000000000000000000..d188a6bb3d559a6e4309c905bbe949bde909de69 --- /dev/null +++ b/extensions/libip6t_SNAT.t @@ -0,0 +1,11 @@ +:POSTROUTING +*nat +-j SNAT --to-source dead::beef;=;OK +-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 +-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 +-p tcp -j SNAT --to-source [dead::beef-dead::fee7]:1025-65535 --to-source [dead::beef-dead::fee8]:1025-65535;;FAIL +-j SNAT;;FAIL diff --git a/extensions/libip6t_SNPT.t b/extensions/libip6t_SNPT.t new file mode 100644 index 0000000000000000000000000000000000000000..7ed6d0c95bb350300a65673ccc297a0a1ba5215a --- /dev/null +++ b/extensions/libip6t_SNPT.t @@ -0,0 +1,7 @@ +:INPUT,POSTROUTING +*mangle +-j SNPT --src-pfx dead::/64 --dst-pfx 1c3::/64;=;OK +-j SNPT --src-pfx dead::beef --dst-pfx 1c3::/64;;FAIL +-j SNPT --src-pfx dead::/64;;FAIL +-j SNPT --dst-pfx dead::/64;;FAIL +-j SNPT;;FAIL diff --git a/extensions/libip6t_ah.t b/extensions/libip6t_ah.t new file mode 100644 index 0000000000000000000000000000000000000000..c1898d44cf1931e9b2b9fdd34b81f454d0305f3d --- /dev/null +++ b/extensions/libip6t_ah.t @@ -0,0 +1,15 @@ +:INPUT,FORWARD,OUTPUT +-m ah --ahspi 0;=;OK +-m ah --ahspi 4294967295;=;OK +-m ah --ahspi 0:4294967295;-m ah;OK +-m ah ! --ahspi 0;=;OK +# ERROR: should fail: iptables -A FORWARD -t mangle -j CLASSIFY --set-class 1:-1 +# -m ah --ahres;=;OK +# ERROR: line 7 (cannot find: ip6tables -I INPUT -m ah --ahlen 32 +# -m ah --ahlen 32;=;OK +-m ah --ahspi -1;;FAIL +-m ah --ahspi 4294967296;;FAIL +-m ah --ahspi invalid;;FAIL +-m ah --ahspi 0:invalid;;FAIL +-m ah --ahspi;;FAIL +-m ah;=;OK diff --git a/extensions/libip6t_dst.t b/extensions/libip6t_dst.t new file mode 100644 index 0000000000000000000000000000000000000000..0b0013b57fc0b35fc052aa6428418304c1cbf632 --- /dev/null +++ b/extensions/libip6t_dst.t @@ -0,0 +1,5 @@ +:INPUT,FORWARD,OUTPUT +-m dst --dst-len 0;=;OK +-m dst --dst-opts 149:92,12:12,123:12;=;OK +-m dst ! --dst-len 42;=;OK +-m dst --dst-len 42 --dst-opts 149:92,12:12,123:12;=;OK diff --git a/extensions/libip6t_eui64.t b/extensions/libip6t_eui64.t new file mode 100644 index 0000000000000000000000000000000000000000..e5aaaacef48bff0a4e129697974f7a58319db4ae --- /dev/null +++ b/extensions/libip6t_eui64.t @@ -0,0 +1,8 @@ +:PREROUTING +*raw +-m eui64;=;OK +:INPUT,FORWARD +*filter +-m eui64;=;OK +:OUTPUT +-m eui64;;FAIL diff --git a/extensions/libip6t_frag.t b/extensions/libip6t_frag.t new file mode 100644 index 0000000000000000000000000000000000000000..299fa03f8845bd66c99ab20e0d6d483cb2f90dc8 --- /dev/null +++ b/extensions/libip6t_frag.t @@ -0,0 +1,13 @@ +:INPUT,FORWARD,OUTPUT +-m frag --fragid 1:42;=;OK +-m frag --fraglen 42;=;OK +-m frag --fragres;=;OK +-m frag --fragfirst;=;OK +-m frag --fragmore;=;OK +-m frag --fraglast;=;OK +-m frag ! --fragid 1 ! --fraglen 42 --fragres --fragfirst;=;OK +-m frag --fragfirst --fragmore;=;OK +-m frag --fragfirst --fraglast;=;OK +-m frag --fraglast --fragmore;;FAIL +-d ff02::fb/128 -p udp -m udp --dport 5353 -m frag --fragmore;=;OK +-d fe80::/64 -p udp --dport 546 -m frag --fraglast;-d fe80::/64 -p udp -m udp --dport 546 -m frag --fraglast;OK diff --git a/extensions/libip6t_hbh.t b/extensions/libip6t_hbh.t new file mode 100644 index 0000000000000000000000000000000000000000..4b58f25a1301ab1b728c3c4ff0557347228b5339 --- /dev/null +++ b/extensions/libip6t_hbh.t @@ -0,0 +1,5 @@ +:INPUT,FORWARD,OUTPUT +-m hbh;=;OK +-m hbh --hbh-len 42;=;OK +-m hbh ! --hbh-len 42;=;OK +-m hbh --hbh-len 42 --hbh-opts 1:2,23:42,4:6,8:10,42,23,4:5;=;OK diff --git a/extensions/libip6t_hl.t b/extensions/libip6t_hl.t new file mode 100644 index 0000000000000000000000000000000000000000..b02816afb827be46740b062606cb30bd0071b26d --- /dev/null +++ b/extensions/libip6t_hl.t @@ -0,0 +1,8 @@ +:INPUT,FORWARD,OUTPUT +-m hl;;FAIL +-m hl --hl-eq 42;=;OK +-m hl ! --hl-eq 42;=;OK +-m hl --hl-lt 42;=;OK +-m hl --hl-gt 42;=;OK +-m hl --hl-gt 42 --hl-eq 42;;FAIL +-m hl --hl-gt;;FAIL diff --git a/extensions/libip6t_icmp6.c b/extensions/libip6t_icmp6.c index 45a71875722c47d24f13f485604453fa8a242696..cc7bfaeb72fd7a355acfcfa311cecf855211e3ec 100644 --- a/extensions/libip6t_icmp6.c +++ b/extensions/libip6t_icmp6.c @@ -230,7 +230,7 @@ static unsigned int type_xlate_print(struct xt_xlate *xl, unsigned int icmptype, type_name = icmp6_type_xlate(icmptype); if (type_name) { - xt_xlate_add(xl, type_name); + xt_xlate_add(xl, "%s", type_name); } else { for (i = 0; i < ARRAY_SIZE(icmpv6_codes); ++i) if (icmpv6_codes[i].type == icmptype && @@ -239,7 +239,7 @@ static unsigned int type_xlate_print(struct xt_xlate *xl, unsigned int icmptype, break; if (i != ARRAY_SIZE(icmpv6_codes)) - xt_xlate_add(xl, icmpv6_codes[i].name); + xt_xlate_add(xl, "%s", icmpv6_codes[i].name); else return 0; } diff --git a/extensions/libip6t_icmp6.t b/extensions/libip6t_icmp6.t new file mode 100644 index 0000000000000000000000000000000000000000..028cfc16ede249bd0a38834ce6dc9b12c43f28d9 --- /dev/null +++ b/extensions/libip6t_icmp6.t @@ -0,0 +1,6 @@ +:INPUT,FORWARD,OUTPUT +-m icmpv6;;FAIL +-p ipv6-icmp -m icmp6 --icmpv6-type 1/0;=;OK +-p ipv6-icmp -m icmp6 --icmpv6-type 2;=;OK +# cannot use option twice: +-p ipv6-icmp -m icmp6 --icmpv6-type no-route --icmpv6-type packet-too-big;;FAIL diff --git a/extensions/libip6t_ipv6header.t b/extensions/libip6t_ipv6header.t new file mode 100644 index 0000000000000000000000000000000000000000..67fa47998ee099d1c2b30dc9ae8d5763b713f2d4 --- /dev/null +++ b/extensions/libip6t_ipv6header.t @@ -0,0 +1,4 @@ +:INPUT,FORWARD,OUTPUT +-m ipv6header --header hop-by-hop;=;OK +-m ipv6header --header hop-by-hop --soft;=;OK +-m ipv6header --header ipv6-nonxt;=;OK diff --git a/extensions/libip6t_mh.t b/extensions/libip6t_mh.t new file mode 100644 index 0000000000000000000000000000000000000000..6b76d13d0a00f72078daddcecf7409ac94afa653 --- /dev/null +++ b/extensions/libip6t_mh.t @@ -0,0 +1,6 @@ +:INPUT,FORWARD,OUTPUT +-m mh;;FAIL +-p mobility-header -m mh;=;OK +-p mobility-header -m mh --mh-type 1;=;OK +-p mobility-header -m mh ! --mh-type 4;=;OK +-p mobility-header -m mh --mh-type 4:123;=;OK diff --git a/extensions/libip6t_mh.txlate b/extensions/libip6t_mh.txlate index ccc07c3d5ecb13fdf8b79b10cf3b97cd9f199989..f5d638c09ca8a92cb5dea0008d954bd8e1df5e82 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 135 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 135 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.t b/extensions/libip6t_rt.t new file mode 100644 index 0000000000000000000000000000000000000000..3c7b2d981324a66cef73cefb2c497dca7ef17307 --- /dev/null +++ b/extensions/libip6t_rt.t @@ -0,0 +1,5 @@ +:INPUT,FORWARD,OUTPUT +-m rt --rt-type 0 --rt-segsleft 1:23 --rt-len 42 --rt-0-res;=;OK +-m rt --rt-type 0 ! --rt-segsleft 1:23 ! --rt-len 42 --rt-0-res;=;OK +-m rt ! --rt-type 1 ! --rt-segsleft 12:23 ! --rt-len 42;=;OK +-m rt;=;OK diff --git a/extensions/libip6t_srh.t b/extensions/libip6t_srh.t new file mode 100644 index 0000000000000000000000000000000000000000..07b540319233e305231a58d7bfb5f75f39e6881e --- /dev/null +++ b/extensions/libip6t_srh.t @@ -0,0 +1,28 @@ +:INPUT,FORWARD,OUTPUT +-m srh --srh-next-hdr 17;=;OK +-m srh --srh-hdr-len-eq 8;=;OK +-m srh --srh-hdr-len-gt 8;=;OK +-m srh --srh-hdr-len-lt 8;=;OK +-m srh --srh-segs-left-eq 1;=;OK +-m srh --srh-segs-left-gt 1;=;OK +-m srh --srh-segs-left-lt 1;=;OK +-m srh --srh-last-entry-eq 4;=;OK +-m srh --srh-last-entry-gt 4;=;OK +-m srh --srh-last-entry-lt 4;=;OK +-m srh --srh-tag 0;=;OK +-m srh ! --srh-next-hdr 17;=;OK +-m srh ! --srh-hdr-len-eq 8;=;OK +-m srh ! --srh-hdr-len-gt 8;=;OK +-m srh ! --srh-hdr-len-lt 8;=;OK +-m srh ! --srh-segs-left-eq 1;=;OK +-m srh ! --srh-segs-left-gt 1;=;OK +-m srh ! --srh-segs-left-lt 1;=;OK +-m srh ! --srh-last-entry-eq 4;=;OK +-m srh ! --srh-last-entry-gt 4;=;OK +-m srh ! --srh-last-entry-lt 4;=;OK +-m srh ! --srh-tag 0;=;OK +-m srh --srh-next-hdr 17 --srh-segs-left-eq 1 --srh-last-entry-eq 4 --srh-tag 0;=;OK +-m srh ! --srh-next-hdr 17 ! --srh-segs-left-eq 0 --srh-tag 0;=;OK +-m srh --srh-psid A::/64 --srh-nsid B:: --srh-lsid C::/0;;OK +-m srh ! --srh-psid A::/64 ! --srh-nsid B:: ! --srh-lsid C::/0;;OK +-m srh;=;OK diff --git a/extensions/libip6t_standard.t b/extensions/libip6t_standard.t new file mode 100644 index 0000000000000000000000000000000000000000..a528af10ea152b71f26f36aef0387286ebb9bff8 --- /dev/null +++ b/extensions/libip6t_standard.t @@ -0,0 +1,5 @@ +:INPUT,FORWARD,OUTPUT +-s ::/128;=;OK +! -d ::;! -d ::/128;OK +! -s ::;! -s ::/128;OK +-s ::/64;=;OK diff --git a/extensions/libipt_CLUSTERIP.t b/extensions/libipt_CLUSTERIP.t new file mode 100644 index 0000000000000000000000000000000000000000..5af555e005c1dc56f715b5bc3e5d8aa4dfcc683c --- /dev/null +++ b/extensions/libipt_CLUSTERIP.t @@ -0,0 +1,4 @@ +:INPUT +-d 10.31.3.236/32 -i lo -j CLUSTERIP --new --hashmode sourceip --clustermac 01:AA:7B:47:F7:D7 --total-nodes 2 --local-node 0 --hash-init 1;=;FAIL +-d 10.31.3.236/32 -i lo -j CLUSTERIP --new --hashmode sourceip --clustermac 01:AA:7B:47:F7:D7 --total-nodes 2 --local-node 1 --hash-init 1;=;OK +-d 10.31.3.236/32 -i lo -j CLUSTERIP --new --hashmode sourceip --clustermac 01:AA:7B:47:F7:D7 --total-nodes 2 --local-node 2 --hash-init 1;=;OK diff --git a/extensions/libipt_DNAT.t b/extensions/libipt_DNAT.t new file mode 100644 index 0000000000000000000000000000000000000000..1c4413b9b3bb5fbbcd9a4385b8ba9d35f2901201 --- /dev/null +++ b/extensions/libipt_DNAT.t @@ -0,0 +1,16 @@ +:PREROUTING +*nat +-j DNAT --to-destination 1.1.1.1;=;OK +-j DNAT --to-destination 1.1.1.1-1.1.1.10;=;OK +-j DNAT --to-destination 1.1.1.1:1025-65535;;FAIL +-j DNAT --to-destination 1.1.1.1 --to-destination 2.2.2.2;;FAIL +-p tcp -j DNAT --to-destination 1.1.1.1:1025-65535;=;OK +-p tcp -j DNAT --to-destination 1.1.1.1-1.1.1.10:1025-65535;=;OK +-p tcp -j DNAT --to-destination 1.1.1.1-1.1.1.10:1025-65536;;FAIL +-p tcp -j DNAT --to-destination 1.1.1.1-1.1.1.10:1025-65535 --to-destination 2.2.2.2-2.2.2.20:1025-65535;;FAIL +-p tcp -j DNAT --to-destination 1.1.1.1:1000-2000/1000;=;OK +-p tcp -j DNAT --to-destination 1.1.1.1:1000-2000/3000;=;OK +-p tcp -j DNAT --to-destination 1.1.1.1:1000-2000/65535;=;OK +-p tcp -j DNAT --to-destination 1.1.1.1:1000-2000/0;;FAIL +-p tcp -j DNAT --to-destination 1.1.1.1:1000-2000/65536;;FAIL +-j DNAT;;FAIL diff --git a/extensions/libipt_ECN.t b/extensions/libipt_ECN.t new file mode 100644 index 0000000000000000000000000000000000000000..2e09205212e7f4761bc5ad3b165952ef7b0bead3 --- /dev/null +++ b/extensions/libipt_ECN.t @@ -0,0 +1,5 @@ +:PREROUTING,FORWARD,OUTPUT,POSTROUTING +*mangle +-j ECN;;FAIL +-p tcp -j ECN;;FAIL +-p tcp -j ECN --ecn-tcp-remove;=;OK diff --git a/extensions/libipt_LOG.t b/extensions/libipt_LOG.t new file mode 100644 index 0000000000000000000000000000000000000000..fbf5118b2382a34fcebb3eac7902777cdd25e0b9 --- /dev/null +++ b/extensions/libipt_LOG.t @@ -0,0 +1,12 @@ +:INPUT,FORWARD,OUTPUT +-j LOG;-j LOG;OK +-j LOG --log-prefix "test: ";=;OK +-j LOG --log-prefix "test: " --log-level 1;=;OK +# iptables displays the log-level output using the number; not the string +-j LOG --log-prefix "test: " --log-level alert;-j LOG --log-prefix "test: " --log-level 1;OK +-j LOG --log-prefix "test: " --log-tcp-sequence;=;OK +-j LOG --log-prefix "test: " --log-tcp-options;=;OK +-j LOG --log-prefix "test: " --log-ip-options;=;OK +-j LOG --log-prefix "test: " --log-uid;=;OK +-j LOG --log-prefix "test: " --log-level bad;;FAIL +-j LOG --log-prefix;;FAIL diff --git a/extensions/libipt_MASQUERADE.t b/extensions/libipt_MASQUERADE.t new file mode 100644 index 0000000000000000000000000000000000000000..e25d2a04ab7b06b25eab3d34e7e73854c42ab4de --- /dev/null +++ b/extensions/libipt_MASQUERADE.t @@ -0,0 +1,9 @@ +:POSTROUTING +*nat +-j MASQUERADE;=;OK +-j MASQUERADE --random;=;OK +-j MASQUERADE --random-fully;=;OK +-p tcp -j MASQUERADE --to-ports 1024;=;OK +-p udp -j MASQUERADE --to-ports 1024-65535;=;OK +-p udp -j MASQUERADE --to-ports 1024-65536;;FAIL +-p udp -j MASQUERADE --to-ports -1;;FAIL diff --git a/extensions/libipt_NETMAP.t b/extensions/libipt_NETMAP.t new file mode 100644 index 0000000000000000000000000000000000000000..31924b985cd6f8c2af7bdc944bfdda1899644595 --- /dev/null +++ b/extensions/libipt_NETMAP.t @@ -0,0 +1,4 @@ +:PREROUTING,INPUT,OUTPUT,POSTROUTING +*nat +-j NETMAP --to 1.2.3.0/24;=;OK +-j NETMAP --to 1.2.3.4;=;OK diff --git a/extensions/libipt_REDIRECT.t b/extensions/libipt_REDIRECT.t new file mode 100644 index 0000000000000000000000000000000000000000..a0fb0ed19a5ea89f2cead940d4e469612417f015 --- /dev/null +++ b/extensions/libipt_REDIRECT.t @@ -0,0 +1,6 @@ +:PREROUTING,OUTPUT +*nat +-p tcp -j REDIRECT --to-ports 42;=;OK +-p udp -j REDIRECT --to-ports 42-1234;=;OK +-p tcp -j REDIRECT --to-ports 42-1234 --random;=;OK +-j REDIRECT --to-ports 42;;FAIL diff --git a/extensions/libipt_REJECT.t b/extensions/libipt_REJECT.t new file mode 100644 index 0000000000000000000000000000000000000000..5b26b1076b5b2a92319e3f88aa3701ab8b926866 --- /dev/null +++ b/extensions/libipt_REJECT.t @@ -0,0 +1,9 @@ +:INPUT,FORWARD,OUTPUT +-j REJECT;=;OK +-j REJECT --reject-with icmp-net-unreachable;=;OK +-j REJECT --reject-with icmp-host-unreachable;=;OK +-j REJECT --reject-with icmp-port-unreachable;=;OK +-j REJECT --reject-with icmp-proto-unreachable;=;OK +-j REJECT --reject-with icmp-net-prohibited;=;OK +-j REJECT --reject-with icmp-host-prohibited;=;OK +-j REJECT --reject-with icmp-admin-prohibited;=;OK diff --git a/extensions/libipt_SNAT.t b/extensions/libipt_SNAT.t new file mode 100644 index 0000000000000000000000000000000000000000..186e1cb82c3f30d4b21e7007aa087bdfce9d4c91 --- /dev/null +++ b/extensions/libipt_SNAT.t @@ -0,0 +1,11 @@ +:POSTROUTING +*nat +-j SNAT --to-source 1.1.1.1;=;OK +-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 +-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 +-p tcp -j SNAT --to-source 1.1.1.1-1.1.1.10:1025-65535 --to-source 2.2.2.2-2.2.2.20:1025-65535;;FAIL +-j SNAT;;FAIL diff --git a/extensions/libipt_TTL.t b/extensions/libipt_TTL.t new file mode 100644 index 0000000000000000000000000000000000000000..36809792a4b9298afe9c4b7aea167259403493b1 --- /dev/null +++ b/extensions/libipt_TTL.t @@ -0,0 +1,10 @@ +:PREROUTING,INPUT,FORWARD,OUTPUT,POSTROUTING +*mangle +-j TTL --ttl-set 42;=;OK +-j TTL --ttl-inc 1;=;OK +-j TTL --ttl-dec 1;=;OK +-j TTL --ttl-set 256;;FAIL +-j TTL --ttl-inc 0;;FAIL +-j TTL --ttl-dec 0;;FAIL +-j TTL --ttl-dec 1 --ttl-inc 1;;FAIL +-j TTL --ttl-set --ttl-inc 1;;FAIL diff --git a/extensions/libipt_ah.t b/extensions/libipt_ah.t new file mode 100644 index 0000000000000000000000000000000000000000..cd853865638e8d58e96344eb962ed3ccc56aa9e8 --- /dev/null +++ b/extensions/libipt_ah.t @@ -0,0 +1,13 @@ +:INPUT,FORWARD,OUTPUT +-p ah -m ah --ahspi 0;=;OK +-p ah -m ah --ahspi 4294967295;=;OK +-p ah -m ah --ahspi 0:4294967295;-p ah -m ah;OK +-p ah -m ah ! --ahspi 0;=;OK +-p ah -m ah --ahspi -1;;FAIL +-p ah -m ah --ahspi 4294967296;;FAIL +-p ah -m ah --ahspi invalid;;FAIL +-p ah -m ah --ahspi 0:invalid;;FAIL +-m ah --ahspi 0;;FAIL +-m ah --ahspi;;FAIL +-m ah;;FAIL +-p ah -m ah;=;OK diff --git a/extensions/libipt_icmp.c b/extensions/libipt_icmp.c index 5418997668d4cc8597e8b0b6cc980cb952a4b40a..e76257c54708c4cff5253f80ff688152c444df48 100644 --- a/extensions/libipt_icmp.c +++ b/extensions/libipt_icmp.c @@ -236,7 +236,7 @@ static unsigned int type_xlate_print(struct xt_xlate *xl, unsigned int icmptype, if (icmp_codes[i].type == icmptype && icmp_codes[i].code_min == code_min && icmp_codes[i].code_max == code_max) { - xt_xlate_add(xl, icmp_codes[i].name); + xt_xlate_add(xl, "%s", icmp_codes[i].name); return 1; } } diff --git a/extensions/libipt_icmp.t b/extensions/libipt_icmp.t new file mode 100644 index 0000000000000000000000000000000000000000..f4ba65c27f032f9a3900646434a9e457fecd955b --- /dev/null +++ b/extensions/libipt_icmp.t @@ -0,0 +1,15 @@ +:INPUT,FORWARD,OUTPUT +-p icmp -m icmp --icmp-type any;=;OK +# output uses the number, better use the name? +# ERROR: cannot find: iptables -I INPUT -p icmp -m icmp --icmp-type echo-reply +# -p icmp -m icmp --icmp-type echo-reply;=;OK +# output uses the number, better use the name? +# ERROR: annot find: iptables -I INPUT -p icmp -m icmp --icmp-type destination-unreachable +# -p icmp -m icmp --icmp-type destination-unreachable;=;OK +# it does not acccept name/name, should we accept this? +# ERROR: cannot load: iptables -A INPUT -p icmp -m icmp --icmp-type destination-unreachable/network-unreachable +# -p icmp -m icmp --icmp-type destination-unreachable/network-unreachable;=;OK +-m icmp;;FAIL +# we accept "iptables -I INPUT -p tcp -m tcp", why not this below? +# ERROR: cannot load: iptables -A INPUT -p icmp -m icmp +# -p icmp -m icmp;=;OK diff --git a/extensions/libipt_realm.man b/extensions/libipt_realm.man index a40b1adc72ba2f06d675861538217b6317eaaedc..72dff9b2e42124633ea8260470b8ac6b9e980e74 100644 --- a/extensions/libipt_realm.man +++ b/extensions/libipt_realm.man @@ -5,3 +5,5 @@ setups involving dynamic routing protocols like BGP. Matches a given realm number (and optionally mask). If not a number, value can be a named realm from /etc/iproute2/rt_realms (mask can not be used in that case). +Both value and mask are four byte unsigned integers and may be specified in +decimal, hex (by prefixing with "0x") or octal (if a leading zero is given). diff --git a/extensions/libipt_realm.t b/extensions/libipt_realm.t new file mode 100644 index 0000000000000000000000000000000000000000..ca66640766983aeb1107d4197974485affd4c9ca --- /dev/null +++ b/extensions/libipt_realm.t @@ -0,0 +1,4 @@ +:INPUT,FORWARD,OUTPUT +-m realm --realm 0x1/0x2a;=;OK +-m realm --realm 0x2a;=;OK +-m realm;;FAIL diff --git a/extensions/libipt_ttl.t b/extensions/libipt_ttl.t new file mode 100644 index 0000000000000000000000000000000000000000..ebe5b3a21a2689b41b8799a438da47f4bb0d24e0 --- /dev/null +++ b/extensions/libipt_ttl.t @@ -0,0 +1,15 @@ +:INPUT,FORWARD,OUTPUT +-m ttl --ttl-eq 0;=;OK +-m ttl --ttl-eq 255;=;OK +-m ttl ! --ttl-eq 0;=;OK +-m ttl ! --ttl-eq 255;=;OK +-m ttl --ttl-gt 0;=;OK +# not possible have anything greater than 255, TTL is 8-bit long +# ERROR: should fail: iptables -A INPUT -m ttl --ttl-gt 255 +## -m ttl --ttl-gt 255;;FAIL +# not possible have anything below 0 +# ERROR: should fail: iptables -A INPUT -m ttl --ttl-lt 0 +## -m ttl --ttl-lt 0;;FAIL +-m ttl --ttl-eq 256;;FAIL +-m ttl --ttl-eq -1;;FAIL +-m ttl;;FAIL diff --git a/extensions/libxt_AUDIT.man b/extensions/libxt_AUDIT.man index cd796967c431abeb23e7050d95eea1f0fa55dd40..4f5562e8ca425cd1c7946d1c319092af3c3fafff 100644 --- a/extensions/libxt_AUDIT.man +++ b/extensions/libxt_AUDIT.man @@ -3,12 +3,14 @@ It can be used to record accepted, dropped, and rejected packets. See auditd(8) for additional details. .TP \fB\-\-type\fP {\fBaccept\fP|\fBdrop\fP|\fBreject\fP} -Set type of audit record. +Set type of audit record. Starting with linux-4.12, this option has no effect +on generated audit messages anymore. It is still accepted by iptables for +compatibility reasons, but ignored. .PP Example: .IP iptables \-N AUDIT_DROP .IP -iptables \-A AUDIT_DROP \-j AUDIT \-\-type drop +iptables \-A AUDIT_DROP \-j AUDIT .IP iptables \-A AUDIT_DROP \-j DROP diff --git a/extensions/libxt_AUDIT.t b/extensions/libxt_AUDIT.t new file mode 100644 index 0000000000000000000000000000000000000000..97575b0eb1ce830b55da513fc879ccc43bd8c46e --- /dev/null +++ b/extensions/libxt_AUDIT.t @@ -0,0 +1,6 @@ +:INPUT,FORWARD,OUTPUT +-j AUDIT --type accept;=;OK +-j AUDIT --type drop;=;OK +-j AUDIT --type reject;=;OK +-j AUDIT;;FAIL +-j AUDIT --type wrong;;FAIL diff --git a/extensions/libxt_CHECKSUM.t b/extensions/libxt_CHECKSUM.t new file mode 100644 index 0000000000000000000000000000000000000000..9451ad86489b2b97752c35019c56f3d3c9ab14e6 --- /dev/null +++ b/extensions/libxt_CHECKSUM.t @@ -0,0 +1,4 @@ +:PREROUTING,FORWARD,POSTROUTING +*mangle +-j CHECKSUM --checksum-fill;=;OK +-j CHECKSUM;;FAIL diff --git a/extensions/libxt_CLASSIFY.c b/extensions/libxt_CLASSIFY.c index f90082dc7c50e396f07db198b5bcb67f94e0265c..75aaf0c41b61a08455acde8e56b72470736deae0 100644 --- a/extensions/libxt_CLASSIFY.c +++ b/extensions/libxt_CLASSIFY.c @@ -73,6 +73,24 @@ CLASSIFY_save(const void *ip, const struct xt_entry_target *target) TC_H_MAJ(clinfo->priority)>>16, TC_H_MIN(clinfo->priority)); } +static void +CLASSIFY_arp_save(const void *ip, const struct xt_entry_target *target) +{ + const struct xt_classify_target_info *clinfo = + (const struct xt_classify_target_info *)target->data; + + printf(" --set-class %x:%x", + TC_H_MAJ(clinfo->priority)>>16, TC_H_MIN(clinfo->priority)); +} + +static void +CLASSIFY_arp_print(const void *ip, + const struct xt_entry_target *target, + int numeric) +{ + CLASSIFY_arp_save(ip, target); +} + static int CLASSIFY_xlate(struct xt_xlate *xl, const struct xt_xlate_tg_params *params) { @@ -98,21 +116,36 @@ static int CLASSIFY_xlate(struct xt_xlate *xl, return 1; } -static struct xtables_target classify_target = { - .family = NFPROTO_UNSPEC, - .name = "CLASSIFY", - .version = XTABLES_VERSION, - .size = XT_ALIGN(sizeof(struct xt_classify_target_info)), - .userspacesize = XT_ALIGN(sizeof(struct xt_classify_target_info)), - .help = CLASSIFY_help, - .print = CLASSIFY_print, - .save = CLASSIFY_save, - .x6_parse = CLASSIFY_parse, - .x6_options = CLASSIFY_opts, - .xlate = CLASSIFY_xlate, +static struct xtables_target classify_tg_reg[] = { + { + .family = NFPROTO_UNSPEC, + .name = "CLASSIFY", + .version = XTABLES_VERSION, + .size = XT_ALIGN(sizeof(struct xt_classify_target_info)), + .userspacesize = XT_ALIGN(sizeof(struct xt_classify_target_info)), + .help = CLASSIFY_help, + .print = CLASSIFY_print, + .save = CLASSIFY_save, + .x6_parse = CLASSIFY_parse, + .x6_options = CLASSIFY_opts, + .xlate = CLASSIFY_xlate, + }, + { + .family = NFPROTO_ARP, + .name = "CLASSIFY", + .version = XTABLES_VERSION, + .size = XT_ALIGN(sizeof(struct xt_classify_target_info)), + .userspacesize = XT_ALIGN(sizeof(struct xt_classify_target_info)), + .help = CLASSIFY_help, + .print = CLASSIFY_arp_print, + .save = CLASSIFY_arp_save, + .x6_parse = CLASSIFY_parse, + .x6_options = CLASSIFY_opts, + .xlate = CLASSIFY_xlate, + } }; void _init(void) { - xtables_register_target(&classify_target); + xtables_register_targets(classify_tg_reg, ARRAY_SIZE(classify_tg_reg)); } diff --git a/extensions/libxt_CLASSIFY.t b/extensions/libxt_CLASSIFY.t new file mode 100644 index 0000000000000000000000000000000000000000..7b3ddbf75039ee3d7fe72465388373a15d3ef9f0 --- /dev/null +++ b/extensions/libxt_CLASSIFY.t @@ -0,0 +1,9 @@ +:FORWARD,OUTPUT,POSTROUTING +*mangle +-j CLASSIFY --set-class 0000:ffff;=;OK +# maximum handle accepted by tc is 0xffff +# ERROR : should fail: iptables -A FORWARD -t mangle -j CLASSIFY --set-class 0000:ffffffff +# -j CLASSIFY --set-class 0000:ffffffff;;FAIL +# ERROR: should fail: iptables -A FORWARD -t mangle -j CLASSIFY --set-class 1:-1 +# -j CLASSIFY --set-class 1:-1;;FAIL +-j CLASSIFY;;FAIL diff --git a/extensions/libxt_CONNMARK.t b/extensions/libxt_CONNMARK.t new file mode 100644 index 0000000000000000000000000000000000000000..79a838fefaa142f0767c37693fc4cc71cbbd1f9f --- /dev/null +++ b/extensions/libxt_CONNMARK.t @@ -0,0 +1,7 @@ +:PREROUTING,FORWARD,OUTPUT,POSTROUTING +*mangle +-j CONNMARK --restore-mark;=;OK +-j CONNMARK --save-mark;=;OK +-j CONNMARK --save-mark --nfmask 0xfffffff --ctmask 0xffffffff;-j CONNMARK --save-mark;OK +-j CONNMARK --restore-mark --nfmask 0xfffffff --ctmask 0xffffffff;-j CONNMARK --restore-mark;OK +-j CONNMARK;;FAIL diff --git a/extensions/libxt_CONNSECMARK.t b/extensions/libxt_CONNSECMARK.t new file mode 100644 index 0000000000000000000000000000000000000000..2751b255cd2739bac7864527973a244405bd7a41 --- /dev/null +++ b/extensions/libxt_CONNSECMARK.t @@ -0,0 +1,5 @@ +:PREROUTING,FORWARD,OUTPUT,POSTROUTING +*mangle +-j CONNSECMARK --restore;=;OK +-j CONNSECMARK --save;=;OK +-j CONNSECMARK;;FAIL diff --git a/extensions/libxt_CT.t b/extensions/libxt_CT.t new file mode 100644 index 0000000000000000000000000000000000000000..3c28534e8169e35741db6eb4f42511298bc1c8ff --- /dev/null +++ b/extensions/libxt_CT.t @@ -0,0 +1,20 @@ +:PREROUTING,OUTPUT +*raw +-j CT --notrack;=;OK +-j CT --ctevents new,related,destroy,reply,assured,protoinfo,helper,mark;=;OK +-j CT --expevents new;=;OK +# ERROR: cannot find: iptables -I PREROUTING -t raw -j CT --zone 0 +# -j CT --zone 0;=;OK +-j CT --zone 65535;=;OK +-j CT --zone 65536;;FAIL +-j CT --zone -1;;FAIL +# ERROR: should fail: iptables -A PREROUTING -t raw -j CT +# -j CT;;FAIL +@nfct timeout add test inet tcp ESTABLISHED 100 +# cannot load: iptables -A PREROUTING -t raw -j CT --timeout test +# -j CT --timeout test;=;OK +@nfct timeout del test +@nfct helper add rpc inet tcp +# cannot load: iptables -A PREROUTING -t raw -j CT --helper rpc +# -j CT --helper rpc;=;OK +@nfct helper del rpc diff --git a/extensions/libxt_DSCP.t b/extensions/libxt_DSCP.t new file mode 100644 index 0000000000000000000000000000000000000000..fcc55986dbcd7a3f0e7100b181e16a0aa95b5e0d --- /dev/null +++ b/extensions/libxt_DSCP.t @@ -0,0 +1,11 @@ +:PREROUTING,INPUT,FORWARD,OUTPUT,POSTROUTING +*mangle +-j DSCP --set-dscp 0;=;OK +-j DSCP --set-dscp 0x3f;=;OK +-j DSCP --set-dscp -1;;FAIL +-j DSCP --set-dscp 0x40;;FAIL +-j DSCP --set-dscp 0x3f --set-dscp-class CS0;;FAIL +-j DSCP --set-dscp-class CS0;-j DSCP --set-dscp 0x00;OK +-j DSCP --set-dscp-class BE;-j DSCP --set-dscp 0x00;OK +-j DSCP --set-dscp-class EF;-j DSCP --set-dscp 0x2e;OK +-j DSCP;;FAIL diff --git a/extensions/libxt_HMARK.t b/extensions/libxt_HMARK.t new file mode 100644 index 0000000000000000000000000000000000000000..3bcf1dada5d0254753edba8cbbd187b8b86c6980 --- /dev/null +++ b/extensions/libxt_HMARK.t @@ -0,0 +1,8 @@ +:INPUT,FORWARD,OUTPUT +-j HMARK;;FAIL +-j HMARK --hmark-src-prefix 32 --hmark-rnd 0x00000004 --hmark-mod 42;=;OK +-j HMARK --hmark-src-prefix 32 --hmark-dst-prefix 32 --hmark-sport-mask 0xffff --hmark-dport-mask 0xffff --hmark-proto-mask 0xffff --hmark-rnd 0x00000004 --hmark-mod 42 --hmark-offset 1 --hmark-tuple ct;=;OK +-j HMARK --hmark-src-prefix 32 --hmark-dst-prefix 32 --hmark-spi-mask 0x00000004 --hmark-proto-mask 0xffff --hmark-rnd 0x00000004 --hmark-mod 42 --hmark-offset 1 --hmark-tuple ct;=;OK +-j HMARK --hmark-src-prefix 1 --hmark-dst-prefix 2 --hmark-sport-mask 0x0003 --hmark-dport-mask 0x0004 --hmark-proto-mask 0x05 --hmark-rnd 0x00000004 --hmark-mod 42 --hmark-offset 1 --hmark-tuple ct;=;OK +# cannot mix in spi mask: +-j HMARK --hmark-src-prefix 32 --hmark-dst-prefix 32 --hmark-sport-mask 0xffff --hmark-dport-mask 0xffff --hmark-proto-mask 0xffff --hmark-rnd 0x00000004 --hmark-mod 42 --hmark-offset 1 --hmark-tuple ct --hmark-spi-mask 4;;FAIL diff --git a/extensions/libxt_IDLETIMER.t b/extensions/libxt_IDLETIMER.t new file mode 100644 index 0000000000000000000000000000000000000000..6afd92c1a1c885cc1366b4187d8e7d34e9a041a4 --- /dev/null +++ b/extensions/libxt_IDLETIMER.t @@ -0,0 +1,4 @@ +:INPUT,FORWARD,OUTPUT +-j IDLETIMER --timeout;;FAIL +-j IDLETIMER --timeout 42;;FAIL +-j IDLETIMER --timeout 42 --label foo;=;OK diff --git a/extensions/libxt_LED.t b/extensions/libxt_LED.t new file mode 100644 index 0000000000000000000000000000000000000000..1f6705f464b1d89852cf014387ba0e7c66d5e704 --- /dev/null +++ b/extensions/libxt_LED.t @@ -0,0 +1,4 @@ +:INPUT,FORWARD,OUTPUT +-j LED;;FAIL +-j LED --led-trigger-id "foo";=;OK +-j LED --led-trigger-id "foo" --led-delay 42 --led-always-blink;=;OK diff --git a/extensions/libxt_MARK.c b/extensions/libxt_MARK.c index 43aa977924b12827669e1184be01305c8e7daa4e..b765af6c35304d965dc1290f7df1f760dc245f0c 100644 --- a/extensions/libxt_MARK.c +++ b/extensions/libxt_MARK.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -245,6 +246,87 @@ static void mark_tg_save(const void *ip, const struct xt_entry_target *target) printf(" --set-xmark 0x%x/0x%x", info->mark, info->mask); } +static void mark_tg_arp_save(const void *ip, const struct xt_entry_target *target) +{ + const struct xt_mark_tginfo2 *info = (const void *)target->data; + + if (info->mark == 0) + printf(" --and-mark %x", (unsigned int)(uint32_t)~info->mask); + else if (info->mark == info->mask) + printf(" --or-mark %x", info->mark); + else + printf(" --set-mark %x", info->mark); +} + +static void mark_tg_arp_print(const void *ip, + const struct xt_entry_target *target, int numeric) +{ + mark_tg_arp_save(ip, target); +} + +#define MARK_OPT 1 +#define AND_MARK_OPT 2 +#define OR_MARK_OPT 3 + +static struct option mark_tg_arp_opts[] = { + { .name = "set-mark", .has_arg = required_argument, .flag = 0, .val = MARK_OPT }, + { .name = "and-mark", .has_arg = required_argument, .flag = 0, .val = AND_MARK_OPT }, + { .name = "or-mark", .has_arg = required_argument, .flag = 0, .val = OR_MARK_OPT }, + { .name = NULL} +}; + +static int +mark_tg_arp_parse(int c, char **argv, int invert, unsigned int *flags, + const void *entry, struct xt_entry_target **target) +{ + struct xt_mark_tginfo2 *info = + (struct xt_mark_tginfo2 *)(*target)->data; + int i; + + switch (c) { + case MARK_OPT: + if (sscanf(argv[optind-1], "%x", &i) != 1) { + xtables_error(PARAMETER_PROBLEM, + "Bad mark value `%s'", optarg); + return 0; + } + info->mark = i; + if (*flags) + xtables_error(PARAMETER_PROBLEM, + "MARK: Can't specify --set-mark twice"); + *flags = 1; + break; + case AND_MARK_OPT: + if (sscanf(argv[optind-1], "%x", &i) != 1) { + xtables_error(PARAMETER_PROBLEM, + "Bad mark value `%s'", optarg); + return 0; + } + info->mark = 0; + info->mask = ~i; + if (*flags) + xtables_error(PARAMETER_PROBLEM, + "MARK: Can't specify --and-mark twice"); + *flags = 1; + break; + case OR_MARK_OPT: + if (sscanf(argv[optind-1], "%x", &i) != 1) { + xtables_error(PARAMETER_PROBLEM, + "Bad mark value `%s'", optarg); + return 0; + } + info->mark = info->mask = i; + if (*flags) + xtables_error(PARAMETER_PROBLEM, + "MARK: Can't specify --or-mark twice"); + *flags = 1; + break; + default: + return 0; + } + return 1; +} + static int mark_tg_xlate(struct xt_xlate *xl, const struct xt_xlate_tg_params *params) { @@ -335,6 +417,19 @@ static struct xtables_target mark_tg_reg[] = { .x6_options = mark_tg_opts, .xlate = mark_tg_xlate, }, + { + .version = XTABLES_VERSION, + .name = "MARK", + .revision = 2, + .family = NFPROTO_ARP, + .size = XT_ALIGN(sizeof(struct xt_mark_tginfo2)), + .userspacesize = XT_ALIGN(sizeof(struct xt_mark_tginfo2)), + .help = mark_tg_help, + .print = mark_tg_arp_print, + .save = mark_tg_arp_save, + .parse = mark_tg_arp_parse, + .extra_opts = mark_tg_arp_opts, + }, }; void _init(void) diff --git a/extensions/libxt_MARK.t b/extensions/libxt_MARK.t new file mode 100644 index 0000000000000000000000000000000000000000..9d1aa7d7d58a4ed1dae9c4ffe6c03bd77771295a --- /dev/null +++ b/extensions/libxt_MARK.t @@ -0,0 +1,7 @@ +:INPUT,FORWARD,OUTPUT +-j MARK --set-xmark 0xfeedcafe/0xfeedcafe;=;OK +-j MARK --set-xmark 0;=;OK +-j MARK --set-xmark 4294967295;-j MARK --set-xmark 0xffffffff;OK +-j MARK --set-xmark 4294967296;;FAIL +-j MARK --set-xmark -1;;FAIL +-j MARK;;FAIL diff --git a/extensions/libxt_NFLOG.t b/extensions/libxt_NFLOG.t new file mode 100644 index 0000000000000000000000000000000000000000..933fa22160e59e01916d45cadb236108eb6e075c --- /dev/null +++ b/extensions/libxt_NFLOG.t @@ -0,0 +1,24 @@ +:INPUT,FORWARD,OUTPUT +-j NFLOG --nflog-group 1;=;OK +-j NFLOG --nflog-group 65535;=;OK +-j NFLOG --nflog-group 65536;;FAIL +-j NFLOG --nflog-group 0;-j NFLOG;OK +-j NFLOG --nflog-range 1;=;OK +-j NFLOG --nflog-range 4294967295;=;OK +-j NFLOG --nflog-range 4294967296;;FAIL +-j NFLOG --nflog-range -1;;FAIL +-j NFLOG --nflog-size 0;=;OK +-j NFLOG --nflog-size 1;=;OK +-j NFLOG --nflog-size 4294967295;=;OK +-j NFLOG --nflog-size 4294967296;;FAIL +-j NFLOG --nflog-size -1;;FAIL +# ERROR: cannot find: iptables -I INPUT -j NFLOG --nflog-prefix xxxxxx [...] +# -j NFLOG --nflog-prefix xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;=;OK +# ERROR: should fail: iptables -A INPUT -j NFLOG --nflog-prefix xxxxxxx [...] +# -j NFLOG --nflog-prefix xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;;FAIL +-j NFLOG --nflog-threshold 1;=;OK +# ERROR: line 13 (should fail: iptables -A INPUT -j NFLOG --nflog-threshold 0 +# -j NFLOG --nflog-threshold 0;;FAIL +-j NFLOG --nflog-threshold 65535;=;OK +-j NFLOG --nflog-threshold 65536;;FAIL +-j NFLOG;=;OK diff --git a/extensions/libxt_NFQUEUE.t b/extensions/libxt_NFQUEUE.t new file mode 100644 index 0000000000000000000000000000000000000000..b51b19fd435f719929649afc5ba304ec472a8f4f --- /dev/null +++ b/extensions/libxt_NFQUEUE.t @@ -0,0 +1,16 @@ +:INPUT,FORWARD,OUTPUT +-j NFQUEUE;=;OK +-j NFQUEUE --queue-num 0;=;OK +-j NFQUEUE --queue-num 65535;=;OK +-j NFQUEUE --queue-num 65536;;FAIL +-j NFQUEUE --queue-num -1;;FAIL +# it says "NFQUEUE: number of total queues is 0", overflow in NFQUEUE_parse_v1? +# ERROR: cannot load: iptables -A INPUT -j NFQUEUE --queue-balance 0:65535 +# -j NFQUEUE --queue-balance 0:65535;=;OK +-j NFQUEUE --queue-balance 0:65536;;FAIL +-j NFQUEUE --queue-balance -1:65535;;FAIL +-j NFQUEUE --queue-num 10 --queue-bypass;=;OK +-j NFQUEUE --queue-balance 0:6 --queue-cpu-fanout --queue-bypass;-j NFQUEUE --queue-balance 0:6 --queue-bypass --queue-cpu-fanout;OK +-j NFQUEUE --queue-bypass --queue-balance 0:6 --queue-cpu-fanout;-j NFQUEUE --queue-balance 0:6 --queue-bypass --queue-cpu-fanout;OK +-j NFQUEUE --queue-balance 0:6 --queue-bypass;=;OK +-j NFQUEUE --queue-bypass;-j NFQUEUE --queue-num 0 --queue-bypass;OK diff --git a/extensions/libxt_NOTRACK.t b/extensions/libxt_NOTRACK.t new file mode 100644 index 0000000000000000000000000000000000000000..585be82d56ecbe59c97c44c53ec7be6655026455 --- /dev/null +++ b/extensions/libxt_NOTRACK.t @@ -0,0 +1,4 @@ +:PREROUTING,OUTPUT +*raw +# ERROR: cannot find: iptables -I PREROUTING -t raw -j NOTRACK +#-j NOTRACK;=;OK diff --git a/extensions/libxt_RATEEST.t b/extensions/libxt_RATEEST.t new file mode 100644 index 0000000000000000000000000000000000000000..c2b6bb34e7aa26f0eeb66b6289a0ecfa3bfc42b4 --- /dev/null +++ b/extensions/libxt_RATEEST.t @@ -0,0 +1,2 @@ +:INPUT,FORWARD,OUTPUT +-j RATEEST --rateest-name RE1 --rateest-interval 250.0ms --rateest-ewmalog 500.0ms;=;OK diff --git a/extensions/libxt_SET.t b/extensions/libxt_SET.t new file mode 100644 index 0000000000000000000000000000000000000000..30c27ca319176c3864fc10ea6519dc4e2c3ec698 --- /dev/null +++ b/extensions/libxt_SET.t @@ -0,0 +1,3 @@ +:INPUT,FORWARD,OUTPUT +# fails: foo does not exist +-j SET --add-set foo src,dst;;FAIL diff --git a/extensions/libxt_SYNPROXY.man b/extensions/libxt_SYNPROXY.man index 25325fc284ae914f1c0eb03d6b3f742746689aac..30a71ed2d6a54786f8f1d3848a4c336d8fdd4f91 100644 --- a/extensions/libxt_SYNPROXY.man +++ b/extensions/libxt_SYNPROXY.man @@ -1,6 +1,8 @@ This target will process TCP three-way-handshake parallel in netfilter context to protect either local or backend system. This target requires connection tracking because sequence numbers need to be translated. +The kernels ability to absorb SYNFLOOD was greatly improved starting with +Linux 4.4, so this target should not be needed anymore to protect Linux servers. .TP \fB\-\-mss\fP \fImaximum segment size\fP Maximum segment size announced to clients. This must match the backend. diff --git a/extensions/libxt_SYNPROXY.t b/extensions/libxt_SYNPROXY.t new file mode 100644 index 0000000000000000000000000000000000000000..dd8b0e769f5685a428e0229960b65a9ddda300d1 --- /dev/null +++ b/extensions/libxt_SYNPROXY.t @@ -0,0 +1,3 @@ +:INPUT,FORWARD +-j SYNPROXY --sack-perm --timestamp --mss 1460 --wscale 9;;FAIL +-p tcp -m tcp --dport 42 -m conntrack --ctstate INVALID,UNTRACKED -j SYNPROXY --sack-perm --timestamp --wscale 9 --mss 1460;=;OK diff --git a/extensions/libxt_TCPMSS.t b/extensions/libxt_TCPMSS.t new file mode 100644 index 0000000000000000000000000000000000000000..553a3452e4876778c17001eb59a360936b3a9e59 --- /dev/null +++ b/extensions/libxt_TCPMSS.t @@ -0,0 +1,6 @@ +:FORWARD,OUTPUT,POSTROUTING +*mangle +-j TCPMSS;;FAIL +-p tcp -j TCPMSS --set-mss 42;;FAIL +-p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -j TCPMSS --set-mss 42;=;OK +-p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -j TCPMSS --clamp-mss-to-pmtu;=;OK diff --git a/extensions/libxt_TCPOPTSTRIP.t b/extensions/libxt_TCPOPTSTRIP.t new file mode 100644 index 0000000000000000000000000000000000000000..b5c7a109e5b91ed312841ba0df2f31ffa941f791 --- /dev/null +++ b/extensions/libxt_TCPOPTSTRIP.t @@ -0,0 +1,8 @@ +:PREROUTING,INPUT,FORWARD,OUTPUT,POSTROUTING +*mangle +-j TCPOPTSTRIP;;FAIL +-p tcp -j TCPOPTSTRIP;=;OK +-p tcp -j TCPOPTSTRIP --strip-options 2,3,4,5,6,7;=;OK +-p tcp -j TCPOPTSTRIP --strip-options 0;;FAIL +-p tcp -j TCPOPTSTRIP --strip-options 1;;FAIL +-p tcp -j TCPOPTSTRIP --strip-options 1,2;;FAIL diff --git a/extensions/libxt_TEE.t b/extensions/libxt_TEE.t new file mode 100644 index 0000000000000000000000000000000000000000..ce8b103e0dc246e4f37e122b07d4d1512474bf06 --- /dev/null +++ b/extensions/libxt_TEE.t @@ -0,0 +1,4 @@ +:INPUT,FORWARD,OUTPUT +-j TEE --gateway 1.1.1.1;=;OK +-j TEE ! --gateway 1.1.1.1;;FAIL +-j TEE;;FAIL diff --git a/extensions/libxt_TOS.t b/extensions/libxt_TOS.t new file mode 100644 index 0000000000000000000000000000000000000000..ae8531cc582e29ab026ed24419dbf7e0d579ec7c --- /dev/null +++ b/extensions/libxt_TOS.t @@ -0,0 +1,16 @@ +:PREROUTING,INPUT,FORWARD,OUTPUT,POSTROUTING +*mangle +-j TOS --set-tos 0x1f;=;OK +-j TOS --set-tos 0x1f/0x1f;=;OK +# maximum TOS is 0x1f (5 bits) +# ERROR: should fail: iptables -A PREROUTING -t mangle -j TOS --set-tos 0xff +# -j TOS --set-tos 0xff;;FAIL +-j TOS --set-tos Minimize-Delay;-j TOS --set-tos 0x10;OK +-j TOS --set-tos Maximize-Throughput;-j TOS --set-tos 0x08;OK +-j TOS --set-tos Maximize-Reliability;-j TOS --set-tos 0x04;OK +-j TOS --set-tos Minimize-Cost;-j TOS --set-tos 0x02;OK +-j TOS --set-tos Normal-Service;-j TOS --set-tos 0x00;OK +-j TOS --and-tos 0x12;-j TOS --set-tos 0x00/0xed;OK +-j TOS --or-tos 0x12;-j TOS --set-tos 0x12/0x12;OK +-j TOS --xor-tos 0x12;-j TOS --set-tos 0x12/0x00;OK +-j TOS;;FAIL diff --git a/extensions/libxt_TPROXY.t b/extensions/libxt_TPROXY.t new file mode 100644 index 0000000000000000000000000000000000000000..12f82b1fae76aaeff6fa1dd8deefd3ca4340fb62 --- /dev/null +++ b/extensions/libxt_TPROXY.t @@ -0,0 +1,5 @@ +:PREROUTING +*mangle +-j TPROXY --on-port 12345 --on-ip 10.0.0.1 --tproxy-mark 0x23/0xff;;FAIL +-p udp -j TPROXY --on-port 12345 --on-ip 10.0.0.1 --tproxy-mark 0x23/0xff;=;OK +-p tcp -m tcp --dport 2342 -j TPROXY --on-port 12345 --on-ip 10.0.0.1 --tproxy-mark 0x23/0xff;=;OK diff --git a/extensions/libxt_TRACE.man b/extensions/libxt_TRACE.man index 8d590a52e26f898e35f7a869c118c741a34a998a..5187a8d22802f4a112c8508257dc6c2bf43366d2 100644 --- a/extensions/libxt_TRACE.man +++ b/extensions/libxt_TRACE.man @@ -1,13 +1,20 @@ This target marks packets so that the kernel will log every rule which match -the packets as those traverse the tables, chains, rules. +the packets as those traverse the tables, chains, rules. It can only be used in +the +.BR raw +table. .PP -A logging backend, such as ip(6)t_LOG or nfnetlink_log, must be loaded for this -to be visible. +With iptables-legacy, a logging backend, such as ip(6)t_LOG or nfnetlink_log, +must be loaded for this to be visible. The packets are logged with the string prefix: "TRACE: tablename:chainname:type:rulenum " where type can be "rule" for plain rule, "return" for implicit rule at the end of a user defined chain and "policy" for the policy of the built in chains. -.br -It can only be used in the -.BR raw -table. +.PP +With iptables-nft, the target is translated into nftables' +.B "meta nftrace" +expression. Hence the kernel sends trace events via netlink to userspace where +they may be displayed using +.B "xtables-monitor --trace" +command. For details, refer to +.BR xtables-monitor (8). diff --git a/extensions/libxt_TRACE.t b/extensions/libxt_TRACE.t new file mode 100644 index 0000000000000000000000000000000000000000..cadb7330174e59ca8d3d900e9fed0c0a80730a08 --- /dev/null +++ b/extensions/libxt_TRACE.t @@ -0,0 +1,3 @@ +:PREROUTING,OUTPUT +*raw +-j TRACE;=;OK diff --git a/extensions/libxt_addrtype.t b/extensions/libxt_addrtype.t new file mode 100644 index 0000000000000000000000000000000000000000..390a63f0fa2323550b95158bc1c3c3cd3f7f063b --- /dev/null +++ b/extensions/libxt_addrtype.t @@ -0,0 +1,17 @@ +:INPUT,FORWARD,OUTPUT +-m addrtype;;FAIL +-m addrtype --src-type wrong;;FAIL +-m addrtype --src-type UNSPEC;=;OK +-m addrtype --dst-type UNSPEC;=;OK +-m addrtype --src-type LOCAL --dst-type LOCAL;=;OK +-m addrtype --dst-type UNSPEC;=;OK +-m addrtype --limit-iface-in;;FAIL +-m addrtype --limit-iface-out;;FAIL +-m addrtype --limit-iface-in --limit-iface-out;;FAIL +-m addrtype --src-type LOCAL --limit-iface-in --limit-iface-out;;FAIL +:INPUT +-m addrtype --src-type LOCAL --limit-iface-in;=;OK +-m addrtype --dst-type LOCAL --limit-iface-in;=;OK +:OUTPUT +-m addrtype --src-type LOCAL --limit-iface-out;=;OK +-m addrtype --dst-type LOCAL --limit-iface-out;=;OK diff --git a/extensions/libxt_bpf.t b/extensions/libxt_bpf.t new file mode 100644 index 0000000000000000000000000000000000000000..80361ad52e7135db342a7bb4101a0973b71a2b7c --- /dev/null +++ b/extensions/libxt_bpf.t @@ -0,0 +1,2 @@ +:INPUT,FORWARD,OUTPUT +-m bpf --bytecode "4,48 0 0 9,21 0 1 6,6 0 0 1,6 0 0 0";=;OK diff --git a/extensions/libxt_cgroup.t b/extensions/libxt_cgroup.t new file mode 100644 index 0000000000000000000000000000000000000000..72c8e37708e95c4ee7fafed9cff1f6c804b347f9 --- /dev/null +++ b/extensions/libxt_cgroup.t @@ -0,0 +1,8 @@ +:INPUT,OUTPUT,POSTROUTING +*mangle +-m cgroup --cgroup 1;=;OK +-m cgroup ! --cgroup 1;=;OK +-m cgroup --path "/";=;OK +-m cgroup ! --path "/";=;OK +-m cgroup --cgroup 1 --path "/";;FAIL +-m cgroup ;;FAIL diff --git a/extensions/libxt_cluster.t b/extensions/libxt_cluster.t new file mode 100644 index 0000000000000000000000000000000000000000..ac608244833f2c40dc8fb7287448ae4e8ddb1f80 --- /dev/null +++ b/extensions/libxt_cluster.t @@ -0,0 +1,10 @@ +:PREROUTING,FORWARD,POSTROUTING +*mangle +-m cluster;;FAIL +-m cluster --cluster-total-nodes 3;;FAIL +-m cluster --cluster-total-nodes 2 --cluster-local-node 2;;FAIL +-m cluster --cluster-total-nodes 2 --cluster-local-node 3 --cluster-hash-seed;;FAIL +# +# outputs --cluster-local-nodemask instead of --cluster-local-node +# +-m cluster --cluster-total-nodes 2 --cluster-local-node 2 --cluster-hash-seed 0xfeedcafe;-m cluster --cluster-local-nodemask 0x00000002 --cluster-total-nodes 2 --cluster-hash-seed 0xfeedcafe;OK diff --git a/extensions/libxt_comment.t b/extensions/libxt_comment.t new file mode 100644 index 0000000000000000000000000000000000000000..f0c8fb999401bdef7ffcce0357eed62a6a0fe4ec --- /dev/null +++ b/extensions/libxt_comment.t @@ -0,0 +1,14 @@ +:INPUT,FORWARD,OUTPUT +-m comment;;FAIL +-m comment --comment;;FAIL +-p tcp -m tcp --dport 22 -m comment --comment foo;=;OK +-p tcp -m comment --comment foo -m tcp --dport 22;=;OK +# +# it fails with 256 characters +# +# should fail: iptables -A INPUT -m comment --comment xxxxxxxxxxxxxxxxx [....] +# -m comment --comment xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;;FAIL +# +# success with 255 characters +# +-m comment --comment xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;=;OK diff --git a/extensions/libxt_connbytes.t b/extensions/libxt_connbytes.t new file mode 100644 index 0000000000000000000000000000000000000000..6b24e266c1a04c65ac5c4484ecf1d7340fab564a --- /dev/null +++ b/extensions/libxt_connbytes.t @@ -0,0 +1,21 @@ +:INPUT,FORWARD,OUTPUT +-m connbytes --connbytes 0:1000 --connbytes-mode packets --connbytes-dir original;=;OK +-m connbytes --connbytes 0:1000 --connbytes-mode packets --connbytes-dir reply;=;OK +-m connbytes --connbytes 0:1000 --connbytes-mode packets --connbytes-dir both;=;OK +-m connbytes --connbytes 0:1000 --connbytes-mode bytes --connbytes-dir original;=;OK +-m connbytes --connbytes 0:1000 --connbytes-mode bytes --connbytes-dir reply;=;OK +-m connbytes --connbytes 0:1000 --connbytes-mode bytes --connbytes-dir both;=;OK +-m connbytes --connbytes 0:1000 --connbytes-mode avgpkt --connbytes-dir original;=;OK +-m connbytes --connbytes 0:1000 --connbytes-mode avgpkt --connbytes-dir reply;=;OK +-m connbytes --connbytes 0:1000 --connbytes-mode avgpkt --connbytes-dir both;=;OK +-m connbytes --connbytes -1:0 --connbytes-mode packets --connbytes-dir original;;FAIL +-m connbytes --connbytes 0:-1 --connbytes-mode packets --connbytes-dir original;;FAIL +# ERROR: cannot find: iptables -I INPUT -m connbytes --connbytes 0:18446744073709551615 --connbytes-mode avgpkt --connbytes-dir both +# -m connbytes --connbytes 0:18446744073709551615 --connbytes-mode avgpkt --connbytes-dir both;=;OK +-m connbytes --connbytes 0:18446744073709551616 --connbytes-mode avgpkt --connbytes-dir both;;FAIL +-m connbytes --connbytes 0:1000 --connbytes-mode wrong --connbytes-dir both;;FAIL +-m connbytes --connbytes 0:1000 --connbytes-dir original;;FAIL +-m connbytes --connbytes 0:1000 --connbytes-mode packets;;FAIL +-m connbytes --connbytes-dir original;;FAIL +-m connbytes --connbytes 0:1000;;FAIL +-m connbytes;;FAIL diff --git a/extensions/libxt_connlabel.c b/extensions/libxt_connlabel.c index d06bb27a7c2e983bd97bcefe6841d65835123055..5a01fe7237bd8bc27f3f737e711c3453ba35d7f6 100644 --- a/extensions/libxt_connlabel.c +++ b/extensions/libxt_connlabel.c @@ -1,8 +1,10 @@ +#define _GNU_SOURCE #include #include #include #include #include +#include #include #include #include @@ -32,40 +34,59 @@ static const struct xt_option_entry connlabel_mt_opts[] = { /* cannot do this via _init, else static builds might spew error message * for every iptables invocation. */ -static void connlabel_open(void) +static int connlabel_open(void) { const char *fname; if (map) - return; + return 0; map = nfct_labelmap_new(NULL); if (map != NULL) - return; + return 0; fname = nfct_labels_get_path(); if (errno) { - xtables_error(RESOURCE_PROBLEM, - "cannot open %s: %s", fname, strerror(errno)); + fprintf(stderr, "Warning: cannot open %s: %s\n", + fname, strerror(errno)); } else { xtables_error(RESOURCE_PROBLEM, "cannot parse %s: no labels found", fname); } + return 1; +} + +static int connlabel_value_parse(const char *in) +{ + char *end; + unsigned long value = strtoul(in, &end, 0); + + if (in[0] == '\0' || *end != '\0') + return -1; + + return value; } static void connlabel_mt_parse(struct xt_option_call *cb) { struct xt_connlabel_mtinfo *info = cb->data; + bool have_labelmap = !connlabel_open(); int tmp; - connlabel_open(); xtables_option_parse(cb); switch (cb->entry->id) { case O_LABEL: - tmp = nfct_labelmap_get_bit(map, cb->arg); + if (have_labelmap) + tmp = nfct_labelmap_get_bit(map, cb->arg); + else + tmp = connlabel_value_parse(cb->arg); + if (tmp < 0) - xtables_error(PARAMETER_PROBLEM, "label '%s' not found", cb->arg); + xtables_error(PARAMETER_PROBLEM, + "label '%s' not found or invalid value", + cb->arg); + info->bit = tmp; if (cb->invert) info->options |= XT_CONNLABEL_OP_INVERT; @@ -81,7 +102,8 @@ static const char *connlabel_get_name(int b) { const char *name; - connlabel_open(); + if (connlabel_open()) + return NULL; name = nfct_labelmap_get_name(map, b); if (name && strcmp(name, "")) @@ -134,9 +156,13 @@ static int connlabel_mt_xlate(struct xt_xlate *xl, const struct xt_connlabel_mtinfo *info = (const void *)params->match->data; const char *name = connlabel_get_name(info->bit); + char *valbuf = NULL; - if (name == NULL) - return 0; + if (name == NULL) { + if (asprintf(&valbuf, "%u", info->bit) < 0) + return 0; + name = valbuf; + } if (info->options & XT_CONNLABEL_OP_SET) xt_xlate_add(xl, "ct label set %s ", name); @@ -146,6 +172,7 @@ static int connlabel_mt_xlate(struct xt_xlate *xl, xt_xlate_add(xl, "and %s != ", name); xt_xlate_add(xl, "%s", name); + free(valbuf); return 1; } diff --git a/extensions/libxt_connlabel.t b/extensions/libxt_connlabel.t new file mode 100644 index 0000000000000000000000000000000000000000..7265bd4764865a9d9b3c714a53f5e98e014d33a8 --- /dev/null +++ b/extensions/libxt_connlabel.t @@ -0,0 +1,7 @@ +:INPUT,FORWARD,OUTPUT +-m connlabel --label "40";=;OK +-m connlabel ! --label "40";=;OK +-m connlabel --label "41" --set;=;OK +-m connlabel ! --label "41" --set;=;OK +-m connlabel --label "2048";;FAIL +-m connlabel --label "foobar_not_there";;FAIL diff --git a/extensions/libxt_connlabel.txlate b/extensions/libxt_connlabel.txlate index 5be422044637d27890b0fefc2634f3c01b680e8c..12e4ac0351103060a0a4579f8cb125bb8136a4a2 100644 --- a/extensions/libxt_connlabel.txlate +++ b/extensions/libxt_connlabel.txlate @@ -1,5 +1,5 @@ -iptables-translate -A INPUT -m connlabel --label bit40 -nft add rule ip filter INPUT ct label bit40 counter +iptables-translate -A INPUT -m connlabel --label 40 +nft add rule ip filter INPUT ct label 40 counter -iptables-translate -A INPUT -m connlabel ! --label bit40 --set -nft add rule ip filter INPUT ct label set bit40 ct label and bit40 != bit40 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 diff --git a/extensions/libxt_connlimit.t b/extensions/libxt_connlimit.t new file mode 100644 index 0000000000000000000000000000000000000000..c7ea61e95fbc85bea261e63cac048f4165044898 --- /dev/null +++ b/extensions/libxt_connlimit.t @@ -0,0 +1,16 @@ +:INPUT,FORWARD,OUTPUT +-m connlimit --connlimit-upto 0;=;OK +-m connlimit --connlimit-upto 4294967295;=;OK +-m connlimit --connlimit-upto 4294967296;;FAIL +-m connlimit --connlimit-upto -1;;FAIL +-m connlimit --connlimit-above 0;=;OK +-m connlimit --connlimit-above 4294967295;=;OK +-m connlimit --connlimit-above 4294967296;;FAIL +-m connlimit --connlimit-above -1;;FAIL +-m connlimit --connlimit-upto 1 --conlimit-above 1;;FAIL +-m connlimit --connlimit-above 10 --connlimit-saddr;-m connlimit --connlimit-above 10 --connlimit-mask 32 --connlimit-saddr;OK +-m connlimit --connlimit-above 10 --connlimit-daddr;-m connlimit --connlimit-above 10 --connlimit-mask 32 --connlimit-daddr;OK +-m connlimit --connlimit-above 10 --connlimit-saddr --connlimit-daddr;;FAIL +-m connlimit --connlimit-above 10 --connlimit-mask 32 --connlimit-saddr;=;OK +-m connlimit --connlimit-above 10 --connlimit-mask 32 --connlimit-daddr;=;OK +-m connlimit;;FAIL diff --git a/extensions/libxt_connmark.t b/extensions/libxt_connmark.t new file mode 100644 index 0000000000000000000000000000000000000000..4dd7d9af265a5c6e2dcbad77fc7fef762a3eb550 --- /dev/null +++ b/extensions/libxt_connmark.t @@ -0,0 +1,9 @@ +:PREROUTING,FORWARD,OUTPUT,POSTROUTING +*mangle +-m connmark --mark 0xffffffff;=;OK +-m connmark --mark 0xffffffff/0xffffffff;-m connmark --mark 0xffffffff;OK +-m connmark --mark 0xffffffff/0;=;OK +-m connmark --mark 0/0xffffffff;-m connmark --mark 0;OK +-m connmark --mark -1;;FAIL +-m connmark --mark 0xfffffffff;;FAIL +-m connmark;;FAIL diff --git a/extensions/libxt_conntrack.t b/extensions/libxt_conntrack.t new file mode 100644 index 0000000000000000000000000000000000000000..db53147532afd664cfdcb279b88b25c432bc95ec --- /dev/null +++ b/extensions/libxt_conntrack.t @@ -0,0 +1,27 @@ +:INPUT,FORWARD,OUTPUT +-m conntrack --ctstate NEW;=;OK +-m conntrack --ctstate NEW,ESTABLISHED;=;OK +-m conntrack --ctstate NEW,RELATED,ESTABLISHED;=;OK +-m conntrack --ctstate INVALID;=;OK +-m conntrack --ctstate UNTRACKED;=;OK +-m conntrack --ctstate SNAT,DNAT;=;OK +-m conntrack --ctstate wrong;;FAIL +# should we convert this to output "tcp" instead of 6? +-m conntrack --ctproto tcp;-m conntrack --ctproto 6;OK +-m conntrack --ctorigsrc 1.1.1.1;=;OK +-m conntrack --ctorigdst 1.1.1.1;=;OK +-m conntrack --ctreplsrc 1.1.1.1;=;OK +-m conntrack --ctrepldst 1.1.1.1;=;OK +-m conntrack --ctexpire 0;=;OK +-m conntrack --ctexpire 4294967295;=;OK +-m conntrack --ctexpire 0:4294967295;=;OK +-m conntrack --ctexpire 42949672956;;FAIL +-m conntrack --ctexpire -1;;FAIL +-m conntrack --ctdir ORIGINAL;=;OK +-m conntrack --ctdir REPLY;=;OK +-m conntrack --ctstatus NONE;=;OK +-m conntrack --ctstatus CONFIRMED;=;OK +-m conntrack --ctstatus ASSURED;=;OK +-m conntrack --ctstatus EXPECTED;=;OK +-m conntrack --ctstatus SEEN_REPLY;=;OK +-m conntrack;;FAIL diff --git a/extensions/libxt_cpu.t b/extensions/libxt_cpu.t new file mode 100644 index 0000000000000000000000000000000000000000..f5adb45db74242088e985e0fa5d6dc2200461ecc --- /dev/null +++ b/extensions/libxt_cpu.t @@ -0,0 +1,6 @@ +:INPUT,FORWARD,OUTPUT +-m cpu --cpu 0;=;OK +-m cpu ! --cpu 0;=;OK +-m cpu --cpu 4294967295;=;OK +-m cpu --cpu 4294967296;;FAIL +-m cpu;;FAIL diff --git a/extensions/libxt_dccp.t b/extensions/libxt_dccp.t new file mode 100644 index 0000000000000000000000000000000000000000..f60b480fb6fc747c70f6bbf38515873e173b2236 --- /dev/null +++ b/extensions/libxt_dccp.t @@ -0,0 +1,30 @@ +:INPUT,FORWARD,OUTPUT +-p dccp -m dccp --sport 1;=;OK +-p dccp -m dccp --sport 65535;=;OK +-p dccp -m dccp --dport 1;=;OK +-p dccp -m dccp --dport 65535;=;OK +-p dccp -m dccp --sport 1:1023;=;OK +-p dccp -m dccp --sport 1024:65535;=;OK +-p dccp -m dccp --sport 1024:;-p dccp -m dccp --sport 1024:65535;OK +-p dccp -m dccp ! --sport 1;=;OK +-p dccp -m dccp ! --sport 65535;=;OK +-p dccp -m dccp ! --dport 1;=;OK +-p dccp -m dccp ! --dport 65535;=;OK +-p dccp -m dccp --sport 1 --dport 65535;=;OK +-p dccp -m dccp --sport 65535 --dport 1;=;OK +-p dccp -m dccp ! --sport 1 --dport 65535;=;OK +-p dccp -m dccp ! --sport 65535 --dport 1;=;OK +# ERROR: should fail: iptables -A INPUT -p dccp -m dccp --sport 65536 +# -p dccp -m dccp --sport 65536;;FAIL +-p dccp -m dccp --sport -1;;FAIL +-p dccp -m dccp --dport -1;;FAIL +-p dccp -m dccp --dccp-types REQUEST,RESPONSE,DATA,ACK,DATAACK,CLOSEREQ,CLOSE,RESET,SYNC,SYNCACK,INVALID;=;OK +-p dccp -m dccp ! --dccp-types REQUEST,RESPONSE,DATA,ACK,DATAACK,CLOSEREQ,CLOSE,RESET,SYNC,SYNCACK,INVALID;=;OK +# DCCP option 0 is valid, see http://tools.ietf.org/html/rfc4340#page-29 +# ERROR: cannot load: iptables -A INPUT -p dccp -m dccp --dccp-option 0 +#-p dccp -m dccp --dccp-option 0;=;OK +-p dccp -m dccp --dccp-option 255;=;OK +-p dccp -m dccp --dccp-option 256;;FAIL +-p dccp -m dccp --dccp-option -1;;FAIL +# should we accept this below? +-p dccp -m dccp;=;OK diff --git a/extensions/libxt_dscp.t b/extensions/libxt_dscp.t new file mode 100644 index 0000000000000000000000000000000000000000..38d7f04e18698d6ce188ccb822dfc86f0c4cdf84 --- /dev/null +++ b/extensions/libxt_dscp.t @@ -0,0 +1,10 @@ +:INPUT,FORWARD,OUTPUT +-m dscp --dscp 0;=;OK +-m dscp --dscp 0x3f;=;OK +-m dscp --dscp -1;;FAIL +-m dscp --dscp 0x40;;FAIL +-m dscp --dscp 0x3f --dscp-class CS0;;FAIL +-m dscp --dscp-class CS0;-m dscp --dscp 0x00;OK +-m dscp --dscp-class BE;-m dscp --dscp 0x00;OK +-m dscp --dscp-class EF;-m dscp --dscp 0x2e;OK +-m dscp;;FAIL diff --git a/extensions/libxt_ecn.t b/extensions/libxt_ecn.t new file mode 100644 index 0000000000000000000000000000000000000000..b32aea306dcaed9eb227de115b2446630494819f --- /dev/null +++ b/extensions/libxt_ecn.t @@ -0,0 +1,5 @@ +:INPUT,FORWARD,OUTPUT +-m ecn --ecn-tcp-cwr;;FAIL +-p tcp -m ecn --ecn-tcp-cwr;=;OK +-p tcp -m ecn --ecn-tcp-ece --ecn-tcp-cwr --ecn-ip-ect 2;=;OK +-p tcp -m ecn ! --ecn-tcp-ece ! --ecn-tcp-cwr ! --ecn-ip-ect 2;=;OK diff --git a/extensions/libxt_esp.t b/extensions/libxt_esp.t new file mode 100644 index 0000000000000000000000000000000000000000..92c5779f860f151d76dc2ccd5ae256aaa3cd05e8 --- /dev/null +++ b/extensions/libxt_esp.t @@ -0,0 +1,8 @@ +:INPUT,FORWARD,OUTPUT +-p esp -m esp --espspi 0;=;OK +-p esp -m esp --espspi :32;-p esp -m esp --espspi 0:32;OK +-p esp -m esp --espspi 0:4294967295;-p esp -m esp;OK +-p esp -m esp ! --espspi 0:4294967294;=;OK +-p esp -m esp --espspi -1;;FAIL +-p esp -m esp;=;OK +-m esp;;FAIL diff --git a/extensions/libxt_hashlimit.t b/extensions/libxt_hashlimit.t new file mode 100644 index 0000000000000000000000000000000000000000..ccd0d1e6a2a1adc8afca45c6ffd483e433dc55f8 --- /dev/null +++ b/extensions/libxt_hashlimit.t @@ -0,0 +1,33 @@ +:INPUT,FORWARD,OUTPUT +-m hashlimit --hashlimit-above 1/sec --hashlimit-burst 5 --hashlimit-name mini1;=;OK +-m hashlimit --hashlimit-above 1000000/sec --hashlimit-burst 5 --hashlimit-name mini1;=;OK +-m hashlimit --hashlimit-above 1/min --hashlimit-burst 5 --hashlimit-name mini1;=;OK +-m hashlimit --hashlimit-above 1/hour --hashlimit-burst 5 --hashlimit-name mini1;=;OK +# kernel says "xt_hashlimit: overflow, try lower: 864000000/5" +-m hashlimit --hashlimit-above 1/day --hashlimit-burst 5 --hashlimit-name mini1;;FAIL +-m hashlimit --hashlimit-upto 1/sec --hashlimit-burst 5 --hashlimit-name mini1;=;OK +-m hashlimit --hashlimit-upto 1000000/sec --hashlimit-burst 5 --hashlimit-name mini1;=;OK +-m hashlimit --hashlimit-upto 1/min --hashlimit-burst 5 --hashlimit-name mini1;=;OK +-m hashlimit --hashlimit-upto 1/hour --hashlimit-burst 5 --hashlimit-name mini1;=;OK +# kernel says "xt_hashlimit: overflow, try lower: 864000000/5" +-m hashlimit --hashlimit-upto 1/day --hashlimit-burst 5 --hashlimit-name mini1;;FAIL +-m hashlimit --hashlimit-upto 1/sec --hashlimit-burst 1 --hashlimit-name mini1 --hashlimit-htable-expire 2000;=;OK +-m hashlimit --hashlimit-upto 1/sec --hashlimit-burst 1 --hashlimit-mode srcip --hashlimit-name mini1 --hashlimit-htable-expire 2000;=;OK +-m hashlimit --hashlimit-upto 1/sec --hashlimit-burst 1 --hashlimit-mode dstip --hashlimit-name mini1 --hashlimit-htable-expire 2000;=;OK +-m hashlimit --hashlimit-upto 1/sec --hashlimit-burst 1 --hashlimit-mode dstip --hashlimit-name mini1 --hashlimit-htable-max 2000 --hashlimit-htable-expire 2000;=;OK +-m hashlimit --hashlimit-upto 1/sec --hashlimit-burst 1 --hashlimit-mode dstip --hashlimit-name mini1 --hashlimit-htable-max 2000 --hashlimit-htable-gcinterval 60000 --hashlimit-htable-expire 2000;=;OK +-m hashlimit --hashlimit-upto 1/sec --hashlimit-name mini1;-m hashlimit --hashlimit-upto 1/sec --hashlimit-burst 5 --hashlimit-name mini1;OK +-m hashlimit --hashlimit-upto 4kb/s --hashlimit-burst 400kb --hashlimit-name mini5;=;OK +-m hashlimit --hashlimit-upto 10mb/s --hashlimit-name mini6;=;OK +-m hashlimit --hashlimit-upto 123456b/s --hashlimit-burst 1mb --hashlimit-name mini7;=;OK +# should work, it says "iptables v1.4.15: burst cannot be smaller than 96b" +# ERROR: cannot load: iptables -A INPUT -m hashlimit --hashlimit-upto 96b/s --hashlimit-burst 5 --hashlimit-name mini1 +# -m hashlimit --hashlimit-upto 96b/s --hashlimit-burst 5 --hashlimit-name mini1;=;OK +-m hashlimit --hashlimit-name mini1;;FAIL +-m hashlimit --hashlimit-upto 1/sec;;FAIL +-m hashlimit;;FAIL +-m hashlimit --hashlimit-upto 40/sec --hashlimit-burst 20 --hashlimit-mode srcip --hashlimit-name syn-flood;=;OK +-m hashlimit --hashlimit-upto 40/sec --hashlimit-burst 20 --hashlimit-mode srcip --hashlimit-name rate1 --hashlimit-rate-match;=;OK +-m hashlimit --hashlimit-upto 40mb/s --hashlimit-mode srcip --hashlimit-name rate2 --hashlimit-rate-match;=;OK +-m hashlimit --hashlimit-upto 40/sec --hashlimit-burst 20 --hashlimit-mode srcip --hashlimit-name rate3 --hashlimit-rate-match --hashlimit-rate-interval 10;=;OK +-m hashlimit --hashlimit-upto 40mb/s --hashlimit-mode srcip --hashlimit-name rate4 --hashlimit-rate-match --hashlimit-rate-interval 10;=;OK diff --git a/extensions/libxt_helper.t b/extensions/libxt_helper.t new file mode 100644 index 0000000000000000000000000000000000000000..8c8420ac5693a7ebffe7822c2a1b78288d57f66e --- /dev/null +++ b/extensions/libxt_helper.t @@ -0,0 +1,6 @@ +:INPUT,FORWARD,OUTPUT +-m helper --helper ftp;=;OK +# should be OK? +# ERROR: should fail: iptables -A INPUT -m helper --helper wrong +# -m helper --helper wrong;;FAIL +-m helper;;FAIL diff --git a/extensions/libxt_ipcomp.t b/extensions/libxt_ipcomp.t new file mode 100644 index 0000000000000000000000000000000000000000..8546ba9ce416f83e0f637947e0c6d1b5ae8def61 --- /dev/null +++ b/extensions/libxt_ipcomp.t @@ -0,0 +1,3 @@ +:INPUT,OUTPUT +-p ipcomp -m ipcomp --ipcompspi 18 -j DROP;=;OK +-p ipcomp -m ipcomp ! --ipcompspi 18 -j ACCEPT;=;OK diff --git a/extensions/libxt_iprange.t b/extensions/libxt_iprange.t new file mode 100644 index 0000000000000000000000000000000000000000..6fd98be656028348d6fc1e3b1bad360e45538809 --- /dev/null +++ b/extensions/libxt_iprange.t @@ -0,0 +1,11 @@ +:INPUT,FORWARD,OUTPUT +-m iprange --src-range 1.1.1.1-1.1.1.10;=;OK +-m iprange ! --src-range 1.1.1.1-1.1.1.10;=;OK +-m iprange --dst-range 1.1.1.1-1.1.1.10;=;OK +-m iprange ! --dst-range 1.1.1.1-1.1.1.10;=;OK +# it shows -A INPUT -m iprange --src-range 1.1.1.1-1.1.1.1, should we support this? +# ERROR: should fail: iptables -A INPUT -m iprange --src-range 1.1.1.1 +# -m iprange --src-range 1.1.1.1;;FAIL +# ERROR: should fail: iptables -A INPUT -m iprange --dst-range 1.1.1.1 +#-m iprange --dst-range 1.1.1.1;;FAIL +-m iprange;;FAIL diff --git a/extensions/libxt_ipvs.c b/extensions/libxt_ipvs.c index a6c57a030d2c643b8898eaa58adea238d599ca26..51952be4245b3405d92bc1d958e9a569ca9260a2 100644 --- a/extensions/libxt_ipvs.c +++ b/extensions/libxt_ipvs.c @@ -27,7 +27,7 @@ enum { static const struct xt_option_entry ipvs_mt_opts[] = { {.name = "ipvs", .id = O_IPVS, .type = XTTYPE_NONE, .flags = XTOPT_INVERT}, - {.name = "vproto", .id = O_VPROTO, .type = XTTYPE_STRING, + {.name = "vproto", .id = O_VPROTO, .type = XTTYPE_PROTOCOL, .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, l4proto)}, {.name = "vaddr", .id = O_VADDR, .type = XTTYPE_HOSTMASK, .flags = XTOPT_INVERT}, @@ -69,9 +69,6 @@ static void ipvs_mt_parse(struct xt_option_call *cb) xtables_option_parse(cb); switch (cb->entry->id) { - case O_VPROTO: - data->l4proto = cb->val.protocol; - break; case O_VADDR: memcpy(&data->vaddr, &cb->val.haddr, sizeof(cb->val.haddr)); memcpy(&data->vmask, &cb->val.hmask, sizeof(cb->val.hmask)); @@ -168,7 +165,7 @@ static void ipvs_mt_dump(const void *ip, const struct xt_ipvs_mtinfo *data, if (data->bitmask & XT_IPVS_PROTO) { if (data->invert & XT_IPVS_PROTO) printf(" !"); - printf(" %sproto %u", prefix, data->l4proto); + printf(" %svproto %u", prefix, data->l4proto); } if (data->bitmask & XT_IPVS_VADDR) { diff --git a/extensions/libxt_ipvs.t b/extensions/libxt_ipvs.t new file mode 100644 index 0000000000000000000000000000000000000000..c2acc6668d1b293e980358054fe28e55853093a4 --- /dev/null +++ b/extensions/libxt_ipvs.t @@ -0,0 +1,20 @@ +:INPUT,FORWARD,OUTPUT +-m ipvs --ipvs;=;OK +-m ipvs ! --ipvs;=;OK +-m ipvs --vproto tcp;-m ipvs --vproto 6;OK +-m ipvs ! --vproto TCP;-m ipvs ! --vproto 6;OK +-m ipvs --vproto 23;=;OK +-m ipvs --vaddr 1.2.3.4;=;OK +-m ipvs ! --vaddr 1.2.3.4/255.255.255.0;-m ipvs ! --vaddr 1.2.3.4/24;OK +-m ipvs --vport http;-m ipvs --vport 80;OK +-m ipvs ! --vport ssh;-m ipvs ! --vport 22;OK +-m ipvs --vport 22;=;OK +-m ipvs ! --vport 443;=;OK +-m ipvs --vdir ORIGINAL;=;OK +-m ipvs --vdir REPLY;=;OK +-m ipvs --vmethod GATE;=;OK +-m ipvs ! --vmethod IPIP;=;OK +-m ipvs --vmethod MASQ;=;OK +-m ipvs --vportctl 21;=;OK +-m ipvs ! --vportctl 21;=;OK +-m ipvs --vproto 6 --vaddr 1.2.3.4/16 --vport 22 --vdir ORIGINAL --vmethod GATE;=;OK diff --git a/extensions/libxt_length.t b/extensions/libxt_length.t new file mode 100644 index 0000000000000000000000000000000000000000..0b6624ee069f68d26bf4029091199c95d2ffaf05 --- /dev/null +++ b/extensions/libxt_length.t @@ -0,0 +1,10 @@ +:INPUT,FORWARD,OUTPUT +-m length --length 1;=;OK +-m length --length :2;-m length --length 0:2;OK +-m length --length 0:3;=;OK +-m length --length 4:;=;OK +-m length --length 0:65535;=;OK +-m length ! --length 0:65535;=;OK +-m length --length 0:65536;;FAIL +-m length --length -1:65535;;FAIL +-m length;;FAIL diff --git a/extensions/libxt_limit.t b/extensions/libxt_limit.t new file mode 100644 index 0000000000000000000000000000000000000000..b0af6538a9c05c04344dd69223e3c6d7a992bedb --- /dev/null +++ b/extensions/libxt_limit.t @@ -0,0 +1,6 @@ +:INPUT,FORWARD,OUTPUT +-m limit --limit 1/sec;=;OK +-m limit --limit 1/min;=;OK +-m limit --limit 1000/hour;=;OK +-m limit --limit 1000/day;=;OK +-m limit --limit 1/sec --limit-burst 1;=;OK diff --git a/extensions/libxt_mac.t b/extensions/libxt_mac.t new file mode 100644 index 0000000000000000000000000000000000000000..a5ec81d80e23d06e1c3f4819a7774885d5aab251 --- /dev/null +++ b/extensions/libxt_mac.t @@ -0,0 +1,5 @@ +:INPUT,FORWARD +-m mac --mac-source 42:01:02:03:04:05;=;OK +-m mac --mac-source 42:01:02:03:04;=;FAIL +-m mac --mac-source 42:01:02:03:04:05:06;=;FAIL +-m mac;;FAIL diff --git a/extensions/libxt_mark.t b/extensions/libxt_mark.t new file mode 100644 index 0000000000000000000000000000000000000000..7c005379f6d64e2d3ad4d141b9b37d2e8f8dc7c6 --- /dev/null +++ b/extensions/libxt_mark.t @@ -0,0 +1,7 @@ +:INPUT,FORWARD,OUTPUT +-m mark --mark 0xfeedcafe/0xfeedcafe;=;OK +-m mark --mark 0;=;OK +-m mark --mark 4294967295;-m mark --mark 0xffffffff;OK +-m mark --mark 4294967296;;FAIL +-m mark --mark -1;;FAIL +-m mark;;FAIL diff --git a/extensions/libxt_multiport.t b/extensions/libxt_multiport.t new file mode 100644 index 0000000000000000000000000000000000000000..e9b80a4ee376b7e49b4722801014a49e70e68a43 --- /dev/null +++ b/extensions/libxt_multiport.t @@ -0,0 +1,23 @@ +:INPUT,FORWARD,OUTPUT +-p tcp -m multiport --sports 53,1024:65535;=;OK +-p tcp -m multiport --dports 53,1024:65535;=;OK +-p udp -m multiport --sports 53,1024:65535;=;OK +-p udp -m multiport --dports 53,1024:65535;=;OK +-p udp -m multiport --ports 53,1024:65535;=;OK +-p udp -m multiport --ports 53,1024:65535;=;OK +-p sctp -m multiport --sports 53,1024:65535;=;OK +-p sctp -m multiport --dports 53,1024:65535;=;OK +-p dccp -m multiport --sports 53,1024:65535;=;OK +-p dccp -m multiport --dports 53,1024:65535;=;OK +-p udplite -m multiport --sports 53,1024:65535;=;OK +-p udplite -m multiport --dports 53,1024:65535;=;OK +-p tcp -m multiport --sports 1024:65536;;FAIL +-p udp -m multiport --sports 1024:65536;;FAIL +-p tcp -m multiport --ports 1024:65536;;FAIL +-p udp -m multiport --ports 1024:65536;;FAIL +-p tcp -m multiport --ports 1,2,3,4,6,7,8,9,10,11,12,13,14,15;=;OK +# fix manpage, it says "up to 15 ports supported" +# ERROR: should fail: iptables -A INPUT -p tcp -m multiport --ports 1,2,3,4,6,7,8,9,10,11,12,13,14,15,16 +# -p tcp -m multiport --ports 1,2,3,4,6,7,8,9,10,11,12,13,14,15,16;;FAIL +-p tcp --multiport;;FAIL +-m multiport;;FAIL diff --git a/extensions/libxt_nfacct.t b/extensions/libxt_nfacct.t new file mode 100644 index 0000000000000000000000000000000000000000..3419b4cebfebf096006ebde4f0c8a510235c7468 --- /dev/null +++ b/extensions/libxt_nfacct.t @@ -0,0 +1,10 @@ +:INPUT,FORWARD,OUTPUT +@nfacct add test +# +# extra space in iptables-save output, fix it +# +# ERROR: cannot load: iptables -A INPUT -m nfacct --nfacct-name test +#-m nfacct --nfacct-name test;=;OK +-m nfacct --nfacct-name wrong;;FAIL +-m nfacct;;FAIL +@nfacct del test diff --git a/extensions/libxt_osf.man b/extensions/libxt_osf.man index f3a85fb02a382580641d75502524eed1752450d0..5ba92ce0db4553d62c64d52284e6c06f33e50b9a 100644 --- a/extensions/libxt_osf.man +++ b/extensions/libxt_osf.man @@ -41,5 +41,5 @@ To remove them again, .PP \fBnfnl_osf -f /usr/share/xtables/pf.os -d\fP .PP -The fingerprint database can be downlaoded from +The fingerprint database can be downloaded from http://www.openbsd.org/cgi-bin/cvsweb/src/etc/pf.os . diff --git a/extensions/libxt_osf.t b/extensions/libxt_osf.t new file mode 100644 index 0000000000000000000000000000000000000000..ede6d32c7cc4c4cdee01b3f929e40f561c7e31ed --- /dev/null +++ b/extensions/libxt_osf.t @@ -0,0 +1,4 @@ +:INPUT,FORWARD +-m osf --genre linux --ttl 0 --log 0;;FAIL +-p tcp -m osf --genre linux --ttl 0 --log 0;=;OK +-p tcp -m osf --genre linux --ttl 3 --log 0;;FAIL diff --git a/extensions/libxt_owner.t b/extensions/libxt_owner.t new file mode 100644 index 0000000000000000000000000000000000000000..aec30b655e9a50537cec02d9ad745a78f52b6e5a --- /dev/null +++ b/extensions/libxt_owner.t @@ -0,0 +1,12 @@ +:OUTPUT,POSTROUTING +*mangle +-m owner --uid-owner root;-m owner --uid-owner 0;OK +-m owner --uid-owner 0-10;=;OK +-m owner --gid-owner root;-m owner --gid-owner 0;OK +-m owner --gid-owner 0-10;=;OK +-m owner --uid-owner root --gid-owner root;-m owner --uid-owner 0 --gid-owner 0;OK +-m owner --uid-owner 0-10 --gid-owner 0-10;=;OK +-m owner ! --uid-owner root;-m owner ! --uid-owner 0;OK +-m owner --socket-exists;=;OK +:INPUT +-m owner --uid-owner root;;FAIL diff --git a/extensions/libxt_physdev.t b/extensions/libxt_physdev.t new file mode 100644 index 0000000000000000000000000000000000000000..1fab7e1920d259aafb8c2ca899218e51dd59d671 --- /dev/null +++ b/extensions/libxt_physdev.t @@ -0,0 +1,14 @@ +:INPUT,FORWARD +-m physdev --physdev-in lo;=;OK +-m physdev --physdev-is-in --physdev-in lo;=;OK +:OUTPUT,FORWARD +# xt_physdev: using --physdev-out in the OUTPUT, FORWARD and POSTROUTING chains for non-bridged traffic is not supported anymore. +# ERROR: should fail: iptables -A FORWARD -m physdev --physdev-out lo +#-m physdev --physdev-out lo;;FAIL +# ERROR: cannot load: iptables -A OUTPUT -m physdev --physdev-is-out --physdev-out lo +#-m physdev --physdev-is-out --physdev-out lo;=;OK +:FORWARD +-m physdev --physdev-in lo --physdev-is-bridged;=;OK +:POSTROUTING +*mangle +-m physdev --physdev-out lo --physdev-is-bridged;=;OK diff --git a/extensions/libxt_pkttype.t b/extensions/libxt_pkttype.t new file mode 100644 index 0000000000000000000000000000000000000000..d93baeaf24ec317c5483dd364a21016690b3fcd3 --- /dev/null +++ b/extensions/libxt_pkttype.t @@ -0,0 +1,6 @@ +:INPUT,FORWARD,OUTPUT +-m pkttype --pkt-type unicast;=;OK +-m pkttype --pkt-type broadcast;=;OK +-m pkttype --pkt-type multicast;=;OK +-m pkttype --pkt-type wrong;;FAIL +-m pkttype;;FAIL diff --git a/extensions/libxt_policy.t b/extensions/libxt_policy.t new file mode 100644 index 0000000000000000000000000000000000000000..6524122bcf793f439bb29bbf612c2dff0f16929c --- /dev/null +++ b/extensions/libxt_policy.t @@ -0,0 +1,8 @@ +:INPUT,FORWARD +-m policy --dir in --pol ipsec;=;OK +-m policy --dir in --pol ipsec --proto ipcomp;=;OK +-m policy --dir in --pol ipsec --strict;;FAIL +-m policy --dir in --pol ipsec --strict --reqid 1 --spi 0x1 --proto ipcomp;=;OK +-m policy --dir in --pol ipsec --strict --reqid 1 --spi 0x1 --proto esp --mode tunnel --tunnel-dst 10.0.0.0/8 --tunnel-src 10.0.0.0/8 --next --reqid 2;=;OK +-m policy --dir in --pol ipsec --strict --reqid 1 --spi 0x1 --proto esp --tunnel-dst 10.0.0.0/8;;FAIL +-m policy --dir in --pol ipsec --strict --reqid 1 --spi 0x1 --proto ipcomp --mode tunnel --tunnel-dst 10.0.0.0/8 --tunnel-src 10.0.0.0/8 --next --reqid 2;=;OK diff --git a/extensions/libxt_quota.t b/extensions/libxt_quota.t new file mode 100644 index 0000000000000000000000000000000000000000..c568427974f8460ca2e864f9d67dc3ca2777aa7f --- /dev/null +++ b/extensions/libxt_quota.t @@ -0,0 +1,7 @@ +:INPUT,FORWARD,OUTPUT +-m quota --quota 0;=;OK +-m quota ! --quota 0;=;OK +-m quota --quota 18446744073709551615;=;OK +-m quota ! --quota 18446744073709551615;=;OK +-m quota --quota 18446744073709551616;;FAIL +-m quota;;FAIL diff --git a/extensions/libxt_rateest.t b/extensions/libxt_rateest.t new file mode 100644 index 0000000000000000000000000000000000000000..c5158614f46a3db062d34a45e18d7eb85dd90be8 --- /dev/null +++ b/extensions/libxt_rateest.t @@ -0,0 +1,16 @@ +:INPUT,FORWARD,OUTPUT +%iptables -I INPUT -j RATEEST --rateest-name RE1 --rateest-interval 250.0ms --rateest-ewmalog 500.0ms +-m rateest --rateest RE1 --rateest-lt --rateest-bps 8bit;=;OK +-m rateest --rateest RE1 --rateest-eq --rateest-pps 5;=;OK +-m rateest --rateest RE1 --rateest-gt --rateest-bps 5kbit;-m rateest --rateest RE1 --rateest-gt --rateest-bps 5000bit;OK +-m rateest --rateest-delta --rateest RE1 --rateest-bps1 8bit --rateest-lt --rateest-bps2 16bit;=;OK +%iptables -I INPUT -j RATEEST --rateest-name RE2 --rateest-interval 250.0ms --rateest-ewmalog 500.0ms +-m rateest --rateest1 RE1 --rateest-lt --rateest-bps --rateest2 RE2;=;OK +-m rateest --rateest-delta --rateest1 RE1 --rateest-pps1 0 --rateest-lt --rateest-pps2 42 --rateest2 RE2;=;OK +-m rateest --rateest-delta --rateest RE1 --rateest-bps1 8bit --rateest-eq --rateest-bps2 16bit;=;OK +-m rateest --rateest-delta --rateest RE1 --rateest-bps1 8bit --rateest-gt --rateest-bps2 16bit;=;OK +-m rateest --rateest-delta --rateest RE1 --rateest-pps1 8 --rateest-lt --rateest-pps2 9;=;OK +-m rateest --rateest-delta --rateest RE1 --rateest-pps1 8 --rateest-eq --rateest-pps2 9;=;OK +-m rateest --rateest-delta --rateest RE1 --rateest-pps1 8 --rateest-gt --rateest-pps2 9;=;OK +%iptables -D INPUT -j RATEEST --rateest-name RE1 --rateest-interval 250.0ms --rateest-ewmalog 500.0ms +%iptables -D INPUT -j RATEEST --rateest-name RE2 --rateest-interval 250.0ms --rateest-ewmalog 500.0ms diff --git a/extensions/libxt_recent.t b/extensions/libxt_recent.t new file mode 100644 index 0000000000000000000000000000000000000000..9a83918ea583581ab6db4ba44a929da6e7bba2b9 --- /dev/null +++ b/extensions/libxt_recent.t @@ -0,0 +1,11 @@ +:INPUT,FORWARD,OUTPUT +-m recent --set;=;OK +-m recent --rcheck --hitcount 8 --name foo --mask 255.255.255.255 --rsource;=;OK +-m recent --rcheck --hitcount 12 --name foo --mask 255.255.255.255 --rsource;=;OK +-m recent --update --rttl;=;OK +-m recent --set --rttl;;FAIL +-m recent --rcheck --hitcount 999 --name foo --mask 255.255.255.255 --rsource;;FAIL +# nonsensical, but all should load successfully: +-m recent --rcheck --hitcount 3 --name foo --mask 255.255.255.255 --rsource -m recent --rcheck --hitcount 4 --name foo --mask 255.255.255.255 --rsource;=;OK +-m recent --rcheck --hitcount 4 --name foo --mask 255.255.255.255 --rsource -m recent --rcheck --hitcount 4 --name foo --mask 255.255.255.255 --rsource;=;OK +-m recent --rcheck --hitcount 8 --name foo --mask 255.255.255.255 --rsource -m recent --rcheck --hitcount 12 --name foo --mask 255.255.255.255 --rsource;=;OK diff --git a/extensions/libxt_rpfilter.t b/extensions/libxt_rpfilter.t new file mode 100644 index 0000000000000000000000000000000000000000..390268f35bce0f30f4f4678be8b13413c3237288 --- /dev/null +++ b/extensions/libxt_rpfilter.t @@ -0,0 +1,4 @@ +:PREROUTING +*mangle +-m rpfilter;=;OK +-m rpfilter --loose --validmark --accept-local --invert;=;OK diff --git a/extensions/libxt_sctp.t b/extensions/libxt_sctp.t new file mode 100644 index 0000000000000000000000000000000000000000..4016e4fb1880e8423a9659532439ccc1b0e9f9c7 --- /dev/null +++ b/extensions/libxt_sctp.t @@ -0,0 +1,29 @@ +:INPUT,FORWARD,OUTPUT +-p sctp -m sctp --sport 1;=;OK +-p sctp -m sctp --sport 65535;=;OK +-p sctp -m sctp --sport 1:65535;=;OK +-p sctp -m sctp --sport -1;;FAIL +-p sctp -m sctp --sport 65536;;FAIL +-p sctp -m sctp --dport 1;=;OK +-p sctp -m sctp --dport 1:65535;=;OK +-p sctp -m sctp --dport 65535;=;OK +-p sctp -m sctp --dport -1;;FAIL +-p sctp -m sctp --dport 65536;;FAIL +-p sctp -m sctp --chunk-types all DATA;=;OK +-p sctp -m sctp --chunk-types all INIT;=;OK +-p sctp -m sctp --chunk-types all INIT_ACK;=;OK +-p sctp -m sctp --chunk-types all SACK;=;OK +-p sctp -m sctp --chunk-types all HEARTBEAT;=;OK +-p sctp -m sctp --chunk-types all HEARTBEAT_ACK;=;OK +-p sctp -m sctp --chunk-types all ABORT;=;OK +-p sctp -m sctp --chunk-types all SHUTDOWN;=;OK +-p sctp -m sctp --chunk-types all SHUTDOWN_ACK;=;OK +-p sctp -m sctp --chunk-types all ERROR;=;OK +-p sctp -m sctp --chunk-types all COOKIE_ECHO;=;OK +-p sctp -m sctp --chunk-types all COOKIE_ACK;=;OK +-p sctp -m sctp --chunk-types all ECN_ECNE;=;OK +-p sctp -m sctp --chunk-types all ECN_CWR;=;OK +-p sctp -m sctp --chunk-types all ASCONF;=;OK +-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 diff --git a/extensions/libxt_set.t b/extensions/libxt_set.t new file mode 100644 index 0000000000000000000000000000000000000000..dd9e9f175b5f8b77f22ec06e684064f86551a5e3 --- /dev/null +++ b/extensions/libxt_set.t @@ -0,0 +1,4 @@ +:INPUT,FORWARD,OUTPUT +-m set --match-set foo;;FAIL +# fails: foo does not exist +-m set --match-set foo src,dst;;FAIL diff --git a/extensions/libxt_socket.t b/extensions/libxt_socket.t new file mode 100644 index 0000000000000000000000000000000000000000..fe4eb3e4ba2d2331e5f50fe949eca77464aba8dd --- /dev/null +++ b/extensions/libxt_socket.t @@ -0,0 +1,8 @@ +:PREROUTING,INPUT +*mangle +-m socket;=;OK +-m socket --transparent --nowildcard;=;OK +-m socket --transparent --nowildcard --restore-skmark;=;OK +-m socket --transparent --restore-skmark;=;OK +-m socket --nowildcard --restore-skmark;=;OK +-m socket --restore-skmark;=;OK diff --git a/extensions/libxt_standard.t b/extensions/libxt_standard.t new file mode 100644 index 0000000000000000000000000000000000000000..4313f7b7bac9d3d68d5e2be7104b9997fa7d4ad5 --- /dev/null +++ b/extensions/libxt_standard.t @@ -0,0 +1,11 @@ +:INPUT,FORWARD,OUTPUT +-s 127.0.0.1/32 -d 0.0.0.0/8 -j DROP;=;OK +! -s 0.0.0.0 -j ACCEPT;! -s 0.0.0.0/32 -j ACCEPT;OK +! -d 0.0.0.0/32 -j ACCEPT;=;OK +-s 0.0.0.0/24 -j RETURN;=;OK +-p tcp -j ACCEPT;=;OK +! -p udp -j ACCEPT;=;OK +-j DROP;=;OK +-j ACCEPT;=;OK +-j RETURN;=;OK +! -p 0 -j ACCEPT;=;FAIL diff --git a/extensions/libxt_state.t b/extensions/libxt_state.t new file mode 100644 index 0000000000000000000000000000000000000000..8e4bce3f96e34d7ab5f42106438ccf951cdcdd2d --- /dev/null +++ b/extensions/libxt_state.t @@ -0,0 +1,6 @@ +:INPUT,FORWARD,OUTPUT +-m state --state INVALID;=;OK +-m state --state NEW,RELATED;=;OK +-m state --state UNTRACKED;=;OK +-m state wrong;;FAIL +-m state;;FAIL diff --git a/extensions/libxt_statistic.t b/extensions/libxt_statistic.t new file mode 100644 index 0000000000000000000000000000000000000000..bb6673dae5e4a9667ff8ad313b748d1d3906d3bc --- /dev/null +++ b/extensions/libxt_statistic.t @@ -0,0 +1,8 @@ +:INPUT,FORWARD,OUTPUT +-m statistic;;FAIL +-m statistic --mode random ! --probability 0.50000000000;=;OK +-m statistic --mode random ! --probability 1.1;;FAIL +-m statistic --probability 1;;FAIL +-m statistic --mode nth ! --every 5 --packet 2;=;OK +-m statistic --mode nth ! --every 5;;FAIL +-m statistic --mode nth ! --every 5 --packet 5;;FAIL diff --git a/extensions/libxt_string.t b/extensions/libxt_string.t new file mode 100644 index 0000000000000000000000000000000000000000..d68f099d966c6aab15d800595790bf9edb905dea --- /dev/null +++ b/extensions/libxt_string.t @@ -0,0 +1,18 @@ +:INPUT,FORWARD,OUTPUT +# ERROR: cannot find: iptables -I INPUT -m string --algo bm --string "test" +# -m string --algo bm --string "test";=;OK +# ERROR: cannot find: iptables -I INPUT -m string --algo kmp --string "test") +# -m string --algo kmp --string "test";=;OK +# ERROR: cannot find: iptables -I INPUT -m string --algo kmp ! --string "test" +# -m string --algo kmp ! --string "test";=;OK +# cannot find: iptables -I INPUT -m string --algo bm --string "xxxxxxxxxxx" ....] +# -m string --algo bm --string "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";=;OK +# ERROR: cannot load: iptables -A INPUT -m string --algo bm --string "xxxx" +# -m string --algo bm --string "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";=;OK +# ERROR: cannot load: iptables -A INPUT -m string --algo bm --hexstring "|0a0a0a0a|" +# -m string --algo bm --hexstring "|0a0a0a0a|";=;OK +# ERROR: cannot find: iptables -I INPUT -m string --algo bm --from 0 --to 65535 --string "test" +# -m string --algo bm --from 0 --to 65535 --string "test";=;OK +-m string --algo wrong;;FAIL +-m string --algo bm;;FAIL +-m string;;FAIL diff --git a/extensions/libxt_tcp.t b/extensions/libxt_tcp.t new file mode 100644 index 0000000000000000000000000000000000000000..b0e8006e51869584850ff22f2076b2c9125f30ee --- /dev/null +++ b/extensions/libxt_tcp.t @@ -0,0 +1,26 @@ +:INPUT,FORWARD,OUTPUT +-p tcp -m tcp --sport 1;=;OK +-p tcp -m tcp --sport 65535;=;OK +-p tcp -m tcp --dport 1;=;OK +-p tcp -m tcp --dport 65535;=;OK +-p tcp -m tcp --sport 1:1023;=;OK +-p tcp -m tcp --sport 1024:65535;=;OK +-p tcp -m tcp --sport 1024:;-p tcp -m tcp --sport 1024:65535;OK +-p tcp -m tcp ! --sport 1;=;OK +-p tcp -m tcp ! --sport 65535;=;OK +-p tcp -m tcp ! --dport 1;=;OK +-p tcp -m tcp ! --dport 65535;=;OK +-p tcp -m tcp --sport 1 --dport 65535;=;OK +-p tcp -m tcp --sport 65535 --dport 1;=;OK +-p tcp -m tcp ! --sport 1 --dport 65535;=;OK +-p tcp -m tcp ! --sport 65535 --dport 1;=;OK +-p tcp -m tcp --sport 65536;;FAIL +-p tcp -m tcp --sport -1;;FAIL +-p tcp -m tcp --dport -1;;FAIL +-p tcp -m tcp --syn;-p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN;OK +-p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN;=;OK +-p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG SYN;=;OK +-p tcp -m tcp ! --tcp-flags FIN,SYN,RST,PSH,ACK,URG SYN;=;OK +-p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG RST;=;OK +# should we accept this below? +-p tcp -m tcp;=;OK diff --git a/extensions/libxt_tcpmss.t b/extensions/libxt_tcpmss.t new file mode 100644 index 0000000000000000000000000000000000000000..2b415957ffd00e98b0bb26692be2b998a31c2682 --- /dev/null +++ b/extensions/libxt_tcpmss.t @@ -0,0 +1,6 @@ +:INPUT,FORWARD,OUTPUT +-m tcpmss --mss 42;;FAIL +-p tcp -m tcpmss --mss 42;=;OK +-p tcp -m tcpmss --mss 42:12345;=;OK +-p tcp -m tcpmss --mss 42:65536;;FAIL +-p tcp -m tcpmss --mss 65535:1000;;FAIL diff --git a/extensions/libxt_time.t b/extensions/libxt_time.t new file mode 100644 index 0000000000000000000000000000000000000000..673af09b21fe22a7b89e84593912f265c33cb0d3 --- /dev/null +++ b/extensions/libxt_time.t @@ -0,0 +1,4 @@ +:INPUT,FORWARD,OUTPUT +-m time --timestart 01:02:03 --timestop 04:05:06 --monthdays 1,2,3,4,5 --weekdays Mon,Fri,Sun --datestart 2001-02-03T04:05:06 --datestop 2012-09-08T09:06:05 --kerneltz;=;OK +-m time --timestart 01:02:03 --timestop 04:05:06 --monthdays 1,2,3,4,5 --weekdays Mon,Fri,Sun --datestart 2001-02-03T04:05:06 --datestop 2012-09-08T09:06:05;=;OK +-m time --timestart 02:00:00 --timestop 03:00:00 --datestart 1970-01-01T02:00:00 --datestop 1970-01-01T03:00:00;=;OK diff --git a/extensions/libxt_tos.t b/extensions/libxt_tos.t new file mode 100644 index 0000000000000000000000000000000000000000..ccbe80099bdd9135befcf908a3bfe3b8914b14a7 --- /dev/null +++ b/extensions/libxt_tos.t @@ -0,0 +1,13 @@ +:INPUT,FORWARD,OUTPUT +-m tos --tos Minimize-Delay;-m tos --tos 0x10/0x3f;OK +-m tos --tos Maximize-Throughput;-m tos --tos 0x08/0x3f;OK +-m tos --tos Maximize-Reliability;-m tos --tos 0x04/0x3f;OK +-m tos --tos Minimize-Cost;-m tos --tos 0x02/0x3f;OK +-m tos --tos Normal-Service;-m tos --tos 0x00/0x3f;OK +-m tos --tos 0xff;=;OK +-m tos ! --tos 0xff;=;OK +-m tos --tos 0x00;=;OK +-m tos --tos 0x0f;=;OK +-m tos --tos 0x0f/0x0f;=;OK +-m tos --tos wrong;;FAIL +-m tos;;FAIL diff --git a/extensions/libxt_u32.t b/extensions/libxt_u32.t new file mode 100644 index 0000000000000000000000000000000000000000..0d9be47a10e84bff06246cdcff9abcb7e7d84800 --- /dev/null +++ b/extensions/libxt_u32.t @@ -0,0 +1,2 @@ +:INPUT,FORWARD,OUTPUT +-m u32 --u32 "0x0=0x0&&0x0=0x1";=;OK diff --git a/extensions/libxt_udp.t b/extensions/libxt_udp.t new file mode 100644 index 0000000000000000000000000000000000000000..1b4d3dd62575989bbfe77027ee03b4fdaa0d1d4c --- /dev/null +++ b/extensions/libxt_udp.t @@ -0,0 +1,22 @@ +:INPUT,OUTPUT,FORWARD +-p udp -m udp --sport 1;=;OK +-p udp -m udp --sport 65535;=;OK +-p udp -m udp --dport 1;=;OK +-p udp -m udp --dport 65535;=;OK +-p udp -m udp --sport 1:1023;=;OK +-p udp -m udp --sport 1024:65535;=;OK +-p udp -m udp --sport 1024:;-p udp -m udp --sport 1024:65535;OK +-p udp -m udp ! --sport 1;=;OK +-p udp -m udp ! --sport 65535;=;OK +-p udp -m udp ! --dport 1;=;OK +-p udp -m udp ! --dport 65535;=;OK +-p udp -m udp --sport 1 --dport 65535;=;OK +-p udp -m udp --sport 65535 --dport 1;=;OK +-p udp -m udp ! --sport 1 --dport 65535;=;OK +-p udp -m udp ! --sport 65535 --dport 1;=;OK +# ERRROR: should fail: iptables -A INPUT -p udp -m udp --sport 65536 +# -p udp -m udp --sport 65536;;FAIL +-p udp -m udp --sport -1;;FAIL +-p udp -m udp --dport -1;;FAIL +# should we accept this below? +-p udp -m udp;=;OK diff --git a/include/libiptc/xtcshared.h b/include/libiptc/xtcshared.h index 773ebc4c77e2c8152d19c9d4dac08f2737868909..341f9d4fac5d0fc4637945a0802e186254ba42be 100644 --- a/include/libiptc/xtcshared.h +++ b/include/libiptc/xtcshared.h @@ -7,11 +7,16 @@ struct xt_counters; struct xtc_ops { int (*commit)(struct xtc_handle *); + struct xtc_handle *(*init)(const char *); void (*free)(struct xtc_handle *); int (*builtin)(const char *, struct xtc_handle *const); int (*is_chain)(const char *, struct xtc_handle *const); int (*flush_entries)(const xt_chainlabel, struct xtc_handle *); int (*create_chain)(const xt_chainlabel, struct xtc_handle *); + const char *(*first_chain)(struct xtc_handle *); + const char *(*next_chain)(struct xtc_handle *); + const char *(*get_policy)(const char *, struct xt_counters *, + struct xtc_handle *); int (*set_policy)(const xt_chainlabel, const xt_chainlabel, struct xt_counters *, struct xtc_handle *); const char *(*strerror)(int); diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index c3f087ac680c32516986c20fbce1508ba6c7d7aa..042d8b1478e0a37d53143e1e1002598afc5cfe88 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -3,8 +3,10 @@ #include +#ifndef _NETINET_IN_H #include #include +#endif #include /* Responses from hook functions. */ diff --git a/iptables-test.py b/iptables-test.py new file mode 100755 index 0000000000000000000000000000000000000000..532dee7c9000fbdd1e46347eb5a6087f3b011f41 --- /dev/null +++ b/iptables-test.py @@ -0,0 +1,373 @@ +#!/usr/bin/python +# +# (C) 2012-2013 by Pablo Neira Ayuso +# +# 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 software has been sponsored by Sophos Astaro +# + +import sys +import os +import subprocess +import argparse + +IPTABLES = "iptables" +IP6TABLES = "ip6tables" +ARPTABLES = "arptables" +EBTABLES = "ebtables" + +IPTABLES_SAVE = "iptables-save" +IP6TABLES_SAVE = "ip6tables-save" +ARPTABLES_SAVE = "arptables-save" +EBTABLES_SAVE = "ebtables-save" +#IPTABLES_SAVE = ['xtables-save','-4'] +#IP6TABLES_SAVE = ['xtables-save','-6'] + +EXTENSIONS_PATH = "extensions" +LOGFILE="/tmp/iptables-test.log" +log_file = None + + +class Colors: + HEADER = '\033[95m' + BLUE = '\033[94m' + GREEN = '\033[92m' + YELLOW = '\033[93m' + RED = '\033[91m' + ENDC = '\033[0m' + + +def print_error(reason, filename=None, lineno=None): + ''' + Prints an error with nice colors, indicating file and line number. + ''' + print (filename + ": " + Colors.RED + "ERROR" + + Colors.ENDC + ": line %d (%s)" % (lineno, reason)) + + +def delete_rule(iptables, rule, filename, lineno): + ''' + Removes an iptables rule + ''' + cmd = iptables + " -D " + rule + ret = execute_cmd(cmd, filename, lineno) + if ret == 1: + reason = "cannot delete: " + iptables + " -I " + rule + print_error(reason, filename, lineno) + return -1 + + return 0 + + +def run_test(iptables, rule, rule_save, res, filename, lineno, netns): + ''' + Executes an unit test. Returns the output of delete_rule(). + + Parameters: + :param iptables: string with the iptables command to execute + :param rule: string with iptables arguments for the rule to test + :param rule_save: string to find the rule in the output of iptables -save + :param 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) + ''' + ret = 0 + + cmd = iptables + " -A " + rule + if netns: + cmd = "ip netns exec ____iptables-container-test " + EXECUTEABLE + " " + cmd + + ret = execute_cmd(cmd, filename, lineno) + + # + # report failed test + # + if ret: + if res == "OK": + reason = "cannot load: " + cmd + print_error(reason, filename, lineno) + return -1 + else: + # do not report this error + return 0 + else: + if res == "FAIL": + reason = "should fail: " + cmd + print_error(reason, filename, lineno) + delete_rule(iptables, rule, filename, lineno) + return -1 + + matching = 0 + splitted = iptables.split(" ") + if len(splitted) == 2: + if splitted[1] == '-4': + command = IPTABLES_SAVE + elif splitted[1] == '-6': + command = IP6TABLES_SAVE + elif len(splitted) == 1: + if splitted[0] == IPTABLES: + command = IPTABLES_SAVE + elif splitted[0] == IP6TABLES: + command = IP6TABLES_SAVE + elif splitted[0] == ARPTABLES: + command = ARPTABLES_SAVE + elif splitted[0] == EBTABLES: + command = EBTABLES_SAVE + + path = os.path.abspath(os.path.curdir) + "/iptables/" + EXECUTEABLE + command = path + " " + command + + if netns: + command = "ip netns exec ____iptables-container-test " + command + + args = splitted[1:] + proc = subprocess.Popen(command, shell=True, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + out, err = proc.communicate() + + # + # check for segfaults + # + if proc.returncode == -11: + reason = "iptables-save segfaults: " + cmd + print_error(reason, filename, lineno) + delete_rule(iptables, rule, filename, lineno) + return -1 + + # find the rule + matching = out.find(rule_save) + if matching < 0: + reason = "cannot find: " + iptables + " -I " + rule + print_error(reason, filename, lineno) + delete_rule(iptables, rule, filename, lineno) + return -1 + + # Test "ip netns del NETNS" path with rules in place + if netns: + return 0 + + return delete_rule(iptables, rule, filename, lineno) + +def execute_cmd(cmd, filename, lineno): + ''' + Executes a command, checking for segfaults and returning the command exit + code. + + :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) + ''' + global log_file + if cmd.startswith('iptables ') or cmd.startswith('ip6tables ') or cmd.startswith('ebtables ') or cmd.startswith('arptables '): + cmd = os.path.abspath(os.path.curdir) + "/iptables/" + EXECUTEABLE + " " + cmd + + print >> log_file, "command: %s" % cmd + ret = subprocess.call(cmd, shell=True, universal_newlines=True, + stderr=subprocess.STDOUT, stdout=log_file) + log_file.flush() + + # generic check for segfaults + if ret == -11: + reason = "command segfaults: " + cmd + print_error(reason, filename, lineno) + return ret + + +def run_test_file(filename, netns): + ''' + Runs a test file + + :param filename: name of the file with the test rules + ''' + # + # if this is not a test file, skip. + # + if not filename.endswith(".t"): + return 0, 0 + + if "libipt_" in filename: + iptables = IPTABLES + elif "libip6t_" in filename: + iptables = IP6TABLES + elif "libxt_" in filename: + iptables = IPTABLES + elif "libarpt_" in filename: + # only supported with nf_tables backend + if EXECUTEABLE != "xtables-nft-multi": + return 0, 0 + iptables = ARPTABLES + elif "libebt_" in filename: + # only supported with nf_tables backend + if EXECUTEABLE != "xtables-nft-multi": + return 0, 0 + iptables = EBTABLES + else: + # default to iptables if not known prefix + iptables = IPTABLES + + f = open(filename) + + tests = 0 + passed = 0 + table = "" + total_test_passed = True + + if netns: + execute_cmd("ip netns add ____iptables-container-test", filename, 0) + + for lineno, line in enumerate(f): + if line[0] == "#": + continue + + if line[0] == ":": + 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_cmd = line.rstrip()[1:] + if netns: + external_cmd = "ip netns exec ____iptables-container-test " + EXECUTEABLE + " " + external_cmd + execute_cmd(external_cmd, filename, lineno) + continue + + if line[0] == "*": + table = line.rstrip()[1:] + continue + + if len(chain_array) == 0: + print "broken test, missing chain, leaving" + sys.exit() + + test_passed = True + tests += 1 + + for chain in chain_array: + item = line.split(";") + if table == "": + rule = chain + " " + item[0] + else: + rule = chain + " -t " + table + " " + item[0] + + if item[1] == "=": + rule_save = chain + " " + item[0] + else: + rule_save = chain + " " + item[1] + + res = item[2].rstrip() + ret = run_test(iptables, rule, rule_save, + res, filename, lineno + 1, netns) + + if ret < 0: + test_passed = False + total_test_passed = False + break + + if test_passed: + passed += 1 + + if netns: + execute_cmd("ip netns del ____iptables-container-test", filename, 0) + if total_test_passed: + print filename + ": " + Colors.GREEN + "OK" + Colors.ENDC + + f.close() + return tests, passed + + +def show_missing(): + ''' + Show the list of missing test files + ''' + file_list = os.listdir(EXTENSIONS_PATH) + testfiles = [i for i in file_list if i.endswith('.t')] + libfiles = [i for i in file_list + if i.startswith('lib') and i.endswith('.c')] + + def test_name(x): + return x[0:-2] + '.t' + missing = [test_name(i) for i in libfiles + if not test_name(i) in testfiles] + + print '\n'.join(missing) + + +# +# main +# +def main(): + parser = argparse.ArgumentParser(description='Run iptables tests') + parser.add_argument('filename', nargs='?', + metavar='path/to/file.t', + help='Run only this test') + parser.add_argument('-l', '--legacy', action='store_true', + help='Test iptables-legacy') + parser.add_argument('-m', '--missing', action='store_true', + 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', + help='Test netnamespace path') + args = parser.parse_args() + + # + # show list of missing test files + # + if args.missing: + show_missing() + return + + global EXECUTEABLE + EXECUTEABLE = "xtables-legacy-multi" + if args.nftables: + EXECUTEABLE = "xtables-nft-multi" + + if os.getuid() != 0: + print "You need to be root to run this, sorry" + return + + os.putenv("XTABLES_LIBDIR", os.path.abspath(EXTENSIONS_PATH)) + 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 + return + + file_list = [os.path.join(EXTENSIONS_PATH, i) + for i in os.listdir(EXTENSIONS_PATH)] + if args.filename: + file_list = [args.filename] + 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)) + + +if __name__ == '__main__': + main() diff --git a/iptables/.gitignore b/iptables/.gitignore index d0301c6de896e147ba4798b1cd814204978b5516..c638139b8a1d085aad49aa9dd3ec0b54c0aacb68 100644 --- a/iptables/.gitignore +++ b/iptables/.gitignore @@ -2,6 +2,7 @@ /ip6tables-save /ip6tables-restore /ip6tables-static +/ip6tables-translate.8 /iptables /iptables.8 /iptables-extensions.8 @@ -11,6 +12,7 @@ /iptables-restore /iptables-restore.8 /iptables-static +/iptables-translate.8 /iptables-xml /iptables-xml.1 /xtables-multi diff --git a/iptables/Makefile.am b/iptables/Makefile.am index 581dc32ba846b9b1ab4278631f7adb591ba77039..3ff85893b2fa8fb48592b8696b055de5ce39d040 100644 --- a/iptables/Makefile.am +++ b/iptables/Makefile.am @@ -13,18 +13,16 @@ if ENABLE_STATIC xtables_legacy_multi_CFLAGS += -DALL_INCLUSIVE endif if ENABLE_IPV4 -xtables_legacy_multi_SOURCES += iptables-save.c iptables-restore.c \ - iptables-standalone.c iptables.c +xtables_legacy_multi_SOURCES += iptables-standalone.c iptables.c 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-save.c ip6tables-restore.c \ - ip6tables-standalone.c ip6tables.c +xtables_legacy_multi_SOURCES += ip6tables-standalone.c ip6tables.c xtables_legacy_multi_CFLAGS += -DENABLE_IPV6 xtables_legacy_multi_LDADD += ../libiptc/libip6tc.la ../extensions/libext6.a endif -xtables_legacy_multi_SOURCES += xshared.c +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 @@ -62,8 +60,14 @@ man_MANS = iptables.8 iptables-restore.8 iptables-save.8 \ iptables-xml.1 ip6tables.8 ip6tables-restore.8 \ ip6tables-save.8 iptables-extensions.8 \ xtables-nft.8 xtables-translate.8 xtables-legacy.8 \ + iptables-translate.8 ip6tables-translate.8 \ xtables-monitor.8 +if ENABLE_NFTABLES +man_MANS += arptables-nft.8 arptables-nft-restore.8 arptables-nft-save.8 \ + ebtables-nft.8 +endif CLEANFILES = iptables.8 xtables-monitor.8 \ + iptables-translate.8 ip6tables-translate.8 \ xtables-config-parser.c xtables-config-syntax.c vx_bin_links = iptables-xml @@ -94,6 +98,9 @@ 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: + ${AM_VERBOSE_GEN} echo '.so man8/xtables-translate.8' >$@ + pkgconfig_DATA = xtables.pc # Using if..fi avoids an ugly "error (ignored)" message :) diff --git a/iptables/Makefile.in b/iptables/Makefile.in index d631fba8e6acc2837629ded965f7a3a85c979c43..0b4c92b3ce0766483dbf90982c67e2f95c8e744b 100644 --- a/iptables/Makefile.in +++ b/iptables/Makefile.in @@ -91,14 +91,10 @@ POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ @ENABLE_STATIC_TRUE@am__append_1 = -DALL_INCLUSIVE -@ENABLE_IPV4_TRUE@am__append_2 = iptables-save.c iptables-restore.c \ -@ENABLE_IPV4_TRUE@ iptables-standalone.c iptables.c - +@ENABLE_IPV4_TRUE@am__append_2 = iptables-standalone.c iptables.c @ENABLE_IPV4_TRUE@am__append_3 = -DENABLE_IPV4 @ENABLE_IPV4_TRUE@am__append_4 = ../libiptc/libip4tc.la ../extensions/libext4.a -@ENABLE_IPV6_TRUE@am__append_5 = ip6tables-save.c ip6tables-restore.c \ -@ENABLE_IPV6_TRUE@ ip6tables-standalone.c ip6tables.c - +@ENABLE_IPV6_TRUE@am__append_5 = ip6tables-standalone.c ip6tables.c @ENABLE_IPV6_TRUE@am__append_6 = -DENABLE_IPV6 @ENABLE_IPV6_TRUE@am__append_7 = ../libiptc/libip6tc.la ../extensions/libext6.a @@ -107,6 +103,9 @@ host_triplet = @host@ @ENABLE_NFTABLES_TRUE@@ENABLE_STATIC_TRUE@am__append_9 = -DALL_INCLUSIVE sbin_PROGRAMS = xtables-legacy-multi$(EXEEXT) $(am__EXEEXT_1) @ENABLE_NFTABLES_TRUE@am__append_10 = xtables-nft-multi +@ENABLE_NFTABLES_TRUE@am__append_11 = arptables-nft.8 arptables-nft-restore.8 arptables-nft-save.8 \ +@ENABLE_NFTABLES_TRUE@ ebtables-nft.8 + subdir = iptables ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_linker_flags.m4 \ @@ -127,22 +126,19 @@ am__installdirs = "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man1dir)" \ "$(DESTDIR)$(man8dir)" "$(DESTDIR)$(pkgconfigdir)" PROGRAMS = $(sbin_PROGRAMS) am__xtables_legacy_multi_SOURCES_DIST = xtables-legacy-multi.c \ - iptables-xml.c iptables-save.c iptables-restore.c \ - iptables-standalone.c iptables.c ip6tables-save.c \ - ip6tables-restore.c ip6tables-standalone.c ip6tables.c \ - xshared.c -@ENABLE_IPV4_TRUE@am__objects_1 = xtables_legacy_multi-iptables-save.$(OBJEXT) \ -@ENABLE_IPV4_TRUE@ xtables_legacy_multi-iptables-restore.$(OBJEXT) \ -@ENABLE_IPV4_TRUE@ xtables_legacy_multi-iptables-standalone.$(OBJEXT) \ + iptables-xml.c iptables-standalone.c iptables.c \ + ip6tables-standalone.c ip6tables.c xshared.c \ + iptables-restore.c iptables-save.c +@ENABLE_IPV4_TRUE@am__objects_1 = xtables_legacy_multi-iptables-standalone.$(OBJEXT) \ @ENABLE_IPV4_TRUE@ xtables_legacy_multi-iptables.$(OBJEXT) -@ENABLE_IPV6_TRUE@am__objects_2 = xtables_legacy_multi-ip6tables-save.$(OBJEXT) \ -@ENABLE_IPV6_TRUE@ xtables_legacy_multi-ip6tables-restore.$(OBJEXT) \ -@ENABLE_IPV6_TRUE@ xtables_legacy_multi-ip6tables-standalone.$(OBJEXT) \ +@ENABLE_IPV6_TRUE@am__objects_2 = xtables_legacy_multi-ip6tables-standalone.$(OBJEXT) \ @ENABLE_IPV6_TRUE@ xtables_legacy_multi-ip6tables.$(OBJEXT) am_xtables_legacy_multi_OBJECTS = \ xtables_legacy_multi-xtables-legacy-multi.$(OBJEXT) \ xtables_legacy_multi-iptables-xml.$(OBJEXT) $(am__objects_1) \ - $(am__objects_2) xtables_legacy_multi-xshared.$(OBJEXT) + $(am__objects_2) xtables_legacy_multi-xshared.$(OBJEXT) \ + xtables_legacy_multi-iptables-restore.$(OBJEXT) \ + xtables_legacy_multi-iptables-save.$(OBJEXT) xtables_legacy_multi_OBJECTS = $(am_xtables_legacy_multi_OBJECTS) xtables_legacy_multi_DEPENDENCIES = ../extensions/libext.a \ $(am__append_4) $(am__append_7) ../libxtables/libxtables.la @@ -475,7 +471,8 @@ AM_CPPFLAGS = ${regular_CPPFLAGS} -I${top_builddir}/include -I${top_srcdir}/incl AM_YFLAGS = -d BUILT_SOURCES = $(am__append_8) xtables_legacy_multi_SOURCES = xtables-legacy-multi.c iptables-xml.c \ - $(am__append_2) $(am__append_5) xshared.c + $(am__append_2) $(am__append_5) xshared.c iptables-restore.c \ + iptables-save.c xtables_legacy_multi_CFLAGS = ${AM_CFLAGS} $(am__append_1) \ $(am__append_3) $(am__append_6) xtables_legacy_multi_LDADD = ../extensions/libext.a $(am__append_4) \ @@ -504,12 +501,12 @@ xtables_legacy_multi_LDADD = ../extensions/libext.a $(am__append_4) \ @ENABLE_NFTABLES_TRUE@ ../extensions/libext_arpt.a \ @ENABLE_NFTABLES_TRUE@ ../libxtables/libxtables.la -lm man_MANS = iptables.8 iptables-restore.8 iptables-save.8 \ - iptables-xml.1 ip6tables.8 ip6tables-restore.8 \ - ip6tables-save.8 iptables-extensions.8 \ - xtables-nft.8 xtables-translate.8 xtables-legacy.8 \ - xtables-monitor.8 - + iptables-xml.1 ip6tables.8 ip6tables-restore.8 \ + ip6tables-save.8 iptables-extensions.8 xtables-nft.8 \ + xtables-translate.8 xtables-legacy.8 iptables-translate.8 \ + ip6tables-translate.8 xtables-monitor.8 $(am__append_11) CLEANFILES = iptables.8 xtables-monitor.8 \ + iptables-translate.8 ip6tables-translate.8 \ xtables-config-parser.c xtables-config-syntax.c vx_bin_links = iptables-xml @@ -649,8 +646,6 @@ mostlyclean-compile: distclean-compile: -rm -f *.tab.c -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xtables_legacy_multi-ip6tables-restore.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xtables_legacy_multi-ip6tables-save.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xtables_legacy_multi-ip6tables-standalone.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xtables_legacy_multi-ip6tables.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xtables_legacy_multi-iptables-restore.Po@am__quote@ @@ -732,34 +727,6 @@ xtables_legacy_multi-iptables-xml.obj: iptables-xml.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xtables_legacy_multi_CFLAGS) $(CFLAGS) -c -o xtables_legacy_multi-iptables-xml.obj `if test -f 'iptables-xml.c'; then $(CYGPATH_W) 'iptables-xml.c'; else $(CYGPATH_W) '$(srcdir)/iptables-xml.c'; fi` -xtables_legacy_multi-iptables-save.o: iptables-save.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xtables_legacy_multi_CFLAGS) $(CFLAGS) -MT xtables_legacy_multi-iptables-save.o -MD -MP -MF $(DEPDIR)/xtables_legacy_multi-iptables-save.Tpo -c -o xtables_legacy_multi-iptables-save.o `test -f 'iptables-save.c' || echo '$(srcdir)/'`iptables-save.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xtables_legacy_multi-iptables-save.Tpo $(DEPDIR)/xtables_legacy_multi-iptables-save.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='iptables-save.c' object='xtables_legacy_multi-iptables-save.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xtables_legacy_multi_CFLAGS) $(CFLAGS) -c -o xtables_legacy_multi-iptables-save.o `test -f 'iptables-save.c' || echo '$(srcdir)/'`iptables-save.c - -xtables_legacy_multi-iptables-save.obj: iptables-save.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xtables_legacy_multi_CFLAGS) $(CFLAGS) -MT xtables_legacy_multi-iptables-save.obj -MD -MP -MF $(DEPDIR)/xtables_legacy_multi-iptables-save.Tpo -c -o xtables_legacy_multi-iptables-save.obj `if test -f 'iptables-save.c'; then $(CYGPATH_W) 'iptables-save.c'; else $(CYGPATH_W) '$(srcdir)/iptables-save.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xtables_legacy_multi-iptables-save.Tpo $(DEPDIR)/xtables_legacy_multi-iptables-save.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='iptables-save.c' object='xtables_legacy_multi-iptables-save.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xtables_legacy_multi_CFLAGS) $(CFLAGS) -c -o xtables_legacy_multi-iptables-save.obj `if test -f 'iptables-save.c'; then $(CYGPATH_W) 'iptables-save.c'; else $(CYGPATH_W) '$(srcdir)/iptables-save.c'; fi` - -xtables_legacy_multi-iptables-restore.o: iptables-restore.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xtables_legacy_multi_CFLAGS) $(CFLAGS) -MT xtables_legacy_multi-iptables-restore.o -MD -MP -MF $(DEPDIR)/xtables_legacy_multi-iptables-restore.Tpo -c -o xtables_legacy_multi-iptables-restore.o `test -f 'iptables-restore.c' || echo '$(srcdir)/'`iptables-restore.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xtables_legacy_multi-iptables-restore.Tpo $(DEPDIR)/xtables_legacy_multi-iptables-restore.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='iptables-restore.c' object='xtables_legacy_multi-iptables-restore.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xtables_legacy_multi_CFLAGS) $(CFLAGS) -c -o xtables_legacy_multi-iptables-restore.o `test -f 'iptables-restore.c' || echo '$(srcdir)/'`iptables-restore.c - -xtables_legacy_multi-iptables-restore.obj: iptables-restore.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xtables_legacy_multi_CFLAGS) $(CFLAGS) -MT xtables_legacy_multi-iptables-restore.obj -MD -MP -MF $(DEPDIR)/xtables_legacy_multi-iptables-restore.Tpo -c -o xtables_legacy_multi-iptables-restore.obj `if test -f 'iptables-restore.c'; then $(CYGPATH_W) 'iptables-restore.c'; else $(CYGPATH_W) '$(srcdir)/iptables-restore.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xtables_legacy_multi-iptables-restore.Tpo $(DEPDIR)/xtables_legacy_multi-iptables-restore.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='iptables-restore.c' object='xtables_legacy_multi-iptables-restore.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xtables_legacy_multi_CFLAGS) $(CFLAGS) -c -o xtables_legacy_multi-iptables-restore.obj `if test -f 'iptables-restore.c'; then $(CYGPATH_W) 'iptables-restore.c'; else $(CYGPATH_W) '$(srcdir)/iptables-restore.c'; fi` - xtables_legacy_multi-iptables-standalone.o: iptables-standalone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xtables_legacy_multi_CFLAGS) $(CFLAGS) -MT xtables_legacy_multi-iptables-standalone.o -MD -MP -MF $(DEPDIR)/xtables_legacy_multi-iptables-standalone.Tpo -c -o xtables_legacy_multi-iptables-standalone.o `test -f 'iptables-standalone.c' || echo '$(srcdir)/'`iptables-standalone.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xtables_legacy_multi-iptables-standalone.Tpo $(DEPDIR)/xtables_legacy_multi-iptables-standalone.Po @@ -788,34 +755,6 @@ xtables_legacy_multi-iptables.obj: iptables.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xtables_legacy_multi_CFLAGS) $(CFLAGS) -c -o xtables_legacy_multi-iptables.obj `if test -f 'iptables.c'; then $(CYGPATH_W) 'iptables.c'; else $(CYGPATH_W) '$(srcdir)/iptables.c'; fi` -xtables_legacy_multi-ip6tables-save.o: ip6tables-save.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xtables_legacy_multi_CFLAGS) $(CFLAGS) -MT xtables_legacy_multi-ip6tables-save.o -MD -MP -MF $(DEPDIR)/xtables_legacy_multi-ip6tables-save.Tpo -c -o xtables_legacy_multi-ip6tables-save.o `test -f 'ip6tables-save.c' || echo '$(srcdir)/'`ip6tables-save.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xtables_legacy_multi-ip6tables-save.Tpo $(DEPDIR)/xtables_legacy_multi-ip6tables-save.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ip6tables-save.c' object='xtables_legacy_multi-ip6tables-save.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xtables_legacy_multi_CFLAGS) $(CFLAGS) -c -o xtables_legacy_multi-ip6tables-save.o `test -f 'ip6tables-save.c' || echo '$(srcdir)/'`ip6tables-save.c - -xtables_legacy_multi-ip6tables-save.obj: ip6tables-save.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xtables_legacy_multi_CFLAGS) $(CFLAGS) -MT xtables_legacy_multi-ip6tables-save.obj -MD -MP -MF $(DEPDIR)/xtables_legacy_multi-ip6tables-save.Tpo -c -o xtables_legacy_multi-ip6tables-save.obj `if test -f 'ip6tables-save.c'; then $(CYGPATH_W) 'ip6tables-save.c'; else $(CYGPATH_W) '$(srcdir)/ip6tables-save.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xtables_legacy_multi-ip6tables-save.Tpo $(DEPDIR)/xtables_legacy_multi-ip6tables-save.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ip6tables-save.c' object='xtables_legacy_multi-ip6tables-save.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xtables_legacy_multi_CFLAGS) $(CFLAGS) -c -o xtables_legacy_multi-ip6tables-save.obj `if test -f 'ip6tables-save.c'; then $(CYGPATH_W) 'ip6tables-save.c'; else $(CYGPATH_W) '$(srcdir)/ip6tables-save.c'; fi` - -xtables_legacy_multi-ip6tables-restore.o: ip6tables-restore.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xtables_legacy_multi_CFLAGS) $(CFLAGS) -MT xtables_legacy_multi-ip6tables-restore.o -MD -MP -MF $(DEPDIR)/xtables_legacy_multi-ip6tables-restore.Tpo -c -o xtables_legacy_multi-ip6tables-restore.o `test -f 'ip6tables-restore.c' || echo '$(srcdir)/'`ip6tables-restore.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xtables_legacy_multi-ip6tables-restore.Tpo $(DEPDIR)/xtables_legacy_multi-ip6tables-restore.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ip6tables-restore.c' object='xtables_legacy_multi-ip6tables-restore.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xtables_legacy_multi_CFLAGS) $(CFLAGS) -c -o xtables_legacy_multi-ip6tables-restore.o `test -f 'ip6tables-restore.c' || echo '$(srcdir)/'`ip6tables-restore.c - -xtables_legacy_multi-ip6tables-restore.obj: ip6tables-restore.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xtables_legacy_multi_CFLAGS) $(CFLAGS) -MT xtables_legacy_multi-ip6tables-restore.obj -MD -MP -MF $(DEPDIR)/xtables_legacy_multi-ip6tables-restore.Tpo -c -o xtables_legacy_multi-ip6tables-restore.obj `if test -f 'ip6tables-restore.c'; then $(CYGPATH_W) 'ip6tables-restore.c'; else $(CYGPATH_W) '$(srcdir)/ip6tables-restore.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xtables_legacy_multi-ip6tables-restore.Tpo $(DEPDIR)/xtables_legacy_multi-ip6tables-restore.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ip6tables-restore.c' object='xtables_legacy_multi-ip6tables-restore.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xtables_legacy_multi_CFLAGS) $(CFLAGS) -c -o xtables_legacy_multi-ip6tables-restore.obj `if test -f 'ip6tables-restore.c'; then $(CYGPATH_W) 'ip6tables-restore.c'; else $(CYGPATH_W) '$(srcdir)/ip6tables-restore.c'; fi` - xtables_legacy_multi-ip6tables-standalone.o: ip6tables-standalone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xtables_legacy_multi_CFLAGS) $(CFLAGS) -MT xtables_legacy_multi-ip6tables-standalone.o -MD -MP -MF $(DEPDIR)/xtables_legacy_multi-ip6tables-standalone.Tpo -c -o xtables_legacy_multi-ip6tables-standalone.o `test -f 'ip6tables-standalone.c' || echo '$(srcdir)/'`ip6tables-standalone.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xtables_legacy_multi-ip6tables-standalone.Tpo $(DEPDIR)/xtables_legacy_multi-ip6tables-standalone.Po @@ -858,6 +797,34 @@ xtables_legacy_multi-xshared.obj: xshared.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xtables_legacy_multi_CFLAGS) $(CFLAGS) -c -o xtables_legacy_multi-xshared.obj `if test -f 'xshared.c'; then $(CYGPATH_W) 'xshared.c'; else $(CYGPATH_W) '$(srcdir)/xshared.c'; fi` +xtables_legacy_multi-iptables-restore.o: iptables-restore.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xtables_legacy_multi_CFLAGS) $(CFLAGS) -MT xtables_legacy_multi-iptables-restore.o -MD -MP -MF $(DEPDIR)/xtables_legacy_multi-iptables-restore.Tpo -c -o xtables_legacy_multi-iptables-restore.o `test -f 'iptables-restore.c' || echo '$(srcdir)/'`iptables-restore.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xtables_legacy_multi-iptables-restore.Tpo $(DEPDIR)/xtables_legacy_multi-iptables-restore.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='iptables-restore.c' object='xtables_legacy_multi-iptables-restore.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xtables_legacy_multi_CFLAGS) $(CFLAGS) -c -o xtables_legacy_multi-iptables-restore.o `test -f 'iptables-restore.c' || echo '$(srcdir)/'`iptables-restore.c + +xtables_legacy_multi-iptables-restore.obj: iptables-restore.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xtables_legacy_multi_CFLAGS) $(CFLAGS) -MT xtables_legacy_multi-iptables-restore.obj -MD -MP -MF $(DEPDIR)/xtables_legacy_multi-iptables-restore.Tpo -c -o xtables_legacy_multi-iptables-restore.obj `if test -f 'iptables-restore.c'; then $(CYGPATH_W) 'iptables-restore.c'; else $(CYGPATH_W) '$(srcdir)/iptables-restore.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xtables_legacy_multi-iptables-restore.Tpo $(DEPDIR)/xtables_legacy_multi-iptables-restore.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='iptables-restore.c' object='xtables_legacy_multi-iptables-restore.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xtables_legacy_multi_CFLAGS) $(CFLAGS) -c -o xtables_legacy_multi-iptables-restore.obj `if test -f 'iptables-restore.c'; then $(CYGPATH_W) 'iptables-restore.c'; else $(CYGPATH_W) '$(srcdir)/iptables-restore.c'; fi` + +xtables_legacy_multi-iptables-save.o: iptables-save.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xtables_legacy_multi_CFLAGS) $(CFLAGS) -MT xtables_legacy_multi-iptables-save.o -MD -MP -MF $(DEPDIR)/xtables_legacy_multi-iptables-save.Tpo -c -o xtables_legacy_multi-iptables-save.o `test -f 'iptables-save.c' || echo '$(srcdir)/'`iptables-save.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xtables_legacy_multi-iptables-save.Tpo $(DEPDIR)/xtables_legacy_multi-iptables-save.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='iptables-save.c' object='xtables_legacy_multi-iptables-save.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xtables_legacy_multi_CFLAGS) $(CFLAGS) -c -o xtables_legacy_multi-iptables-save.o `test -f 'iptables-save.c' || echo '$(srcdir)/'`iptables-save.c + +xtables_legacy_multi-iptables-save.obj: iptables-save.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xtables_legacy_multi_CFLAGS) $(CFLAGS) -MT xtables_legacy_multi-iptables-save.obj -MD -MP -MF $(DEPDIR)/xtables_legacy_multi-iptables-save.Tpo -c -o xtables_legacy_multi-iptables-save.obj `if test -f 'iptables-save.c'; then $(CYGPATH_W) 'iptables-save.c'; else $(CYGPATH_W) '$(srcdir)/iptables-save.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xtables_legacy_multi-iptables-save.Tpo $(DEPDIR)/xtables_legacy_multi-iptables-save.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='iptables-save.c' object='xtables_legacy_multi-iptables-save.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xtables_legacy_multi_CFLAGS) $(CFLAGS) -c -o xtables_legacy_multi-iptables-save.obj `if test -f 'iptables-save.c'; then $(CYGPATH_W) 'iptables-save.c'; else $(CYGPATH_W) '$(srcdir)/iptables-save.c'; fi` + xtables_nft_multi-xtables-nft-multi.o: xtables-nft-multi.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xtables_nft_multi_CFLAGS) $(CFLAGS) -MT xtables_nft_multi-xtables-nft-multi.o -MD -MP -MF $(DEPDIR)/xtables_nft_multi-xtables-nft-multi.Tpo -c -o xtables_nft_multi-xtables-nft-multi.o `test -f 'xtables-nft-multi.c' || echo '$(srcdir)/'`xtables-nft-multi.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xtables_nft_multi-xtables-nft-multi.Tpo $(DEPDIR)/xtables_nft_multi-xtables-nft-multi.Po @@ -1515,6 +1482,9 @@ 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: + ${AM_VERBOSE_GEN} echo '.so man8/xtables-translate.8' >$@ + # Using if..fi avoids an ugly "error (ignored)" message :) install-exec-hook: -if test -z "${DESTDIR}"; then /sbin/ldconfig; fi; diff --git a/iptables/arptables-nft-restore.8 b/iptables/arptables-nft-restore.8 new file mode 100644 index 0000000000000000000000000000000000000000..09d9082cf9fd351ccb434c4767f9394afbe82419 --- /dev/null +++ b/iptables/arptables-nft-restore.8 @@ -0,0 +1,39 @@ +.TH ARPTABLES-RESTORE 8 "March 2019" "" "" +.\" +.\" Man page written by Jesper Dangaard Brouer based on a +.\" Man page written by Harald Welte +.\" It is based on the iptables-restore man page. +.\" +.\" This program is free software; you can redistribute it and/or modify +.\" it under the terms of the GNU General Public License as published by +.\" the Free Software Foundation; either version 2 of the License, or +.\" (at your option) any later version. +.\" +.\" This program is distributed in the hope that it will be useful, +.\" but WITHOUT ANY WARRANTY; without even the implied warranty of +.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +.\" GNU General Public License for more details. +.\" +.\" You should have received a copy of the GNU General Public License +.\" along with this program; if not, write to the Free Software +.\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +.\" +.\" +.SH NAME +arptables-restore \- Restore ARP Tables (nft-based) +.SH SYNOPSIS +\fBarptables\-restore +.SH DESCRIPTION +.PP +.B arptables-restore +is used to restore ARP Tables from data specified on STDIN or +via a file as first argument. +Use I/O redirection provided by your shell to read from a file +.TP +.B arptables-restore +flushes (deletes) all previous contents of the respective ARP Table. +.SH AUTHOR +Jesper Dangaard Brouer +.SH SEE ALSO +\fBarptables\-save\fP(8), \fBarptables\fP(8) +.PP diff --git a/iptables/arptables-nft-save.8 b/iptables/arptables-nft-save.8 new file mode 100644 index 0000000000000000000000000000000000000000..905e59854cc28b6b2ae2158375aea84ef8cd6f5e --- /dev/null +++ b/iptables/arptables-nft-save.8 @@ -0,0 +1,47 @@ +.TH ARPTABLES-SAVE 8 "March 2019" "" "" +.\" +.\" Man page written by Jesper Dangaard Brouer based on a +.\" Man page written by Harald Welte +.\" It is based on the iptables-save man page. +.\" +.\" This program is free software; you can redistribute it and/or modify +.\" it under the terms of the GNU General Public License as published by +.\" the Free Software Foundation; either version 2 of the License, or +.\" (at your option) any later version. +.\" +.\" This program is distributed in the hope that it will be useful, +.\" but WITHOUT ANY WARRANTY; without even the implied warranty of +.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +.\" GNU General Public License for more details. +.\" +.\" You should have received a copy of the GNU General Public License +.\" along with this program; if not, write to the Free Software +.\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +.\" +.\" +.SH NAME +arptables-save \- dump arptables rules to stdout (nft-based) +.SH SYNOPSIS +\fBarptables\-save\fP [\fB\-M\fP \fImodprobe\fP] [\fB\-c\fP] +.P +\fBarptables\-save\fP [\fB\-V\fP] +.SH DESCRIPTION +.PP +.B arptables-save +is used to dump the contents of an ARP Table in easily parseable format +to STDOUT. Use I/O-redirection provided by your shell to write to a file. +.TP +\fB\-M\fR, \fB\-\-modprobe\fR \fImodprobe_program\fP +Specify the path to the modprobe program. By default, arptables-save will +inspect /proc/sys/kernel/modprobe to determine the executable's path. +.TP +\fB\-c\fR, \fB\-\-counters\fR +Include the current values of all packet and byte counters in the output. +.TP +\fB\-V\fR, \fB\-\-version\fR +Print version information and exit. +.SH AUTHOR +Jesper Dangaard Brouer +.SH SEE ALSO +\fBarptables\-restore\fP(8), \fBarptables\fP(8) +.PP diff --git a/iptables/arptables-nft.8 b/iptables/arptables-nft.8 new file mode 100644 index 0000000000000000000000000000000000000000..ea31e0842acd4218074e7d78e791d615d8dad098 --- /dev/null +++ b/iptables/arptables-nft.8 @@ -0,0 +1,348 @@ +.TH ARPTABLES 8 "March 2019" +.\" +.\" Man page originally written by Jochen Friedrich , +.\" maintained by Bart De Schuymer. +.\" It is based on the iptables man page. +.\" +.\" Iptables page by Herve Eychenne March 2000. +.\" +.\" This program is free software; you can redistribute it and/or modify +.\" it under the terms of the GNU General Public License as published by +.\" the Free Software Foundation; either version 2 of the License, or +.\" (at your option) any later version. +.\" +.\" This program is distributed in the hope that it will be useful, +.\" but WITHOUT ANY WARRANTY; without even the implied warranty of +.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +.\" GNU General Public License for more details. +.\" +.\" You should have received a copy of the GNU General Public License +.\" along with this program; if not, write to the Free Software +.\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +.\" +.\" +.SH NAME +arptables \- ARP table administration (nft-based) +.SH SYNOPSIS +.BR "arptables " [ "-t table" ] " -" [ AD ] " chain rule-specification " [ options ] +.br +.BR "arptables " [ "-t table" ] " -" [ RI ] " chain rulenum rule-specification " [ options ] +.br +.BR "arptables " [ "-t table" ] " -D chain rulenum " [ options ] +.br +.BR "arptables " [ "-t table" ] " -" [ "LFZ" ] " " [ chain ] " " [ options ] +.br +.BR "arptables " [ "-t table" ] " -" [ "NX" ] " chain" +.br +.BR "arptables " [ "-t table" ] " -E old-chain-name new-chain-name" +.br +.BR "arptables " [ "-t table" ] " -P chain target " [ options ] + +.SH DESCRIPTION +.B arptables +is a user space tool, it is used to set up and maintain the +tables of ARP rules in the Linux kernel. These rules inspect +the ARP frames which they see. +.B arptables +is analogous to the +.B iptables +user space tool, but +.B arptables +is less complicated. + +.SS CHAINS +The kernel table is 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 ARP frames. If a +rule matches an ARP frame, then a processing specification tells +what to do with that matching frame. The processing specification is +called a 'target'. However, if the frame does not match the current +rule in the chain, then the next rule in the chain is examined and so forth. +The user can create new (user-defined) chains which can be used as the 'target' of a rule. + +.SS TARGETS +A firewall rule specifies criteria for an ARP frame and a frame +processing specification called a target. When a frame matches a rule, +then the next action performed by the kernel is specified by the target. +The target can be one of these values: +.IR ACCEPT , +.IR DROP , +.IR CONTINUE , +.IR RETURN , +an 'extension' (see below) or a user-defined chain. +.PP +.I ACCEPT +means to let the frame through. +.I DROP +means the frame has to be dropped. +.I CONTINUE +means the next rule has to be checked. This can be handy to know how many +frames pass a certain point in the chain or to log those frames. +.I RETURN +means stop traversing this chain and resume at the next rule in the +previous (calling) chain. +For the extension targets please see the +.B "TARGET EXTENSIONS" +section of this man page. +.SS TABLES +There is only one ARP table in the Linux +kernel. The table is +.BR filter. +You can drop the '-t filter' argument to the arptables command. +The -t argument must be the +first argument on the arptables command line, if used. +.TP +.B "-t, --table" +.br +.BR filter , +is the only table and contains two built-in chains: +.B INPUT +(for frames destined for the host) and +.B OUTPUT +(for locally-generated frames). +.br +.br +.SH ARPTABLES COMMAND LINE ARGUMENTS +After the initial arptables command line argument, the remaining +arguments can be divided into several different groups. These groups +are commands, miscellaneous commands, rule-specifications, match-extensions, +and watcher-extensions. +.SS COMMANDS +The arptables command arguments specify the actions to perform on the table +defined with the -t argument. If you do not use the -t argument to name +a table, the commands apply to the default filter table. +With the exception of the +.B "-Z" +command, only one command may be used on the command line at a time. +.TP +.B "-A, --append" +Append a rule to the end of the selected chain. +.TP +.B "-D, --delete" +Delete the specified rule from the selected chain. There are two ways to +use this command. The first is by specifying an interval of rule numbers +to delete, syntax: start_nr[:end_nr]. Using negative numbers is allowed, for more +details about using negative numbers, see the -I command. The second usage is by +specifying the complete rule as it would have been specified when it was added. +.TP +.B "-I, --insert" +Insert the specified rule into the selected chain at the specified rule number. +If the current number of rules equals N, then the specified number can be +between -N and N+1. For a positive number i, it holds that i and i-N-1 specify the +same place in the chain where the rule should be inserted. The number 0 specifies +the place past the last rule in the chain and using this number is therefore +equivalent with using the -A command. +.TP +.B "-R, --replace" +Replaces the specified rule into the selected chain at the specified rule number. +If the current number of rules equals N, then the specified number can be +between 1 and N. i specifies the place in the chain where the rule should be replaced. +.TP +.B "-P, --policy" +Set the policy for the chain to the given target. The policy can be +.BR ACCEPT ", " DROP " or " RETURN . +.TP +.B "-F, --flush" +Flush the selected chain. If no chain is selected, then every chain will be +flushed. Flushing the chain does not change the policy of the +chain, however. +.TP +.B "-Z, --zero" +Set the counters of the selected chain to zero. If no chain is selected, all the counters +are set to zero. The +.B "-Z" +command can be used in conjunction with the +.B "-L" +command. +When both the +.B "-Z" +and +.B "-L" +commands are used together in this way, the rule counters are printed on the screen +before they are set to zero. +.TP +.B "-L, --list" +List all rules in the selected chain. If no chain is selected, all chains +are listed. +.TP +.B "-N, --new-chain" +Create a new user-defined chain with the given name. The number of +user-defined chains is unlimited. A user-defined chain name has maximum +length of 31 characters. +.TP +.B "-X, --delete-chain" +Delete the specified user-defined chain. There must be no remaining references +to the specified chain, otherwise +.B arptables +will refuse to delete it. If no chain is specified, all user-defined +chains that aren't referenced will be removed. +.TP +.B "-E, --rename-chain" +Rename the specified chain to a new name. Besides renaming a user-defined +chain, you may rename a standard chain name to a name that suits your +taste. For example, if you like PREBRIDGING more than PREROUTING, +then you can use the -E command to rename the PREROUTING chain. If you do +rename one of the standard +.B arptables +chain names, please be sure to mention +this fact should you post a question on the +.B arptables +mailing lists. +It would be wise to use the standard name in your post. Renaming a standard +.B arptables +chain in this fashion has no effect on the structure or function +of the +.B arptables +kernel table. + +.SS MISCELLANOUS COMMANDS +.TP +.B "-V, --version" +Show the version of the arptables userspace program. +.TP +.B "-h, --help" +Give a brief description of the command syntax. +.TP +.BR "-j, --jump " "\fItarget\fP" +The target of the rule. This is one of the following values: +.BR ACCEPT , +.BR DROP , +.BR CONTINUE , +.BR RETURN , +a target extension (see +.BR "TARGET EXTENSIONS" ")" +or a user-defined chain name. +.TP +.BI "-c, --set-counters " "PKTS BYTES" +This enables the administrator to initialize the packet and byte +counters of a rule (during +.B INSERT, +.B APPEND, +.B REPLACE +operations). + +.SS RULE-SPECIFICATIONS +The following command line arguments make up a rule specification (as used +in the add and delete commands). A "!" option before the specification +inverts the test for that specification. Apart from these standard rule +specifications there are some other command line arguments of interest. +.TP +.BR "-s, --source-ip " "[!] \fIaddress\fP[/\fImask]\fP" +The Source IP specification. +.TP +.BR "-d, --destination-ip " "[!] \fIaddress\fP[/\fImask]\fP" +The Destination IP specification. +.TP +.BR "--source-mac " "[!] \fIaddress\fP[/\fImask\fP]" +The source mac address. Both mask and address are written as 6 hexadecimal +numbers separated by colons. +.TP +.BR "--destination-mac " "[!] \fIaddress\fP[/\fImask\fP]" +The destination mac address. Both mask and address are written as 6 hexadecimal +numbers separated by colons. +.TP +.BR "-i, --in-interface " "[!] \fIname\fP" +The interface via which a frame is received (for the +.B INPUT +chain). The flag +.B --in-if +is an alias for this option. +.TP +.BR "-o, --out-interface " "[!] \fIname\fP" +The interface via which a frame is going to be sent (for the +.B OUTPUT +chain). The flag +.B --out-if +is an alias for this option. +.TP +.BR "-l, --h-length " "\fIlength\fP[/\fImask\fP]" +The hardware length (nr of bytes) +.TP +.BR "--opcode " "\fIcode\fP[/\fImask\fP] +The operation code (2 bytes). Available values are: +.BR 1 = Request +.BR 2 = Reply +.BR 3 = Request_Reverse +.BR 4 = Reply_Reverse +.BR 5 = DRARP_Request +.BR 6 = DRARP_Reply +.BR 7 = DRARP_Error +.BR 8 = InARP_Request +.BR 9 = ARP_NAK . +.TP +.BR "--h-type " "\fItype\fP[/\fImask\fP]" +The hardware type (2 bytes, hexadecimal). Available values are: +.BR 1 = Ethernet . +.TP +.BR "--proto-type " "\fItype\fP[/\fImask\fP]" +The protocol type (2 bytes). Available values are: +.BR 0x800 = IPv4 . + +.SS TARGET-EXTENSIONS +.B arptables +extensions are precompiled into the userspace tool. So there is no need +to explicitly load them with a -m option like in +.BR iptables . +However, these +extensions deal with functionality supported by supplemental kernel modules. +.SS mangle +.TP +.BR "--mangle-ip-s IP address" +Mangles Source IP Address to given value. +.TP +.BR "--mangle-ip-d IP address" +Mangles Destination IP Address to given value. +.TP +.BR "--mangle-mac-s MAC address" +Mangles Source MAC Address to given value. +.TP +.BR "--mangle-mac-d MAC address" +Mangles Destination MAC Address to given value. +.TP +.BR "--mangle-target target " +Target of ARP mangle operation +.BR "" ( DROP ", " CONTINUE " or " ACCEPT " -- default is " ACCEPT ). +.SS CLASSIFY +This module allows you to set the skb->priority value (and thus clas- +sify the packet into a specific CBQ class). + +.TP +.BR "--set-class major:minor" + +Set the major and minor class value. The values are always +interpreted as hexadecimal even if no 0x prefix is given. + +.SS MARK +This module allows you to set the skb->mark value (and thus classify +the packet by the mark in u32) + +.TP +.BR "--set-mark mark" +Set the mark value. The values are always +interpreted as hexadecimal even if no 0x prefix is given + +.TP +.BR "--and-mark mark" +Binary AND the mark with bits. + +.TP +.BR "--or-mark mark" +Binary OR the mark with bits. + +.SH NOTES +In this nft-based version of +.BR arptables , +support for +.B FORWARD +chain has not been implemented. Since ARP packets are "forwarded" only by Linux +bridges, the same may be achieved using +.B FORWARD +chain in +.BR ebtables . + +.SH MAILINGLISTS +.BR "" "See " http://netfilter.org/mailinglists.html +.SH SEE ALSO +.BR xtables-nft "(8), " iptables "(8), " ebtables "(8), " ip (8) +.PP +.BR "" "See " https://wiki.nftables.org diff --git a/iptables/ebtables-nft.8 b/iptables/ebtables-nft.8 new file mode 100644 index 0000000000000000000000000000000000000000..db8b2ab28cca5b370d2072abd0df75374985ec1c --- /dev/null +++ b/iptables/ebtables-nft.8 @@ -0,0 +1,1116 @@ +.TH EBTABLES 8 "December 2011" +.\" +.\" Man page written by Bart De Schuymer +.\" It is based on the iptables man page. +.\" +.\" The man page was edited, February 25th 2003, by +.\" Greg Morgan <" dr_kludge_at_users_sourceforge_net > +.\" +.\" Iptables page by Herve Eychenne March 2000. +.\" +.\" This program is free software; you can redistribute it and/or modify +.\" it under the terms of the GNU General Public License as published by +.\" the Free Software Foundation; either version 2 of the License, or +.\" (at your option) any later version. +.\" +.\" This program is distributed in the hope that it will be useful, +.\" but WITHOUT ANY WARRANTY; without even the implied warranty of +.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +.\" GNU General Public License for more details. +.\" +.\" You should have received a copy of the GNU General Public License +.\" along with this program; if not, write to the Free Software +.\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +.\" +.\" +.SH NAME +ebtables \- Ethernet bridge frame table administration (nft-based) +.SH SYNOPSIS +.BR "ebtables " [ -t " table ] " - [ ACDI "] chain rule specification [match extensions] [watcher extensions] target" +.br +.BR "ebtables " [ -t " table ] " -P " chain " ACCEPT " | " DROP " | " RETURN +.br +.BR "ebtables " [ -t " table ] " -F " [chain]" +.br +.BR "ebtables " [ -t " table ] " -Z " [chain]" +.br +.BR "ebtables " [ -t " table ] " -L " [" -Z "] [chain] [ [" --Ln "] | [" --Lx "] ] [" --Lc "] [" --Lmac2 ] +.br +.BR "ebtables " [ -t " table ] " -N " chain [" "-P ACCEPT " | " DROP " | " RETURN" ] +.br +.BR "ebtables " [ -t " table ] " -X " [chain]" +.br +.BR "ebtables " [ -t " table ] " -E " old-chain-name new-chain-name" +.br +.BR "ebtables " [ -t " table ] " --init-table +.br +.BR "ebtables " [ -t " table ] [" --atomic-file " file] " --atomic-commit +.br +.BR "ebtables " [ -t " table ] [" --atomic-file " file] " --atomic-init +.br +.BR "ebtables " [ -t " table ] [" --atomic-file " file] " --atomic-save +.br + +.SH DESCRIPTION +.B ebtables +is an application program used to set up and maintain the +tables of rules (inside the Linux kernel) that inspect +Ethernet frames. +It is analogous to the +.B iptables +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 +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 +rule matches an Ethernet frame, then a processing specification tells +what to do with that matching frame. The processing specification is +called a 'target'. However, if the frame does not match the current +rule in the chain, then the next rule in the chain is examined and so forth. +The user can create new (user-defined) chains that can be used as the 'target' +of a rule. User-defined chains are very useful to get better performance +over the linear traversal of the rules and are also essential for structuring +the filtering rules into well-organized and maintainable sets of rules. +.SS TARGETS +A firewall rule specifies criteria for an Ethernet frame and a frame +processing specification called a target. When a frame matches a rule, +then the next action performed by the kernel is specified by the target. +The target can be one of these values: +.BR ACCEPT , +.BR DROP , +.BR CONTINUE , +.BR RETURN , +an 'extension' (see below) or a jump to a user-defined chain. +.PP +.B ACCEPT +means to let the frame through. +.B DROP +means the frame has to be dropped. +.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 +targets on a frame. +.B RETURN +means stop traversing this chain and resume at the next rule in the +previous (calling) chain. +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, +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. +.TP +.B "-t, --table" +.br +.B filter +is the default table and contains three built-in chains: +.B INPUT +(for frames destined for the bridge itself, on the level of the MAC destination address), +.B OUTPUT +(for locally-generated or (b)routed frames) and +.B FORWARD +(for frames being forwarded by the bridge). +.br +.br +.B nat +is mostly used to change the mac addresses and contains three built-in chains: +.B PREROUTING +(for altering frames as soon as they come in), +.B OUTPUT +(for altering locally generated or (b)routed frames before they are bridged) and +.B POSTROUTING +(for altering frames as they are about to go out). A small note on the naming +of chains PREROUTING and POSTROUTING: it would be more accurate to call them +PREFORWARDING and POSTFORWARDING, but for all those who come from the +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. +.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 +are commands, miscellaneous commands, rule specifications, match extensions, +watcher extensions and target extensions. +.SS COMMANDS +The ebtables command arguments specify the actions to perform on the table +defined with the -t argument. If you do not use the -t argument to name +a table, the commands apply to the default filter table. +Only one command may be used on the command line at a time, except when +the commands +.BR -L " and " -Z +are combined, the commands +.BR -N " and " -P +are combined, or when +.B --atomic-file +is used. +.TP +.B "-A, --append" +Append a rule to the end of the selected chain. +.TP +.B "-D, --delete" +Delete the specified rule or rules from the selected chain. There are two ways to +use this command. The first is by specifying an interval of rule numbers +to delete (directly after +.BR -D ). +Syntax: \fIstart_nr\fP[\fI:end_nr\fP] (use +.B -L --Ln +to list the rules with their rule number). When \fIend_nr\fP is omitted, all rules starting +from \fIstart_nr\fP are deleted. Using negative numbers is allowed, for more +details about using negative numbers, see the +.B -I +command. The second usage is by +specifying the complete rule as it would have been specified when it was added. Only +the first encountered rule that is the same as this specified rule, in other +words the matching rule with the lowest (positive) rule number, is deleted. +.TP +.B "-C, --change-counters" +Change the counters of the specified rule or rules from the selected chain. There are two ways to +use this command. The first is by specifying an interval of rule numbers +to do the changes on (directly after +.BR -C ). +Syntax: \fIstart_nr\fP[\fI:end_nr\fP] (use +.B -L --Ln +to list the rules with their rule number). The details are the same as for the +.BR -D " command. The second usage is by" +specifying the complete rule as it would have been specified when it was added. Only +the counters of the first encountered rule that is the same as this specified rule, in other +words the matching rule with the lowest (positive) rule number, are changed. +In the first usage, the counters are specified directly after the interval specification, +in the second usage directly after +.BR -C . +First the packet counter is specified, then the byte counter. If the specified counters start +with a '+', the counter values are added to the respective current counter values. +If the specified counters start with a '-', the counter values are decreased from the respective +current counter values. No bounds checking is done. If the counters don't start with '+' or '-', +the current counters are changed to the specified counters. +.TP +.B "-I, --insert" +Insert the specified rule into the selected chain at the specified rule number. If the +rule number is not specified, the rule is added at the head of the chain. +If the current number of rules equals +.IR N , +then the specified number can be +between +.IR -N " and " N+1 . +For a positive number +.IR i , +it holds that +.IR i " and " i-N-1 +specify the same place in the chain where the rule should be inserted. The rule number +0 specifies the place past the last rule in the chain and using this number is therefore +equivalent to using the +.BR -A " command." +Rule numbers structly smaller than 0 can be useful when more than one rule needs to be inserted +in a chain. +.TP +.B "-P, --policy" +Set the policy for the chain to the given target. The policy can be +.BR ACCEPT ", " DROP " or " RETURN . +.TP +.B "-F, --flush" +Flush the selected chain. If no chain is selected, then every chain will be +flushed. Flushing a chain does not change the policy of the +chain, however. +.TP +.B "-Z, --zero" +Set the counters of the selected chain to zero. If no chain is selected, all the counters +are set to zero. The +.B "-Z" +command can be used in conjunction with the +.B "-L" +command. +When both the +.B "-Z" +and +.B "-L" +commands are used together in this way, the rule counters are printed on the screen +before they are set to zero. +.TP +.B "-L, --list" +List all rules in the selected chain. If no chain is selected, all chains +are listed. +.br +The following options change the output of the +.B "-L" +command. +.br +.B "--Ln" +.br +Places the rule number in front of every rule. This option is incompatible with the +.BR --Lx " option." +.br +.B "--Lc" +.br +Shows the counters at the end of each rule displayed by the +.B "-L" +command. Both a frame counter (pcnt) and a byte counter (bcnt) are displayed. +The frame counter shows how many frames have matched the specific rule, the byte +counter shows the sum of the frame sizes of these matching frames. Using this option +.BR "" "in combination with the " --Lx " option causes the counters to be written out" +.BR "" "in the '" -c " ' option format." +.br +.B "--Lx" +.br +Changes the output so that it produces a set of ebtables commands that construct +the contents of the chain, when specified. +If no chain is specified, ebtables commands to construct the contents of the +table are given, including commands for creating the user-defined chains (if any). +You can use this set of commands in an ebtables boot or reload +script. For example the output could be used at system startup. +The +.B "--Lx" +option is incompatible with the +.B "--Ln" +listing option. Using the +.BR --Lx " option together with the " --Lc " option will cause the counters to be written out" +.BR "" "in the '" -c " ' option format." +.br +.B "--Lmac2" +.br +Shows all MAC addresses with the same length, adding leading zeroes +if necessary. The default representation omits leading zeroes in the addresses. +.TP +.B "-N, --new-chain" +Create a new user-defined chain with the given name. The number of +user-defined chains is limited only by the number of possible chain names. +A user-defined chain name has a maximum +length of 31 characters. The standard policy of the user-defined chain is +ACCEPT. The policy of the new chain can be initialized to a different standard +target by using the +.B -P +command together with the +.B -N +command. In this case, the chain name does not have to be specified for the +.B -P +command. +.TP +.B "-X, --delete-chain" +Delete the specified user-defined chain. There must be no remaining references (jumps) +to the specified chain, otherwise ebtables will refuse to delete it. If no chain is +specified, all user-defined chains that aren't referenced will be removed. +.TP +.B "-E, --rename-chain" +Rename the specified chain to a new name. Besides renaming a user-defined +chain, you can rename a standard chain to a name that suits your +taste. For example, if you like PREFORWARDING more than PREROUTING, +then you can use the -E command to rename the PREROUTING chain. If you do +rename one of the standard ebtables chain names, please be sure to mention +this fact should you post a question on the ebtables mailing lists. +It would be wise to use the standard name in your post. Renaming a standard +ebtables chain in this fashion has no effect on the structure or functioning +of the ebtables kernel table. +.TP +.B "--init-table" +Replace the current table data by the initial table data. +.TP +.B "--atomic-init" +Copy the kernel's initial data of the table to the specified +file. This can be used as the first action, after which rules are added +to the file. The file can be specified using the +.B --atomic-file +command or through the +.IR EBTABLES_ATOMIC_FILE " environment variable." +.TP +.B "--atomic-save" +Copy the kernel's current data of the table to the specified +file. This can be used as the first action, after which rules are added +to the file. The file can be specified using the +.B --atomic-file +command or through the +.IR EBTABLES_ATOMIC_FILE " environment variable." +.TP +.B "--atomic-commit" +Replace the kernel table data with the data contained in the specified +file. This is a useful command that allows you to load all your rules of a +certain table into the kernel at once, saving the kernel a lot of precious +time and allowing atomic updates of the tables. The file which contains +the table data is constructed by using either the +.B "--atomic-init" +or the +.B "--atomic-save" +command to generate a starting file. After that, using the +.B "--atomic-file" +command when constructing rules or setting the +.IR EBTABLES_ATOMIC_FILE " environment variable" +allows you to extend the file and build the complete table before +committing it to the kernel. This command can be very useful in boot scripts +to populate the ebtables tables in a fast way. +.SS MISCELLANOUS COMMANDS +.TP +.B "-V, --version" +Show the version of the ebtables userspace program. +.TP +.BR "-h, --help " "[\fIlist of module names\fP]" +Give a brief description of the command syntax. Here you can also specify +names of extensions and ebtables will try to write help about those +extensions. E.g. +.IR "ebtables -h snat log ip arp" . +Specify +.I list_extensions +to list all extensions supported by the userspace +utility. +.TP +.BR "-j, --jump " "\fItarget\fP" +The target of the rule. This is one of the following values: +.BR ACCEPT , +.BR DROP , +.BR CONTINUE , +.BR RETURN , +a target extension (see +.BR "TARGET EXTENSIONS" ")" +or a user-defined chain name. +.TP +.B --atomic-file "\fIfile\fP" +Let the command operate on the specified +.IR file . +The data of the table to +operate on will be extracted from the file and the result of the operation +will be saved back into the file. If specified, this option should come +before the command specification. An alternative that should be preferred, +is setting the +.IR EBTABLES_ATOMIC_FILE " environment variable." +.TP +.B -M, --modprobe "\fIprogram\fP" +When talking to the kernel, use this +.I program +to try to automatically load missing kernel modules. +.TP +.B --concurrent +Use a file lock to support concurrent scripts updating the ebtables kernel tables. + +.SS +RULE SPECIFICATIONS +The following command line arguments make up a rule specification (as used +in the add and delete commands). A "!" option before the specification +inverts the test for that specification. Apart from these standard rule +specifications there are some other command line arguments of interest. +See both the +.BR "MATCH EXTENSIONS" +and the +.BR "WATCHER EXTENSIONS" +below. +.TP +.BR "-p, --protocol " "[!] \fIprotocol\fP" +The protocol that was responsible for creating the frame. This can be a +hexadecimal number, above +.IR 0x0600 , +a name (e.g. +.I ARP +) or +.BR LENGTH . +The protocol field of the Ethernet frame can be used to denote the +length of the header (802.2/802.3 networks). When the value of that field is +below or equals +.IR 0x0600 , +the value equals the size of the header and shouldn't be used as a +protocol number. Instead, all frames where the protocol field is used as +the length field are assumed to be of the same 'protocol'. The protocol +name used in ebtables for these frames is +.BR LENGTH . +.br +The file +.B /etc/ethertypes +can be used to show readable +characters instead of hexadecimal numbers for the protocols. For example, +.I 0x0800 +will be represented by +.IR IPV4 . +The use of this file is not case sensitive. +See that file for more information. The flag +.B --proto +is an alias for this option. +.TP +.BR "-i, --in-interface " "[!] \fIname\fP" +The interface (bridge port) via which a frame is received (this option is useful in the +.BR INPUT , +.BR FORWARD , +.BR PREROUTING " and " BROUTING +chains). If the interface name ends with '+', then +any interface name that begins with this name (disregarding '+') will match. +The flag +.B --in-if +is an alias for this option. +.TP +.BR "--logical-in " "[!] \fIname\fP" +The (logical) bridge interface via which a frame is received (this option is useful in the +.BR INPUT , +.BR FORWARD , +.BR PREROUTING " and " BROUTING +chains). +If the interface name ends with '+', then +any interface name that begins with this name (disregarding '+') will match. +.TP +.BR "-o, --out-interface " "[!] \fIname\fP" +The interface (bridge port) via which a frame is going to be sent (this option is useful in the +.BR OUTPUT , +.B FORWARD +and +.B POSTROUTING +chains). If the interface name ends with '+', then +any interface name that begins with this name (disregarding '+') will match. +The flag +.B --out-if +is an alias for this option. +.TP +.BR "--logical-out " "[!] \fIname\fP" +The (logical) bridge interface via which a frame is going to be sent (this option +is useful in the +.BR OUTPUT , +.B FORWARD +and +.B POSTROUTING +chains). +If the interface name ends with '+', then +any interface name that begins with this name (disregarding '+') will match. +.TP +.BR "-s, --source " "[!] \fIaddress\fP[/\fImask\fP]" +The source MAC address. Both mask and address are written as 6 hexadecimal +numbers separated by colons. Alternatively one can specify Unicast, +Multicast, Broadcast or BGA (Bridge Group Address): +.br +.IR "Unicast" "=00:00:00:00:00:00/01:00:00:00:00:00," +.IR "Multicast" "=01:00:00:00:00:00/01:00:00:00:00:00," +.IR "Broadcast" "=ff:ff:ff:ff:ff:ff/ff:ff:ff:ff:ff:ff or" +.IR "BGA" "=01:80:c2:00:00:00/ff:ff:ff:ff:ff:ff." +Note that a broadcast +address will also match the multicast specification. The flag +.B --src +is an alias for this option. +.TP +.BR "-d, --destination " "[!] \fIaddress\fP[/\fImask\fP]" +The destination MAC address. See +.B -s +(above) for more details on MAC addresses. The flag +.B --dst +is an alias for this option. +.TP +.BR "-c, --set-counter " "\fIpcnt bcnt\fP" +If used with +.BR -A " or " -I ", then the packet and byte counters of the new rule will be set to +.IR pcnt ", resp. " bcnt ". +If used with the +.BR -C " or " -D " commands, only rules with a packet and byte count equal to" +.IR pcnt ", resp. " bcnt " will match." + +.SS MATCH EXTENSIONS +Ebtables extensions are dynamically loaded into the userspace tool, +there is therefore no need to explicitly load them with a +-m option like is done in iptables. +These extensions deal with functionality supported by kernel modules supplemental to +the core ebtables code. +.SS 802_3 +Specify 802.3 DSAP/SSAP fields or SNAP type. The protocol must be specified as +.IR "LENGTH " "(see the option " " -p " above). +.TP +.BR "--802_3-sap " "[!] \fIsap\fP" +DSAP and SSAP are two one byte 802.3 fields. The bytes are always +equal, so only one byte (hexadecimal) is needed as an argument. +.TP +.BR "--802_3-type " "[!] \fItype\fP" +If the 802.3 DSAP and SSAP values are 0xaa then the SNAP type field must +be consulted to determine the payload protocol. This is a two byte +(hexadecimal) argument. Only 802.3 frames with DSAP/SSAP 0xaa are +checked for type. +.\" .SS among +.\" Match a MAC address or MAC/IP address pair versus a list of MAC addresses +.\" and MAC/IP address pairs. +.\" A list entry has the following format: +.\" .IR xx:xx:xx:xx:xx:xx[=ip.ip.ip.ip][,] ". Multiple" +.\" list entries are separated by a comma, specifying an IP address corresponding to +.\" the MAC address is optional. Multiple MAC/IP address pairs with the same MAC address +.\" but different IP address (and vice versa) can be specified. If the MAC address doesn't +.\" match any entry from the list, the frame doesn't match the rule (unless "!" was used). +.\" .TP +.\" .BR "--among-dst " "[!] \fIlist\fP" +.\" Compare the MAC destination to the given list. If the Ethernet frame has type +.\" .IR IPv4 " or " ARP , +.\" then comparison with MAC/IP destination address pairs from the +.\" list is possible. +.\" .TP +.\" .BR "--among-src " "[!] \fIlist\fP" +.\" Compare the MAC source to the given list. If the Ethernet frame has type +.\" .IR IPv4 " or " ARP , +.\" then comparison with MAC/IP source address pairs from the list +.\" is possible. +.\" .TP +.\" .BR "--among-dst-file " "[!] \fIfile\fP" +.\" Same as +.\" .BR --among-dst " but the list is read in from the specified file." +.\" .TP +.\" .BR "--among-src-file " "[!] \fIfile\fP" +.\" Same as +.\" .BR --among-src " but the list is read in from the specified file." +.SS arp +Specify (R)ARP fields. The protocol must be specified as +.IR ARP " or " RARP . +.TP +.BR "--arp-opcode " "[!] \fIopcode\fP" +The (R)ARP opcode (decimal or a string, for more details see +.BR "ebtables -h arp" ). +.TP +.BR "--arp-htype " "[!] \fIhardware type\fP" +The hardware type, this can be a decimal or the string +.I Ethernet +(which sets +.I type +to 1). Most (R)ARP packets have Eternet as hardware type. +.TP +.BR "--arp-ptype " "[!] \fIprotocol type\fP" +The protocol type for which the (r)arp is used (hexadecimal or the string +.IR IPv4 , +denoting 0x0800). +Most (R)ARP packets have protocol type IPv4. +.TP +.BR "--arp-ip-src " "[!] \fIaddress\fP[/\fImask\fP]" +The (R)ARP IP source address specification. +.TP +.BR "--arp-ip-dst " "[!] \fIaddress\fP[/\fImask\fP]" +The (R)ARP IP destination address specification. +.TP +.BR "--arp-mac-src " "[!] \fIaddress\fP[/\fImask\fP]" +The (R)ARP MAC source address specification. +.TP +.BR "--arp-mac-dst " "[!] \fIaddress\fP[/\fImask\fP]" +The (R)ARP MAC destination address specification. +.TP +.BR "" "[!]" " --arp-gratuitous" +Checks for ARP gratuitous packets: checks equality of IPv4 source +address and IPv4 destination address inside the ARP header. +.SS ip +Specify IPv4 fields. The protocol must be specified as +.IR IPv4 . +.TP +.BR "--ip-source " "[!] \fIaddress\fP[/\fImask\fP]" +The source IP address. +The flag +.B --ip-src +is an alias for this option. +.TP +.BR "--ip-destination " "[!] \fIaddress\fP[/\fImask\fP]" +The destination IP address. +The flag +.B --ip-dst +is an alias for this option. +.TP +.BR "--ip-tos " "[!] \fItos\fP" +The IP type of service, in hexadecimal numbers. +.BR IPv4 . +.TP +.BR "--ip-protocol " "[!] \fIprotocol\fP" +The IP protocol. +The flag +.B --ip-proto +is an alias for this option. +.TP +.BR "--ip-source-port " "[!] \fIport1\fP[:\fIport2\fP]" +The source port or port range for the IP protocols 6 (TCP), 17 +(UDP), 33 (DCCP) or 132 (SCTP). The +.B --ip-protocol +option must be specified as +.IR TCP ", " UDP ", " DCCP " or " SCTP . +If +.IR port1 " is omitted, " 0:port2 " is used; if " port2 " is omitted but a colon is specified, " port1:65535 " is used." +The flag +.B --ip-sport +is an alias for this option. +.TP +.BR "--ip-destination-port " "[!] \fIport1\fP[:\fIport2\fP]" +The destination port or port range for ip protocols 6 (TCP), 17 +(UDP), 33 (DCCP) or 132 (SCTP). The +.B --ip-protocol +option must be specified as +.IR TCP ", " UDP ", " DCCP " or " SCTP . +If +.IR port1 " is omitted, " 0:port2 " is used; if " port2 " is omitted but a colon is specified, " port1:65535 " is used." +The flag +.B --ip-dport +is an alias for this option. +.SS ip6 +Specify IPv6 fields. The protocol must be specified as +.IR IPv6 . +.TP +.BR "--ip6-source " "[!] \fIaddress\fP[/\fImask\fP]" +The source IPv6 address. +The flag +.B --ip6-src +is an alias for this option. +.TP +.BR "--ip6-destination " "[!] \fIaddress\fP[/\fImask\fP]" +The destination IPv6 address. +The flag +.B --ip6-dst +is an alias for this option. +.TP +.BR "--ip6-tclass " "[!] \fItclass\fP" +The IPv6 traffic class, in hexadecimal numbers. +.TP +.BR "--ip6-protocol " "[!] \fIprotocol\fP" +The IP protocol. +The flag +.B --ip6-proto +is an alias for this option. +.TP +.BR "--ip6-source-port " "[!] \fIport1\fP[:\fIport2\fP]" +The source port or port range for the IPv6 protocols 6 (TCP), 17 +(UDP), 33 (DCCP) or 132 (SCTP). The +.B --ip6-protocol +option must be specified as +.IR TCP ", " UDP ", " DCCP " or " SCTP . +If +.IR port1 " is omitted, " 0:port2 " is used; if " port2 " is omitted but a colon is specified, " port1:65535 " is used." +The flag +.B --ip6-sport +is an alias for this option. +.TP +.BR "--ip6-destination-port " "[!] \fIport1\fP[:\fIport2\fP]" +The destination port or port range for IPv6 protocols 6 (TCP), 17 +(UDP), 33 (DCCP) or 132 (SCTP). The +.B --ip6-protocol +option must be specified as +.IR TCP ", " UDP ", " DCCP " or " SCTP . +If +.IR port1 " is omitted, " 0:port2 " is used; if " port2 " is omitted but a colon is specified, " port1:65535 " is used." +The flag +.B --ip6-dport +is an alias for this option. +.TP +.BR "--ip6-icmp-type " "[!] {\fItype\fP[:\fItype\fP]/\fIcode\fP[:\fIcode\fP]|\fItypename\fP}" +Specify ipv6\-icmp type and code to match. +Ranges for both type and code are supported. Type and code are +separated by a slash. Valid numbers for type and range are 0 to 255. +To match a single type including all valid codes, symbolic names can +be used instead of numbers. The list of known type names is shown by the command +.nf + ebtables \-\-help ip6 +.fi +This option is only valid for \-\-ip6-prococol ipv6-icmp. +.SS limit +This module matches at a limited rate using a token bucket filter. +A rule using this extension will match until this limit is reached. +It can be used with the +.B --log +watcher to give limited logging, for example. Its use is the same +as the limit match of iptables. +.TP +.BR "--limit " "[\fIvalue\fP]" +Maximum average matching rate: specified as a number, with an optional +.IR /second ", " /minute ", " /hour ", or " /day " suffix; the default is " 3/hour . +.TP +.BR "--limit-burst " "[\fInumber\fP]" +Maximum initial number of packets to match: this number gets recharged by +one every time the limit specified above is not reached, up to this +number; the default is +.IR 5 . +.SS mark_m +.TP +.BR "--mark " "[!] [\fIvalue\fP][/\fImask\fP]" +Matches frames with the given unsigned mark value. If a +.IR value " and " mask " are specified, the logical AND of the mark value of the frame and" +the user-specified +.IR mask " is taken before comparing it with the" +user-specified mark +.IR value ". When only a mark " +.IR value " is specified, the packet" +only matches when the mark value of the frame equals the user-specified +mark +.IR value . +If only a +.IR mask " is specified, the logical" +AND of the mark value of the frame and the user-specified +.IR mask " is taken and the frame matches when the result of this logical AND is" +non-zero. Only specifying a +.IR mask " is useful to match multiple mark values." +.SS pkttype +.TP +.BR "--pkttype-type " "[!] \fItype\fP" +Matches on the Ethernet "class" of the frame, which is determined by the +generic networking code. Possible values: +.IR broadcast " (MAC destination is the broadcast address)," +.IR multicast " (MAC destination is a multicast address)," +.IR host " (MAC destination is the receiving network device), or " +.IR otherhost " (none of the above)." +.SS stp +Specify stp BPDU (bridge protocol data unit) fields. The destination +address +.BR "" ( -d ") must be specified as the bridge group address" +.IR "" ( BGA ). +For all options for which a range of values can be specified, it holds that +if the lower bound is omitted (but the colon is not), then the lowest possible lower bound +for that option is used, while if the upper bound is omitted (but the colon again is not), the +highest possible upper bound for that option is used. +.TP +.BR "--stp-type " "[!] \fItype\fP" +The BPDU type (0-255), recognized non-numerical types are +.IR config ", denoting a configuration BPDU (=0), and" +.IR tcn ", denothing a topology change notification BPDU (=128)." +.TP +.BR "--stp-flags " "[!] \fIflag\fP" +The BPDU flag (0-255), recognized non-numerical flags are +.IR topology-change ", denoting the topology change flag (=1), and" +.IR topology-change-ack ", denoting the topology change acknowledgement flag (=128)." +.TP +.BR "--stp-root-prio " "[!] [\fIprio\fP][:\fIprio\fP]" +The root priority (0-65535) range. +.TP +.BR "--stp-root-addr " "[!] [\fIaddress\fP][/\fImask\fP]" +The root mac address, see the option +.BR -s " for more details." +.TP +.BR "--stp-root-cost " "[!] [\fIcost\fP][:\fIcost\fP]" +The root path cost (0-4294967295) range. +.TP +.BR "--stp-sender-prio " "[!] [\fIprio\fP][:\fIprio\fP]" +The BPDU's sender priority (0-65535) range. +.TP +.BR "--stp-sender-addr " "[!] [\fIaddress\fP][/\fImask\fP]" +The BPDU's sender mac address, see the option +.BR -s " for more details." +.TP +.BR "--stp-port " "[!] [\fIport\fP][:\fIport\fP]" +The port identifier (0-65535) range. +.TP +.BR "--stp-msg-age " "[!] [\fIage\fP][:\fIage\fP]" +The message age timer (0-65535) range. +.TP +.BR "--stp-max-age " "[!] [\fIage\fP][:\fIage\fP]" +The max age timer (0-65535) range. +.TP +.BR "--stp-hello-time " "[!] [\fItime\fP][:\fItime\fP]" +The hello time timer (0-65535) range. +.TP +.BR "--stp-forward-delay " "[!] [\fIdelay\fP][:\fIdelay\fP]" +The forward delay timer (0-65535) range. +.\" .SS string +.\" This module matches on a given string using some pattern matching strategy. +.\" .TP +.\" .BR "--string-algo " "\fIalgorithm\fP" +.\" The pattern matching strategy. (bm = Boyer-Moore, kmp = Knuth-Pratt-Morris) +.\" .TP +.\" .BR "--string-from " "\fIoffset\fP" +.\" The lowest offset from which a match can start. (default: 0) +.\" .TP +.\" .BR "--string-to " "\fIoffset\fP" +.\" The highest offset from which a match can start. (default: size of frame) +.\" .TP +.\" .BR "--string " "[!] \fIpattern\fP" +.\" Matches the given pattern. +.\" .TP +.\" .BR "--string-hex " "[!] \fIpattern\fP" +.\" Matches the given pattern in hex notation, e.g. '|0D 0A|', '|0D0A|', 'www|09|netfilter|03|org|00|' +.\" .TP +.\" .BR "--string-icase" +.\" Ignore case when searching. +.SS vlan +Specify 802.1Q Tag Control Information fields. +The protocol must be specified as +.IR 802_1Q " (0x8100)." +.TP +.BR "--vlan-id " "[!] \fIid\fP" +The VLAN identifier field (VID). Decimal number from 0 to 4095. +.TP +.BR "--vlan-prio " "[!] \fIprio\fP" +The user priority field, a decimal number from 0 to 7. +The VID should be set to 0 ("null VID") or unspecified +(in the latter case the VID is deliberately set to 0). +.TP +.BR "--vlan-encap " "[!] \fItype\fP" +The encapsulated Ethernet frame type/length. +Specified as a hexadecimal +number from 0x0000 to 0xFFFF or as a symbolic name +from +.BR /etc/ethertypes . + +.SS WATCHER EXTENSIONS +Watchers only look at frames passing by, they don't modify them nor decide +to accept the frames or not. These watchers only +see the frame if the frame matches the rule, and they see it before the +target is executed. +.SS log +The log watcher writes descriptive data about a frame to the syslog. +.TP +.B "--log" +.br +Log with the default loggin options: log-level= +.IR info , +log-prefix="", no ip logging, no arp logging. +.TP +.B --log-level "\fIlevel\fP" +.br +Defines the logging level. For the possible values, see +.BR "ebtables -h log" . +The default level is +.IR info . +.TP +.BR --log-prefix " \fItext\fP" +.br +Defines the prefix +.I text +to be printed at the beginning of the line with the logging information. +.TP +.B --log-ip +.br +Will log the ip information when a frame made by the ip protocol matches +the rule. The default is no ip information logging. +.TP +.B --log-ip6 +.br +Will log the ipv6 information when a frame made by the ipv6 protocol matches +the rule. The default is no ipv6 information logging. +.TP +.B --log-arp +.br +Will log the (r)arp information when a frame made by the (r)arp protocols +matches the rule. The default is no (r)arp information logging. +.SS nflog +The nflog watcher passes the packet to the loaded logging backend +in order to log the packet. This is usually used in combination with +nfnetlink_log as logging backend, which will multicast the packet +through a +.IR netlink +socket to the specified multicast group. One or more userspace processes +may subscribe to the group to receive the packets. +.TP +.B "--nflog" +.br +Log with the default logging options +.TP +.B --nflog-group "\fInlgroup\fP" +.br +The netlink group (1 - 2^32-1) to which packets are (only applicable for +nfnetlink_log). The default value is 1. +.TP +.B --nflog-prefix "\fIprefix\fP" +.br +A prefix string to include in the log message, up to 30 characters +long, useful for distinguishing messages in the logs. +.TP +.B --nflog-range "\fIsize\fP" +.br +The number of bytes to be copied to userspace (only applicable for +nfnetlink_log). nfnetlink_log instances may specify their own +range, this option overrides it. +.TP +.B --nflog-threshold "\fIsize\fP" +.br +Number of packets to queue inside the kernel before sending them +to userspace (only applicable for nfnetlink_log). Higher values +result in less overhead per packet, but increase delay until the +packets reach userspace. The default value is 1. +.SS ulog +The ulog watcher passes the packet to a userspace +logging daemon using netlink multicast sockets. This differs +from the log watcher in the sense that the complete packet is +sent to userspace instead of a descriptive text and that +netlink multicast sockets are used instead of the syslog. +This watcher enables parsing of packets with userspace programs, the +physical bridge in and out ports are also included in the netlink messages. +The ulog watcher module accepts 2 parameters when the module is loaded +into the kernel (e.g. with modprobe): +.B nlbufsiz +specifies how big the buffer for each netlink multicast +group is. If you say +.IR nlbufsiz=8192 , +for example, up to eight kB of packets will +get accumulated in the kernel until they are sent to userspace. It is +not possible to allocate more than 128kB. Please also keep in mind that +this buffer size is allocated for each nlgroup you are using, so the +total kernel memory usage increases by that factor. The default is 4096. +.B flushtimeout +specifies after how many hundredths of a second the queue should be +flushed, even if it is not full yet. The default is 10 (one tenth of +a second). +.TP +.B "--ulog" +.br +Use the default settings: ulog-prefix="", ulog-nlgroup=1, +ulog-cprange=4096, ulog-qthreshold=1. +.TP +.B --ulog-prefix "\fItext\fP" +.br +Defines the prefix included with the packets sent to userspace. +.TP +.BR --ulog-nlgroup " \fIgroup\fP" +.br +Defines which netlink group number to use (a number from 1 to 32). +Make sure the netlink group numbers used for the iptables ULOG +target differ from those used for the ebtables ulog watcher. +The default group number is 1. +.TP +.BR --ulog-cprange " \fIrange\fP" +.br +Defines the maximum copy range to userspace, for packets matching the +rule. The default range is 0, which means the maximum copy range is +given by +.BR nlbufsiz . +A maximum copy range larger than +128*1024 is meaningless as the packets sent to userspace have an upper +size limit of 128*1024. +.TP +.BR --ulog-qthreshold " \fIthreshold\fP" +.br +Queue at most +.I threshold +number of packets before sending them to +userspace with a netlink socket. Note that packets can be sent to +userspace before the queue is full, this happens when the ulog +kernel timer goes off (the frequency of this timer depends on +.BR flushtimeout ). +.SS TARGET EXTENSIONS +.SS arpreply +The +.B arpreply +target can be used in the +.BR PREROUTING " chain of the " nat " table." +If this target sees an ARP request it will automatically reply +with an ARP reply. The used MAC address for the reply can be specified. +The protocol must be specified as +.IR ARP . +When the ARP message is not an ARP request or when the ARP request isn't +for an IP address on an Ethernet network, it is ignored by this target +.BR "" ( CONTINUE ). +When the ARP request is malformed, it is dropped +.BR "" ( DROP ). +.TP +.BR "--arpreply-mac " "\fIaddress\fP" +Specifies the MAC address to reply with: the Ethernet source MAC and the +ARP payload source MAC will be filled in with this address. +.TP +.BR "--arpreply-target " "\fItarget\fP" +Specifies the standard target. After sending the ARP reply, the rule still +has to give a standard target so ebtables knows what to do with the ARP request. +The default target +.BR "" "is " DROP . +.SS dnat +The +.B dnat +target can only be used in the +.BR PREROUTING " and " OUTPUT " chains of the " nat " table." +It specifies that the destination MAC address has to be changed. +.TP +.BR "--to-destination " "\fIaddress\fP" +.br +Change the destination MAC address to the specified +.IR address . +The flag +.B --to-dst +is an alias for this option. +.TP +.BR "--dnat-target " "\fItarget\fP" +.br +Specifies the standard target. After doing the dnat, the rule still has to +give a standard target so ebtables knows what to do with the dnated frame. +The default target is +.BR ACCEPT . +Making it +.BR CONTINUE " could let you use" +multiple target extensions on the same frame. Making it +.BR DROP " only makes" +sense in the +.BR BROUTING " chain but using the " redirect " target is more logical there. " RETURN " is also allowed. Note that using " RETURN +in a base chain is not allowed (for obvious reasons). +.SS mark +.BR "" "The " mark " target can be used in every chain of every table. It is possible" +to use the marking of a frame/packet in both ebtables and iptables, +if the bridge-nf code is compiled into the kernel. Both put the marking at the +same place. This allows for a form of communication between ebtables and iptables. +.TP +.BR "--mark-set " "\fIvalue\fP" +.br +Mark the frame with the specified non-negative +.IR value . +.TP +.BR "--mark-or " "\fIvalue\fP" +.br +Or the frame with the specified non-negative +.IR value . +.TP +.BR "--mark-and " "\fIvalue\fP" +.br +And the frame with the specified non-negative +.IR value . +.TP +.BR "--mark-xor " "\fIvalue\fP" +.br +Xor the frame with the specified non-negative +.IR value . +.TP +.BR "--mark-target " "\fItarget\fP" +.br +Specifies the standard target. After marking the frame, the rule +still has to give a standard target so ebtables knows what to do. +The default target is +.BR ACCEPT ". Making it " CONTINUE " can let you do other" +things with the frame in subsequent rules of the chain. +.SS redirect +The +.B redirect +target will change the MAC target address to that of the bridge device the +frame arrived on. This target can only be used in the +.BR PREROUTING " chain of the " nat " table." +The MAC address of the bridge is used as destination address." +.TP +.BR "--redirect-target " "\fItarget\fP" +.br +Specifies the standard target. After doing the MAC redirect, the rule +still has to give a standard target so ebtables knows what to do. +The default target is +.BR ACCEPT ". Making it " CONTINUE " could let you use" +multiple target extensions on the same frame. Making it +.BR DROP " in the " BROUTING " chain will let the frames be routed. " RETURN " is also allowed. Note" +.BR "" "that using " RETURN " in a base chain is not allowed." +.SS snat +The +.B snat +target can only be used in the +.BR POSTROUTING " chain of the " nat " table." +It specifies that the source MAC address has to be changed. +.TP +.BR "--to-source " "\fIaddress\fP" +.br +Changes the source MAC address to the specified +.IR address ". The flag" +.B --to-src +is an alias for this option. +.TP +.BR "--snat-target " "\fItarget\fP" +.br +Specifies the standard target. After doing the snat, the rule still has +to give a standard target so ebtables knows what to do. +.BR "" "The default target is " ACCEPT ". Making it " CONTINUE " could let you use" +.BR "" "multiple target extensions on the same frame. Making it " DROP " doesn't" +.BR "" "make sense, but you could do that too. " RETURN " is also allowed. Note" +.BR "" "that using " RETURN " in a base chain is not allowed." +.br +.TP +.BR "--snat-arp " +.br +Also change the hardware source address inside the arp header if the packet is an +arp message and the hardware address length in the arp header is 6 bytes. +.br +.SH FILES +.I /etc/ethertypes +.SH ENVIRONMENT VARIABLES +.I EBTABLES_ATOMIC_FILE +.SH MAILINGLISTS +.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 +.BR among " and " string +matches. And finally, this list is probably not complete. +.SH SEE ALSO +.BR xtables-nft "(8), " iptables "(8), " ip (8) +.PP +.BR "" "See " https://wiki.nftables.org diff --git a/iptables/ip6tables-restore.c b/iptables/ip6tables-restore.c deleted file mode 100644 index 3706b981a806a9ecd35930671ac2df1f2a036c26..0000000000000000000000000000000000000000 --- a/iptables/ip6tables-restore.c +++ /dev/null @@ -1,391 +0,0 @@ -/* Code to restore the iptables state, from file by ip6tables-save. - * Author: Andras Kis-Szabo - * - * based on iptables-restore - * Authors: - * Harald Welte - * Rusty Russell - * This code is distributed under the terms of GNU GPL v2 - */ - -#include -#include -#include -#include -#include -#include -#include "ip6tables.h" -#include "xshared.h" -#include "xtables.h" -#include "libiptc/libip6tc.h" -#include "ip6tables-multi.h" - -static int counters, verbose, noflush, wait; - -static struct timeval wait_interval = { - .tv_sec = 1, -}; - -/* Keeping track of external matches and targets. */ -static const struct option options[] = { - {.name = "counters", .has_arg = 0, .val = 'c'}, - {.name = "verbose", .has_arg = 0, .val = 'v'}, - {.name = "version", .has_arg = 0, .val = 'V'}, - {.name = "test", .has_arg = 0, .val = 't'}, - {.name = "help", .has_arg = 0, .val = 'h'}, - {.name = "noflush", .has_arg = 0, .val = 'n'}, - {.name = "modprobe", .has_arg = 1, .val = 'M'}, - {.name = "table", .has_arg = 1, .val = 'T'}, - {.name = "wait", .has_arg = 2, .val = 'w'}, - {.name = "wait-interval", .has_arg = 2, .val = 'W'}, - {NULL}, -}; - -#define prog_name ip6tables_globals.program_name -#define prog_vers ip6tables_globals.program_version - -static void print_usage(const char *name, const char *version) -{ - fprintf(stderr, "Usage: %s [-c] [-v] [-V] [-t] [-h] [-n] [-w secs] [-W usecs] [-T table] [-M command]\n" - " [ --counters ]\n" - " [ --verbose ]\n" - " [ --version]\n" - " [ --test ]\n" - " [ --help ]\n" - " [ --noflush ]\n" - " [ --wait=\n" - " [ --wait-interval=\n" - " [ --table= ]\n" - " [ --modprobe= ]\n", name); -} - -static struct xtc_handle *create_handle(const char *tablename) -{ - struct xtc_handle *handle; - - handle = ip6tc_init(tablename); - - if (!handle) { - /* try to insmod the module if iptc_init failed */ - xtables_load_ko(xtables_modprobe_program, false); - handle = ip6tc_init(tablename); - } - - if (!handle) { - xtables_error(PARAMETER_PROBLEM, "%s: unable to initialize " - "table '%s'\n", prog_name, tablename); - exit(1); - } - return handle; -} - -int ip6tables_restore_main(int argc, char *argv[]) -{ - struct xtc_handle *handle = NULL; - char buffer[10240]; - int c, lock; - char curtable[XT_TABLE_MAXNAMELEN + 1] = {}; - FILE *in; - int in_table = 0, testing = 0; - const char *tablename = NULL; - const struct xtc_ops *ops = &ip6tc_ops; - - line = 0; - lock = XT_LOCK_NOT_ACQUIRED; - - ip6tables_globals.program_name = "ip6tables-restore"; - c = xtables_init_all(&ip6tables_globals, NFPROTO_IPV6); - if (c < 0) { - fprintf(stderr, "%s/%s Failed to initialize xtables\n", - ip6tables_globals.program_name, - ip6tables_globals.program_version); - exit(1); - } -#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS) - init_extensions(); - init_extensions6(); -#endif - - while ((c = getopt_long(argc, argv, "bcvVthnwWM:T:", options, NULL)) != -1) { - switch (c) { - case 'b': - fprintf(stderr, "-b/--binary option is not implemented\n"); - break; - case 'c': - counters = 1; - break; - case 'v': - verbose = 1; - break; - case 'V': - printf("%s v%s (legacy)\n", prog_name, prog_vers); - exit(0); - case 't': - testing = 1; - break; - case 'h': - print_usage("ip6tables-restore", - IPTABLES_VERSION); - exit(0); - case 'n': - noflush = 1; - break; - case 'w': - wait = parse_wait_time(argc, argv); - break; - case 'W': - parse_wait_interval(argc, argv, &wait_interval); - break; - case 'M': - xtables_modprobe_program = optarg; - break; - case 'T': - tablename = optarg; - break; - default: - fprintf(stderr, - "Try `ip6tables-restore -h' for more information.\n"); - exit(1); - } - } - - if (optind == argc - 1) { - in = fopen(argv[optind], "re"); - if (!in) { - fprintf(stderr, "Can't open %s: %s\n", argv[optind], - strerror(errno)); - exit(1); - } - } - else if (optind < argc) { - fprintf(stderr, "Unknown arguments found on commandline\n"); - exit(1); - } - else in = stdin; - - if (!wait_interval.tv_sec && !wait) { - fprintf(stderr, "Option --wait-interval requires option --wait\n"); - exit(1); - } - - /* Grab standard input. */ - while (fgets(buffer, sizeof(buffer), in)) { - int ret = 0; - - line++; - if (buffer[0] == '\n') - continue; - else if (buffer[0] == '#') { - if (verbose) - fputs(buffer, stdout); - continue; - } else if ((strcmp(buffer, "COMMIT\n") == 0) && (in_table)) { - if (!testing) { - DEBUGP("Calling commit\n"); - ret = ops->commit(handle); - ops->free(handle); - handle = NULL; - } else { - DEBUGP("Not calling commit, testing\n"); - ret = 1; - } - - /* Done with the current table, release the lock. */ - if (lock >= 0) { - xtables_unlock(lock); - lock = XT_LOCK_NOT_ACQUIRED; - } - - in_table = 0; - } else if ((buffer[0] == '*') && (!in_table)) { - /* Acquire a lock before we create a new table handle */ - lock = xtables_lock_or_exit(wait, &wait_interval); - - /* New table */ - char *table; - - table = strtok(buffer+1, " \t\n"); - 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); - exit(1); - } - strncpy(curtable, table, XT_TABLE_MAXNAMELEN); - curtable[XT_TABLE_MAXNAMELEN] = '\0'; - - if (tablename != NULL && strcmp(tablename, table) != 0) { - if (lock >= 0) { - xtables_unlock(lock); - lock = XT_LOCK_NOT_ACQUIRED; - } - continue; - } - if (handle) - ops->free(handle); - - handle = create_handle(table); - if (noflush == 0) { - DEBUGP("Cleaning all chains of table '%s'\n", - table); - for_each_chain6(flush_entries6, verbose, 1, - handle); - - DEBUGP("Deleting all user-defined chains " - "of table '%s'\n", table); - for_each_chain6(delete_chain6, verbose, 0, - handle); - } - - ret = 1; - in_table = 1; - - } else if ((buffer[0] == ':') && (in_table)) { - /* New chain. */ - char *policy, *chain; - - chain = strtok(buffer+1, " \t\n"); - 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); - exit(1); - } - - if (strlen(chain) >= XT_EXTENSION_MAXNAMELEN) - xtables_error(PARAMETER_PROBLEM, - "Invalid chain name `%s' " - "(%u chars max)", - chain, XT_EXTENSION_MAXNAMELEN - 1); - - if (ops->builtin(chain, handle) <= 0) { - if (noflush && ops->is_chain(chain, handle)) { - DEBUGP("Flushing existing user defined chain '%s'\n", chain); - if (!ops->flush_entries(chain, handle)) - xtables_error(PARAMETER_PROBLEM, - "error flushing chain " - "'%s':%s\n", chain, - strerror(errno)); - } else { - DEBUGP("Creating new chain '%s'\n", chain); - if (!ops->create_chain(chain, handle)) - xtables_error(PARAMETER_PROBLEM, - "error creating chain " - "'%s':%s\n", chain, - strerror(errno)); - } - } - - policy = strtok(NULL, " \t\n"); - 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); - exit(1); - } - - if (strcmp(policy, "-") != 0) { - struct xt_counters count = {}; - - if (counters) { - char *ctrs; - ctrs = strtok(NULL, " \t\n"); - - if (!ctrs || !parse_counters(ctrs, &count)) - xtables_error(PARAMETER_PROBLEM, - "invalid policy counters " - "for chain '%s'\n", chain); - } - - DEBUGP("Setting policy of chain %s to %s\n", - chain, policy); - - if (!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, - ops->strerror(errno)); - } - - ret = 1; - - } else if (in_table) { - int a; - char *pcnt = NULL; - char *bcnt = NULL; - char *parsestart; - - if (buffer[0] == '[') { - /* we have counters in our input */ - char *ptr = strchr(buffer, ']'); - - if (!ptr) - xtables_error(PARAMETER_PROBLEM, - "Bad line %u: need ]\n", - line); - - pcnt = strtok(buffer+1, ":"); - if (!pcnt) - xtables_error(PARAMETER_PROBLEM, - "Bad line %u: need :\n", - line); - - bcnt = strtok(NULL, "]"); - if (!bcnt) - xtables_error(PARAMETER_PROBLEM, - "Bad line %u: need ]\n", - line); - - /* start command parsing after counter */ - parsestart = ptr + 1; - } else { - /* start command parsing at start of line */ - parsestart = buffer; - } - - add_argv(argv[0], 0); - add_argv("-t", 0); - add_argv(curtable, 0); - - if (counters && pcnt && bcnt) { - add_argv("--set-counters", 0); - add_argv((char *) pcnt, 0); - add_argv((char *) bcnt, 0); - } - - add_param_to_argv(parsestart, line); - - DEBUGP("calling do_command6(%u, argv, &%s, handle):\n", - newargc, curtable); - - for (a = 0; a < newargc; a++) - DEBUGP("argv[%u]: %s\n", a, newargv[a]); - - ret = do_command6(newargc, newargv, - &newargv[2], &handle, true); - - free_argv(); - fflush(stdout); - } - if (tablename != NULL && strcmp(tablename, curtable) != 0) - continue; - if (!ret) { - fprintf(stderr, "%s: line %u failed\n", - xt_params->program_name, line); - exit(1); - } - } - if (in_table) { - fprintf(stderr, "%s: COMMIT expected at line %u\n", - xt_params->program_name, line + 1); - exit(1); - } - - fclose(in); - return 0; -} diff --git a/iptables/ip6tables-save.c b/iptables/ip6tables-save.c deleted file mode 100644 index 5085982bfc197554a21b8698364c1087d5475417..0000000000000000000000000000000000000000 --- a/iptables/ip6tables-save.c +++ /dev/null @@ -1,203 +0,0 @@ -/* Code to save the ip6tables state, in human readable-form. */ -/* Author: Andras Kis-Szabo - * Original code: iptables-save - * Authors: Paul 'Rusty' Russel and - * Harald Welte - * This code is distributed under the terms of GNU GPL v2 - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "libiptc/libip6tc.h" -#include "ip6tables.h" -#include "ip6tables-multi.h" - -#define prog_name ip6tables_globals.program_name -#define prog_vers ip6tables_globals.program_version - -static int show_counters; - -static const struct option options[] = { - {.name = "counters", .has_arg = false, .val = 'c'}, - {.name = "dump", .has_arg = false, .val = 'd'}, - {.name = "table", .has_arg = true, .val = 't'}, - {.name = "modprobe", .has_arg = true, .val = 'M'}, - {.name = "file", .has_arg = true, .val = 'f'}, - {.name = "version", .has_arg = false, .val = 'V'}, - {NULL}, -}; - - -/* Debugging prototype. */ -static int for_each_table(int (*func)(const char *tablename)) -{ - int ret = 1; - FILE *procfile = NULL; - char tablename[XT_TABLE_MAXNAMELEN+1]; - static const char filename[] = "/proc/net/ip6_tables_names"; - - procfile = fopen(filename, "re"); - if (!procfile) { - if (errno == ENOENT) - return ret; - fprintf(stderr, "Failed to list table names in %s: %s\n", - filename, strerror(errno)); - exit(1); - } - - while (fgets(tablename, sizeof(tablename), procfile)) { - if (tablename[strlen(tablename) - 1] != '\n') - xtables_error(OTHER_PROBLEM, - "Badly formed tablename `%s'\n", - tablename); - tablename[strlen(tablename) - 1] = '\0'; - ret &= func(tablename); - } - - fclose(procfile); - return ret; -} - - -static int do_output(const char *tablename) -{ - struct xtc_handle *h; - const char *chain = NULL; - - if (!tablename) - return for_each_table(&do_output); - - h = ip6tc_init(tablename); - if (h == NULL) { - xtables_load_ko(xtables_modprobe_program, false); - h = ip6tc_init(tablename); - } - if (!h) - xtables_error(OTHER_PROBLEM, "Cannot initialize: %s\n", - ip6tc_strerror(errno)); - - time_t now = time(NULL); - - printf("# Generated by ip6tables-save v%s on %s", - IPTABLES_VERSION, ctime(&now)); - printf("*%s\n", tablename); - - /* Dump out chain names first, - * thereby preventing dependency conflicts */ - for (chain = ip6tc_first_chain(h); - chain; - chain = ip6tc_next_chain(h)) { - - printf(":%s ", chain); - if (ip6tc_builtin(chain, h)) { - struct xt_counters count; - printf("%s ", - ip6tc_get_policy(chain, &count, h)); - printf("[%llu:%llu]\n", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt); - } else { - printf("- [0:0]\n"); - } - } - - for (chain = ip6tc_first_chain(h); - chain; - chain = ip6tc_next_chain(h)) { - const struct ip6t_entry *e; - - /* Dump out rules */ - e = ip6tc_first_rule(chain, h); - while(e) { - print_rule6(e, h, chain, show_counters); - e = ip6tc_next_rule(e, h); - } - } - - now = time(NULL); - printf("COMMIT\n"); - printf("# Completed on %s", ctime(&now)); - ip6tc_free(h); - - return 1; -} - -/* Format: - * :Chain name POLICY packets bytes - * rule - */ -int ip6tables_save_main(int argc, char *argv[]) -{ - const char *tablename = NULL; - FILE *file = NULL; - int ret, c; - - ip6tables_globals.program_name = "ip6tables-save"; - c = xtables_init_all(&ip6tables_globals, NFPROTO_IPV6); - if (c < 0) { - fprintf(stderr, "%s/%s Failed to initialize xtables\n", - ip6tables_globals.program_name, - ip6tables_globals.program_version); - exit(1); - } -#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS) - init_extensions(); - init_extensions6(); -#endif - - while ((c = getopt_long(argc, argv, "bcdt:M:f:V", options, NULL)) != -1) { - switch (c) { - case 'b': - fprintf(stderr, "-b/--binary option is not implemented\n"); - break; - case 'c': - show_counters = 1; - break; - - case 't': - /* Select specific table. */ - tablename = optarg; - break; - case 'M': - xtables_modprobe_program = optarg; - break; - case 'f': - file = fopen(optarg, "w"); - if (file == NULL) { - fprintf(stderr, "Failed to open file, error: %s\n", - strerror(errno)); - exit(1); - } - ret = dup2(fileno(file), STDOUT_FILENO); - if (ret == -1) { - fprintf(stderr, "Failed to redirect stdout, error: %s\n", - strerror(errno)); - exit(1); - } - fclose(file); - break; - case 'd': - do_output(tablename); - exit(0); - case 'V': - printf("%s v%s (legacy)\n", prog_name, prog_vers); - exit(0); - default: - fprintf(stderr, - "Look at manual page `ip6tables-save.8' for more information.\n"); - exit(1); - } - } - - if (optind < argc) { - fprintf(stderr, "Unknown arguments found on commandline\n"); - exit(1); - } - - return !do_output(tablename); -} diff --git a/iptables/ip6tables.c b/iptables/ip6tables.c index fe089de4c85d76ab166b4a449bf30e61045663e4..050afa9a36458c3721c4595244d9032f3159d270 100644 --- a/iptables/ip6tables.c +++ b/iptables/ip6tables.c @@ -1441,7 +1441,7 @@ int do_command6(int argc, char *argv[], char **table, case 'j': set_option(&cs.options, OPT_JUMP, &cs.fw6.ipv6.invflags, cs.invert); - command_jump(&cs); + command_jump(&cs, optarg); break; diff --git a/iptables/iptables-restore.c b/iptables/iptables-restore.c index daee5fd99564a632fc0ea5ea79113098b587336b..575e619cc30db2620bd4fbbfd2798feb77147fa9 100644 --- a/iptables/iptables-restore.c +++ b/iptables/iptables-restore.c @@ -12,10 +12,13 @@ #include #include #include "iptables.h" +#include "ip6tables.h" #include "xshared.h" #include "xtables.h" #include "libiptc/libiptc.h" +#include "libiptc/libip6tc.h" #include "iptables-multi.h" +#include "ip6tables-multi.h" static int counters, verbose, noflush, wait; @@ -38,9 +41,6 @@ static const struct option options[] = { {NULL}, }; -#define prog_name iptables_globals.program_name -#define prog_vers iptables_globals.program_version - static void print_usage(const char *name, const char *version) { fprintf(stderr, "Usage: %s [-c] [-v] [-V] [-t] [-h] [-n] [-w secs] [-W usecs] [-T table] [-M command]\n" @@ -56,28 +56,42 @@ static void print_usage(const char *name, const char *version) " [ --modprobe= ]\n", name); } -static struct xtc_handle *create_handle(const char *tablename) +struct iptables_restore_cb { + const struct xtc_ops *ops; + + int (*for_each_chain)(int (*fn)(const xt_chainlabel, + int, struct xtc_handle *), + int verbose, int builtinstoo, + struct xtc_handle *handle); + int (*flush_entries)(const xt_chainlabel, int, struct xtc_handle *); + int (*delete_chain)(const xt_chainlabel, int, struct xtc_handle *); + int (*do_command)(int argc, char *argv[], char **table, + struct xtc_handle **handle, bool restore); +}; + +static struct xtc_handle * +create_handle(struct iptables_restore_cb *cb, const char *tablename) { struct xtc_handle *handle; - handle = iptc_init(tablename); + handle = cb->ops->init(tablename); if (!handle) { /* try to insmod the module if iptc_init failed */ xtables_load_ko(xtables_modprobe_program, false); - handle = iptc_init(tablename); + handle = cb->ops->init(tablename); } if (!handle) { xtables_error(PARAMETER_PROBLEM, "%s: unable to initialize " - "table '%s'\n", prog_name, tablename); + "table '%s'\n", xt_params->program_name, tablename); exit(1); } return handle; } -int -iptables_restore_main(int argc, char *argv[]) +static int +ip46tables_restore_main(struct iptables_restore_cb *cb, int argc, char *argv[]) { struct xtc_handle *handle = NULL; char buffer[10240]; @@ -86,24 +100,10 @@ iptables_restore_main(int argc, char *argv[]) FILE *in; int in_table = 0, testing = 0; const char *tablename = NULL; - const struct xtc_ops *ops = &iptc_ops; line = 0; lock = XT_LOCK_NOT_ACQUIRED; - iptables_globals.program_name = "iptables-restore"; - c = xtables_init_all(&iptables_globals, NFPROTO_IPV4); - if (c < 0) { - fprintf(stderr, "%s/%s Failed to initialize xtables\n", - iptables_globals.program_name, - iptables_globals.program_version); - exit(1); - } -#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS) - init_extensions(); - init_extensions4(); -#endif - while ((c = getopt_long(argc, argv, "bcvVthnwWM:T:", options, NULL)) != -1) { switch (c) { case 'b': @@ -116,13 +116,15 @@ iptables_restore_main(int argc, char *argv[]) verbose = 1; break; case 'V': - printf("%s v%s (legacy)\n", prog_name, prog_vers); + printf("%s v%s (legacy)\n", + xt_params->program_name, + xt_params->program_version); exit(0); case 't': testing = 1; break; case 'h': - print_usage("iptables-restore", + print_usage(xt_params->program_name, IPTABLES_VERSION); exit(0); case 'n': @@ -142,7 +144,8 @@ iptables_restore_main(int argc, char *argv[]) break; default: fprintf(stderr, - "Try `iptables-restore -h' for more information.\n"); + "Try `%s -h' for more information.\n", + xt_params->program_name); exit(1); } } @@ -180,8 +183,8 @@ iptables_restore_main(int argc, char *argv[]) } else if ((strcmp(buffer, "COMMIT\n") == 0) && (in_table)) { if (!testing) { DEBUGP("Calling commit\n"); - ret = ops->commit(handle); - ops->free(handle); + ret = cb->ops->commit(handle); + cb->ops->free(handle); handle = NULL; } else { DEBUGP("Not calling commit, testing\n"); @@ -213,7 +216,7 @@ iptables_restore_main(int argc, char *argv[]) strncpy(curtable, table, XT_TABLE_MAXNAMELEN); curtable[XT_TABLE_MAXNAMELEN] = '\0'; - if (tablename && (strcmp(tablename, table) != 0)) { + if (tablename && strcmp(tablename, table) != 0) { if (lock >= 0) { xtables_unlock(lock); lock = XT_LOCK_NOT_ACQUIRED; @@ -221,18 +224,18 @@ iptables_restore_main(int argc, char *argv[]) continue; } if (handle) - ops->free(handle); + cb->ops->free(handle); - handle = create_handle(table); + handle = create_handle(cb, table); if (noflush == 0) { DEBUGP("Cleaning all chains of table '%s'\n", table); - for_each_chain4(flush_entries4, verbose, 1, + cb->for_each_chain(cb->flush_entries, verbose, 1, handle); DEBUGP("Deleting all user-defined chains " "of table '%s'\n", table); - for_each_chain4(delete_chain4, verbose, 0, + cb->for_each_chain(cb->delete_chain, verbose, 0, handle); } @@ -258,17 +261,17 @@ iptables_restore_main(int argc, char *argv[]) "(%u chars max)", chain, XT_EXTENSION_MAXNAMELEN - 1); - if (ops->builtin(chain, handle) <= 0) { - if (noflush && ops->is_chain(chain, handle)) { + if (cb->ops->builtin(chain, handle) <= 0) { + if (noflush && cb->ops->is_chain(chain, handle)) { DEBUGP("Flushing existing user defined chain '%s'\n", chain); - if (!ops->flush_entries(chain, handle)) + if (!cb->ops->flush_entries(chain, handle)) xtables_error(PARAMETER_PROBLEM, "error flushing chain " "'%s':%s\n", chain, strerror(errno)); } else { DEBUGP("Creating new chain '%s'\n", chain); - if (!ops->create_chain(chain, handle)) + if (!cb->ops->create_chain(chain, handle)) xtables_error(PARAMETER_PROBLEM, "error creating chain " "'%s':%s\n", chain, @@ -294,20 +297,20 @@ iptables_restore_main(int argc, char *argv[]) if (!ctrs || !parse_counters(ctrs, &count)) xtables_error(PARAMETER_PROBLEM, - "invalid policy counters " - "for chain '%s'\n", chain); + "invalid policy counters " + "for chain '%s'\n", chain); } DEBUGP("Setting policy of chain %s to %s\n", chain, policy); - if (!ops->set_policy(chain, policy, &count, + 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, - ops->strerror(errno)); + cb->ops->strerror(errno)); } ret = 1; @@ -358,19 +361,19 @@ iptables_restore_main(int argc, char *argv[]) add_param_to_argv(parsestart, line); - DEBUGP("calling do_command4(%u, argv, &%s, handle):\n", + DEBUGP("calling do_command(%u, argv, &%s, handle):\n", newargc, curtable); for (a = 0; a < newargc; a++) DEBUGP("argv[%u]: %s\n", a, newargv[a]); - ret = do_command4(newargc, newargv, + ret = cb->do_command(newargc, newargv, &newargv[2], &handle, true); free_argv(); fflush(stdout); } - if (tablename && (strcmp(tablename, curtable) != 0)) + if (tablename && strcmp(tablename, curtable) != 0) continue; if (!ret) { fprintf(stderr, "%s: line %u failed\n", @@ -387,3 +390,66 @@ iptables_restore_main(int argc, char *argv[]) fclose(in); return 0; } + + +#if defined ENABLE_IPV4 +struct iptables_restore_cb ipt_restore_cb = { + .ops = &iptc_ops, + .for_each_chain = for_each_chain4, + .flush_entries = flush_entries4, + .delete_chain = delete_chain4, + .do_command = do_command4, +}; + +int +iptables_restore_main(int argc, char *argv[]) +{ + int c; + + iptables_globals.program_name = "iptables-restore"; + c = xtables_init_all(&iptables_globals, NFPROTO_IPV4); + if (c < 0) { + fprintf(stderr, "%s/%s Failed to initialize xtables\n", + iptables_globals.program_name, + iptables_globals.program_version); + exit(1); + } +#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS) + init_extensions(); + init_extensions4(); +#endif + + return ip46tables_restore_main(&ipt_restore_cb, argc, argv); +} +#endif + +#if defined ENABLE_IPV6 +struct iptables_restore_cb ip6t_restore_cb = { + .ops = &ip6tc_ops, + .for_each_chain = for_each_chain6, + .flush_entries = flush_entries6, + .delete_chain = delete_chain6, + .do_command = do_command6, +}; + +int +ip6tables_restore_main(int argc, char *argv[]) +{ + int c; + + ip6tables_globals.program_name = "ip6tables-restore"; + c = xtables_init_all(&ip6tables_globals, NFPROTO_IPV6); + if (c < 0) { + fprintf(stderr, "%s/%s Failed to initialize xtables\n", + ip6tables_globals.program_name, + ip6tables_globals.program_version); + exit(1); + } +#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS) + init_extensions(); + init_extensions6(); +#endif + + return ip46tables_restore_main(&ip6t_restore_cb, argc, argv); +} +#endif diff --git a/iptables/iptables-save.8.in b/iptables/iptables-save.8.in index 51e11f3e7adca0d5550814b6979ea38d41f20907..29ef2829fb330c37e99796771dfc0f6bc82ab807 100644 --- a/iptables/iptables-save.8.in +++ b/iptables/iptables-save.8.in @@ -48,8 +48,11 @@ will log to STDOUT. include the current values of all packet and byte counters in the output .TP \fB\-t\fR, \fB\-\-table\fR \fItablename\fP -restrict output to only one table. If not specified, output includes all -available tables. +restrict output to only one table. If the kernel is configured with automatic +module loading, an attempt will be made to load the appropriate module for +that table if it is not already there. +.br +If not specified, output includes all available tables. .SH BUGS None known as of iptables-1.2.1 release .SH AUTHORS diff --git a/iptables/iptables-save.c b/iptables/iptables-save.c index d694d212d7edf0d30aeaef2253d09872479080de..826cb1e4f7b941b7c254e7546cc5a84d59e4693b 100644 --- a/iptables/iptables-save.c +++ b/iptables/iptables-save.c @@ -15,11 +15,12 @@ #include #include #include "libiptc/libiptc.h" +#include "libiptc/libip6tc.h" #include "iptables.h" +#include "ip6tables.h" #include "iptables-multi.h" - -#define prog_name iptables_globals.program_name -#define prog_vers iptables_globals.program_version +#include "ip6tables-multi.h" +#include "xshared.h" static int show_counters; @@ -33,20 +34,26 @@ static const struct option options[] = { {NULL}, }; -/* Debugging prototype. */ -static int for_each_table(int (*func)(const char *tablename)) +struct iptables_save_cb { + const struct xtc_ops *ops; + + void (*dump_rules)(const char *chain, struct xtc_handle *handle); +}; + +static int +for_each_table(int (*func)(struct iptables_save_cb *cb, const char *tablename), + struct iptables_save_cb *cb) { int ret = 1; FILE *procfile = NULL; char tablename[XT_TABLE_MAXNAMELEN+1]; - static const char filename[] = "/proc/net/ip_tables_names"; - procfile = fopen(filename, "re"); + procfile = fopen(afinfo->proc_exists, "re"); if (!procfile) { if (errno == ENOENT) return ret; fprintf(stderr, "Failed to list table names in %s: %s\n", - filename, strerror(errno)); + afinfo->proc_exists, strerror(errno)); exit(1); } @@ -56,71 +63,65 @@ static int for_each_table(int (*func)(const char *tablename)) "Badly formed tablename `%s'\n", tablename); tablename[strlen(tablename) - 1] = '\0'; - ret &= func(tablename); + ret &= func(cb, tablename); } fclose(procfile); return ret; } - -static int do_output(const char *tablename) +static int do_output(struct iptables_save_cb *cb, const char *tablename) { struct xtc_handle *h; const char *chain = NULL; if (!tablename) - return for_each_table(&do_output); + return for_each_table(&do_output, cb); - h = iptc_init(tablename); + h = cb->ops->init(tablename); if (h == NULL) { xtables_load_ko(xtables_modprobe_program, false); - h = iptc_init(tablename); + h = cb->ops->init(tablename); } if (!h) xtables_error(OTHER_PROBLEM, "Cannot initialize: %s\n", - iptc_strerror(errno)); + cb->ops->strerror(errno)); time_t now = time(NULL); - printf("# Generated by iptables-save v%s on %s", - IPTABLES_VERSION, ctime(&now)); + printf("# Generated by %s v%s on %s", + xt_params->program_name, IPTABLES_VERSION, ctime(&now)); printf("*%s\n", tablename); /* Dump out chain names first, * thereby preventing dependency conflicts */ - for (chain = iptc_first_chain(h); + for (chain = cb->ops->first_chain(h); chain; - chain = iptc_next_chain(h)) { + chain = cb->ops->next_chain(h)) { printf(":%s ", chain); - if (iptc_builtin(chain, h)) { + if (cb->ops->builtin(chain, h)) { struct xt_counters count; - printf("%s ", - iptc_get_policy(chain, &count, h)); - printf("[%llu:%llu]\n", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt); + + printf("%s ", cb->ops->get_policy(chain, &count, h)); + printf("[%llu:%llu]\n", + (unsigned long long)count.pcnt, + (unsigned long long)count.bcnt); } else { printf("- [0:0]\n"); } } - for (chain = iptc_first_chain(h); + for (chain = cb->ops->first_chain(h); chain; - chain = iptc_next_chain(h)) { - const struct ipt_entry *e; - - /* Dump out rules */ - e = iptc_first_rule(chain, h); - while(e) { - print_rule4(e, h, chain, show_counters); - e = iptc_next_rule(e, h); - } + chain = cb->ops->next_chain(h)) { + cb->dump_rules(chain, h); } now = time(NULL); printf("COMMIT\n"); printf("# Completed on %s", ctime(&now)); - iptc_free(h); + cb->ops->free(h); return 1; } @@ -129,26 +130,13 @@ static int do_output(const char *tablename) * :Chain name POLICY packets bytes * rule */ -int -iptables_save_main(int argc, char *argv[]) +static int +do_iptables_save(struct iptables_save_cb *cb, int argc, char *argv[]) { const char *tablename = NULL; FILE *file = NULL; int ret, c; - iptables_globals.program_name = "iptables-save"; - c = xtables_init_all(&iptables_globals, NFPROTO_IPV4); - if (c < 0) { - fprintf(stderr, "%s/%s Failed to initialize xtables\n", - iptables_globals.program_name, - iptables_globals.program_version); - exit(1); - } -#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS) - init_extensions(); - init_extensions4(); -#endif - while ((c = getopt_long(argc, argv, "bcdt:M:f:V", options, NULL)) != -1) { switch (c) { case 'b': @@ -181,14 +169,17 @@ iptables_save_main(int argc, char *argv[]) fclose(file); break; case 'd': - do_output(tablename); + do_output(cb, tablename); exit(0); case 'V': - printf("%s v%s (legacy)\n", prog_name, prog_vers); + printf("%s v%s (legacy)\n", + xt_params->program_name, + xt_params->program_version); exit(0); default: fprintf(stderr, - "Look at manual page `iptables-save.8' for more information.\n"); + "Look at manual page `%s.8' for more information.\n", + xt_params->program_name); exit(1); } } @@ -198,5 +189,87 @@ iptables_save_main(int argc, char *argv[]) exit(1); } - return !do_output(tablename); + return !do_output(cb, tablename); +} + +#ifdef ENABLE_IPV4 +static void iptables_dump_rules(const char *chain, struct xtc_handle *h) +{ + const struct ipt_entry *e; + + /* Dump out rules */ + e = iptc_first_rule(chain, h); + while(e) { + print_rule4(e, h, chain, show_counters); + e = iptc_next_rule(e, h); + } +} + +struct iptables_save_cb ipt_save_cb = { + .ops = &iptc_ops, + .dump_rules = iptables_dump_rules, +}; + +/* Format: + * :Chain name POLICY packets bytes + * rule + */ +int +iptables_save_main(int argc, char *argv[]) +{ + iptables_globals.program_name = "iptables-save"; + if (xtables_init_all(&iptables_globals, NFPROTO_IPV4) < 0) { + fprintf(stderr, "%s/%s Failed to initialize xtables\n", + iptables_globals.program_name, + iptables_globals.program_version); + exit(1); + } +#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS) + init_extensions(); + init_extensions4(); +#endif + + return do_iptables_save(&ipt_save_cb, argc, argv); +} +#endif /* ENABLE_IPV4 */ + +#ifdef ENABLE_IPV6 +static void ip6tables_dump_rules(const char *chain, struct xtc_handle *h) +{ + const struct ip6t_entry *e; + + /* Dump out rules */ + e = ip6tc_first_rule(chain, h); + while(e) { + print_rule6(e, h, chain, show_counters); + e = ip6tc_next_rule(e, h); + } +} + +struct iptables_save_cb ip6t_save_cb = { + .ops = &ip6tc_ops, + .dump_rules = ip6tables_dump_rules, +}; + +/* Format: + * :Chain name POLICY packets bytes + * rule + */ +int +ip6tables_save_main(int argc, char *argv[]) +{ + ip6tables_globals.program_name = "ip6tables-save"; + if (xtables_init_all(&ip6tables_globals, NFPROTO_IPV6) < 0) { + fprintf(stderr, "%s/%s Failed to initialize xtables\n", + ip6tables_globals.program_name, + ip6tables_globals.program_version); + exit(1); + } +#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS) + init_extensions(); + init_extensions6(); +#endif + + return do_iptables_save(&ip6t_save_cb, argc, argv); } +#endif /* ENABLE_IPV6 */ diff --git a/iptables/iptables.c b/iptables/iptables.c index f8041f56ce70daf237ad3d610ff95c6a12d184d6..38c4bfe8ecf5c7d9d8e24afa67db876688b870d9 100644 --- a/iptables/iptables.c +++ b/iptables/iptables.c @@ -1421,7 +1421,7 @@ int do_command4(int argc, char *argv[], char **table, case 'j': set_option(&cs.options, OPT_JUMP, &cs.fw.ip.invflags, cs.invert); - command_jump(&cs); + command_jump(&cs, optarg); break; diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c index 1a98996f94bdad146d77b6d10f3939f63aa48a2f..9805bbe0de87b276a79c8ae41115fd8261addd55 100644 --- a/iptables/nft-arp.c +++ b/iptables/nft-arp.c @@ -29,7 +29,7 @@ #include "nft.h" /* a few names */ -char *opcodes[] = +char *arp_opcodes[] = { "Request", "Reply", @@ -338,7 +338,8 @@ static void nft_arp_parse_payload(struct nft_xt_ctx *ctx, struct iptables_command_state *cs = data; struct arpt_entry *fw = &cs->arp; struct in_addr addr; - unsigned short int ar_hrd, ar_pro, ar_op, ar_hln; + uint16_t ar_hrd, ar_pro, ar_op; + uint8_t ar_hln; bool inv; switch (ctx->payload.offset) { @@ -364,7 +365,7 @@ static void nft_arp_parse_payload(struct nft_xt_ctx *ctx, fw->arp.invflags |= ARPT_INV_ARPOP; break; case offsetof(struct arphdr, ar_hln): - get_cmp_data(e, &ar_hln, sizeof(ar_op), &inv); + get_cmp_data(e, &ar_hln, sizeof(ar_hln), &inv); fw->arp.arhln = ar_hln; fw->arp.arhln_mask = 0xff; if (inv) @@ -412,56 +413,6 @@ static void nft_arp_parse_payload(struct nft_xt_ctx *ctx, } } -static void nft_arp_rule_to_cs(const struct nftnl_rule *r, - struct iptables_command_state *cs) -{ - struct nftnl_expr_iter *iter; - struct nftnl_expr *expr; - int family = nftnl_rule_get_u32(r, NFTNL_RULE_FAMILY); - struct nft_xt_ctx ctx = { - .cs = cs, - .family = family, - }; - - 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->arp.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, "target") == 0) - nft_parse_target(&ctx, expr); - - expr = nftnl_expr_iter_next(iter); - } - - nftnl_expr_iter_destroy(iter); - - if (cs->jumpto != NULL) - return; - - if (cs->target != NULL && cs->target->name != NULL) - cs->target = xtables_find_target(cs->target->name, XTF_TRY_LOAD); - else - cs->jumpto = ""; -} - static void nft_arp_print_header(unsigned int format, const char *chain, const char *pol, const struct xt_counters *counters, @@ -484,14 +435,21 @@ static void nft_arp_print_header(unsigned int format, const char *chain, } } -static void nft_arp_print_rule_details(const struct arpt_entry *fw, +static void nft_arp_print_rule_details(const struct iptables_command_state *cs, unsigned int format) { + const struct arpt_entry *fw = &cs->arp; char buf[BUFSIZ]; char iface[IFNAMSIZ+2]; + const char *sep = ""; int print_iface = 0; int i; + if (strlen(cs->jumpto)) { + printf("%s-j %s", sep, cs->jumpto); + sep = " "; + } + iface[0] = '\0'; if (fw->arp.iniface[0] != '\0') { @@ -503,9 +461,11 @@ static void nft_arp_print_rule_details(const struct arpt_entry *fw, if (format & FMT_NUMERIC) strcat(iface, "*"); else strcat(iface, "any"); } - if (print_iface) - printf("%s-i %s ", fw->arp.invflags & ARPT_INV_VIA_IN ? + if (print_iface) { + printf("%s%s-i %s", sep, fw->arp.invflags & ARPT_INV_VIA_IN ? "! " : "", iface); + sep = " "; + } print_iface = 0; iface[0] = '\0'; @@ -519,12 +479,14 @@ static void nft_arp_print_rule_details(const struct arpt_entry *fw, if (format & FMT_NUMERIC) strcat(iface, "*"); else strcat(iface, "any"); } - if (print_iface) - printf("%s-o %s ", fw->arp.invflags & ARPT_INV_VIA_OUT ? + if (print_iface) { + printf("%s%s-o %s", sep, fw->arp.invflags & ARPT_INV_VIA_OUT ? "! " : "", iface); + sep = " "; + } if (fw->arp.smsk.s_addr != 0L) { - printf("%s", fw->arp.invflags & ARPT_INV_SRCIP + printf("%s%s", sep, fw->arp.invflags & ARPT_INV_SRCIP ? "! " : ""); if (format & FMT_NUMERIC) sprintf(buf, "%s", addr_to_dotted(&(fw->arp.src))); @@ -532,7 +494,8 @@ static void nft_arp_print_rule_details(const struct arpt_entry *fw, sprintf(buf, "%s", addr_to_anyname(&(fw->arp.src))); strncat(buf, mask_to_dotted(&(fw->arp.smsk)), sizeof(buf) - strlen(buf) - 1); - printf("-s %s ", buf); + printf("-s %s", buf); + sep = " "; } for (i = 0; i < ARPT_DEV_ADDR_LEN_MAX; i++) @@ -540,16 +503,16 @@ static void nft_arp_print_rule_details(const struct arpt_entry *fw, break; if (i == ARPT_DEV_ADDR_LEN_MAX) goto after_devsrc; - printf("%s", fw->arp.invflags & ARPT_INV_SRCDEVADDR + printf("%s%s", sep, fw->arp.invflags & ARPT_INV_SRCDEVADDR ? "! " : ""); printf("--src-mac "); print_mac_and_mask((unsigned char *)fw->arp.src_devaddr.addr, (unsigned char *)fw->arp.src_devaddr.mask, ETH_ALEN); - printf(" "); + sep = " "; after_devsrc: if (fw->arp.tmsk.s_addr != 0L) { - printf("%s", fw->arp.invflags & ARPT_INV_TGTIP + printf("%s%s", sep, fw->arp.invflags & ARPT_INV_TGTIP ? "! " : ""); if (format & FMT_NUMERIC) sprintf(buf, "%s", addr_to_dotted(&(fw->arp.tgt))); @@ -557,7 +520,8 @@ after_devsrc: sprintf(buf, "%s", addr_to_anyname(&(fw->arp.tgt))); strncat(buf, mask_to_dotted(&(fw->arp.tmsk)), sizeof(buf) - strlen(buf) - 1); - printf("-d %s ", buf); + printf("-d %s", buf); + sep = " "; } for (i = 0; i arp.invflags & ARPT_INV_TGTDEVADDR + printf("%s%s", sep, fw->arp.invflags & ARPT_INV_TGTDEVADDR ? "! " : ""); printf("--dst-mac "); print_mac_and_mask((unsigned char *)fw->arp.tgt_devaddr.addr, (unsigned char *)fw->arp.tgt_devaddr.mask, ETH_ALEN); - printf(" "); + sep = " "; after_devdst: - if (fw->arp.arhln_mask != 0) { - printf("%s", fw->arp.invflags & ARPT_INV_ARPHLN + if (fw->arp.arhln_mask != 255 || fw->arp.arhln != 6) { + printf("%s%s", sep, fw->arp.invflags & ARPT_INV_ARPHLN ? "! " : ""); printf("--h-length %d", fw->arp.arhln); if (fw->arp.arhln_mask != 255) printf("/%d", fw->arp.arhln_mask); - printf(" "); + sep = " "; } if (fw->arp.arpop_mask != 0) { int tmp = ntohs(fw->arp.arpop); - printf("%s", fw->arp.invflags & ARPT_INV_ARPOP + printf("%s%s", sep, fw->arp.invflags & ARPT_INV_ARPOP ? "! " : ""); if (tmp <= NUMOPCODES && !(format & FMT_NUMERIC)) - printf("--opcode %s", opcodes[tmp-1]); + printf("--opcode %s", arp_opcodes[tmp-1]); else printf("--opcode %d", tmp); if (fw->arp.arpop_mask != 65535) printf("/%d", ntohs(fw->arp.arpop_mask)); - printf(" "); + sep = " "; } - if (fw->arp.arhrd_mask != 0) { + if (fw->arp.arhrd_mask != 65535 || fw->arp.arhrd != htons(1)) { uint16_t tmp = ntohs(fw->arp.arhrd); - printf("%s", fw->arp.invflags & ARPT_INV_ARPHRD + printf("%s%s", sep, fw->arp.invflags & ARPT_INV_ARPHRD ? "! " : ""); if (tmp == 1 && !(format & FMT_NUMERIC)) printf("--h-type %s", "Ethernet"); @@ -609,13 +573,13 @@ after_devdst: printf("--h-type %u", tmp); if (fw->arp.arhrd_mask != 65535) printf("/%d", ntohs(fw->arp.arhrd_mask)); - printf(" "); + sep = " "; } if (fw->arp.arpro_mask != 0) { int tmp = ntohs(fw->arp.arpro); - printf("%s", fw->arp.invflags & ARPT_INV_ARPPRO + printf("%s%s", sep, fw->arp.invflags & ARPT_INV_ARPPRO ? "! " : ""); if (tmp == 0x0800 && !(format & FMT_NUMERIC)) printf("--proto-type %s", "IPv4"); @@ -623,18 +587,10 @@ after_devdst: printf("--proto-type 0x%x", tmp); if (fw->arp.arpro_mask != 65535) printf("/%x", ntohs(fw->arp.arpro_mask)); - printf(" "); + sep = " "; } } -static void nft_arp_save_counters(const void *data) -{ - const struct iptables_command_state *cs = data; - - printf("[%llu:%llu] ", (unsigned long long)cs->arp.counters.pcnt, - (unsigned long long)cs->arp.counters.bcnt); -} - static void nft_arp_save_rule(const void *data, unsigned int format) { @@ -642,18 +598,10 @@ nft_arp_save_rule(const void *data, unsigned int format) format |= FMT_NUMERIC; - nft_arp_print_rule_details(&cs->arp, format); - - if (cs->jumpto != NULL && strcmp(cs->jumpto, "") != 0) { - printf("-j %s", cs->jumpto); - } else if (cs->target) { - printf("-j %s", cs->target->name); - if (cs->target->save != NULL) - cs->target->save(&cs->arp, cs->target->t); - } - - if (!(format & FMT_NONEWLINE)) - fputc('\n', stdout); + nft_arp_print_rule_details(cs, format); + if (cs->target && cs->target->save) + cs->target->save(&cs->fw, cs->target->t); + printf("\n"); } static void @@ -664,22 +612,16 @@ nft_arp_print_rule(struct nftnl_rule *r, unsigned int num, unsigned int format) if (format & FMT_LINENUMBERS) printf("%u ", num); - nft_arp_rule_to_cs(r, &cs); - - nft_arp_print_rule_details(&cs.arp, format); + nft_rule_to_iptables_command_state(r, &cs); - if (cs.jumpto != NULL && strcmp(cs.jumpto, "") != 0) { - printf("-j %s", cs.jumpto); - } else if (cs.target) { - printf("-j %s", cs.target->name); - cs.target->print(&cs.arp, cs.target->t, format & FMT_NUMERIC); - } + nft_arp_print_rule_details(&cs, format); + print_matches_and_target(&cs, format); if (!(format & FMT_NOCOUNTS)) { - printf(", pcnt="); - xtables_print_num(cs.arp.counters.pcnt, format); + printf(" , pcnt="); + xtables_print_num(cs.counters.pcnt, format | FMT_NOTABLE); printf("-- bcnt="); - xtables_print_num(cs.arp.counters.bcnt, format); + xtables_print_num(cs.counters.bcnt, format | FMT_NOTABLE); } if (!(format & FMT_NONEWLINE)) @@ -718,20 +660,24 @@ static bool nft_arp_rule_find(struct nft_family_ops *ops, struct nftnl_rule *r, { const struct iptables_command_state *cs = data; struct iptables_command_state this = {}; + bool ret = false; /* Delete by matching rule case */ - nft_arp_rule_to_cs(r, &this); + nft_rule_to_iptables_command_state(r, &this); if (!nft_arp_is_same(&cs->arp, &this.arp)) - return false; + goto out; if (!compare_targets(cs->target, this.target)) - return false; + goto out; if (this.jumpto && strcmp(cs->jumpto, this.jumpto) != 0) - return false; + goto out; - return true; + ret = true; +out: + ops->clear_cs(&this); + return ret; } static void nft_arp_save_chain(const struct nftnl_chain *c, const char *policy) @@ -751,10 +697,10 @@ struct nft_family_ops nft_family_ops_arp = { .print_header = nft_arp_print_header, .print_rule = nft_arp_print_rule, .save_rule = nft_arp_save_rule, - .save_counters = nft_arp_save_counters, + .save_counters = save_counters, .save_chain = nft_arp_save_chain, .post_parse = NULL, - .rule_to_cs = nft_arp_rule_to_cs, + .rule_to_cs = nft_rule_to_iptables_command_state, .clear_cs = nft_clear_iptables_command_state, .rule_find = nft_arp_rule_find, .parse_target = nft_ipv46_parse_target, diff --git a/iptables/nft-arp.h b/iptables/nft-arp.h index da6bd380162c307fd32eacc7306c39c220650776..3411fc3d7c7b336732f5a842fb1279d07c465f92 100644 --- a/iptables/nft-arp.h +++ b/iptables/nft-arp.h @@ -1,7 +1,7 @@ #ifndef _NFT_ARP_H_ #define _NFT_ARP_H_ -extern char *opcodes[]; +extern char *arp_opcodes[]; #define NUMOPCODES 9 #endif diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index ad583a60c424d07e8a67102a5f533afe7cb61616..ddfbee165da937c827e8d416aececd1b1224cb7f 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -45,6 +45,16 @@ void ebt_cs_clean(struct iptables_command_state *cs) free(m); m = nm; } + + if (cs->target) { + free(cs->target->t); + cs->target->t = NULL; + + if (cs->target == cs->target->next) { + free(cs->target); + cs->target = NULL; + } + } } static void ebt_print_mac(const unsigned char *mac) @@ -334,7 +344,7 @@ static void nft_rule_to_ebtables_command_state(const struct nftnl_rule *r, static void print_iface(const char *option, const char *name, bool invert) { if (*name) - printf("%s%s %s ", invert ? "! " : "", option, name); + printf("%s%s %s ", option, invert ? " !" : "", name); } static void nft_bridge_print_table_header(const char *tablename) @@ -348,7 +358,7 @@ static void nft_bridge_print_header(unsigned int format, const char *chain, bool basechain, uint32_t refs, uint32_t entries) { printf("Bridge chain: %s, entries: %u, policy: %s\n", - chain, entries, basechain ? pol : "RETURN"); + chain, entries, pol ?: "RETURN"); } static void print_matches_and_watchers(const struct iptables_command_state *cs, @@ -379,9 +389,9 @@ static void print_mac(char option, const unsigned char *mac, const unsigned char *mask, bool invert) { + printf("-%c ", option); if (invert) printf("! "); - printf("-%c ", option); ebt_print_mac_and_mask(mac, mask); printf(" "); } @@ -396,9 +406,9 @@ static void print_protocol(uint16_t ethproto, bool invert, unsigned int bitmask) if (bitmask & EBT_NOPROTO) return; + printf("-p "); if (invert) printf("! "); - printf("-p "); if (bitmask & EBT_802_3) { printf("length "); @@ -469,6 +479,11 @@ static void nft_bridge_save_rule(const void *data, unsigned int format) (uint64_t)cs->counters.pcnt, (uint64_t)cs->counters.bcnt); + if (!(format & FMT_NOCOUNTS)) + printf(" , pcnt = %"PRIu64" -- bcnt = %"PRIu64"", + (uint64_t)cs->counters.pcnt, + (uint64_t)cs->counters.bcnt); + if (!(format & FMT_NONEWLINE)) fputc('\n', stdout); } @@ -482,11 +497,7 @@ static void nft_bridge_print_rule(struct nftnl_rule *r, unsigned int num, printf("%d ", num); nft_rule_to_ebtables_command_state(r, &cs); - nft_bridge_save_rule(&cs, format & ~FMT_EBT_SAVE); - if (!(format & FMT_NOCOUNTS)) - printf(" , pcnt = %"PRIu64" -- bcnt = %"PRIu64"", - (uint64_t)cs.counters.pcnt, - (uint64_t)cs.counters.bcnt); + nft_bridge_save_rule(&cs, format); ebt_cs_clean(&cs); } @@ -547,30 +558,34 @@ static bool nft_bridge_rule_find(struct nft_family_ops *ops, struct nftnl_rule * { struct iptables_command_state *cs = data; struct iptables_command_state this = {}; + bool ret = false; nft_rule_to_ebtables_command_state(r, &this); DEBUGP("comparing with... "); if (!nft_bridge_is_same(cs, &this)) - return false; + goto out; if (!compare_matches(cs->matches, this.matches)) { DEBUGP("Different matches\n"); - return false; + goto out; } if (!compare_targets(cs->target, this.target)) { DEBUGP("Different target\n"); - return false; + goto out; } if (cs->jumpto != NULL && strcmp(cs->jumpto, this.jumpto) != 0) { DEBUGP("Different verdict\n"); - return false; + goto out; } - return true; + ret = true; +out: + ops->clear_cs(&this); + return ret; } static int xlate_ebmatches(const struct iptables_command_state *cs, struct xt_xlate *xl) diff --git a/iptables/nft-bridge.h b/iptables/nft-bridge.h index de52cd7195bbb06cf436f1814229b2e70823e716..d90066f1030a2cc5ef703256044c80bba6694f9b 100644 --- a/iptables/nft-bridge.h +++ b/iptables/nft-bridge.h @@ -32,7 +32,6 @@ int ebt_get_mac_and_mask(const char *from, unsigned char *to, unsigned char *mas */ #define EBT_TABLE_MAXNAMELEN 32 -#define EBT_CHAIN_MAXNAMELEN EBT_TABLE_MAXNAMELEN #define EBT_FUNCTION_MAXNAMELEN EBT_TABLE_MAXNAMELEN /* verdicts >0 are "branches" */ @@ -122,6 +121,5 @@ void ebt_add_match(struct xtables_match *m, void ebt_add_watcher(struct xtables_target *watcher, struct iptables_command_state *cs); int ebt_command_default(struct iptables_command_state *cs); -struct xtables_target *ebt_command_jump(const char *jumpto); #endif diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c index ffb439b4a1128ea8be659d550b9e91a643245709..4497eb9b9347c4ba18a7f32ec78d9c62f9201a09 100644 --- a/iptables/nft-ipv4.c +++ b/iptables/nft-ipv4.c @@ -77,17 +77,9 @@ static int nft_ipv4_add(struct nftnl_rule *r, void *data) add_compat(r, cs->fw.ip.proto, cs->fw.ip.invflags & XT_INV_PROTO); for (matchp = cs->matches; matchp; matchp = matchp->next) { - /* Use nft built-in comments support instead of comment match */ - if (strcmp(matchp->match->name, "comment") == 0) { - ret = add_comment(r, (char *)matchp->match->m->data); - if (ret < 0) - goto try_match; - } else { -try_match: - ret = add_match(r, matchp->match->m); - if (ret < 0) - return ret; - } + ret = add_match(r, matchp->match->m); + if (ret < 0) + return ret; } /* Counters need to me added before the target, otherwise they are diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c index 7bacee4ab3a219465e7bc2146733d0fa50c2377e..cacb1c9e141f27c3840d3e34ddcf0c34215175c0 100644 --- a/iptables/nft-ipv6.c +++ b/iptables/nft-ipv6.c @@ -66,17 +66,9 @@ static int nft_ipv6_add(struct nftnl_rule *r, void *data) add_compat(r, cs->fw6.ipv6.proto, cs->fw6.ipv6.invflags & XT_INV_PROTO); for (matchp = cs->matches; matchp; matchp = matchp->next) { - /* Use nft built-in comments support instead of comment match */ - if (strcmp(matchp->match->name, "comment") == 0) { - ret = add_comment(r, (char *)matchp->match->m->data); - if (ret < 0) - goto try_match; - } else { -try_match: - ret = add_match(r, matchp->match->m); - if (ret < 0) - return ret; - } + ret = add_match(r, matchp->match->m); + if (ret < 0) + return ret; } /* Counters need to me added before the target, otherwise they are diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index 7b8ca5e4becaf0adb5910a7a52673bd28c4ae534..1c09277d85fb5b0dab276d1ab5715b7fd9a304ca 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -302,7 +302,7 @@ int parse_meta(struct nftnl_expr *e, uint8_t key, char *iniface, return 0; } -void nft_parse_target(struct nft_xt_ctx *ctx, struct nftnl_expr *e) +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); @@ -331,7 +331,7 @@ void nft_parse_target(struct nft_xt_ctx *ctx, struct nftnl_expr *e) ops->parse_target(target, data); } -void nft_parse_match(struct nft_xt_ctx *ctx, struct nftnl_expr *e) +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); @@ -433,7 +433,7 @@ static void nft_meta_set_to_target(struct nft_xt_ctx *ctx) ops->parse_target(target, ctx->cs); } -void nft_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e) +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); @@ -449,14 +449,14 @@ void nft_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e) ctx->flags |= NFT_XT_CTX_META; } -void nft_parse_payload(struct nft_xt_ctx *ctx, struct nftnl_expr *e) +static void nft_parse_payload(struct nft_xt_ctx *ctx, struct nftnl_expr *e) { ctx->reg = nftnl_expr_get_u32(e, NFTNL_EXPR_META_DREG); ctx->payload.offset = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_OFFSET); ctx->flags |= NFT_XT_CTX_PAYLOAD; } -void nft_parse_bitwise(struct nft_xt_ctx *ctx, struct nftnl_expr *e) +static void nft_parse_bitwise(struct nft_xt_ctx *ctx, struct nftnl_expr *e) { uint32_t reg, len; const void *data; @@ -472,7 +472,7 @@ void nft_parse_bitwise(struct nft_xt_ctx *ctx, struct nftnl_expr *e) ctx->flags |= NFT_XT_CTX_BITWISE; } -void nft_parse_cmp(struct nft_xt_ctx *ctx, struct nftnl_expr *e) +static void nft_parse_cmp(struct nft_xt_ctx *ctx, struct nftnl_expr *e) { struct nft_family_ops *ops = nft_family_ops_lookup(ctx->family); void *data = ctx->cs; @@ -493,13 +493,13 @@ void nft_parse_cmp(struct nft_xt_ctx *ctx, struct nftnl_expr *e) } } -void nft_parse_counter(struct nftnl_expr *e, struct xt_counters *counters) +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); } -void nft_parse_immediate(struct nft_xt_ctx *ctx, struct nftnl_expr *e) +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 nft_family_ops *ops; @@ -639,40 +639,65 @@ void nft_rule_to_iptables_command_state(const struct nftnl_rule *r, if (nftnl_rule_is_set(r, NFTNL_RULE_USERDATA)) { const void *data; uint32_t len, size; - struct xtables_match *match; - struct xt_entry_match *m; + const char *comment; data = nftnl_rule_get_data(r, NFTNL_RULE_USERDATA, &len); - 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, get_comment(data, len), - match->size - 1); - m->u.match_size = size; - m->u.user.revision = 0; - strcpy(m->u.user.name, match->name); - - match->m = m; + 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->target != NULL) + if (cs->target != NULL) { cs->jumpto = cs->target->name; - else if (cs->jumpto != NULL) + } else if (cs->jumpto != NULL) { + struct xt_entry_target *t; + uint32_t size; + cs->target = xtables_find_target(cs->jumpto, XTF_TRY_LOAD); - else + 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; + } else { cs->jumpto = ""; + } } void nft_clear_iptables_command_state(struct iptables_command_state *cs) { xtables_rule_matches_free(&cs->matches); - if (cs->target) + if (cs->target) { free(cs->target->t); + cs->target->t = NULL; + + if (cs->target == cs->target->next) { + free(cs->target); + cs->target = NULL; + } + } } void print_header(unsigned int format, const char *chain, const char *pol, @@ -961,6 +986,7 @@ bool nft_ipv46_rule_find(struct nft_family_ops *ops, struct nftnl_rule *r, void *data) { struct iptables_command_state *cs = data, this = {}; + bool ret = false; nft_rule_to_iptables_command_state(r, &this); @@ -969,24 +995,27 @@ bool nft_ipv46_rule_find(struct nft_family_ops *ops, nft_rule_print_save(r, NFT_RULE_APPEND, 0); #endif if (!ops->is_same(cs, &this)) - return false; + goto out; if (!compare_matches(cs->matches, this.matches)) { DEBUGP("Different matches\n"); - return false; + goto out; } if (!compare_targets(cs->target, this.target)) { DEBUGP("Different target\n"); - return false; + goto out; } if (strcmp(cs->jumpto, this.jumpto) != 0) { DEBUGP("Different verdict\n"); - return false; + goto out; } - return true; + ret = true; +out: + ops->clear_cs(&this); + return ret; } void nft_check_xt_legacy(int family, bool is_ipt_save) diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index e3ecdb4d23df3eaedc3a7039d380701ea6daea4c..de889ead7b60582d0c36ddb227e0e0834ff25beb 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -137,14 +137,6 @@ int parse_meta(struct nftnl_expr *e, uint8_t key, char *iniface, unsigned char *outiface_mask, uint8_t *invflags); void print_proto(uint16_t proto, int invert); void get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, bool *inv); -void nft_parse_bitwise(struct nft_xt_ctx *ctx, struct nftnl_expr *e); -void nft_parse_cmp(struct nft_xt_ctx *ctx, struct nftnl_expr *e); -void nft_parse_match(struct nft_xt_ctx *ctx, struct nftnl_expr *e); -void nft_parse_target(struct nft_xt_ctx *ctx, struct nftnl_expr *e); -void nft_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e); -void nft_parse_payload(struct nft_xt_ctx *ctx, struct nftnl_expr *e); -void nft_parse_counter(struct nftnl_expr *e, struct xt_counters *counters); -void nft_parse_immediate(struct nft_xt_ctx *ctx, struct nftnl_expr *e); void nft_rule_to_iptables_command_state(const struct nftnl_rule *r, struct iptables_command_state *cs); void nft_clear_iptables_command_state(struct iptables_command_state *cs); @@ -251,17 +243,13 @@ struct nftnl_chain_list; struct nft_xt_restore_cb { void (*table_new)(struct nft_handle *h, const char *table); - struct nftnl_chain_list *(*chain_list)(struct nft_handle *h); - void (*chain_del)(struct nftnl_chain_list *clist, const char *curtable, - const char *chain); - int (*chain_user_flush)(struct nft_handle *h, - struct nftnl_chain_list *clist, - const char *table, const char *chain); + struct nftnl_chain_list *(*chain_list)(struct nft_handle *h, + const char *table); int (*chain_set)(struct nft_handle *h, const char *table, const char *chain, const char *policy, const struct xt_counters *counters); - int (*chain_user_add)(struct nft_handle *h, const char *chain, - const char *table); + int (*chain_restore)(struct nft_handle *h, const char *chain, + const char *table); int (*table_flush)(struct nft_handle *h, const char *table); diff --git a/iptables/nft.c b/iptables/nft.c index e8538d38e01097fc458667805a9802a7190550db..2c61521455de85275f00160d0a7fdcfd9a8923f9 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -41,6 +41,7 @@ #include #include +#include #include #include #include @@ -55,10 +56,41 @@ #include "nft.h" #include "xshared.h" /* proto_to_name */ #include "nft-shared.h" +#include "nft-bridge.h" /* EBT_NOPROTO */ #include "xtables-config-parser.h" static void *nft_fn; +static int genid_cb(const struct nlmsghdr *nlh, void *data) +{ + uint32_t *genid = data; + struct nftnl_gen *gen; + + gen = nftnl_gen_alloc(); + if (!gen) + return MNL_CB_ERROR; + + if (nftnl_gen_nlmsg_parse(nlh, gen) < 0) + goto out; + + *genid = nftnl_gen_get_u32(gen, NFTNL_GEN_ID); + + nftnl_gen_free(gen); + return MNL_CB_STOP; +out: + nftnl_gen_free(gen); + return MNL_CB_ERROR; +} + +static int mnl_genid_get(struct nft_handle *h, uint32_t *genid) +{ + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct nlmsghdr *nlh; + + nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETGEN, 0, 0, h->seq); + return mnl_talk(h, nlh, genid_cb, genid); +} + int mnl_talk(struct nft_handle *h, struct nlmsghdr *nlh, int (*cb)(const struct nlmsghdr *nlh, void *data), void *data) @@ -108,9 +140,14 @@ static void mnl_nft_batch_continue(struct nftnl_batch *batch) assert(nftnl_batch_update(batch) >= 0); } -static uint32_t mnl_batch_begin(struct nftnl_batch *batch, uint32_t seqnum) +static uint32_t mnl_batch_begin(struct nftnl_batch *batch, uint32_t genid, uint32_t seqnum) { - nftnl_batch_begin(nftnl_batch_buffer(batch), seqnum); + struct nlmsghdr *nlh; + + nlh = nftnl_batch_begin(nftnl_batch_buffer(batch), seqnum); + + mnl_attr_put_u32(nlh, NFTA_GEN_ID, htonl(genid)); + mnl_nft_batch_continue(batch); return seqnum; @@ -263,7 +300,9 @@ enum obj_action { struct obj_update { struct list_head head; - enum obj_update_type type; + enum obj_update_type type:8; + uint8_t skip:1; + uint8_t implicit:1; unsigned int seq; union { struct nftnl_table *table; @@ -341,13 +380,13 @@ static int mnl_append_error(const struct nft_handle *h, return snprintf(buf, len, "%s: %s", errmsg, tcr); } -static int batch_add(struct nft_handle *h, enum obj_update_type type, void *ptr) +static struct obj_update *batch_add(struct nft_handle *h, enum obj_update_type type, void *ptr) { struct obj_update *obj; obj = calloc(1, sizeof(struct obj_update)); if (obj == NULL) - return -1; + return NULL; obj->ptr = ptr; obj->error.lineno = h->error.lineno; @@ -355,11 +394,12 @@ static int batch_add(struct nft_handle *h, enum obj_update_type type, void *ptr) list_add_tail(&obj->head, &h->obj_list); h->obj_list_num++; - return 0; + return obj; } -static int batch_table_add(struct nft_handle *h, enum obj_update_type type, - struct nftnl_table *t) +static struct obj_update * +batch_table_add(struct nft_handle *h, enum obj_update_type type, + struct nftnl_table *t) { return batch_add(h, type, t); } @@ -367,18 +407,20 @@ static int batch_table_add(struct nft_handle *h, enum obj_update_type type, static int batch_chain_add(struct nft_handle *h, enum obj_update_type type, struct nftnl_chain *c) { - return batch_add(h, type, c); + return batch_add(h, type, c) ? 0 : -1; } -static int batch_rule_add(struct nft_handle *h, enum obj_update_type type, +static struct obj_update * +batch_rule_add(struct nft_handle *h, enum obj_update_type type, struct nftnl_rule *r) { return batch_add(h, type, r); } -struct builtin_table xtables_ipv4[NFT_TABLE_MAX] = { +const struct builtin_table xtables_ipv4[NFT_TABLE_MAX] = { [NFT_TABLE_RAW] = { .name = "raw", + .type = NFT_TABLE_RAW, .chains = { { .name = "PREROUTING", @@ -396,6 +438,7 @@ struct builtin_table xtables_ipv4[NFT_TABLE_MAX] = { }, [NFT_TABLE_MANGLE] = { .name = "mangle", + .type = NFT_TABLE_MANGLE, .chains = { { .name = "PREROUTING", @@ -431,6 +474,7 @@ struct builtin_table xtables_ipv4[NFT_TABLE_MAX] = { }, [NFT_TABLE_FILTER] = { .name = "filter", + .type = NFT_TABLE_FILTER, .chains = { { .name = "INPUT", @@ -454,6 +498,7 @@ struct builtin_table xtables_ipv4[NFT_TABLE_MAX] = { }, [NFT_TABLE_SECURITY] = { .name = "security", + .type = NFT_TABLE_SECURITY, .chains = { { .name = "INPUT", @@ -477,6 +522,7 @@ struct builtin_table xtables_ipv4[NFT_TABLE_MAX] = { }, [NFT_TABLE_NAT] = { .name = "nat", + .type = NFT_TABLE_NAT, .chains = { { .name = "PREROUTING", @@ -508,9 +554,10 @@ struct builtin_table xtables_ipv4[NFT_TABLE_MAX] = { #include -struct builtin_table xtables_arp[NFT_TABLE_MAX] = { +const struct builtin_table xtables_arp[NFT_TABLE_MAX] = { [NFT_TABLE_FILTER] = { .name = "filter", + .type = NFT_TABLE_FILTER, .chains = { { .name = "INPUT", @@ -530,9 +577,10 @@ struct builtin_table xtables_arp[NFT_TABLE_MAX] = { #include -struct builtin_table xtables_bridge[NFT_TABLE_MAX] = { +const struct builtin_table xtables_bridge[NFT_TABLE_MAX] = { [NFT_TABLE_FILTER] = { .name = "filter", + .type = NFT_TABLE_FILTER, .chains = { { .name = "INPUT", @@ -556,6 +604,7 @@ struct builtin_table xtables_bridge[NFT_TABLE_MAX] = { }, [NFT_TABLE_NAT] = { .name = "nat", + .type = NFT_TABLE_NAT, .chains = { { .name = "PREROUTING", @@ -579,13 +628,19 @@ struct builtin_table xtables_bridge[NFT_TABLE_MAX] = { }, }; +static bool nft_table_initialized(const struct nft_handle *h, + enum nft_table_type type) +{ + return h->cache->table[type].initialized; +} + static int nft_table_builtin_add(struct nft_handle *h, - struct builtin_table *_t) + const struct builtin_table *_t) { struct nftnl_table *t; int ret; - if (_t->initialized) + if (nft_table_initialized(h, _t->type)) return 0; t = nftnl_table_alloc(); @@ -594,14 +649,14 @@ static int nft_table_builtin_add(struct nft_handle *h, nftnl_table_set(t, NFTNL_TABLE_NAME, (char *)_t->name); - ret = batch_table_add(h, NFT_COMPAT_TABLE_ADD, t); + ret = batch_table_add(h, NFT_COMPAT_TABLE_ADD, t) ? 0 : - 1; return ret; } static struct nftnl_chain * -nft_chain_builtin_alloc(struct builtin_table *table, - struct builtin_chain *chain, int policy) +nft_chain_builtin_alloc(const struct builtin_table *table, + const struct builtin_chain *chain, int policy) { struct nftnl_chain *c; @@ -620,8 +675,8 @@ nft_chain_builtin_alloc(struct builtin_table *table, } static void nft_chain_builtin_add(struct nft_handle *h, - struct builtin_table *table, - struct builtin_chain *chain) + const struct builtin_table *table, + const struct builtin_chain *chain) { struct nftnl_chain *c; @@ -630,32 +685,39 @@ static void nft_chain_builtin_add(struct nft_handle *h, return; batch_chain_add(h, NFT_COMPAT_CHAIN_ADD, c); + nftnl_chain_list_add_tail(c, h->cache->table[table->type].chains); } -/* find if built-in table already exists */ -struct builtin_table * -nft_table_builtin_find(struct nft_handle *h, const char *table) +static const struct builtin_table * +__nft_table_builtin_find(const struct builtin_table *tables, const char *table) { int i; bool found = false; for (i = 0; i < NFT_TABLE_MAX; i++) { - if (h->tables[i].name == NULL) + if (tables[i].name == NULL) continue; - if (strcmp(h->tables[i].name, table) != 0) + if (strcmp(tables[i].name, table) != 0) continue; found = true; break; } - return found ? &h->tables[i] : NULL; + return found ? &tables[i] : NULL; +} + +/* find if built-in table already exists */ +const struct builtin_table * +nft_table_builtin_find(struct nft_handle *h, const char *table) +{ + return __nft_table_builtin_find(h->tables, table); } /* find if built-in chain already exists */ -struct builtin_chain * -nft_chain_builtin_find(struct builtin_table *t, const char *chain) +const struct builtin_chain * +nft_chain_builtin_find(const struct builtin_table *t, const char *chain) { int i; bool found = false; @@ -671,17 +733,19 @@ nft_chain_builtin_find(struct builtin_table *t, const char *chain) } static void nft_chain_builtin_init(struct nft_handle *h, - struct builtin_table *table) + const struct builtin_table *table) { - struct nftnl_chain_list *list = nft_chain_list_get(h); + struct nftnl_chain_list *list = nft_chain_list_get(h, table->name); struct nftnl_chain *c; int i; + if (!list) + return; + /* Initialize built-in chains if they don't exist yet */ for (i=0; i < NF_INET_NUMHOOKS && table->chains[i].name != NULL; i++) { - c = nft_chain_list_find(list, table->name, - table->chains[i].name); + c = nftnl_chain_list_lookup_byname(list, table->chains[i].name); if (c != NULL) continue; @@ -691,13 +755,13 @@ static void nft_chain_builtin_init(struct nft_handle *h, static int nft_xt_builtin_init(struct nft_handle *h, const char *table) { - struct builtin_table *t; + const struct builtin_table *t; t = nft_table_builtin_find(h, table); if (t == NULL) return -1; - if (t->initialized) + if (nft_table_initialized(h, t->type)) return 0; if (nft_table_builtin_add(h, t) < 0) @@ -705,7 +769,7 @@ static int nft_xt_builtin_init(struct nft_handle *h, const char *table) nft_chain_builtin_init(h, t); - t->initialized = true; + h->cache->table[t->type].initialized = true; return 0; } @@ -730,11 +794,12 @@ static int nft_restart(struct nft_handle *h) return -1; h->portid = mnl_socket_get_portid(h->nl); + nlbuffsiz = 0; return 0; } -int nft_init(struct nft_handle *h, struct builtin_table *t) +int nft_init(struct nft_handle *h, const struct builtin_table *t) { h->nl = mnl_socket_open(NETLINK_NETFILTER); if (h->nl == NULL) @@ -747,6 +812,7 @@ int nft_init(struct nft_handle *h, struct builtin_table *t) h->portid = mnl_socket_get_portid(h->nl); h->tables = t; + h->cache = &h->__cache[0]; INIT_LIST_HEAD(&h->obj_list); INIT_LIST_HEAD(&h->err_list); @@ -756,60 +822,68 @@ int nft_init(struct nft_handle *h, struct builtin_table *t) static int __flush_rule_cache(struct nftnl_rule *r, void *data) { - const char *tablename = data; + nftnl_rule_list_del(r); + nftnl_rule_free(r); - if (!strcmp(nftnl_rule_get_str(r, NFTNL_RULE_TABLE), tablename)) { - nftnl_rule_list_del(r); - nftnl_rule_free(r); - } + return 0; +} + +static void flush_rule_cache(struct nftnl_chain *c) +{ + nftnl_rule_foreach(c, __flush_rule_cache, NULL); +} + +static int __flush_chain_cache(struct nftnl_chain *c, void *data) +{ + nftnl_chain_list_del(c); + nftnl_chain_free(c); return 0; } -static void flush_rule_cache(struct nft_handle *h, const char *tablename) +static int flush_cache(struct nft_cache *c, const struct builtin_table *tables, + const char *tablename) { - if (!h->rule_cache) - return; + const struct builtin_table *table; + int i; if (tablename) { - nftnl_rule_list_foreach(h->rule_cache, __flush_rule_cache, - (void *)tablename); - } else { - nftnl_rule_list_free(h->rule_cache); - h->rule_cache = NULL; + table = __nft_table_builtin_find(tables, tablename); + if (!table || !c->table[table->type].chains) + return 0; + nftnl_chain_list_foreach(c->table[table->type].chains, + __flush_chain_cache, NULL); + return 0; } -} -static int __flush_chain_cache(struct nftnl_chain *c, void *data) -{ - const char *tablename = data; + for (i = 0; i < NFT_TABLE_MAX; i++) { + if (tables[i].name == NULL) + continue; - if (!strcmp(nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE), tablename)) { - nftnl_chain_list_del(c); - nftnl_chain_free(c); + if (!c->table[i].chains) + continue; + + nftnl_chain_list_free(c->table[i].chains); + c->table[i].chains = NULL; } + nftnl_table_list_free(c->tables); + c->tables = NULL; - return 0; + return 1; } static void flush_chain_cache(struct nft_handle *h, const char *tablename) { - if (!h->chain_cache) + if (!h->have_cache) return; - if (tablename) { - nftnl_chain_list_foreach(h->chain_cache, __flush_chain_cache, - (void *)tablename); - } else { - nftnl_chain_list_free(h->chain_cache); - h->chain_cache = NULL; - } + if (flush_cache(h->cache, h->tables, tablename)) + h->have_cache = false; } void nft_fini(struct nft_handle *h) { flush_chain_cache(h, NULL); - flush_rule_cache(h, NULL); mnl_socket_close(h->nl); } @@ -830,8 +904,8 @@ static struct nftnl_chain *nft_chain_new(struct nft_handle *h, const struct xt_counters *counters) { struct nftnl_chain *c; - struct builtin_table *_t; - struct builtin_chain *_c; + const struct builtin_table *_t; + const struct builtin_chain *_c; _t = nft_table_builtin_find(h, table); if (!_t) { @@ -1103,37 +1177,11 @@ int add_counters(struct nftnl_rule *r, uint64_t packets, uint64_t bytes) enum udata_type { UDATA_TYPE_COMMENT, + UDATA_TYPE_EBTABLES_POLICY, __UDATA_TYPE_MAX, }; #define UDATA_TYPE_MAX (__UDATA_TYPE_MAX - 1) -int add_comment(struct nftnl_rule *r, const char *comment) -{ - struct nftnl_udata_buf *udata; - uint32_t len; - - if (nftnl_rule_get_data(r, NFTNL_RULE_USERDATA, &len)) - return -EALREADY; - - udata = nftnl_udata_buf_alloc(NFT_USERDATA_MAXLEN); - if (!udata) - return -ENOMEM; - - if (strnlen(comment, 255) == 255) - return -ENOSPC; - - if (!nftnl_udata_put_strz(udata, UDATA_TYPE_COMMENT, comment)) - return -ENOMEM; - - nftnl_rule_set_data(r, NFTNL_RULE_USERDATA, - nftnl_udata_buf_data(udata), - nftnl_udata_buf_len(udata)); - - nftnl_udata_buf_free(udata); - - return 0; -} - static int parse_udata_cb(const struct nftnl_udata *attr, void *data) { unsigned char *value = nftnl_udata_get(attr); @@ -1146,6 +1194,8 @@ static int parse_udata_cb(const struct nftnl_udata *attr, void *data) if (value[len - 1] != '\0') return -1; break; + case UDATA_TYPE_EBTABLES_POLICY: + break; default: return 0; } @@ -1196,12 +1246,14 @@ err: return NULL; } -static struct nftnl_rule_list *nft_rule_list_get(struct nft_handle *h); +static struct nftnl_chain * +nft_chain_find(struct nft_handle *h, const char *table, const char *chain); int nft_rule_append(struct nft_handle *h, const char *chain, const char *table, - void *data, uint64_t handle, bool verbose) + void *data, struct nftnl_rule *ref, bool verbose) { + struct nftnl_chain *c; struct nftnl_rule *r; int type; @@ -1215,13 +1267,14 @@ nft_rule_append(struct nft_handle *h, const char *chain, const char *table, if (r == NULL) return 0; - if (handle > 0) { - nftnl_rule_set(r, NFTNL_RULE_HANDLE, &handle); + if (ref) { + nftnl_rule_set_u64(r, NFTNL_RULE_HANDLE, + nftnl_rule_get_u64(ref, NFTNL_RULE_HANDLE)); type = NFT_COMPAT_RULE_REPLACE; } else type = NFT_COMPAT_RULE_APPEND; - if (batch_rule_add(h, type, r) < 0) { + if (batch_rule_add(h, type, r) == NULL) { nftnl_rule_free(r); return 0; } @@ -1229,10 +1282,17 @@ nft_rule_append(struct nft_handle *h, const char *chain, const char *table, if (verbose) h->ops->print_rule(r, 0, FMT_PRINT_RULE); - if (!nft_rule_list_get(h)) - return 0; - - nftnl_rule_list_add_tail(r, h->rule_cache); + if (ref) { + nftnl_chain_rule_insert_at(r, ref); + nftnl_chain_rule_del(r); + } else { + c = nft_chain_find(h, table, chain); + if (!c) { + errno = ENOENT; + return 0; + } + nftnl_chain_rule_add_tail(r, c); + } return 1; } @@ -1271,8 +1331,9 @@ nft_rule_print_save(const struct nftnl_rule *r, enum nft_rule_print type, static int nftnl_chain_list_cb(const struct nlmsghdr *nlh, void *data) { + struct nft_handle *h = data; + const struct builtin_table *t; struct nftnl_chain *c; - struct nftnl_chain_list *list = data; c = nftnl_chain_alloc(); if (c == NULL) @@ -1281,7 +1342,12 @@ static int nftnl_chain_list_cb(const struct nlmsghdr *nlh, void *data) if (nftnl_chain_nlmsg_parse(nlh, c) < 0) goto out; - nftnl_chain_list_add_tail(c, list); + t = nft_table_builtin_find(h, + nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE)); + if (!t) + goto out; + + nftnl_chain_list_add_tail(c, h->cache->table[t->type].chains); return MNL_CB_OK; out: @@ -1290,230 +1356,414 @@ err: return MNL_CB_OK; } -struct nftnl_chain_list *nft_chain_list_get(struct nft_handle *h) +static int nftnl_table_list_cb(const struct nlmsghdr *nlh, void *data) +{ + struct nftnl_table *t; + struct nftnl_table_list *list = data; + + t = nftnl_table_alloc(); + if (t == NULL) + goto err; + + if (nftnl_table_nlmsg_parse(nlh, t) < 0) + goto out; + + nftnl_table_list_add_tail(t, list); + + return MNL_CB_OK; +out: + nftnl_table_free(t); +err: + return MNL_CB_OK; +} + +static int fetch_table_cache(struct nft_handle *h) { char buf[16536]; struct nlmsghdr *nlh; - struct nftnl_chain_list *list; + struct nftnl_table_list *list; int ret; - if (h->chain_cache) - return h->chain_cache; -retry: - list = nftnl_chain_list_alloc(); - if (list == NULL) { - errno = ENOMEM; - return NULL; - } + list = nftnl_table_list_alloc(); + if (list == NULL) + return 0; - nlh = nftnl_chain_nlmsg_build_hdr(buf, NFT_MSG_GETCHAIN, h->family, + nlh = nftnl_rule_nlmsg_build_hdr(buf, NFT_MSG_GETTABLE, h->family, NLM_F_DUMP, h->seq); - ret = mnl_talk(h, nlh, nftnl_chain_list_cb, list); - if (ret < 0 && errno == EINTR) { + ret = mnl_talk(h, nlh, nftnl_table_list_cb, list); + if (ret < 0 && errno == EINTR) assert(nft_restart(h) >= 0); - nftnl_chain_list_free(list); - goto retry; + + h->cache->tables = list; + + return 1; +} + +static int fetch_chain_cache(struct nft_handle *h) +{ + char buf[16536]; + struct nlmsghdr *nlh; + int i, ret; + + fetch_table_cache(h); + + for (i = 0; i < NFT_TABLE_MAX; i++) { + enum nft_table_type type = h->tables[i].type; + + if (!h->tables[i].name) + continue; + + h->cache->table[type].chains = nftnl_chain_list_alloc(); + if (!h->cache->table[type].chains) + return -1; } - h->chain_cache = list; + nlh = nftnl_chain_nlmsg_build_hdr(buf, NFT_MSG_GETCHAIN, h->family, + NLM_F_DUMP, h->seq); + + ret = mnl_talk(h, nlh, nftnl_chain_list_cb, h); + if (ret < 0 && errno == EINTR) + assert(nft_restart(h) >= 0); - return list; + return ret; } -static const char *policy_name[NF_ACCEPT+1] = { - [NF_DROP] = "DROP", - [NF_ACCEPT] = "ACCEPT", -}; +static bool nft_rule_is_policy_rule(struct nftnl_rule *r) +{ + const struct nftnl_udata *tb[UDATA_TYPE_MAX + 1] = {}; + const void *data; + uint32_t len; + + if (!nftnl_rule_is_set(r, NFTNL_RULE_USERDATA)) + return false; -int nft_chain_save(struct nft_handle *h, struct nftnl_chain_list *list, - const char *table) + data = nftnl_rule_get_data(r, NFTNL_RULE_USERDATA, &len); + if (nftnl_udata_parse(data, len, parse_udata_cb, tb) < 0) + return NULL; + + if (!tb[UDATA_TYPE_EBTABLES_POLICY] || + nftnl_udata_get_u32(tb[UDATA_TYPE_EBTABLES_POLICY]) != 1) + return false; + + return true; +} + +static struct nftnl_rule *nft_chain_last_rule(struct nftnl_chain *c) { - struct nftnl_chain_list_iter *iter; - struct nft_family_ops *ops; - struct nftnl_chain *c; + struct nftnl_rule *r = NULL, *last; + struct nftnl_rule_iter *iter; - ops = nft_family_ops_lookup(h->family); + iter = nftnl_rule_iter_create(c); + if (!iter) + return NULL; - iter = nftnl_chain_list_iter_create(list); - if (iter == NULL) - return 0; + do { + last = r; + r = nftnl_rule_iter_next(iter); + } while (r); + nftnl_rule_iter_destroy(iter); - c = nftnl_chain_list_iter_next(iter); - while (c != NULL) { - const char *chain_table = - nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE); - const char *policy = NULL; + return last; +} - if (strcmp(table, chain_table) != 0) - goto next; +static void nft_bridge_chain_postprocess(struct nft_handle *h, + struct nftnl_chain *c) +{ + struct nftnl_rule *last = nft_chain_last_rule(c); + struct nftnl_expr_iter *iter; + struct nftnl_expr *expr; + int verdict; - if (nft_chain_builtin(c)) { - uint32_t pol = NF_ACCEPT; + if (!last || !nft_rule_is_policy_rule(last)) + return; - if (nftnl_chain_get(c, NFTNL_CHAIN_POLICY)) - pol = nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY); - policy = policy_name[pol]; - } + iter = nftnl_expr_iter_create(last); + if (!iter) + return; - if (ops->save_chain) - ops->save_chain(c, policy); -next: - c = nftnl_chain_list_iter_next(iter); - } + expr = nftnl_expr_iter_next(iter); + if (!expr || + strcmp("counter", nftnl_expr_get_str(expr, NFTNL_EXPR_NAME))) + goto out_iter; - nftnl_chain_list_iter_destroy(iter); + expr = nftnl_expr_iter_next(iter); + if (!expr || + strcmp("immediate", nftnl_expr_get_str(expr, NFTNL_EXPR_NAME)) || + !nftnl_expr_is_set(expr, NFTNL_EXPR_IMM_VERDICT)) + goto out_iter; + + verdict = nftnl_expr_get_u32(expr, NFTNL_EXPR_IMM_VERDICT); + switch (verdict) { + case NF_ACCEPT: + case NF_DROP: + break; + default: + goto out_iter; + } - return 1; + nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, verdict); + if (batch_rule_add(h, NFT_COMPAT_RULE_DELETE, last) == NULL) + fprintf(stderr, "Failed to delete old policy rule\n"); + nftnl_chain_rule_del(last); +out_iter: + nftnl_expr_iter_destroy(iter); } static int nftnl_rule_list_cb(const struct nlmsghdr *nlh, void *data) { + struct nftnl_chain *c = data; struct nftnl_rule *r; - struct nftnl_rule_list *list = data; r = nftnl_rule_alloc(); if (r == NULL) - goto err; - - if (nftnl_rule_nlmsg_parse(nlh, r) < 0) - goto out; + return MNL_CB_OK; - nftnl_rule_list_add_tail(r, list); + if (nftnl_rule_nlmsg_parse(nlh, r) < 0) { + nftnl_rule_free(r); + return MNL_CB_OK; + } - return MNL_CB_OK; -out: - nftnl_rule_free(r); - nftnl_rule_list_free(list); -err: + nftnl_chain_rule_add_tail(r, c); return MNL_CB_OK; } -static struct nftnl_rule_list *nft_rule_list_get(struct nft_handle *h) +static int nft_rule_list_update(struct nftnl_chain *c, void *data) { + struct nft_handle *h = data; char buf[16536]; struct nlmsghdr *nlh; - struct nftnl_rule_list *list; + struct nftnl_rule *rule; int ret; - if (h->rule_cache) - return h->rule_cache; + rule = nftnl_rule_alloc(); + if (!rule) + return -1; -retry: - list = nftnl_rule_list_alloc(); - if (list == NULL) - return 0; + nftnl_rule_set_str(rule, NFTNL_RULE_TABLE, + nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE)); + 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); + nftnl_rule_nlmsg_build_payload(nlh, rule); - ret = mnl_talk(h, nlh, nftnl_rule_list_cb, list); - if (ret < 0) { - if (errno == EINTR) { - assert(nft_restart(h) >= 0); - nftnl_rule_list_free(list); - goto retry; - } + ret = mnl_talk(h, nlh, nftnl_rule_list_cb, c); + if (ret < 0 && errno == EINTR) + assert(nft_restart(h) >= 0); - nftnl_rule_list_free(list); - return NULL; - } + nftnl_rule_free(rule); + + if (h->family == NFPROTO_BRIDGE) + nft_bridge_chain_postprocess(h, c); - h->rule_cache = list; - return list; + return 0; } -int nft_rule_save(struct nft_handle *h, const char *table, unsigned int format) +static int fetch_rule_cache(struct nft_handle *h) { - struct nftnl_rule_list *list; - struct nftnl_rule_list_iter *iter; - struct nftnl_rule *r; - - list = nft_rule_list_get(h); - if (list == NULL) - return 0; + int i; - iter = nftnl_rule_list_iter_create(list); - if (iter == NULL) - return 0; + for (i = 0; i < NFT_TABLE_MAX; i++) { + enum nft_table_type type = h->tables[i].type; - r = nftnl_rule_list_iter_next(iter); - while (r != NULL) { - const char *rule_table = - nftnl_rule_get_str(r, NFTNL_RULE_TABLE); + if (!h->tables[i].name) + continue; - if (strcmp(table, rule_table) != 0) - goto next; + if (nftnl_chain_list_foreach(h->cache->table[type].chains, + nft_rule_list_update, h)) + return -1; + } + return 0; +} - nft_rule_print_save(r, NFT_RULE_APPEND, format); +static void __nft_build_cache(struct nft_handle *h) +{ + uint32_t genid_start, genid_stop; -next: - r = nftnl_rule_list_iter_next(iter); +retry: + mnl_genid_get(h, &genid_start); + fetch_chain_cache(h); + fetch_rule_cache(h); + h->have_cache = true; + mnl_genid_get(h, &genid_stop); + + if (genid_start != genid_stop) { + flush_chain_cache(h, NULL); + goto retry; } - nftnl_rule_list_iter_destroy(iter); + h->nft_genid = genid_start; +} - /* the core expects 1 for success and 0 for error */ - return 1; +void nft_build_cache(struct nft_handle *h) +{ + if (!h->have_cache) + __nft_build_cache(h); } -static void -__nft_rule_flush(struct nft_handle *h, const char *table, const char *chain) +static void __nft_flush_cache(struct nft_handle *h) { - struct nftnl_rule *r; + if (!h->cache_index) { + h->cache_index++; + h->cache = &h->__cache[h->cache_index]; + } else { + flush_chain_cache(h, NULL); + } +} - r = nftnl_rule_alloc(); - if (r == NULL) - return; +static void nft_rebuild_cache(struct nft_handle *h) +{ + if (h->have_cache) + __nft_flush_cache(h); - nftnl_rule_set(r, NFTNL_RULE_TABLE, (char *)table); - nftnl_rule_set(r, NFTNL_RULE_CHAIN, (char *)chain); + __nft_build_cache(h); +} - if (batch_rule_add(h, NFT_COMPAT_RULE_FLUSH, r) < 0) - nftnl_rule_free(r); +static void nft_release_cache(struct nft_handle *h) +{ + if (h->cache_index) + flush_cache(&h->__cache[0], h->tables, NULL); } -struct chain_user_flush_data { - struct nft_handle *handle; - const char *table; - const char *chain; +struct nftnl_chain_list *nft_chain_list_get(struct nft_handle *h, + const char *table) +{ + const struct builtin_table *t; + + t = nft_table_builtin_find(h, table); + if (!t) + return NULL; + + nft_build_cache(h); + + return h->cache->table[t->type].chains; +} + +static const char *policy_name[NF_ACCEPT+1] = { + [NF_DROP] = "DROP", + [NF_ACCEPT] = "ACCEPT", }; -static int __nft_chain_user_flush(struct nftnl_chain *c, void *data) +int nft_chain_save(struct nft_handle *h, struct nftnl_chain_list *list) { - const char *table_name = nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE); - const char *chain_name = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME); - struct chain_user_flush_data *d = data; - struct nft_handle *h = d->handle; - const char *table = d->table; - const char *chain = d->chain; + struct nftnl_chain_list_iter *iter; + struct nft_family_ops *ops; + struct nftnl_chain *c; - if (strcmp(table, table_name) != 0) - return 0; + ops = nft_family_ops_lookup(h->family); - if (strcmp(chain, chain_name) != 0) + iter = nftnl_chain_list_iter_create(list); + if (iter == NULL) return 0; - if (!nftnl_chain_is_set(c, NFTNL_CHAIN_HOOKNUM)) - __nft_rule_flush(h, table, chain); + c = nftnl_chain_list_iter_next(iter); + while (c != NULL) { + const char *policy = NULL; + + if (nft_chain_builtin(c)) { + uint32_t pol = NF_ACCEPT; + + if (nftnl_chain_get(c, NFTNL_CHAIN_POLICY)) + pol = nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY); + policy = policy_name[pol]; + } else if (h->family == NFPROTO_BRIDGE) { + if (nftnl_chain_is_set(c, NFTNL_CHAIN_POLICY)) { + uint32_t pol; + + pol = nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY); + policy = policy_name[pol]; + } else { + policy = "RETURN"; + } + } + + if (ops->save_chain) + ops->save_chain(c, policy); + + c = nftnl_chain_list_iter_next(iter); + } + + nftnl_chain_list_iter_destroy(iter); + + return 1; +} +static int nft_chain_save_rules(struct nft_handle *h, + struct nftnl_chain *c, unsigned int format) +{ + struct nftnl_rule_iter *iter; + struct nftnl_rule *r; + + iter = nftnl_rule_iter_create(c); + if (iter == NULL) + return 1; + + r = nftnl_rule_iter_next(iter); + while (r != NULL) { + nft_rule_print_save(r, NFT_RULE_APPEND, format); + r = nftnl_rule_iter_next(iter); + } + + nftnl_rule_iter_destroy(iter); return 0; } -int nft_chain_user_flush(struct nft_handle *h, struct nftnl_chain_list *list, - const char *table, const char *chain) +int nft_rule_save(struct nft_handle *h, const char *table, unsigned int format) { - struct chain_user_flush_data d = { - .handle = h, - .table = table, - .chain = chain, - }; + struct nftnl_chain_list_iter *iter; + struct nftnl_chain_list *list; + struct nftnl_chain *c; + int ret = 0; - nft_fn = nft_chain_user_flush; + list = nft_chain_list_get(h, table); + if (!list) + return 0; - nftnl_chain_list_foreach(list, __nft_chain_user_flush, &d); + iter = nftnl_chain_list_iter_create(list); + if (!iter) + return 0; - return 1; + c = nftnl_chain_list_iter_next(iter); + while (c) { + ret = nft_chain_save_rules(h, c, format); + if (ret != 0) + break; + + c = nftnl_chain_list_iter_next(iter); + } + + nftnl_chain_list_iter_destroy(iter); + + /* the core expects 1 for success and 0 for error */ + return ret == 0 ? 1 : 0; +} + +static void +__nft_rule_flush(struct nft_handle *h, const char *table, + const char *chain, bool verbose, bool implicit) +{ + struct obj_update *obj; + struct nftnl_rule *r; + + if (verbose) + fprintf(stdout, "Flushing chain `%s'\n", chain); + + r = nftnl_rule_alloc(); + if (r == NULL) + return; + + nftnl_rule_set(r, NFTNL_RULE_TABLE, (char *)table); + nftnl_rule_set(r, NFTNL_RULE_CHAIN, (char *)chain); + + obj = batch_rule_add(h, NFT_COMPAT_RULE_FLUSH, r); + if (!obj) { + nftnl_rule_free(r); + return; + } + + obj->implicit = implicit; } int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table, @@ -1529,12 +1779,22 @@ int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table, nft_fn = nft_rule_flush; - list = nft_chain_list_get(h); + list = nft_chain_list_get(h, table); if (list == NULL) { ret = 1; goto err; } + if (chain) { + c = nftnl_chain_list_lookup_byname(list, chain); + if (!c) + return 0; + + __nft_rule_flush(h, table, chain, verbose, false); + flush_rule_cache(c); + return 1; + } + iter = nftnl_chain_list_iter_create(list); if (iter == NULL) { ret = 1; @@ -1543,29 +1803,14 @@ int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table, c = nftnl_chain_list_iter_next(iter); while (c != NULL) { - const char *table_name = - nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE); const char *chain_name = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME); - if (strcmp(table, table_name) != 0) - goto next; - - if (chain != NULL && strcmp(chain, chain_name) != 0) - goto next; - - if (verbose) - fprintf(stdout, "Flushing chain `%s'\n", chain_name); - - __nft_rule_flush(h, table_name, chain_name); - - if (chain != NULL) - break; -next: + __nft_rule_flush(h, table, chain_name, verbose, false); + flush_rule_cache(c); c = nftnl_chain_list_iter_next(iter); } nftnl_chain_list_iter_destroy(iter); - flush_rule_cache(h, table); err: /* the core expects 1 for success and 0 for error */ return ret == 0 ? 1 : 0; @@ -1573,6 +1818,7 @@ err: int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *table) { + struct nftnl_chain_list *list; struct nftnl_chain *c; int ret; @@ -1582,125 +1828,138 @@ int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *tabl if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0) nft_xt_builtin_init(h, table); + if (nft_chain_exists(h, table, chain)) { + errno = EEXIST; + return 0; + } + c = nftnl_chain_alloc(); if (c == NULL) return 0; nftnl_chain_set(c, NFTNL_CHAIN_TABLE, (char *)table); nftnl_chain_set(c, NFTNL_CHAIN_NAME, (char *)chain); + if (h->family == NFPROTO_BRIDGE) + nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, NF_ACCEPT); ret = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_ADD, c); - nft_chain_list_get(h); - - nftnl_chain_list_add(c, h->chain_cache); + list = nft_chain_list_get(h, table); + if (list) + nftnl_chain_list_add(c, list); /* the core expects 1 for success and 0 for error */ return ret == 0 ? 1 : 0; } -/* From linux/netlink.h */ -#ifndef NLM_F_NONREC -#define NLM_F_NONREC 0x100 /* Do not delete recursively */ -#endif - -int nft_chain_user_del(struct nft_handle *h, const char *chain, - const char *table, bool verbose) +int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table) { struct nftnl_chain_list *list; - struct nftnl_chain_list_iter *iter; struct nftnl_chain *c; - int ret = 0; - int deleted_ctr = 0; - - nft_fn = nft_chain_user_del; + bool created = false; + int ret; - list = nft_chain_list_get(h); - if (list == NULL) - goto err; + c = nft_chain_find(h, table, chain); + if (c) { + /* Apparently -n still flushes existing user defined + * chains that are redefined. + */ + if (h->noflush) + __nft_rule_flush(h, table, chain, false, true); + } else { + c = nftnl_chain_alloc(); + if (!c) + return -1; - iter = nftnl_chain_list_iter_create(list); - if (iter == NULL) - goto err; + nftnl_chain_set(c, NFTNL_CHAIN_TABLE, (char *)table); + nftnl_chain_set(c, NFTNL_CHAIN_NAME, (char *)chain); + created = true; + } - c = nftnl_chain_list_iter_next(iter); - while (c != NULL) { - const char *table_name = - nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE); - const char *chain_name = - nftnl_chain_get_str(c, NFTNL_CHAIN_NAME); + if (h->family == NFPROTO_BRIDGE) + nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, NF_ACCEPT); - /* don't delete built-in chain */ - if (nft_chain_builtin(c)) - goto next; + if (!created) + return 0; - if (strcmp(table, table_name) != 0) - goto next; + ret = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_ADD, c); - if (chain != NULL && strcmp(chain, chain_name) != 0) - goto next; + list = nft_chain_list_get(h, table); + if (list) + nftnl_chain_list_add(c, list); - if (verbose) - fprintf(stdout, "Deleting chain `%s'\n", chain); + return ret; +} - ret = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_DEL, c); +/* From linux/netlink.h */ +#ifndef NLM_F_NONREC +#define NLM_F_NONREC 0x100 /* Do not delete recursively */ +#endif - if (ret < 0) - break; +struct chain_user_del_data { + struct nft_handle *handle; + bool verbose; + int builtin_err; +}; - deleted_ctr++; - nftnl_chain_list_del(c); +static int __nft_chain_user_del(struct nftnl_chain *c, void *data) +{ + struct chain_user_del_data *d = data; + struct nft_handle *h = d->handle; + int ret; - if (chain != NULL) - break; -next: - c = nftnl_chain_list_iter_next(iter); - } + /* don't delete built-in chain */ + if (nft_chain_builtin(c)) + return d->builtin_err; - nftnl_chain_list_iter_destroy(iter); -err: + if (d->verbose) + fprintf(stdout, "Deleting chain `%s'\n", + nftnl_chain_get_str(c, NFTNL_CHAIN_NAME)); - /* chain not found */ - if (chain != NULL && deleted_ctr == 0) { - ret = -1; - errno = ENOENT; - } + /* XXX This triggers a fast lookup from the kernel. */ + nftnl_chain_unset(c, NFTNL_CHAIN_HANDLE); + ret = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_DEL, c); + if (ret) + return -1; - /* the core expects 1 for success and 0 for error */ - return ret == 0 ? 1 : 0; + nftnl_chain_list_del(c); + return 0; } -struct nftnl_chain * -nft_chain_list_find(struct nftnl_chain_list *list, - const char *table, const char *chain) +int nft_chain_user_del(struct nft_handle *h, const char *chain, + const char *table, bool verbose) { - struct nftnl_chain_list_iter *iter; + struct chain_user_del_data d = { + .handle = h, + .verbose = verbose, + }; + struct nftnl_chain_list *list; struct nftnl_chain *c; + int ret = 0; - iter = nftnl_chain_list_iter_create(list); - if (iter == NULL) - return NULL; - - c = nftnl_chain_list_iter_next(iter); - while (c != NULL) { - const char *table_name = - nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE); - const char *chain_name = - nftnl_chain_get_str(c, NFTNL_CHAIN_NAME); - - if (strcmp(table, table_name) != 0) - goto next; + nft_fn = nft_chain_user_del; - if (strcmp(chain, chain_name) != 0) - goto next; + list = nft_chain_list_get(h, table); + if (list == NULL) + return 0; - nftnl_chain_list_iter_destroy(iter); - return c; -next: - c = nftnl_chain_list_iter_next(iter); + if (chain) { + c = nftnl_chain_list_lookup_byname(list, chain); + if (!c) { + errno = ENOENT; + return 0; + } + d.builtin_err = -2; + ret = __nft_chain_user_del(c, &d); + if (ret == -2) + errno = EINVAL; + goto out; } - nftnl_chain_list_iter_destroy(iter); - return NULL; + + ret = nftnl_chain_list_foreach(list, __nft_chain_user_del, &d); +out: + /* the core expects 1 for success and 0 for error */ + return ret == 0 ? 1 : 0; } static struct nftnl_chain * @@ -1708,17 +1967,17 @@ nft_chain_find(struct nft_handle *h, const char *table, const char *chain) { struct nftnl_chain_list *list; - list = nft_chain_list_get(h); + list = nft_chain_list_get(h, table); if (list == NULL) return NULL; - return nft_chain_list_find(list, table, chain); + return nftnl_chain_list_lookup_byname(list, chain); } bool nft_chain_exists(struct nft_handle *h, const char *table, const char *chain) { - struct builtin_table *t = nft_table_builtin_find(h, table); + const struct builtin_table *t = nft_table_builtin_find(h, table); /* xtables does not support custom tables */ if (!t) @@ -1737,7 +1996,12 @@ int nft_chain_user_rename(struct nft_handle *h,const char *chain, uint64_t handle; int ret; - nft_fn = nft_chain_user_add; + nft_fn = nft_chain_user_rename; + + if (nft_chain_exists(h, table, newname)) { + errno = EEXIST; + return 0; + } /* If built-in chains don't exist for this table, create them */ if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0) @@ -1769,56 +2033,17 @@ int nft_chain_user_rename(struct nft_handle *h,const char *chain, return ret == 0 ? 1 : 0; } -static int nftnl_table_list_cb(const struct nlmsghdr *nlh, void *data) -{ - struct nftnl_table *t; - struct nftnl_table_list *list = data; - - t = nftnl_table_alloc(); - if (t == NULL) - goto err; - - if (nftnl_table_nlmsg_parse(nlh, t) < 0) - goto out; - - nftnl_table_list_add_tail(t, list); - - return MNL_CB_OK; -out: - nftnl_table_free(t); -err: - return MNL_CB_OK; -} - static struct nftnl_table_list *nftnl_table_list_get(struct nft_handle *h) { - char buf[16536]; - struct nlmsghdr *nlh; - struct nftnl_table_list *list; - int ret; - -retry: - list = nftnl_table_list_alloc(); - if (list == NULL) - return 0; - - nlh = nftnl_rule_nlmsg_build_hdr(buf, NFT_MSG_GETTABLE, h->family, - NLM_F_DUMP, h->seq); - - ret = mnl_talk(h, nlh, nftnl_table_list_cb, list); - if (ret < 0 && errno == EINTR) { - assert(nft_restart(h) >= 0); - nftnl_table_list_free(list); - goto retry; - } + nft_build_cache(h); - return list; + return h->cache->tables; } bool nft_table_find(struct nft_handle *h, const char *tablename) { - struct nftnl_table_list *list; struct nftnl_table_list_iter *iter; + struct nftnl_table_list *list; struct nftnl_table *t; bool ret = false; @@ -1844,7 +2069,6 @@ bool nft_table_find(struct nft_handle *h, const char *tablename) } nftnl_table_list_iter_destroy(iter); - nftnl_table_list_free(list); err: return ret; @@ -1877,13 +2101,13 @@ int nft_for_each_table(struct nft_handle *h, } nftnl_table_list_iter_destroy(iter); - nftnl_table_list_free(list); return 0; } -static int __nft_table_flush(struct nft_handle *h, const char *table) +static int __nft_table_flush(struct nft_handle *h, const char *table, bool exists) { - struct builtin_table *_t; + const struct builtin_table *_t; + struct obj_update *obj; struct nftnl_table *t; t = nftnl_table_alloc(); @@ -1892,14 +2116,20 @@ static int __nft_table_flush(struct nft_handle *h, const char *table) nftnl_table_set_str(t, NFTNL_TABLE_NAME, table); - batch_table_add(h, NFT_COMPAT_TABLE_FLUSH, t); + obj = batch_table_add(h, NFT_COMPAT_TABLE_FLUSH, t); + if (!obj) { + nftnl_table_free(t); + return -1; + } + + if (!exists) + obj->skip = 1; _t = nft_table_builtin_find(h, table); assert(_t); - _t->initialized = false; + h->cache->table[_t->type].initialized = false; flush_chain_cache(h, table); - flush_rule_cache(h, table); return 0; } @@ -1909,6 +2139,7 @@ int nft_table_flush(struct nft_handle *h, const char *table) struct nftnl_table_list_iter *iter; struct nftnl_table_list *list; struct nftnl_table *t; + bool exists = false; int ret = 0; nft_fn = nft_table_flush; @@ -1930,26 +2161,17 @@ int nft_table_flush(struct nft_handle *h, const char *table) const char *table_name = nftnl_table_get_str(t, NFTNL_TABLE_NAME); - if (strcmp(table_name, table) != 0) - goto next; + if (strcmp(table_name, table) == 0) { + exists = true; + break; + } - ret = __nft_table_flush(h, table); - if (ret < 0) - goto err_table_iter; -next: t = nftnl_table_list_iter_next(iter); } - if (!h->rule_cache) { - h->rule_cache = nftnl_rule_list_alloc(); - if (h->rule_cache == NULL) - return -1; - } - -err_table_iter: + ret = __nft_table_flush(h, table, exists); nftnl_table_list_iter_destroy(iter); err_table_list: - nftnl_table_list_free(list); err_out: /* the core expects 1 for success and 0 for error */ return ret == 0 ? 1 : 0; @@ -1961,15 +2183,14 @@ void nft_table_new(struct nft_handle *h, const char *table) nft_xt_builtin_init(h, table); } -static int __nft_rule_del(struct nft_handle *h, struct nftnl_rule_list *list, - struct nftnl_rule *r) +static int __nft_rule_del(struct nft_handle *h, struct nftnl_rule *r) { - int ret; + struct obj_update *obj; nftnl_rule_list_del(r); - ret = batch_rule_add(h, NFT_COMPAT_RULE_DELETE, r); - if (ret < 0) { + obj = batch_rule_add(h, NFT_COMPAT_RULE_DELETE, r); + if (!obj) { nftnl_rule_free(r); return -1; } @@ -1977,48 +2198,29 @@ static int __nft_rule_del(struct nft_handle *h, struct nftnl_rule_list *list, } static struct nftnl_rule * -nft_rule_find(struct nft_handle *h, struct nftnl_rule_list *list, - const char *chain, const char *table, void *data, int rulenum) +nft_rule_find(struct nft_handle *h, struct nftnl_chain *c, void *data, int rulenum) { struct nftnl_rule *r; - struct nftnl_rule_list_iter *iter; - int rule_ctr = 0; + struct nftnl_rule_iter *iter; bool found = false; - iter = nftnl_rule_list_iter_create(list); + if (rulenum >= 0) + /* Delete by rule number case */ + return nftnl_rule_lookup_byindex(c, rulenum); + + iter = nftnl_rule_iter_create(c); if (iter == NULL) return 0; - r = nftnl_rule_list_iter_next(iter); + r = nftnl_rule_iter_next(iter); while (r != NULL) { - const char *rule_table = - nftnl_rule_get_str(r, NFTNL_RULE_TABLE); - const char *rule_chain = - nftnl_rule_get_str(r, NFTNL_RULE_CHAIN); - - if (strcmp(table, rule_table) != 0 || - strcmp(chain, rule_chain) != 0) { - DEBUGP("different chain / table\n"); - goto next; - } - - if (rulenum >= 0) { - /* Delete by rule number case */ - if (rule_ctr == rulenum) { - found = true; - break; - } - } else { - found = h->ops->rule_find(h->ops, r, data); - if (found) - break; - } - rule_ctr++; -next: - r = nftnl_rule_list_iter_next(iter); + found = h->ops->rule_find(h->ops, r, data); + if (found) + break; + r = nftnl_rule_iter_next(iter); } - nftnl_rule_list_iter_destroy(iter); + nftnl_rule_iter_destroy(iter); return found ? r : NULL; } @@ -2026,42 +2228,46 @@ next: int nft_rule_check(struct nft_handle *h, const char *chain, const char *table, void *data, bool verbose) { - struct nftnl_rule_list *list; + struct nftnl_chain *c; struct nftnl_rule *r; nft_fn = nft_rule_check; - list = nft_rule_list_get(h); - if (list == NULL) - return 0; + c = nft_chain_find(h, table, chain); + if (!c) + goto fail_enoent; + + r = nft_rule_find(h, c, data, -1); + if (r == NULL) + goto fail_enoent; - r = nft_rule_find(h, list, chain, table, data, -1); - if (r == NULL) { - errno = ENOENT; - return 0; - } if (verbose) h->ops->print_rule(r, 0, FMT_PRINT_RULE); return 1; +fail_enoent: + errno = ENOENT; + return 0; } int nft_rule_delete(struct nft_handle *h, const char *chain, const char *table, void *data, bool verbose) { int ret = 0; + struct nftnl_chain *c; struct nftnl_rule *r; - struct nftnl_rule_list *list; nft_fn = nft_rule_delete; - list = nft_rule_list_get(h); - if (list == NULL) + c = nft_chain_find(h, table, chain); + if (!c) { + errno = ENOENT; return 0; + } - r = nft_rule_find(h, list, chain, table, data, -1); + r = nft_rule_find(h, c, data, -1); if (r != NULL) { - ret =__nft_rule_del(h, list, r); + ret =__nft_rule_del(h, r); if (ret < 0) errno = ENOMEM; if (verbose) @@ -2075,18 +2281,32 @@ int nft_rule_delete(struct nft_handle *h, const char *chain, static struct nftnl_rule * nft_rule_add(struct nft_handle *h, const char *chain, const char *table, struct iptables_command_state *cs, - uint64_t handle, bool verbose) + struct nftnl_rule *ref, bool verbose) { struct nftnl_rule *r; + uint64_t ref_id; r = nft_rule_new(h, chain, table, cs); if (r == NULL) return NULL; - if (handle > 0) - nftnl_rule_set_u64(r, NFTNL_RULE_POSITION, handle); + if (ref) { + ref_id = nftnl_rule_get_u64(ref, NFTNL_RULE_HANDLE); + if (ref_id > 0) { + nftnl_rule_set_u64(r, NFTNL_RULE_POSITION, ref_id); + DEBUGP("adding after rule handle %"PRIu64"\n", ref_id); + } else { + ref_id = nftnl_rule_get_u32(ref, NFTNL_RULE_ID); + if (!ref_id) { + ref_id = ++h->rule_id; + nftnl_rule_set_u32(ref, NFTNL_RULE_ID, ref_id); + } + nftnl_rule_set_u32(r, NFTNL_RULE_POSITION_ID, ref_id); + DEBUGP("adding after rule ID %"PRIu64"\n", ref_id); + } + } - if (batch_rule_add(h, NFT_COMPAT_RULE_INSERT, r) < 0) { + if (!batch_rule_add(h, NFT_COMPAT_RULE_INSERT, r)) { nftnl_rule_free(r); return NULL; } @@ -2100,9 +2320,8 @@ nft_rule_add(struct nft_handle *h, const char *chain, int nft_rule_insert(struct nft_handle *h, const char *chain, const char *table, void *data, int rulenum, bool verbose) { - struct nftnl_rule *r, *new_rule; - struct nftnl_rule_list *list; - uint64_t handle = 0; + struct nftnl_rule *r = NULL, *new_rule; + struct nftnl_chain *c; /* If built-in chains don't exist for this table, create them */ if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0) @@ -2110,40 +2329,36 @@ int nft_rule_insert(struct nft_handle *h, const char *chain, nft_fn = nft_rule_insert; - if (rulenum > 0) { - list = nft_rule_list_get(h); - if (list == NULL) - goto err; + c = nft_chain_find(h, table, chain); + if (!c) { + errno = ENOENT; + goto err; + } - r = nft_rule_find(h, list, chain, table, data, rulenum); + if (rulenum > 0) { + r = nft_rule_find(h, c, data, rulenum); if (r == NULL) { /* special case: iptables allows to insert into * rule_count + 1 position. */ - r = nft_rule_find(h, list, chain, table, data, - rulenum - 1); + r = nft_rule_find(h, c, data, rulenum - 1); if (r != NULL) return nft_rule_append(h, chain, table, data, - 0, verbose); + NULL, verbose); - errno = ENOENT; + errno = E2BIG; goto err; } - - handle = nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE); - DEBUGP("adding after rule handle %"PRIu64"\n", handle); - } else { - nft_rule_list_get(h); } - new_rule = nft_rule_add(h, chain, table, data, handle, verbose); + new_rule = nft_rule_add(h, chain, table, data, r, verbose); if (!new_rule) goto err; - if (handle) - nftnl_rule_list_insert_at(new_rule, r); + if (r) + nftnl_chain_rule_insert_at(new_rule, r); else - nftnl_rule_list_add(new_rule, h->rule_cache); + nftnl_chain_rule_add(new_rule, c); return 1; err: @@ -2154,23 +2369,25 @@ int nft_rule_delete_num(struct nft_handle *h, const char *chain, const char *table, int rulenum, bool verbose) { int ret = 0; + struct nftnl_chain *c; struct nftnl_rule *r; - struct nftnl_rule_list *list; nft_fn = nft_rule_delete_num; - list = nft_rule_list_get(h); - if (list == NULL) + c = nft_chain_find(h, table, chain); + if (!c) { + errno = ENOENT; return 0; + } - r = nft_rule_find(h, list, chain, table, NULL, rulenum); + r = nft_rule_find(h, c, NULL, rulenum); if (r != NULL) { DEBUGP("deleting rule by number %d\n", rulenum); - ret = __nft_rule_del(h, list, r); + ret = __nft_rule_del(h, r); if (ret < 0) errno = ENOMEM; } else - errno = ENOENT; + errno = E2BIG; return ret; } @@ -2179,117 +2396,106 @@ int nft_rule_replace(struct nft_handle *h, const char *chain, const char *table, void *data, int rulenum, bool verbose) { int ret = 0; + struct nftnl_chain *c; struct nftnl_rule *r; - struct nftnl_rule_list *list; nft_fn = nft_rule_replace; - list = nft_rule_list_get(h); - if (list == NULL) + c = nft_chain_find(h, table, chain); + if (!c) { + errno = ENOENT; return 0; + } - r = nft_rule_find(h, list, chain, table, data, rulenum); + r = nft_rule_find(h, c, data, rulenum); if (r != NULL) { DEBUGP("replacing rule with handle=%llu\n", (unsigned long long) nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE)); - nftnl_rule_list_del(r); - - ret = nft_rule_append(h, chain, table, data, - nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE), - verbose); + ret = nft_rule_append(h, chain, table, data, r, verbose); } else - errno = ENOENT; + errno = E2BIG; return ret; } static int -__nft_rule_list(struct nft_handle *h, const char *chain, const char *table, +__nft_rule_list(struct nft_handle *h, struct nftnl_chain *c, int rulenum, unsigned int format, void (*cb)(struct nftnl_rule *r, unsigned int num, unsigned int format)) { - struct nftnl_rule_list *list; - struct nftnl_rule_list_iter *iter; + struct nftnl_rule_iter *iter; struct nftnl_rule *r; int rule_ctr = 0; - list = nft_rule_list_get(h); - if (list == NULL) - return 0; + if (rulenum > 0) { + r = nftnl_rule_lookup_byindex(c, rulenum - 1); + if (!r) + /* iptables-legacy returns 0 when listing for + * valid chain but invalid rule number + */ + return 1; + cb(r, rulenum, format); + return 1; + } - iter = nftnl_rule_list_iter_create(list); + iter = nftnl_rule_iter_create(c); if (iter == NULL) return 0; - r = nftnl_rule_list_iter_next(iter); + r = nftnl_rule_iter_next(iter); while (r != NULL) { - const char *rule_table = - nftnl_rule_get_str(r, NFTNL_RULE_TABLE); - const char *rule_chain = - nftnl_rule_get_str(r, NFTNL_RULE_CHAIN); - - if (strcmp(table, rule_table) != 0 || - strcmp(chain, rule_chain) != 0) - goto next; - - rule_ctr++; - - if (rulenum > 0 && rule_ctr != rulenum) { - /* List by rule number case */ - goto next; - } - - cb(r, rule_ctr, format); - if (rulenum > 0) - break; - -next: - r = nftnl_rule_list_iter_next(iter); + cb(r, ++rule_ctr, format); + r = nftnl_rule_iter_next(iter); } - nftnl_rule_list_iter_destroy(iter); + nftnl_rule_iter_destroy(iter); return 1; } -static int nft_rule_count(struct nft_handle *h, - const char *chain, const char *table) +static int nft_rule_count(struct nft_handle *h, struct nftnl_chain *c) { - struct nftnl_rule_list_iter *iter; - struct nftnl_rule_list *list; + struct nftnl_rule_iter *iter; struct nftnl_rule *r; int rule_ctr = 0; - list = nft_rule_list_get(h); - if (list == NULL) - return 0; - - iter = nftnl_rule_list_iter_create(list); + iter = nftnl_rule_iter_create(c); if (iter == NULL) return 0; - r = nftnl_rule_list_iter_next(iter); + r = nftnl_rule_iter_next(iter); while (r != NULL) { - const char *rule_table = - nftnl_rule_get_str(r, NFTNL_RULE_TABLE); - const char *rule_chain = - nftnl_rule_get_str(r, NFTNL_RULE_CHAIN); - - if (strcmp(table, rule_table) != 0 || - strcmp(chain, rule_chain) != 0) - goto next; - rule_ctr++; -next: - r = nftnl_rule_list_iter_next(iter); + r = nftnl_rule_iter_next(iter); } - nftnl_rule_list_iter_destroy(iter); + nftnl_rule_iter_destroy(iter); return rule_ctr; } +static void __nft_print_header(struct nft_handle *h, + const struct nft_family_ops *ops, + struct nftnl_chain *c, unsigned int format) +{ + const char *chain_name = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME); + bool basechain = !!nftnl_chain_get(c, NFTNL_CHAIN_HOOKNUM); + uint32_t refs = nftnl_chain_get_u32(c, NFTNL_CHAIN_USE); + uint32_t entries = nft_rule_count(h, c); + struct xt_counters ctrs = { + .pcnt = nftnl_chain_get_u64(c, NFTNL_CHAIN_PACKETS), + .bcnt = nftnl_chain_get_u64(c, NFTNL_CHAIN_BYTES), + }; + const char *pname = NULL; + + if (nftnl_chain_is_set(c, NFTNL_CHAIN_POLICY)) + pname = policy_name[nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY)]; + + ops->print_header(format, chain_name, pname, + &ctrs, basechain, refs - entries, entries); +} + int nft_rule_list(struct nft_handle *h, const char *chain, const char *table, int rulenum, unsigned int format) { @@ -2300,16 +2506,8 @@ int nft_rule_list(struct nft_handle *h, const char *chain, const char *table, bool found = false; /* If built-in chains don't exist for this table, create them */ - if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0) { + if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0) nft_xt_builtin_init(h, table); - /* Force table and chain creation, otherwise first iptables -L - * lists no table/chains. - */ - if (!list_empty(&h->obj_list)) { - nft_commit(h); - flush_chain_cache(h, NULL); - } - } ops = nft_family_ops_lookup(h->family); @@ -2318,75 +2516,43 @@ int nft_rule_list(struct nft_handle *h, const char *chain, const char *table, return 0; } - if (chain && rulenum) { - __nft_rule_list(h, chain, table, - rulenum, format, ops->print_rule); + list = nft_chain_list_get(h, table); + if (!list) + return 0; + + if (chain) { + c = nftnl_chain_list_lookup_byname(list, chain); + if (!c) + return 0; + + if (!rulenum) { + if (ops->print_table_header) + ops->print_table_header(table); + __nft_print_header(h, ops, c, format); + } + __nft_rule_list(h, c, rulenum, format, ops->print_rule); return 1; } - list = nft_chain_list_get(h); - iter = nftnl_chain_list_iter_create(list); if (iter == NULL) - goto err; + return 0; - if (!chain && ops->print_table_header) + if (ops->print_table_header) ops->print_table_header(table); c = nftnl_chain_list_iter_next(iter); while (c != NULL) { - const char *chain_table = - nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE); - const char *chain_name = - nftnl_chain_get_str(c, NFTNL_CHAIN_NAME); - uint32_t policy = - nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY); - uint32_t refs = - nftnl_chain_get_u32(c, NFTNL_CHAIN_USE); - struct xt_counters ctrs = { - .pcnt = nftnl_chain_get_u64(c, NFTNL_CHAIN_PACKETS), - .bcnt = nftnl_chain_get_u64(c, NFTNL_CHAIN_BYTES), - }; - bool basechain = false; - uint32_t entries; - - if (nftnl_chain_get(c, NFTNL_CHAIN_HOOKNUM)) - basechain = true; - - if (strcmp(table, chain_table) != 0) - goto next; - if (chain) { - if (strcmp(chain, chain_name) != 0) - goto next; - else if (ops->print_table_header) - ops->print_table_header(table); - } - if (found) printf("\n"); - entries = nft_rule_count(h, chain_name, table); - ops->print_header(format, chain_name, policy_name[policy], - &ctrs, basechain, refs - entries, entries); - - __nft_rule_list(h, chain_name, table, - rulenum, format, ops->print_rule); + __nft_print_header(h, ops, c, format); + __nft_rule_list(h, c, rulenum, format, ops->print_rule); found = true; - - /* we printed the chain we wanted, stop processing. */ - if (chain) - break; - -next: c = nftnl_chain_list_iter_next(iter); } - nftnl_chain_list_iter_destroy(iter); -err: - if (chain && !found) - return 0; - return 1; } @@ -2396,50 +2562,44 @@ list_save(struct nftnl_rule *r, unsigned int num, unsigned int format) nft_rule_print_save(r, NFT_RULE_APPEND, format); } -static int -nftnl_rule_list_chain_save(struct nft_handle *h, const char *chain, - const char *table, struct nftnl_chain_list *list, - int counters) +static int __nftnl_rule_list_chain_save(struct nftnl_chain *c, void *data) { - struct nftnl_chain_list_iter *iter; - struct nftnl_chain *c; + const char *chain_name = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME); + uint32_t policy = nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY); + int *counters = data; - iter = nftnl_chain_list_iter_create(list); - if (iter == NULL) + if (!nft_chain_builtin(c)) { + printf("-N %s\n", chain_name); return 0; + } - c = nftnl_chain_list_iter_next(iter); - while (c != NULL) { - const char *chain_table = - nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE); - const char *chain_name = - nftnl_chain_get_str(c, NFTNL_CHAIN_NAME); - uint32_t policy = - nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY); + /* this is a base chain */ - if (strcmp(table, chain_table) != 0 || - (chain && strcmp(chain, chain_name) != 0)) - goto next; + printf("-P %s %s", chain_name, policy_name[policy]); + if (*counters) + printf(" -c %"PRIu64" %"PRIu64, + nftnl_chain_get_u64(c, NFTNL_CHAIN_PACKETS), + nftnl_chain_get_u64(c, NFTNL_CHAIN_BYTES)); + printf("\n"); + return 0; +} - /* this is a base chain */ - if (nft_chain_builtin(c)) { - printf("-P %s %s", chain_name, policy_name[policy]); - - if (counters) { - printf(" -c %"PRIu64" %"PRIu64"\n", - nftnl_chain_get_u64(c, NFTNL_CHAIN_PACKETS), - nftnl_chain_get_u64(c, NFTNL_CHAIN_BYTES)); - } else - printf("\n"); - } else { - printf("-N %s\n", chain_name); - } -next: - c = nftnl_chain_list_iter_next(iter); - } +static int +nftnl_rule_list_chain_save(struct nft_handle *h, const char *chain, + struct nftnl_chain_list *list, int counters) +{ + struct nftnl_chain *c; - nftnl_chain_list_iter_destroy(iter); + if (chain) { + c = nftnl_chain_list_lookup_byname(list, chain); + if (!c) + return 0; + + __nftnl_rule_list_chain_save(c, &counters); + return 1; + } + nftnl_chain_list_foreach(list, __nftnl_rule_list_chain_save, &counters); return 1; } @@ -2453,62 +2613,46 @@ int nft_rule_list_save(struct nft_handle *h, const char *chain, int ret = 0; /* If built-in chains don't exist for this table, create them */ - if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0) { + if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0) nft_xt_builtin_init(h, table); - /* Force table and chain creation, otherwise first iptables -L - * lists no table/chains. - */ - if (!list_empty(&h->obj_list)) { - nft_commit(h); - flush_chain_cache(h, NULL); - } - } if (!nft_is_table_compatible(h, table)) { xtables_error(OTHER_PROBLEM, "table `%s' is incompatible, use 'nft' tool.\n", table); return 0; } - list = nft_chain_list_get(h); - - /* Dump policies and custom chains first */ - if (!rulenum) - nftnl_rule_list_chain_save(h, chain, table, list, counters); - - /* Now dump out rules in this table */ - iter = nftnl_chain_list_iter_create(list); - if (iter == NULL) - goto err; + list = nft_chain_list_get(h, table); + if (!list) + return 0; + + /* Dump policies and custom chains first */ + if (!rulenum) + nftnl_rule_list_chain_save(h, chain, list, counters); if (counters < 0) format = FMT_C_COUNTS; else if (counters == 0) format = FMT_NOCOUNTS; - c = nftnl_chain_list_iter_next(iter); - while (c != NULL) { - const char *chain_table = - nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE); - const char *chain_name = - nftnl_chain_get_str(c, NFTNL_CHAIN_NAME); + if (chain) { + c = nftnl_chain_list_lookup_byname(list, chain); + if (!c) + return 0; - if (strcmp(table, chain_table) != 0) - goto next; - if (chain && strcmp(chain, chain_name) != 0) - goto next; + return __nft_rule_list(h, c, rulenum, format, list_save); + } - ret = __nft_rule_list(h, chain_name, table, rulenum, - format, list_save); + /* Now dump out rules in this table */ + iter = nftnl_chain_list_iter_create(list); + if (iter == NULL) + return 0; - /* we printed the chain we wanted, stop processing. */ - if (chain) - break; -next: + c = nftnl_chain_list_iter_next(iter); + while (c != NULL) { + ret = __nft_rule_list(h, c, rulenum, format, list_save); c = nftnl_chain_list_iter_next(iter); } - nftnl_chain_list_iter_destroy(iter); -err: return ret; } @@ -2516,17 +2660,17 @@ int nft_rule_zero_counters(struct nft_handle *h, const char *chain, const char *table, int rulenum) { struct iptables_command_state cs = {}; - struct nftnl_rule_list *list; + struct nftnl_chain *c; struct nftnl_rule *r; int ret = 0; nft_fn = nft_rule_delete; - list = nft_rule_list_get(h); - if (list == NULL) + c = nft_chain_find(h, table, chain); + if (!c) return 0; - r = nft_rule_find(h, list, chain, table, NULL, rulenum); + r = nft_rule_find(h, c, NULL, rulenum); if (r == NULL) { errno = ENOENT; ret = 1; @@ -2537,9 +2681,7 @@ int nft_rule_zero_counters(struct nft_handle *h, const char *chain, cs.counters.pcnt = cs.counters.bcnt = 0; - ret = nft_rule_append(h, chain, table, &cs, - nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE), - false); + ret = nft_rule_append(h, chain, table, &cs, r, false); error: return ret; @@ -2589,8 +2731,8 @@ static void batch_obj_del(struct nft_handle *h, struct obj_update *o) break; case NFT_COMPAT_CHAIN_ZERO: case NFT_COMPAT_CHAIN_USER_ADD: - break; case NFT_COMPAT_CHAIN_ADD: + break; case NFT_COMPAT_CHAIN_USER_DEL: case NFT_COMPAT_CHAIN_USER_FLUSH: case NFT_COMPAT_CHAIN_UPDATE: @@ -2611,6 +2753,71 @@ static void batch_obj_del(struct nft_handle *h, struct obj_update *o) free(o); } +static void nft_refresh_transaction(struct nft_handle *h) +{ + const char *tablename, *chainname; + const struct nftnl_chain *c; + struct obj_update *n, *tmp; + bool exists; + + h->error.lineno = 0; + + list_for_each_entry_safe(n, tmp, &h->obj_list, head) { + if (n->implicit) { + batch_obj_del(h, n); + continue; + } + + switch (n->type) { + case NFT_COMPAT_TABLE_FLUSH: + tablename = nftnl_table_get_str(n->table, NFTNL_TABLE_NAME); + if (!tablename) + continue; + exists = nft_table_find(h, tablename); + if (exists) + n->skip = 0; + else + n->skip = 1; + break; + case NFT_COMPAT_CHAIN_USER_ADD: + tablename = nftnl_chain_get_str(n->chain, NFTNL_CHAIN_TABLE); + if (!tablename) + continue; + + chainname = nftnl_chain_get_str(n->chain, NFTNL_CHAIN_NAME); + if (!chainname) + continue; + + if (!h->noflush) + break; + + c = nft_chain_find(h, tablename, chainname); + if (c) { + /* -restore -n flushes existing rules from redefined user-chain */ + __nft_rule_flush(h, tablename, + chainname, false, true); + n->skip = 1; + } else if (!c) { + n->skip = 0; + } + break; + case NFT_COMPAT_TABLE_ADD: + case NFT_COMPAT_CHAIN_ADD: + case NFT_COMPAT_CHAIN_ZERO: + case NFT_COMPAT_CHAIN_USER_DEL: + case NFT_COMPAT_CHAIN_USER_FLUSH: + case NFT_COMPAT_CHAIN_UPDATE: + case NFT_COMPAT_CHAIN_RENAME: + case NFT_COMPAT_RULE_APPEND: + case NFT_COMPAT_RULE_INSERT: + case NFT_COMPAT_RULE_REPLACE: + case NFT_COMPAT_RULE_DELETE: + case NFT_COMPAT_RULE_FLUSH: + break; + } + } +} + static int nft_action(struct nft_handle *h, int action) { struct obj_update *n, *tmp; @@ -2618,14 +2825,21 @@ static int nft_action(struct nft_handle *h, int action) unsigned int buflen, i, len; bool show_errors = true; char errmsg[1024]; - uint32_t seq = 1; + uint32_t seq; int ret = 0; +retry: + seq = 1; h->batch = mnl_batch_init(); - mnl_batch_begin(h->batch, seq++); + mnl_batch_begin(h->batch, h->nft_genid, seq++); + h->nft_genid++; list_for_each_entry(n, &h->obj_list, head) { + + if (n->skip) + continue; + n->seq = seq++; switch (n->type) { case NFT_COMPAT_TABLE_ADD: @@ -2702,7 +2916,20 @@ static int nft_action(struct nft_handle *h, int action) break; } + errno = 0; ret = mnl_batch_talk(h->nl, h->batch, &h->err_list); + if (ret && errno == ERESTART) { + nft_rebuild_cache(h); + + nft_refresh_transaction(h); + + i=0; + list_for_each_entry_safe(err, ne, &h->err_list, head) + mnl_err_list_free(err); + + mnl_batch_reset(h->batch); + goto retry; + } i = 0; buflen = sizeof(errmsg); @@ -2726,6 +2953,7 @@ static int nft_action(struct nft_handle *h, int action) batch_obj_del(h, n); } + nft_release_cache(h); mnl_batch_reset(h->batch); if (i) @@ -2734,8 +2962,111 @@ static int nft_action(struct nft_handle *h, int action) return ret == 0 ? 1 : 0; } +static int ebt_add_policy_rule(struct nftnl_chain *c, void *data) +{ + uint32_t policy = nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY); + struct iptables_command_state cs = { + .eb.bitmask = EBT_NOPROTO, + }; + struct nftnl_udata_buf *udata; + struct nft_handle *h = data; + struct nftnl_rule *r; + const char *pname; + + if (nftnl_chain_get(c, NFTNL_CHAIN_HOOKNUM)) + return 0; /* ignore base chains */ + + if (!nftnl_chain_is_set(c, NFTNL_CHAIN_POLICY)) + return 0; + + nftnl_chain_unset(c, NFTNL_CHAIN_POLICY); + + switch (policy) { + case NFT_RETURN: + return 0; /* return policy is default for nft chains */ + case NF_ACCEPT: + pname = "ACCEPT"; + break; + case NF_DROP: + pname = "DROP"; + break; + default: + return -1; + } + + command_jump(&cs, pname); + + r = nft_rule_new(h, nftnl_chain_get_str(c, NFTNL_CHAIN_NAME), + nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE), &cs); + if (!r) + return -1; + + udata = nftnl_udata_buf_alloc(NFT_USERDATA_MAXLEN); + if (!udata) + return -1; + + if (!nftnl_udata_put_u32(udata, UDATA_TYPE_EBTABLES_POLICY, 1)) + return -1; + + nftnl_rule_set_data(r, NFTNL_RULE_USERDATA, + nftnl_udata_buf_data(udata), + nftnl_udata_buf_len(udata)); + nftnl_udata_buf_free(udata); + + if (!batch_rule_add(h, NFT_COMPAT_RULE_APPEND, r)) { + nftnl_rule_free(r); + return -1; + } + + return 0; +} + +int ebt_set_user_chain_policy(struct nft_handle *h, const char *table, + const char *chain, const char *policy) +{ + struct nftnl_chain *c = nft_chain_find(h, table, chain); + int pval; + + if (!c) + return 0; + + if (!strcmp(policy, "DROP")) + pval = NF_DROP; + else if (!strcmp(policy, "ACCEPT")) + pval = NF_ACCEPT; + else if (!strcmp(policy, "RETURN")) + pval = NFT_RETURN; + else + return 0; + + nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, pval); + return 1; +} + +static void nft_bridge_commit_prepare(struct nft_handle *h) +{ + const struct builtin_table *t; + struct nftnl_chain_list *list; + int i; + + for (i = 0; i < NFT_TABLE_MAX; i++) { + t = &h->tables[i]; + + if (!t->name) + continue; + + list = h->cache->table[t->type].chains; + if (!list) + continue; + + nftnl_chain_list_foreach(list, ebt_add_policy_rule, h); + } +} + int nft_commit(struct nft_handle *h) { + if (h->family == NFPROTO_BRIDGE) + nft_bridge_commit_prepare(h); return nft_action(h, NFT_COMPAT_COMMIT); } @@ -2744,6 +3075,27 @@ int nft_abort(struct nft_handle *h) return nft_action(h, NFT_COMPAT_ABORT); } +int nft_abort_policy_rule(struct nft_handle *h, const char *table) +{ + struct obj_update *n, *tmp; + + list_for_each_entry_safe(n, tmp, &h->obj_list, head) { + if (n->type != NFT_COMPAT_RULE_APPEND && + n->type != NFT_COMPAT_RULE_DELETE) + continue; + + if (strcmp(table, + nftnl_rule_get_str(n->rule, NFTNL_RULE_TABLE))) + continue; + + if (!nft_rule_is_policy_rule(n->rule)) + continue; + + batch_obj_del(h, n); + } + return 0; +} + int nft_compatible_revision(const char *name, uint8_t rev, int opt) { struct mnl_socket *nl; @@ -2830,10 +3182,11 @@ const char *nft_strerror(int err) { nft_chain_user_del, EMLINK, "Can't delete chain with references left" }, { nft_chain_user_add, EEXIST, "Chain already exists" }, - { nft_rule_insert, ENOENT, "Index of insertion too big" }, + { nft_chain_user_rename, EEXIST, "File exists" }, + { nft_rule_insert, E2BIG, "Index of insertion too big" }, { nft_rule_check, ENOENT, "Bad rule (does a matching rule exist in that chain?)" }, - { nft_rule_replace, ENOENT, "Index of replacement too big" }, - { nft_rule_delete_num, ENOENT, "Index of deletion too big" }, + { nft_rule_replace, E2BIG, "Index of replacement too big" }, + { nft_rule_delete_num, E2BIG, "Index of deletion too big" }, /* { TC_READ_COUNTER, E2BIG, "Index of counter too big" }, { TC_ZERO_COUNTER, E2BIG, "Index of counter too big" }, */ /* ENOENT for DELETE probably means no matching rule */ @@ -2992,41 +3345,41 @@ int nft_xtables_config_load(struct nft_handle *h, const char *filename, return h->config_done; } -static void nft_chain_zero_rule_counters(struct nft_handle *h, - struct nftnl_chain *c) +struct chain_zero_data { + struct nft_handle *handle; + bool verbose; +}; + +static int __nft_chain_zero_counters(struct nftnl_chain *c, void *data) { - struct nftnl_rule_list_iter *iter; - struct nftnl_rule_list *list; - const char *table_name; - const char *chain_name; + struct chain_zero_data *d = data; + struct nft_handle *h = d->handle; + struct nftnl_rule_iter *iter; struct nftnl_rule *r; - list = nft_rule_list_get(h); - if (list == NULL) - return; - iter = nftnl_rule_list_iter_create(list); - if (iter == NULL) - return; + if (d->verbose) + fprintf(stdout, "Zeroing chain `%s'\n", + nftnl_chain_get_str(c, NFTNL_CHAIN_NAME)); + + if (nftnl_chain_is_set(c, NFTNL_CHAIN_HOOKNUM)) { + /* zero base chain counters. */ + nftnl_chain_set_u64(c, NFTNL_CHAIN_PACKETS, 0); + nftnl_chain_set_u64(c, NFTNL_CHAIN_BYTES, 0); + nftnl_chain_unset(c, NFTNL_CHAIN_HANDLE); + if (batch_chain_add(h, NFT_COMPAT_CHAIN_ZERO, c)) + return -1; + } - table_name = nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE); - chain_name = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME); + iter = nftnl_rule_iter_create(c); + if (iter == NULL) + return -1; - r = nftnl_rule_list_iter_next(iter); + r = nftnl_rule_iter_next(iter); while (r != NULL) { struct nftnl_expr_iter *ei; - const char *table_chain; - const char *rule_chain; struct nftnl_expr *e; bool zero_needed; - table_chain = nftnl_rule_get_str(r, NFTNL_RULE_TABLE); - if (strcmp(table_chain, table_name)) - goto next; - - rule_chain = nftnl_rule_get_str(r, NFTNL_RULE_CHAIN); - if (strcmp(rule_chain, chain_name)) - goto next; - ei = nftnl_expr_iter_create(r); if (!ei) break; @@ -3055,67 +3408,45 @@ static void nft_chain_zero_rule_counters(struct nft_handle *h, * rule based on its handle only. */ nftnl_rule_unset(r, NFTNL_RULE_POSITION); - batch_rule_add(h, NFT_COMPAT_RULE_REPLACE, r); + if (!batch_rule_add(h, NFT_COMPAT_RULE_REPLACE, r)) { + nftnl_rule_iter_destroy(iter); + return -1; + } } -next: - r = nftnl_rule_list_iter_next(iter); + r = nftnl_rule_iter_next(iter); } - nftnl_rule_list_iter_destroy(iter); + nftnl_rule_iter_destroy(iter); + return 0; } int nft_chain_zero_counters(struct nft_handle *h, const char *chain, const char *table, bool verbose) { struct nftnl_chain_list *list; - struct nftnl_chain_list_iter *iter; + struct chain_zero_data d = { + .handle = h, + .verbose = verbose, + }; struct nftnl_chain *c; int ret = 0; - list = nft_chain_list_get(h); + list = nft_chain_list_get(h, table); if (list == NULL) goto err; - iter = nftnl_chain_list_iter_create(list); - if (iter == NULL) - goto err; - - c = nftnl_chain_list_iter_next(iter); - while (c != NULL) { - const char *chain_name = - nftnl_chain_get(c, NFTNL_CHAIN_NAME); - const char *chain_table = - nftnl_chain_get(c, NFTNL_CHAIN_TABLE); - - if (strcmp(table, chain_table) != 0) - goto next; - - if (chain != NULL && strcmp(chain, chain_name) != 0) - goto next; - - if (verbose) - fprintf(stdout, "Zeroing chain `%s'\n", chain_name); - - if (nftnl_chain_is_set(c, NFTNL_CHAIN_HOOKNUM)) { - /* zero base chain counters. */ - nftnl_chain_set_u64(c, NFTNL_CHAIN_PACKETS, 0); - nftnl_chain_set_u64(c, NFTNL_CHAIN_BYTES, 0); + if (chain) { + c = nftnl_chain_list_lookup_byname(list, chain); + if (!c) { + errno = ENOENT; + return 0; } - nft_chain_zero_rule_counters(h, c); - - nftnl_chain_unset(c, NFTNL_CHAIN_HANDLE); - - ret = batch_chain_add(h, NFT_COMPAT_CHAIN_ZERO, c); - - if (chain != NULL) - break; -next: - c = nftnl_chain_list_iter_next(iter); + ret = __nft_chain_zero_counters(c, &d); + goto err; } - nftnl_chain_list_iter_destroy(iter); - + ret = nftnl_chain_list_foreach(list, __nft_chain_zero_counters, &d); err: /* the core expects 1 for success and 0 for error */ return ret == 0 ? 1 : 0; @@ -3143,7 +3474,7 @@ static const char *supported_exprs[NFT_COMPAT_EXPR_MAX] = { }; -static int nft_is_expr_compatible(const struct nftnl_expr *expr) +static int nft_is_expr_compatible(struct nftnl_expr *expr, void *data) { const char *name = nftnl_expr_get_str(expr, NFTNL_EXPR_NAME); int i; @@ -3158,143 +3489,60 @@ static int nft_is_expr_compatible(const struct nftnl_expr *expr) nftnl_expr_get_u32(expr, NFTNL_EXPR_LIMIT_FLAGS) == 0) return 0; - return 1; + return -1; } -static bool nft_is_rule_compatible(struct nftnl_rule *rule) +static int nft_is_rule_compatible(struct nftnl_rule *rule, void *data) { - struct nftnl_expr_iter *iter; - struct nftnl_expr *expr; - bool compatible = false; - - iter = nftnl_expr_iter_create(rule); - if (iter == NULL) - return false; - - expr = nftnl_expr_iter_next(iter); - while (expr != NULL) { - if (nft_is_expr_compatible(expr) == 0) { - expr = nftnl_expr_iter_next(iter); - continue; - } - - compatible = true; - break; - } - - nftnl_expr_iter_destroy(iter); - return compatible; + return nftnl_expr_foreach(rule, nft_is_expr_compatible, NULL); } -static int nft_is_chain_compatible(const struct nft_handle *h, - const struct nftnl_chain *chain) +static int nft_is_chain_compatible(struct nftnl_chain *c, void *data) { - const char *table, *name, *type, *cur_table; - struct builtin_chain *chains; - int i, j, prio; + const struct builtin_table *table; + const struct builtin_chain *chain; + const char *tname, *cname, *type; + struct nft_handle *h = data; enum nf_inet_hooks hook; + int prio; - table = nftnl_chain_get(chain, NFTNL_CHAIN_TABLE); - name = nftnl_chain_get(chain, NFTNL_CHAIN_NAME); - type = nftnl_chain_get(chain, NFTNL_CHAIN_TYPE); - prio = nftnl_chain_get_u32(chain, NFTNL_CHAIN_PRIO); - hook = nftnl_chain_get_u32(chain, NFTNL_CHAIN_HOOKNUM); - - for (i = 0; i < NFT_TABLE_MAX; i++) { - cur_table = h->tables[i].name; - chains = h->tables[i].chains; - - if (!cur_table || strcmp(table, cur_table) != 0) - continue; - - for (j = 0; j < NF_INET_NUMHOOKS && chains[j].name; j++) { - if (strcmp(name, chains[j].name) != 0) - continue; - - if (strcmp(type, chains[j].type) == 0 && - prio == chains[j].prio && - hook == chains[j].hook) - return 0; - break; - } - } - - return 1; -} + if (nftnl_rule_foreach(c, nft_is_rule_compatible, NULL)) + return -1; -static int nft_are_chains_compatible(struct nft_handle *h, const char *tablename) -{ - struct nftnl_chain_list *list; - struct nftnl_chain_list_iter *iter; - struct nftnl_chain *chain; - int ret = 0; + if (!nft_chain_builtin(c)) + return 0; - list = nft_chain_list_get(h); - if (list == NULL) + tname = nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE); + table = nft_table_builtin_find(h, tname); + if (!table) return -1; - iter = nftnl_chain_list_iter_create(list); - if (iter == NULL) + cname = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME); + chain = nft_chain_builtin_find(table, cname); + if (!chain) return -1; - chain = nftnl_chain_list_iter_next(iter); - while (chain != NULL) { - const char *chain_table; - - chain_table = nftnl_chain_get_str(chain, NFTNL_CHAIN_TABLE); - - if (strcmp(chain_table, tablename) || - !nft_chain_builtin(chain)) - goto next; - - ret = nft_is_chain_compatible(h, chain); - if (ret != 0) - break; -next: - chain = nftnl_chain_list_iter_next(iter); - } - - nftnl_chain_list_iter_destroy(iter); + type = nftnl_chain_get_str(c, NFTNL_CHAIN_TYPE); + prio = nftnl_chain_get_u32(c, NFTNL_CHAIN_PRIO); + hook = nftnl_chain_get_u32(c, NFTNL_CHAIN_HOOKNUM); + if (strcmp(type, chain->type) || + prio != chain->prio || + hook != chain->hook) + return -1; - return ret; + return 0; } bool nft_is_table_compatible(struct nft_handle *h, const char *tablename) { - struct nftnl_rule_list *list; - struct nftnl_rule_list_iter *iter; - struct nftnl_rule *rule; - int ret = 0; + struct nftnl_chain_list *clist; - if (!nft_table_builtin_find(h, tablename)) + clist = nft_chain_list_get(h, tablename); + if (clist == NULL) return false; - ret = nft_are_chains_compatible(h, tablename); - if (ret != 0) + if (nftnl_chain_list_foreach(clist, nft_is_chain_compatible, h)) return false; - list = nft_rule_list_get(h); - if (list == NULL) - return true; - - iter = nftnl_rule_list_iter_create(list); - if (iter == NULL) - return true; - - rule = nftnl_rule_list_iter_next(iter); - while (rule != NULL) { - const char *table = nftnl_rule_get_str(rule, NFTNL_RULE_TABLE); - - if (strcmp(table, tablename)) - goto next_rule; - - ret = nft_is_rule_compatible(rule); - if (ret != 0) - break; -next_rule: - rule = nftnl_rule_list_iter_next(iter); - } - - nftnl_rule_list_iter_destroy(iter); - return ret == 0; + return true; } diff --git a/iptables/nft.h b/iptables/nft.h index 9b4ba5f9a63ebb71b16bf542da9010f898d2d158..43eb8a39dd9c1d5db1cdde344b1717135dc23743 100644 --- a/iptables/nft.h +++ b/iptables/nft.h @@ -23,8 +23,16 @@ struct builtin_chain { struct builtin_table { const char *name; + enum nft_table_type type; struct builtin_chain chains[NF_INET_NUMHOOKS]; - bool initialized; +}; + +struct nft_cache { + struct nftnl_table_list *tables; + struct { + struct nftnl_chain_list *chains; + bool initialized; + } table[NFT_TABLE_MAX]; }; struct nft_handle { @@ -32,15 +40,20 @@ struct nft_handle { struct mnl_socket *nl; uint32_t portid; uint32_t seq; + uint32_t nft_genid; + uint32_t rule_id; struct list_head obj_list; int obj_list_num; struct nftnl_batch *batch; struct list_head err_list; struct nft_family_ops *ops; - struct builtin_table *tables; - struct nftnl_chain_list *chain_cache; - struct nftnl_rule_list *rule_cache; + const struct builtin_table *tables; + unsigned int cache_index; + struct nft_cache __cache[2]; + struct nft_cache *cache; + bool have_cache; bool restore; + bool noflush; int8_t config_done; /* meta data, for error reporting */ @@ -49,15 +62,16 @@ struct nft_handle { } error; }; -extern struct builtin_table xtables_ipv4[NFT_TABLE_MAX]; -extern struct builtin_table xtables_arp[NFT_TABLE_MAX]; -extern struct builtin_table xtables_bridge[NFT_TABLE_MAX]; +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); -int nft_init(struct nft_handle *h, struct builtin_table *t); +int nft_init(struct nft_handle *h, const struct builtin_table *t); void nft_fini(struct nft_handle *h); +void nft_build_cache(struct nft_handle *h); /* * Operations with tables. @@ -70,7 +84,7 @@ bool nft_table_find(struct nft_handle *h, const char *tablename); int nft_table_purge_chains(struct nft_handle *h, const char *table, struct nftnl_chain_list *list); int nft_table_flush(struct nft_handle *h, const char *table); void nft_table_new(struct nft_handle *h, const char *table); -struct builtin_table *nft_table_builtin_find(struct nft_handle *h, const char *table); +const struct builtin_table *nft_table_builtin_find(struct nft_handle *h, const char *table); /* * Operations with chains. @@ -78,16 +92,15 @@ struct builtin_table *nft_table_builtin_find(struct nft_handle *h, const char *t struct nftnl_chain; int nft_chain_set(struct nft_handle *h, const char *table, const char *chain, const char *policy, const struct xt_counters *counters); -struct nftnl_chain_list *nft_chain_list_get(struct nft_handle *h); -struct nftnl_chain *nft_chain_list_find(struct nftnl_chain_list *list, const char *table, const char *chain); -int nft_chain_save(struct nft_handle *h, struct nftnl_chain_list *list, const char *table); +struct nftnl_chain_list *nft_chain_list_get(struct nft_handle *h, + const char *table); +int nft_chain_save(struct nft_handle *h, struct nftnl_chain_list *list); int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *table); int nft_chain_user_del(struct nft_handle *h, const char *chain, const char *table, bool verbose); -int nft_chain_user_flush(struct nft_handle *h, struct nftnl_chain_list *list, - const char *chain, const char *table); +int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table); int nft_chain_user_rename(struct nft_handle *h, const char *chain, const char *table, const char *newname); int nft_chain_zero_counters(struct nft_handle *h, const char *chain, const char *table, bool verbose); -struct builtin_chain *nft_chain_builtin_find(struct builtin_table *t, const char *chain); +const struct builtin_chain *nft_chain_builtin_find(const struct builtin_table *t, const char *chain); bool nft_chain_exists(struct nft_handle *h, const char *table, const char *chain); /* @@ -95,7 +108,7 @@ bool nft_chain_exists(struct nft_handle *h, const char *table, const char *chain */ struct nftnl_rule; -int nft_rule_append(struct nft_handle *h, const char *chain, const char *table, void *data, uint64_t handle, bool verbose); +int nft_rule_append(struct nft_handle *h, const char *chain, const char *table, void *data, struct nftnl_rule *ref, bool verbose); int nft_rule_insert(struct nft_handle *h, const char *chain, const char *table, void *data, int rulenum, bool verbose); int nft_rule_check(struct nft_handle *h, const char *chain, const char *table, void *data, bool verbose); int nft_rule_delete(struct nft_handle *h, const char *chain, const char *table, void *data, bool verbose); @@ -116,7 +129,6 @@ int add_match(struct nftnl_rule *r, struct xt_entry_match *m); int add_target(struct nftnl_rule *r, struct xt_entry_target *t); int add_jumpto(struct nftnl_rule *r, const char *name, int verdict); int add_action(struct nftnl_rule *r, struct iptables_command_state *cs, bool goto_set); -int add_comment(struct nftnl_rule *r, const char *comment); char *get_comment(const void *data, uint32_t data_len); enum nft_rule_print { @@ -134,6 +146,7 @@ uint32_t nft_invflags2cmp(uint32_t invflags, uint32_t flag); */ int nft_commit(struct nft_handle *h); int nft_abort(struct nft_handle *h); +int nft_abort_policy_rule(struct nft_handle *h, const char *table); /* * revision compatibility. @@ -200,4 +213,7 @@ void nft_rule_to_arpt_entry(struct nftnl_rule *r, struct arpt_entry *fw); bool nft_is_table_compatible(struct nft_handle *h, const char *name); +int ebt_set_user_chain_policy(struct nft_handle *h, const char *table, + const char *chain, const char *policy); + #endif diff --git a/iptables/tests/shell/run-tests.sh b/iptables/tests/shell/run-tests.sh index b6eb01c6e0102d97c8c9570fdf8d0e4d063182bb..7bef09f74643d8275a92e947a9b08380e063765c 100755 --- a/iptables/tests/shell/run-tests.sh +++ b/iptables/tests/shell/run-tests.sh @@ -3,10 +3,6 @@ #configuration TESTDIR="./$(dirname $0)/" RETURNCODE_SEPARATOR="_" -XTABLES_NFT_MULTI="$(dirname $0)/../../xtables-nft-multi" -XTABLES_LEGACY_MULTI="$(dirname $0)/../../xtables-legacy-multi" - -export XTABLES_LIBDIR=${TESTDIR}/../../../extensions msg_error() { echo "E: $1 ..." >&2 @@ -29,20 +25,40 @@ if [ ! -d "$TESTDIR" ] ; then msg_error "missing testdir $TESTDIR" fi -if [ "$1" == "-v" ] ; then - VERBOSE=y - shift -fi - -for arg in "$@"; do - if grep ^.*${RETURNCODE_SEPARATOR}[0-9]\\+$ <<< $arg >/dev/null ; then - SINGLE+=" $arg" - VERBOSE=y - else - msg_error "unknown parameter '$arg'" - fi +# support matching repeated pattern in SINGLE check below +shopt -s extglob + +while [ -n "$1" ]; do + case "$1" in + -v|--verbose) + VERBOSE=y + shift + ;; + -H|--host) + HOST=y + shift + ;; + *${RETURNCODE_SEPARATOR}+([0-9])) + SINGLE+=" $1" + VERBOSE=y + shift + ;; + *) + msg_error "unknown parameter '$1'" + ;; + esac done +if [ "$HOST" != "y" ]; then + XTABLES_NFT_MULTI="$(dirname $0)/../../xtables-nft-multi" + XTABLES_LEGACY_MULTI="$(dirname $0)/../../xtables-legacy-multi" + + export XTABLES_LIBDIR=${TESTDIR}/../../../extensions +else + XTABLES_NFT_MULTI="xtables-nft-multi" + XTABLES_LEGACY_MULTI="xtables-legacy-multi" +fi + find_tests() { if [ ! -z "$SINGLE" ] ; then echo $SINGLE diff --git a/iptables/tests/shell/testcases/arptables/0001-arptables-save-restore_0 b/iptables/tests/shell/testcases/arptables/0001-arptables-save-restore_0 index 73b3b0cf88e18ffacdb88ce369ccf12dc9915738..e10f61cc8f95b045aeecd470e47ef87486e71e03 100755 --- a/iptables/tests/shell/testcases/arptables/0001-arptables-save-restore_0 +++ b/iptables/tests/shell/testcases/arptables/0001-arptables-save-restore_0 @@ -35,22 +35,22 @@ DUMP='*filter :INPUT ACCEPT :OUTPUT DROP :foo - --A INPUT -s 10.0.0.0/8 --h-length 6 --h-type 1 -j ACCEPT --A INPUT -d 192.168.123.1 --h-length 6 --h-type 1 -j ACCEPT --A INPUT --src-mac fe:ed:ba:be:00:01 --h-length 6 --h-type 1 -j ACCEPT --A INPUT --dst-mac fe:ed:ba:be:00:01 --h-length 6 --h-type 1 -j ACCEPT --A INPUT --h-length 6 --h-type 1 -j foo --A INPUT --h-length 6 --h-type 1 --A OUTPUT -o lo --h-length 6 --h-type 1 -j ACCEPT --A OUTPUT -o eth134 --h-length 6 --h-type 1 -j mangle --mangle-ip-s 10.0.0.1 --A OUTPUT -o eth432 --h-length 6 --h-type 1 -j CLASSIFY --set-class feed:babe --A OUTPUT -o eth432 --h-length 6 --opcode 1 --h-type 1 -j CLASSIFY --set-class feed:babe --A foo -i lo --h-length 6 --h-type 1 -j ACCEPT --A foo --h-length 6 --h-type 1 -j ACCEPT --A foo --h-length 6 --h-type 1 -j MARK --set-xmark 0x3039/0xffffffff --A foo --h-length 6 --opcode 1 --h-type 1 -j ACCEPT --A foo --h-length 6 --h-type 1 --proto-type 0x800 -j ACCEPT --A foo -i lo --h-length 6 --opcode 1 --h-type 1 --proto-type 0x800 -j ACCEPT +-A INPUT -j ACCEPT -s 10.0.0.0/8 +-A INPUT -j ACCEPT -d 192.168.123.1 +-A INPUT -j ACCEPT --src-mac fe:ed:ba:be:00:01 +-A INPUT -j ACCEPT --dst-mac fe:ed:ba:be:00:01 +-A INPUT -j foo +-A INPUT +-A OUTPUT -j ACCEPT -o lo +-A OUTPUT -j mangle -o eth134 --mangle-ip-s 10.0.0.1 +-A OUTPUT -j CLASSIFY -o eth432 --set-class feed:babe +-A OUTPUT -j CLASSIFY -o eth432 --opcode 1 --set-class feed:babe +-A foo -j ACCEPT -i lo +-A foo -j ACCEPT +-A foo -j MARK --set-mark 12345 +-A foo -j ACCEPT --opcode 1 +-A foo -j ACCEPT --proto-type 0x800 +-A foo -j ACCEPT -i lo --opcode 1 --proto-type 0x800 ' diff -u <(echo -e "$DUMP") <($XT_MULTI arptables-save) diff --git a/iptables/tests/shell/testcases/arptables/0002-arptables-restore-defaults_0 b/iptables/tests/shell/testcases/arptables/0002-arptables-restore-defaults_0 index ee17da0023b82068dbc5a1857b6542512ae720f4..b2ed95e87bb401d57ed1d1aeeab214a23b7c5a4f 100755 --- a/iptables/tests/shell/testcases/arptables/0002-arptables-restore-defaults_0 +++ b/iptables/tests/shell/testcases/arptables/0002-arptables-restore-defaults_0 @@ -11,7 +11,7 @@ set -e DUMP='*filter :OUTPUT ACCEPT -A OUTPUT -j mangle --mangle-ip-s 10.0.0.1 --A OUTPUT --h-length 6 --h-type 1 -j mangle --mangle-ip-d 10.0.0.2 +-A OUTPUT -j mangle --mangle-ip-d 10.0.0.2 ' # note how mangle-ip-s is unset in second rule @@ -19,8 +19,8 @@ DUMP='*filter EXPECT='*filter :INPUT ACCEPT :OUTPUT ACCEPT --A OUTPUT --h-length 6 --h-type 1 -j mangle --mangle-ip-s 10.0.0.1 --A OUTPUT --h-length 6 --h-type 1 -j mangle --mangle-ip-d 10.0.0.2 +-A OUTPUT -j mangle --mangle-ip-s 10.0.0.1 +-A OUTPUT -j mangle --mangle-ip-d 10.0.0.2 ' $XT_MULTI arptables -F diff --git a/iptables/tests/shell/testcases/arptables/0003-arptables-verbose-output_0 b/iptables/tests/shell/testcases/arptables/0003-arptables-verbose-output_0 new file mode 100755 index 0000000000000000000000000000000000000000..3a9807a1cfe0b74e677a9b1b87db9ec53dbb0fcc --- /dev/null +++ b/iptables/tests/shell/testcases/arptables/0003-arptables-verbose-output_0 @@ -0,0 +1,64 @@ +#!/bin/bash + +set -e +set -x + +# there is no legacy backend to test +[[ $XT_MULTI == */xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; } + +$XT_MULTI arptables -N foo + +# check verbose output matches expectations + +RULE1='-i eth23 -j ACCEPT' +VOUT1='-j ACCEPT -i eth23 -o *' + +RULE2='-i eth23' +VOUT2='-i eth23 -o *' + +RULE3='-i eth23 -j MARK --set-mark 42' +VOUT3='-j MARK -i eth23 -o * --set-mark 42' + +RULE4='-o eth23 -j CLASSIFY --set-class 23:42' +VOUT4='-j CLASSIFY -i * -o eth23 --set-class 23:42' + +RULE5='-o eth23 -j foo' +VOUT5='-j foo -i * -o eth23' + +RULE6='-o eth23 -j mangle --mangle-ip-s 10.0.0.1' +VOUT6='-j mangle -i * -o eth23 --mangle-ip-s 10.0.0.1' + +diff -u -Z <(echo -e "$VOUT1") <($XT_MULTI arptables -v -A INPUT $RULE1) +diff -u -Z <(echo -e "$VOUT2") <($XT_MULTI arptables -v -A INPUT $RULE2) +diff -u -Z <(echo -e "$VOUT3") <($XT_MULTI arptables -v -A INPUT $RULE3) +diff -u -Z <(echo -e "$VOUT4") <($XT_MULTI arptables -v -A OUTPUT $RULE4) +diff -u -Z <(echo -e "$VOUT5") <($XT_MULTI arptables -v -A OUTPUT $RULE5) +diff -u -Z <(echo -e "$VOUT6") <($XT_MULTI arptables -v -A foo $RULE6) + +EXPECT='Chain INPUT (policy ACCEPT 0 packets, 0 bytes) +-j ACCEPT -i eth23 -o * , pcnt=0 -- bcnt=0 +-i eth23 -o * , pcnt=0 -- bcnt=0 +-j MARK -i eth23 -o * --set-mark 42 , pcnt=0 -- bcnt=0 + +Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes) +-j CLASSIFY -i * -o eth23 --set-class 23:42 , pcnt=0 -- bcnt=0 +-j foo -i * -o eth23 , pcnt=0 -- bcnt=0 + +Chain foo (1 references) +-j mangle -i * -o eth23 --mangle-ip-s 10.0.0.1 , pcnt=0 -- bcnt=0' + +diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI arptables -v -n -L) + +EXPECT='*filter +:INPUT ACCEPT +:OUTPUT ACCEPT +:foo - +-A INPUT -j ACCEPT -i eth23 +-A INPUT -i eth23 +-A INPUT -j MARK -i eth23 --set-mark 42 +-A OUTPUT -j CLASSIFY -o eth23 --set-class 23:42 +-A OUTPUT -j foo -o eth23 +-A foo -j mangle -o eth23 --mangle-ip-s 10.0.0.1 +' + +diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI arptables-save) 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 b23c1ee18c8ae1111ee9048dc32e079563c57ef8..080ba49a4974dae6f22a555afa52e32870aae55d 100755 --- a/iptables/tests/shell/testcases/ebtables/0002-ebtables-save-restore_0 +++ b/iptables/tests/shell/testcases/ebtables/0002-ebtables-save-restore_0 @@ -50,6 +50,9 @@ $XT_MULTI ebtables -A foo --pkttype-type multicast --limit 100 -j ACCEPT $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 --to-src fe:ed:ba:be:00:01 @@ -59,6 +62,8 @@ $XT_MULTI ebtables -t nat -P OUTPUT DROP $XT_MULTI ebtables -t nat -A POSTROUTING -j ACCEPT #$XT_MULTI ebtables -t nat -A POSTROUTING --to-dst fe:ed:ba:be:00:01 --dnat-target ACCEPT +$XT_MULTI ebtables -t nat -N nat_foo -P DROP + # compare against stored ebtables dump DUMP='*filter @@ -66,6 +71,7 @@ DUMP='*filter :FORWARD DROP :OUTPUT ACCEPT :foo ACCEPT +:bar RETURN -A INPUT -p IPv4 -i lo -j ACCEPT -A FORWARD -j foo -A OUTPUT -s Broadcast -j DROP @@ -98,6 +104,7 @@ DUMP='*filter :PREROUTING ACCEPT :OUTPUT DROP :POSTROUTING ACCEPT +:nat_foo DROP -A PREROUTING -j redirect -A OUTPUT -j ACCEPT -A POSTROUTING -j ACCEPT diff --git a/iptables/tests/shell/testcases/ipt-restore/0003-restore-ordering_0 b/iptables/tests/shell/testcases/ipt-restore/0003-restore-ordering_0 new file mode 100755 index 0000000000000000000000000000000000000000..51f2422e15259c975e1bd7dc39938a4573c6c42a --- /dev/null +++ b/iptables/tests/shell/testcases/ipt-restore/0003-restore-ordering_0 @@ -0,0 +1,117 @@ +#!/bin/bash + +# Make sure iptables-restore does the right thing +# when encountering INSERT rules with index. + +set -e + +# show rules, drop uninteresting policy settings +ipt_show() { + $XT_MULTI iptables -S | grep -v '^-P' +} + +# basic issue reproducer + +$XT_MULTI iptables-restore < /dev/null && have_nft=true + +dumpfile="" +tmpfile="" + +set -e + +clean() +{ + $XT_MULTI iptables -t filter -F + $XT_MULTI iptables -t filter -X + $have_nft && nft flush ruleset +} + +clean_tempfile() +{ + [ -n "${tmpfile}" ] && rm -f "${tmpfile}" + [ -n "${dumpfile}" ] && rm -f "${dumpfile}" + clean +} + +trap clean_tempfile EXIT + +ENTRY_NUM=$((RANDOM%100)) +UCHAIN_NUM=$((RANDOM%10)) + +get_target() +{ + if [ $UCHAIN_NUM -eq 0 ]; then + echo -n "ACCEPT" + return + fi + + + x=$((RANDOM%2)) + if [ $x -eq 0 ];then + echo -n "ACCEPT" + else + printf -- "UC-%x" $((RANDOM%UCHAIN_NUM)) + fi +} + +make_dummy_rules() +{ + + echo "*filter" + echo ":INPUT ACCEPT [0:0]" + echo ":FORWARD ACCEPT [0:0]" + echo ":OUTPUT ACCEPT [0:0]" + + if [ $UCHAIN_NUM -gt 0 ]; then + for i in $(seq 0 $UCHAIN_NUM); do + printf -- ":UC-%x - [0:0]\n" $i + done + fi + + for proto in tcp udp sctp; do + for i in $(seq 0 $ENTRY_NUM); do + t=$(get_target) + printf -- "-A INPUT -i lo -p $proto --dport %d -j %s\n" $((61000-i)) $t + t=$(get_target) + printf -- "-A FORWARD -i lo -o lo -p $proto --dport %d -j %s\n" $((61000-i)) $t + t=$(get_target) + printf -- "-A OUTPUT -o lo -p $proto --dport %d -j %s\n" $((61000-i)) $t + [ $UCHAIN_NUM -gt 0 ] && printf -- "-A UC-%x -j ACCEPT\n" $((RANDOM%UCHAIN_NUM)) + done + done + echo COMMIT +} + +tmpfile=$(mktemp) || exit 1 +dumpfile=$(mktemp) || exit 1 + +make_dummy_rules > $dumpfile +$XT_MULTI iptables-restore -w < $dumpfile +LINES1=$(wc -l < $dumpfile) +$XT_MULTI iptables-save | grep -v '^#' > $dumpfile +LINES2=$(wc -l < $dumpfile) + +if [ $LINES1 -ne $LINES2 ]; then + echo "Original dump has $LINES1, not $LINES2" 1>&2 + exit 111 +fi + +case "$XT_MULTI" in +*/xtables-nft-multi) + attempts=$((RANDOM%200)) + attempts=$((attempts+1)) + ;; +*) + attempts=1 + ;; +esac + +while [ $attempts -gt 0 ]; do + attempts=$((attempts-1)) + + clean + + for i in $(seq 1 10); do + $XT_MULTI iptables-restore -w 15 < $dumpfile & + done + + for i in $(seq 1 10); do + # causes exit in case ipt-restore failed (runs with set -e) + wait %$i + done + + $XT_MULTI iptables-save | grep -v '^#' > $tmpfile + + clean + cmp $tmpfile $dumpfile +done + +exit 0 diff --git a/iptables/tests/shell/testcases/iptables/0002-verbose-output_0 b/iptables/tests/shell/testcases/iptables/0002-verbose-output_0 index 2e8059536ea7bc7f6b0dc73f2ed42cd11781ecd0..b1ef91f61f4813d2a6ffaacd7622e9508b011327 100755 --- a/iptables/tests/shell/testcases/iptables/0002-verbose-output_0 +++ b/iptables/tests/shell/testcases/iptables/0002-verbose-output_0 @@ -29,23 +29,28 @@ Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes) diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI iptables -v -n -L) +[[ -z $($XT_MULTI iptables -v -N foobar) ]] || exit 1 + diff -u -Z <(echo -e "$VOUT1") <($XT_MULTI iptables -v -D FORWARD $RULE1) diff -u -Z <(echo -e "$VOUT2") <($XT_MULTI iptables -v -D FORWARD $RULE2) EXPECT="Flushing chain \`INPUT' Flushing chain \`FORWARD' -Flushing chain \`OUTPUT'" +Flushing chain \`OUTPUT' +Flushing chain \`foobar'" diff -u <(echo -e "$EXPECT") <($XT_MULTI iptables -v -F) EXPECT="Zeroing chain \`INPUT' Zeroing chain \`FORWARD' -Zeroing chain \`OUTPUT'" +Zeroing chain \`OUTPUT' +Zeroing chain \`foobar'" diff -u <(echo -e "$EXPECT") <($XT_MULTI iptables -v -Z) diff -u <(echo "Flushing chain \`OUTPUT'") <($XT_MULTI iptables -v -F OUTPUT) diff -u <(echo "Zeroing chain \`OUTPUT'") <($XT_MULTI iptables -v -Z OUTPUT) +diff -u <(echo "Flushing chain \`foobar'") <($XT_MULTI iptables -v -F foobar) +diff -u <(echo "Zeroing chain \`foobar'") <($XT_MULTI iptables -v -Z foobar) -$XT_MULTI iptables -N foo -diff -u <(echo "Deleting chain \`foo'") <($XT_MULTI iptables -v -X foo) +diff -u <(echo "Deleting chain \`foobar'") <($XT_MULTI iptables -v -X foobar) diff --git a/iptables/tests/shell/testcases/iptables/0004-return-codes_0 b/iptables/tests/shell/testcases/iptables/0004-return-codes_0 index 5b6e1f6f1bc7a195d28db14bc37b17649e56f1d0..ce02e0bcb128ba23a500ecf91b3b1e637305a734 100755 --- a/iptables/tests/shell/testcases/iptables/0004-return-codes_0 +++ b/iptables/tests/shell/testcases/iptables/0004-return-codes_0 @@ -1,42 +1,81 @@ -#!/bin/sh +#!/bin/bash # make sure error return codes are as expected useful cases # (e.g. commands to check ruleset state) global_rc=0 -cmd() { # (rc, cmd, [args ...]) +cmd() { # (rc, msg, cmd, [args ...]) rc_exp=$1; shift - $XT_MULTI "$@" + msg_exp="" + [ $rc_exp != 0 ] && { + msg_exp="$1"; shift + } + + msg="$($XT_MULTI "$@" 2>&1 >/dev/null)" rc=$? [ $rc -eq $rc_exp ] || { - echo "---> expected $rc_exp, got $rc for command '$@'" + echo "---> expected return code $rc_exp, got $rc for command '$@'" + global_rc=1 + } + + [ -n "$msg_exp" ] || return + grep -q "$msg_exp" <<< $msg || { + echo "---> expected error message '$msg_exp', got '$msg' for command '$@'" global_rc=1 } } +EEXIST_F="File exists." +EEXIST="Chain already exists." +ENOENT="No chain/target/match by that name." +E2BIG_I="Index of insertion too big." +E2BIG_D="Index of deletion too big." +E2BIG_R="Index of replacement too big." +EBADRULE="Bad rule (does a matching rule exist in that chain?)." +ENOTGT="Couldn't load target \`foobar':No such file or directory" +ENOMTH="Couldn't load match \`foobar':No such file or directory" +ENOTBL="can't initialize iptables table \`foobar': Table does not exist" + # test chain creation cmd 0 iptables -N foo -cmd 1 iptables -N foo +cmd 1 "$EEXIST" iptables -N foo # iptables-nft allows this - bug or feature? #cmd 2 iptables -N "invalid name" +# test chain flushing/zeroing +cmd 0 iptables -F foo +cmd 0 iptables -Z foo +cmd 1 "$ENOENT" iptables -F bar +cmd 1 "$ENOENT" iptables -Z bar + # test chain rename cmd 0 iptables -E foo bar -cmd 1 iptables -E foo bar +cmd 1 "$EEXIST_F" iptables -E foo bar # test rule adding cmd 0 iptables -A INPUT -j ACCEPT -cmd 1 iptables -A noexist -j ACCEPT +cmd 1 "$ENOENT" iptables -A noexist -j ACCEPT + +# test rulenum commands +cmd 1 "$E2BIG_I" iptables -I INPUT 23 -j ACCEPT +cmd 1 "$E2BIG_D" iptables -D INPUT 23 +cmd 1 "$E2BIG_R" iptables -R INPUT 23 -j ACCEPT +cmd 1 "$ENOENT" iptables -I nonexist 23 -j ACCEPT +cmd 1 "$ENOENT" iptables -D nonexist 23 +cmd 1 "$ENOENT" iptables -R nonexist 23 -j ACCEPT # test rule checking cmd 0 iptables -C INPUT -j ACCEPT -cmd 1 iptables -C FORWARD -j ACCEPT -cmd 1 iptables -C nonexist -j ACCEPT -cmd 2 iptables -C INPUT -j foobar -cmd 2 iptables -C INPUT -m foobar -j ACCEPT -cmd 3 iptables -t foobar -C INPUT -j ACCEPT +cmd 1 "$EBADRULE" iptables -C FORWARD -j ACCEPT +cmd 1 "$BADRULE" iptables -C nonexist -j ACCEPT +cmd 2 "$ENOMTH" iptables -C INPUT -m foobar -j ACCEPT +# messages of those don't match, but iptables-nft ones are actually nicer. +#cmd 2 "$ENOTGT" iptables -C INPUT -j foobar +#cmd 3 "$ENOTBL" iptables -t foobar -C INPUT -j ACCEPT +cmd 2 "" iptables -C INPUT -j foobar +cmd 3 "" iptables -t foobar -C INPUT -j ACCEPT exit $global_rc diff --git a/iptables/tests/shell/testcases/iptables/0005-delete-rules_0 b/iptables/tests/shell/testcases/iptables/0005-delete-rules_0 new file mode 100755 index 0000000000000000000000000000000000000000..5038cbce5a5cf22e316b12289405e09eb60ac594 --- /dev/null +++ b/iptables/tests/shell/testcases/iptables/0005-delete-rules_0 @@ -0,0 +1,14 @@ +#!/bin/bash + +# test for crash when comparing rules with standard target + +$XT_MULTI iptables -A FORWARD -i eth23 -o eth42 -j DROP +$XT_MULTI iptables -D FORWARD -i eth23 -o eth42 -j REJECT +[[ $? -eq 1 ]] || exit 1 + +# test incorrect deletion of rules with deviating payload +# in non-standard target + +$XT_MULTI iptables -A FORWARD -i eth23 -o eth42 -j MARK --set-mark 23 +$XT_MULTI iptables -D FORWARD -i eth23 -o eth42 -j MARK --set-mark 42 +[[ $? -eq 1 ]] || exit 1 diff --git a/iptables/tests/shell/testcases/iptables/0005-rule-replace_0 b/iptables/tests/shell/testcases/iptables/0005-rule-replace_0 new file mode 100755 index 0000000000000000000000000000000000000000..5a3e922e50672abaa03a9284e1cce1b6725f2c40 --- /dev/null +++ b/iptables/tests/shell/testcases/iptables/0005-rule-replace_0 @@ -0,0 +1,38 @@ +#!/bin/bash + +# test rule replacement + +set -e + +# show rules, drop uninteresting policy settings +ipt_show() { + $XT_MULTI iptables -S | grep -v '^-P' +} + +$XT_MULTI iptables -A FORWARD -m comment --comment "rule 1" -j ACCEPT +$XT_MULTI iptables -A FORWARD -m comment --comment "rule 2" -j ACCEPT +$XT_MULTI iptables -A FORWARD -m comment --comment "rule 3" -j ACCEPT + +$XT_MULTI iptables -R FORWARD 2 -m comment --comment "replaced 2" -j ACCEPT + +EXPECT='-A FORWARD -m comment --comment "rule 1" -j ACCEPT +-A FORWARD -m comment --comment "replaced 2" -j ACCEPT +-A FORWARD -m comment --comment "rule 3" -j ACCEPT' + +diff -u -Z <(echo -e "$EXPECT") <(ipt_show) + +$XT_MULTI iptables -R FORWARD 1 -m comment --comment "replaced 1" -j ACCEPT + +EXPECT='-A FORWARD -m comment --comment "replaced 1" -j ACCEPT +-A FORWARD -m comment --comment "replaced 2" -j ACCEPT +-A FORWARD -m comment --comment "rule 3" -j ACCEPT' + +diff -u -Z <(echo -e "$EXPECT") <(ipt_show) + +$XT_MULTI iptables -R FORWARD 3 -m comment --comment "replaced 3" -j ACCEPT + +EXPECT='-A FORWARD -m comment --comment "replaced 1" -j ACCEPT +-A FORWARD -m comment --comment "replaced 2" -j ACCEPT +-A FORWARD -m comment --comment "replaced 3" -j ACCEPT' + +diff -u -Z <(echo -e "$EXPECT") <(ipt_show) diff --git a/iptables/xshared.c b/iptables/xshared.c index b16f5fa68e56948074ca1a42dd2d3306bd38fa31..36a2ec5f193d32a4b7ffee9db83f327330b80ba2 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -433,10 +433,24 @@ void save_argv(void) } } +struct xt_param_buf { + char buffer[1024]; + int len; +}; + +static void add_param(struct xt_param_buf *param, const char *curchar) +{ + param->buffer[param->len++] = *curchar; + if (param->len >= sizeof(param->buffer)) + xtables_error(PARAMETER_PROBLEM, + "Parameter too long!"); +} + void add_param_to_argv(char *parsestart, int line) { - int quote_open = 0, escaped = 0, param_len = 0; - char param_buffer[1024], *curchar; + int quote_open = 0, escaped = 0; + struct xt_param_buf param = {}; + char *curchar; /* After fighting with strtok enough, here's now * a 'real' parser. According to Rusty I'm now no @@ -445,7 +459,7 @@ void add_param_to_argv(char *parsestart, int line) for (curchar = parsestart; *curchar; curchar++) { if (quote_open) { if (escaped) { - param_buffer[param_len++] = *curchar; + add_param(¶m, curchar); escaped = 0; continue; } else if (*curchar == '\\') { @@ -455,7 +469,7 @@ void add_param_to_argv(char *parsestart, int line) quote_open = 0; *curchar = '"'; } else { - param_buffer[param_len++] = *curchar; + add_param(¶m, curchar); continue; } } else { @@ -471,36 +485,32 @@ void add_param_to_argv(char *parsestart, int line) case ' ': case '\t': case '\n': - if (!param_len) { + if (!param.len) { /* two spaces? */ continue; } break; default: /* regular character, copy to buffer */ - param_buffer[param_len++] = *curchar; - - if (param_len >= sizeof(param_buffer)) - xtables_error(PARAMETER_PROBLEM, - "Parameter too long!"); + add_param(¶m, curchar); continue; } - param_buffer[param_len] = '\0'; + param.buffer[param.len] = '\0'; /* check if table name specified */ - if ((param_buffer[0] == '-' && - param_buffer[1] != '-' && - strchr(param_buffer, 't')) || - (!strncmp(param_buffer, "--t", 3) && - !strncmp(param_buffer, "--table", strlen(param_buffer)))) { + if ((param.buffer[0] == '-' && + param.buffer[1] != '-' && + strchr(param.buffer, 't')) || + (!strncmp(param.buffer, "--t", 3) && + !strncmp(param.buffer, "--table", strlen(param.buffer)))) { xtables_error(PARAMETER_PROBLEM, "The -t option (seen in line %u) cannot be used in %s.\n", line, xt_params->program_name); } - add_argv(param_buffer, 0); - param_len = 0; + add_argv(param.buffer, 0); + param.len = 0; } } @@ -653,12 +663,12 @@ const char *xt_parse_target(const char *targetname) return targetname; } -void command_jump(struct iptables_command_state *cs) +void command_jump(struct iptables_command_state *cs, const char *jumpto) { struct option *opts = xt_params->opts; size_t size; - cs->jumpto = xt_parse_target(optarg); + cs->jumpto = xt_parse_target(jumpto); /* TRY_LOAD (may be chain name) */ cs->target = xtables_find_target(cs->jumpto, XTF_TRY_LOAD); diff --git a/iptables/xshared.h b/iptables/xshared.h index db499f29236ed475a552a2871a1656e4846fb894..fd1f96bad1b989a33324fc5ccaf95d312a44500c 100644 --- a/iptables/xshared.h +++ b/iptables/xshared.h @@ -176,6 +176,6 @@ void print_ifaces(const char *iniface, const char *outiface, uint8_t invflags, void command_match(struct iptables_command_state *cs); const char *xt_parse_target(const char *targetname); -void command_jump(struct iptables_command_state *cs); +void command_jump(struct iptables_command_state *cs, const char *jumpto); #endif /* IPTABLES_XSHARED_H */ diff --git a/iptables/xtables-arp.c b/iptables/xtables-arp.c index 819e7e6c940347314285fbbf0edc35b97b0d6774..d3cb9df823febbc2561831260d9779c0bcafba96 100644 --- a/iptables/xtables-arp.c +++ b/iptables/xtables-arp.c @@ -144,6 +144,7 @@ static struct option original_opts[] = { { "help", 2, 0, 'h' }, { "line-numbers", 0, 0, '0' }, { "modprobe", 1, 0, 'M' }, + { "set-counters", 1, 0, 'c' }, { 0 } }; @@ -481,11 +482,11 @@ exit_printhelp(void) " --line-numbers print line numbers when listing\n" " --exact -x expand numbers (display exact values)\n" " --modprobe= try to insert modules using this command\n" -" --set-counters PKTS BYTES set the counter during insert/append\n" +" --set-counters -c PKTS BYTES set the counter during insert/append\n" "[!] --version -V print package version.\n"); printf(" opcode strings: \n"); for (i = 0; i < NUMOPCODES; i++) - printf(" %d = %s\n", i + 1, opcodes[i]); + printf(" %d = %s\n", i + 1, arp_opcodes[i]); printf( " hardware type string: 1 = Ethernet\n" " protocol type string: 0x800 = IPv4\n"); @@ -825,7 +826,7 @@ append_entry(struct nft_handle *h, for (j = 0; j < ndaddrs; j++) { cs->arp.arp.tgt.s_addr = daddrs[j].s_addr; if (append) { - ret = nft_rule_append(h, chain, table, cs, 0, + ret = nft_rule_append(h, chain, table, cs, NULL, verbose); } else { ret = nft_rule_insert(h, chain, table, cs, @@ -909,8 +910,12 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table, { struct iptables_command_state cs = { .jumpto = "", - .arp.arp.arhln = 6, - .arp.arp.arhrd = htons(ARPHRD_ETHER), + .arp.arp = { + .arhln = 6, + .arhln_mask = 255, + .arhrd = htons(ARPHRD_ETHER), + .arhrd_mask = 65535, + }, }; int invert = 0; unsigned int nsaddrs = 0, ndaddrs = 0; @@ -1121,7 +1126,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table, int i; for (i = 0; i < NUMOPCODES; i++) - if (!strcasecmp(opcodes[i], optarg)) + if (!strcasecmp(arp_opcodes[i], optarg)) break; if (i == NUMOPCODES) xtables_error(PARAMETER_PROBLEM, "Problem with specified opcode"); @@ -1156,7 +1161,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table, case 'j': set_option(&options, OPT_JUMP, &cs.arp.arp.invflags, invert); - command_jump(&cs); + command_jump(&cs, optarg); break; case 'i': diff --git a/iptables/xtables-eb-standalone.c b/iptables/xtables-eb-standalone.c index 84ce0b60a7076e118c4184cdb8acc4bb7501a68b..fb3daba0bd604008b56f04f61952eaa7eaa4005c 100644 --- a/iptables/xtables-eb-standalone.c +++ b/iptables/xtables-eb-standalone.c @@ -54,7 +54,7 @@ int xtables_eb_main(int argc, char *argv[]) ret = nft_commit(&h); if (!ret) - fprintf(stderr, "%s\n", nft_strerror(errno)); + fprintf(stderr, "ebtables: %s\n", nft_strerror(errno)); exit(!ret); } diff --git a/iptables/xtables-eb-translate.c b/iptables/xtables-eb-translate.c index f98c385555eb1cef5352408a158df4baa2974df0..96b2730fa97edea172714b750de22c9e96b06a38 100644 --- a/iptables/xtables-eb-translate.c +++ b/iptables/xtables-eb-translate.c @@ -64,27 +64,6 @@ static int parse_rule_number(const char *rule) return rule_nr; } -static const char * -parse_target(const char *targetname) -{ - const char *ptr; - - if (strlen(targetname) < 1) - xtables_error(PARAMETER_PROBLEM, - "Invalid target name (too short)"); - - if (strlen(targetname)+1 > EBT_CHAIN_MAXNAMELEN) - xtables_error(PARAMETER_PROBLEM, - "Invalid target '%s' (%d chars max)", - targetname, EBT_CHAIN_MAXNAMELEN); - - for (ptr = targetname; *ptr; ptr++) - if (isspace(*ptr)) - xtables_error(PARAMETER_PROBLEM, - "Invalid target name `%s'", targetname); - return targetname; -} - static int get_current_chain(const char *chain) { if (strcmp(chain, "PREROUTING") == 0) @@ -411,8 +390,7 @@ print_zero: break; } else if (c == 'j') { ebt_check_option2(&flags, OPT_JUMP); - cs.jumpto = parse_target(optarg); - cs.target = ebt_command_jump(cs.jumpto); + command_jump(&cs, optarg); break; } else if (c == 's') { ebt_check_option2(&flags, OPT_SOURCE); diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c index 871891442e4318989075b6afdfa638c8b81f1a96..bc71e12226fdc91fc2c4e143002a2559c3cb5a8d 100644 --- a/iptables/xtables-eb.c +++ b/iptables/xtables-eb.c @@ -139,27 +139,6 @@ static int parse_rule_number(const char *rule) return rule_nr; } -static const char * -parse_target(const char *targetname) -{ - const char *ptr; - - if (strlen(targetname) < 1) - xtables_error(PARAMETER_PROBLEM, - "Invalid target name (too short)"); - - if (strlen(targetname)+1 > EBT_CHAIN_MAXNAMELEN) - xtables_error(PARAMETER_PROBLEM, - "Invalid target '%s' (%d chars max)", - targetname, EBT_CHAIN_MAXNAMELEN); - - for (ptr = targetname; *ptr; ptr++) - if (isspace(*ptr)) - xtables_error(PARAMETER_PROBLEM, - "Invalid target name `%s'", targetname); - return targetname; -} - static int append_entry(struct nft_handle *h, const char *chain, @@ -171,7 +150,7 @@ append_entry(struct nft_handle *h, int ret = 1; if (append) - ret = nft_rule_append(h, chain, table, cs, 0, verbose); + ret = nft_rule_append(h, chain, table, cs, NULL, verbose); else ret = nft_rule_insert(h, chain, table, cs, rule_nr, verbose); @@ -291,23 +270,12 @@ struct option ebt_original_options[] = { 0 } }; -static void __attribute__((__noreturn__,format(printf,2,3))) -ebt_print_error(enum xtables_exittype status, const char *format, ...) -{ - va_list l; - - va_start(l, format); - vfprintf(stderr, format, l); - fprintf(stderr, ".\n"); - va_end(l); - exit(-1); -} - +extern void xtables_exit_error(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3))); struct xtables_globals ebtables_globals = { .option_offset = 0, .program_version = IPTABLES_VERSION, .orig_opts = ebt_original_options, - .exit_err = ebt_print_error, + .exit_err = xtables_exit_error, .compat_rev = nft_compatible_revision, }; @@ -376,29 +344,6 @@ static struct option *merge_options(struct option *oldopts, return merge; } -/* - * More glue code. - */ -struct xtables_target *ebt_command_jump(const char *jumpto) -{ - struct xtables_target *target; - unsigned int verdict; - - /* Standard target? */ - if (!ebt_fill_target(jumpto, &verdict)) - jumpto = "standard"; - - /* For ebtables, all targets are preloaded. Hence it is either in - * xtables_targets or a custom chain to jump to, in which case - * returning NULL is fine. */ - for (target = xtables_targets; target; target = target->next) { - if (!strcmp(target->name, jumpto)) - break; - } - - return target; -} - static void print_help(const struct xtables_target *t, const struct xtables_rule_match *m, const char *table) { @@ -855,7 +800,6 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table, case 'E': /* Rename chain */ case 'X': /* Delete chain */ /* We allow -N chainname -P policy */ - /* XXX: Not in ebtables-compat */ if (command == 'N' && c == 'P') { command = c; optind--; /* No table specified */ @@ -1066,8 +1010,7 @@ print_zero: } else if (c == 'j') { ebt_check_option2(&flags, OPT_JUMP); if (strcmp(optarg, "CONTINUE") != 0) { - cs.jumpto = parse_target(optarg); - cs.target = ebt_command_jump(cs.jumpto); + command_jump(&cs, optarg); } break; } else if (c == 's') { @@ -1281,17 +1224,16 @@ print_zero: if (command == 'P') { if (selected_chain < 0) { - xtables_error(PARAMETER_PROBLEM, - "Policy %s not allowed for user defined chains", - policy); - } - if (strcmp(policy, "RETURN") == 0) { - xtables_error(PARAMETER_PROBLEM, - "Policy RETURN only allowed for user defined chains"); + ret = ebt_set_user_chain_policy(h, *table, chain, policy); + } else { + if (strcmp(policy, "RETURN") == 0) { + xtables_error(PARAMETER_PROBLEM, + "Policy RETURN only allowed for user defined chains"); + } + ret = nft_chain_set(h, *table, chain, policy, NULL); + if (ret < 0) + xtables_error(PARAMETER_PROBLEM, "Wrong policy"); } - ret = nft_chain_set(h, *table, chain, policy, NULL); - if (ret < 0) - xtables_error(PARAMETER_PROBLEM, "Wrong policy"); } else if (command == 'L') { ret = list_rules(h, chain, *table, rule_nr, 0, diff --git a/iptables/xtables-legacy-multi.c b/iptables/xtables-legacy-multi.c index e68814dd082ef780e800a3a524ad38e65ae4476e..3b7905ff76b13f6c2a893276bd87874d7434e47a 100644 --- a/iptables/xtables-legacy-multi.c +++ b/iptables/xtables-legacy-multi.c @@ -1,3 +1,4 @@ +#include #include #include #include diff --git a/iptables/xtables-legacy.8 b/iptables/xtables-legacy.8 index 5b4ab32a3ea12975e818ad8afcd446e7167f725d..6db7d2cb4357a28fb6af7b7bc980f68773798e38 100644 --- a/iptables/xtables-legacy.8 +++ b/iptables/xtables-legacy.8 @@ -67,7 +67,7 @@ iptables-legacy-save and checking for any differences in output. .B xtables\-monitor(8) will need the .B xtables\-nft(8) -versions to work, it cannot display changes made using the. +versions to work, it cannot display changes made using the .B iptables-legacy tools. diff --git a/iptables/xtables-monitor.c b/iptables/xtables-monitor.c index 3b1ca777a28a0d60fca014c759186aa31860ad9b..f835c5e503e0f32e9d8df840f69371a66f9fbd72 100644 --- a/iptables/xtables-monitor.c +++ b/iptables/xtables-monitor.c @@ -9,6 +9,7 @@ * This software has been sponsored by Sophos Astaro */ +#define _GNU_SOURCE #include #include #include @@ -403,26 +404,24 @@ static void trace_print_packet(const struct nftnl_trace *nlt, struct cb_arg *arg case IPPROTO_UDP: if (len < 4) break; - printf("SPORT=%d DPORT=%d ", ntohs(tcph->th_sport), ntohs(tcph->th_dport)); + printf("SPORT=%d DPORT=%d ", ntohs(tcph->source), ntohs(tcph->dest)); break; case IPPROTO_TCP: if (len < sizeof(*tcph)) break; - printf("SPORT=%d DPORT=%d ", ntohs(tcph->th_sport), ntohs(tcph->th_dport)); - if (tcph->th_flags & (TH_FIN|TH_SYN|TH_RST|TH_PUSH|TH_ACK|TH_URG)) { - if (tcph->th_flags & TH_SYN) - printf("SYN "); - if (tcph->th_flags & TH_ACK) - printf("ACK "); - if (tcph->th_flags & TH_FIN) - printf("FIN "); - if (tcph->th_flags & TH_RST) - printf("RST "); - if (tcph->th_flags & TH_PUSH) - printf("PSH "); - if (tcph->th_flags & TH_URG) - printf("URG "); - } + printf("SPORT=%d DPORT=%d ", ntohs(tcph->source), ntohs(tcph->dest)); + if (tcph->syn) + printf("SYN "); + if (tcph->ack) + printf("ACK "); + if (tcph->fin) + printf("FIN "); + if (tcph->rst) + printf("RST "); + if (tcph->psh) + printf("PSH "); + if (tcph->urg) + printf("URG "); break; default: break; diff --git a/iptables/xtables-restore.c b/iptables/xtables-restore.c index f52977405421522dd030b1b900cb111eeecbd142..a6a331d398687959e3e65f2742da5861d826336f 100644 --- a/iptables/xtables-restore.c +++ b/iptables/xtables-restore.c @@ -19,7 +19,7 @@ #include "nft-bridge.h" #include -static int counters, verbose, noflush; +static int counters, verbose; /* Keeping track of external matches and targets. */ static const struct option options[] = { @@ -56,43 +56,27 @@ static void print_usage(const char *name, const char *version) " [ --ipv6 ]\n", name); } -static struct nftnl_chain_list *get_chain_list(struct nft_handle *h) +static struct nftnl_chain_list *get_chain_list(struct nft_handle *h, + const char *table) { struct nftnl_chain_list *chain_list; - chain_list = nft_chain_list_get(h); + chain_list = nft_chain_list_get(h, table); if (chain_list == NULL) xtables_error(OTHER_PROBLEM, "cannot retrieve chain list\n"); return chain_list; } -static void chain_delete(struct nftnl_chain_list *clist, const char *curtable, - const char *chain) -{ - struct nftnl_chain *chain_obj; - - chain_obj = nft_chain_list_find(clist, curtable, chain); - /* This chain has been found, delete from list. Later - * on, unvisited chains will be purged out. - */ - if (chain_obj != NULL) { - nftnl_chain_list_del(chain_obj); - nftnl_chain_free(chain_obj); - } -} - struct nft_xt_restore_cb restore_cb = { .chain_list = get_chain_list, .commit = nft_commit, .abort = nft_abort, .table_new = nft_table_new, .table_flush = nft_table_flush, - .chain_user_flush = nft_chain_user_flush, - .chain_del = chain_delete, .do_command = do_commandx, .chain_set = nft_chain_set, - .chain_user_add = nft_chain_user_add, + .chain_restore = nft_chain_restore, }; static const struct xtc_ops xtc_ops = { @@ -104,17 +88,13 @@ void xtables_restore_parse(struct nft_handle *h, struct nft_xt_restore_cb *cb, int argc, char *argv[]) { + const struct builtin_table *curtable = NULL; char buffer[10240]; int in_table = 0; - struct builtin_table *curtable = NULL; const struct xtc_ops *ops = &xtc_ops; - struct nftnl_chain_list *chain_list = NULL; line = 0; - if (cb->chain_list) - chain_list = cb->chain_list(h); - /* Grab standard input. */ while (fgets(buffer, sizeof(buffer), p->in)) { int ret = 0; @@ -165,7 +145,9 @@ void xtables_restore_parse(struct nft_handle *h, if (p->tablename && (strcmp(p->tablename, table) != 0)) continue; - if (noflush == 0) { + nft_build_cache(h); + + if (h->noflush == 0) { DEBUGP("Cleaning all chains of table '%s'\n", table); if (cb->table_flush) @@ -182,7 +164,6 @@ void xtables_restore_parse(struct nft_handle *h, /* New chain. */ char *policy, *chain = NULL; struct xt_counters count = {}; - bool chain_exists = false; chain = strtok(buffer+1, " \t\n"); DEBUGP("line %u, chain '%s'\n", line, chain); @@ -193,22 +174,6 @@ void xtables_restore_parse(struct nft_handle *h, exit(1); } - if (noflush == 0) { - if (cb->chain_del) - cb->chain_del(chain_list, curtable->name, - chain); - } else if (nft_chain_list_find(chain_list, - curtable->name, chain)) { - chain_exists = true; - /* Apparently -n still flushes existing user - * defined chains that are redefined. Otherwise, - * leave them as is. - */ - if (cb->chain_user_flush) - cb->chain_user_flush(h, chain_list, - curtable->name, chain); - } - if (strlen(chain) >= XT_EXTENSION_MAXNAMELEN) xtables_error(PARAMETER_PROBLEM, "Invalid chain name `%s' " @@ -246,24 +211,22 @@ void xtables_restore_parse(struct nft_handle *h, } DEBUGP("Setting policy of chain %s to %s\n", chain, policy); - ret = 1; - - } else { - if (!chain_exists && - cb->chain_user_add && - cb->chain_user_add(h, chain, - curtable->name) < 0) { - if (errno == EEXIST) - continue; - - xtables_error(PARAMETER_PROBLEM, - "cannot create chain " - "'%s' (%s)\n", chain, - strerror(errno)); - } - continue; + } else if (cb->chain_restore(h, chain, curtable->name) < 0 && + errno != EEXIST) { + xtables_error(PARAMETER_PROBLEM, + "cannot create chain " + "'%s' (%s)\n", chain, + strerror(errno)); + } else if (h->family == NFPROTO_BRIDGE && + !ebt_set_user_chain_policy(h, curtable->name, + chain, policy)) { + xtables_error(OTHER_PROBLEM, + "Can't set policy `%s'" + " on `%s' line %u: %s\n", + policy, chain, line, + ops->strerror(errno)); } - + ret = 1; } else if (in_table) { int a; char *pcnt = NULL; @@ -359,7 +322,7 @@ void xtables_restore_parse(struct nft_handle *h, static int xtables_restore_main(int family, const char *progname, int argc, char *argv[]) { - struct builtin_table *tables; + const struct builtin_table *tables; struct nft_handle h = { .family = family, .restore = true, @@ -402,7 +365,7 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[]) IPTABLES_VERSION); exit(0); case 'n': - noflush = 1; + h.noflush = 1; break; case 'M': xtables_modprobe_program = optarg; @@ -490,16 +453,21 @@ int xtables_ip6_restore_main(int argc, char *argv[]) argc, argv); } +static int ebt_table_flush(struct nft_handle *h, const char *table) +{ + /* drop any pending policy rule add/removal jobs */ + nft_abort_policy_rule(h, table); + return nft_table_flush(h, table); +} + struct nft_xt_restore_cb ebt_restore_cb = { .chain_list = get_chain_list, .commit = nft_commit, .table_new = nft_table_new, - .table_flush = nft_table_flush, - .chain_user_flush = nft_chain_user_flush, - .chain_del = chain_delete, + .table_flush = ebt_table_flush, .do_command = do_commandeb, .chain_set = nft_chain_set, - .chain_user_add = nft_chain_user_add, + .chain_restore = nft_chain_restore, }; static const struct option ebt_restore_options[] = { @@ -512,6 +480,7 @@ int xtables_eb_restore_main(int argc, char *argv[]) struct nft_xt_restore_parse p = { .in = stdin, }; + bool noflush = false; struct nft_handle h; int c; @@ -530,6 +499,7 @@ int xtables_eb_restore_main(int argc, char *argv[]) } nft_init_eb(&h, "ebtables-restore"); + h.noflush = noflush; xtables_restore_parse(&h, &p, &ebt_restore_cb, argc, argv); nft_fini(&h); @@ -541,11 +511,9 @@ struct nft_xt_restore_cb arp_restore_cb = { .commit = nft_commit, .table_new = nft_table_new, .table_flush = nft_table_flush, - .chain_user_flush = nft_chain_user_flush, - .chain_del = chain_delete, .do_command = do_commandarp, .chain_set = nft_chain_set, - .chain_user_add = nft_chain_user_add, + .chain_restore = nft_chain_restore, }; int xtables_arp_restore_main(int argc, char *argv[]) diff --git a/iptables/xtables-save.c b/iptables/xtables-save.c index bed3ee03189957c765bea39e61cf390d742e35fd..2cc5a7c7540beebb9e9d774b043b1b28f140ac45 100644 --- a/iptables/xtables-save.c +++ b/iptables/xtables-save.c @@ -73,7 +73,9 @@ __do_output(struct nft_handle *h, const char *tablename, bool counters) return 0; } - chain_list = nft_chain_list_get(h); + chain_list = nft_chain_list_get(h, tablename); + if (!chain_list) + return 0; time_t now = time(NULL); @@ -83,7 +85,7 @@ __do_output(struct nft_handle *h, const char *tablename, bool counters) /* Dump out chain names first, * thereby preventing dependency conflicts */ - nft_chain_save(h, chain_list, tablename); + nft_chain_save(h, chain_list); nft_rule_save(h, tablename, counters ? 0 : FMT_NOCOUNTS); now = time(NULL); @@ -103,8 +105,9 @@ do_output(struct nft_handle *h, const char *tablename, bool counters) return !!ret; } - if (!nft_table_find(h, tablename)) { - printf("Table `%s' does not exist\n", tablename); + if (!nft_table_find(h, tablename) && + !nft_table_builtin_find(h, tablename)) { + fprintf(stderr, "Table `%s' does not exist\n", tablename); return 1; } @@ -120,7 +123,7 @@ do_output(struct nft_handle *h, const char *tablename, bool counters) static int xtables_save_main(int family, const char *progname, int argc, char *argv[]) { - struct builtin_table *tables; + const struct builtin_table *tables; const char *tablename = NULL; bool dump = false; struct nft_handle h = { @@ -184,7 +187,8 @@ xtables_save_main(int family, const char *progname, int argc, char *argv[]) exit(0); default: fprintf(stderr, - "Look at manual page `xtables-save.8' for more information.\n"); + "Look at manual page `%s.8' for more information.\n", + prog_name); exit(1); } } @@ -257,7 +261,7 @@ static int __ebt_save(struct nft_handle *h, const char *tablename, bool counters return 0; } - chain_list = nft_chain_list_get(h); + chain_list = nft_chain_list_get(h, tablename); if (first) { now = time(NULL); @@ -272,7 +276,7 @@ static int __ebt_save(struct nft_handle *h, const char *tablename, bool counters /* Dump out chain names first, * thereby preventing dependency conflicts */ - nft_chain_save(h, chain_list, tablename); + nft_chain_save(h, chain_list); nft_rule_save(h, tablename, format); printf("\n"); return 0; @@ -330,7 +334,8 @@ int xtables_eb_save_main(int argc_, char *argv_[]) exit(0); default: fprintf(stderr, - "Look at manual page `xtables-save.8' for more information.\n"); + "Look at manual page `%s.8' for more information.\n", + prog_name); exit(1); } } @@ -377,7 +382,8 @@ int xtables_arp_save_main(int argc, char **argv) exit(0); default: fprintf(stderr, - "Look at manual page `xtables-save.8' for more information.\n"); + "Look at manual page `%s.8' for more information.\n", + prog_name); exit(1); } } @@ -399,7 +405,7 @@ int xtables_arp_save_main(int argc, char **argv) } printf("*filter\n"); - nft_chain_save(&h, nft_chain_list_get(&h), "filter"); + nft_chain_save(&h, nft_chain_list_get(&h, "filter")); nft_rule_save(&h, "filter", show_counters ? 0 : FMT_NOCOUNTS); printf("\n"); nft_fini(&h); diff --git a/iptables/xtables-translate.8 b/iptables/xtables-translate.8 index c40f9f0297b5d691a20228097a6f2d7051765655..3dc72760e863650ee27fef69e61262c355a0cdd3 100644 --- a/iptables/xtables-translate.8 +++ b/iptables/xtables-translate.8 @@ -22,11 +22,12 @@ .\" . .\" %%%LICENSE_END .\" -.TH XTABLES-TRANSLATE 8 "Mar 16, 2018" +.TH IPTABLES-TRANSLATE 8 "May 14, 2019" .SH NAME -xtables-translate \- translation tools to migrate from iptables to nftables - +iptables-translate \(em translation tool to migrate from iptables to nftables +.P +ip6tables-translate \(em translation tool to migrate from ip6tables to nftables .SH DESCRIPTION There is a set of tools to help the system administrator translate a given ruleset from \fBiptables(8)\fP and \fBip6tables(8)\fP to \fBnftables(8)\fP. @@ -123,7 +124,7 @@ To get up-to-date information about this, please head to \fBhttps://wiki.nftables.org/\fP. .SH SEE ALSO -\fBnft(8)\fP, \fBxtables-compat(8)\fP +\fBnft(8)\fP, \fBiptables(8)\fP .SH AUTHORS The nftables framework is written by the Netfilter project diff --git a/iptables/xtables-translate.c b/iptables/xtables-translate.c index 849c53f30e1557a484b709b6243e2433e2fc370a..eb35890afa782b98315a6a7d14fb30cac46937a2 100644 --- a/iptables/xtables-translate.c +++ b/iptables/xtables-translate.c @@ -329,8 +329,8 @@ static const struct option options[] = { { NULL }, }; -static int xlate_chain_user_add(struct nft_handle *h, const char *chain, - const char *table) +static int xlate_chain_user_restore(struct nft_handle *h, const char *chain, + const char *table) { printf("add chain %s %s %s\n", family2str[h->family], table, chain); return 0; @@ -416,7 +416,7 @@ static int dummy_compat_rev(const char *name, uint8_t rev, int opt) static struct nft_xt_restore_cb cb_xlate = { .table_new = xlate_table_new, .chain_set = xlate_chain_set, - .chain_user_add = xlate_chain_user_add, + .chain_restore = xlate_chain_user_restore, .do_command = do_command_xlate, .commit = commit, .abort = commit, @@ -426,7 +426,7 @@ static int xtables_xlate_main_common(struct nft_handle *h, int family, const char *progname) { - struct builtin_table *tables; + const struct builtin_table *tables; int ret; xtables_globals.program_name = progname; diff --git a/iptables/xtables.c b/iptables/xtables.c index 24a6e234bcf4b9efdce888fab5fb6d0aefc9ea68..44986a37aaf50df9cfbcf2f9948f6c7d38326697 100644 --- a/iptables/xtables.c +++ b/iptables/xtables.c @@ -406,7 +406,7 @@ add_entry(const char *chain, if (append) { ret = nft_rule_append(h, chain, table, - cs, 0, + cs, NULL, verbose); } else { ret = nft_rule_insert(h, chain, table, @@ -426,7 +426,7 @@ add_entry(const char *chain, &d.mask.v6[j], sizeof(struct in6_addr)); if (append) { ret = nft_rule_append(h, chain, table, - cs, 0, + cs, NULL, verbose); } else { ret = nft_rule_insert(h, chain, table, @@ -820,7 +820,7 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], case 'j': set_option(&cs->options, OPT_JUMP, &cs->fw.ip.invflags, cs->invert); - command_jump(cs); + command_jump(cs, optarg); break; @@ -1064,18 +1064,11 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], p->chain); } - if (!p->xlate && !nft_chain_exists(h, p->table, p->chain)) - xtables_error(OTHER_PROBLEM, - "Chain '%s' does not exist", p->chain); - if (!p->xlate && !cs->target && strlen(cs->jumpto) > 0 && !nft_chain_exists(h, p->table, cs->jumpto)) xtables_error(PARAMETER_PROBLEM, "Chain '%s' does not exist", cs->jumpto); } - if (!p->xlate && p->command == CMD_NEW_CHAIN && - nft_chain_exists(h, p->table, p->chain)) - xtables_error(OTHER_PROBLEM, "Chain already exists"); } int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table, @@ -1189,8 +1182,10 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table, *table = p.table; xtables_rule_matches_free(&cs.matches); - if (cs.target) + if (cs.target) { free(cs.target->t); + cs.target->t = NULL; + } if (h->family == AF_INET) { free(args.s.addr.v4); diff --git a/libiptc/Makefile.am b/libiptc/Makefile.am index f789d34e00c946bb4c207d86f597524d19815678..638295dbb737087f09e6eff2b2a23599ebc3761e 100644 --- a/libiptc/Makefile.am +++ b/libiptc/Makefile.am @@ -10,6 +10,6 @@ libiptc_la_SOURCES = libiptc_la_LIBADD = libip4tc.la libip6tc.la libiptc_la_LDFLAGS = -version-info 0:0:0 ${libiptc_LDFLAGS2} libip4tc_la_SOURCES = libip4tc.c -libip4tc_la_LDFLAGS = -version-info 1:0:1 +libip4tc_la_LDFLAGS = -version-info 2:0:0 libip6tc_la_SOURCES = libip6tc.c -libip6tc_la_LDFLAGS = -version-info 1:0:1 ${libiptc_LDFLAGS2} +libip6tc_la_LDFLAGS = -version-info 2:0:0 ${libiptc_LDFLAGS2} diff --git a/libiptc/Makefile.in b/libiptc/Makefile.in index 558e2661e32c24674f68d43b8b8d8bb0756717dd..eb68a250b1f4b92718e69b504e3bb8ceba7567f1 100644 --- a/libiptc/Makefile.in +++ b/libiptc/Makefile.in @@ -380,9 +380,9 @@ libiptc_la_SOURCES = libiptc_la_LIBADD = libip4tc.la libip6tc.la libiptc_la_LDFLAGS = -version-info 0:0:0 ${libiptc_LDFLAGS2} libip4tc_la_SOURCES = libip4tc.c -libip4tc_la_LDFLAGS = -version-info 1:0:1 +libip4tc_la_LDFLAGS = -version-info 2:0:0 libip6tc_la_SOURCES = libip6tc.c -libip6tc_la_LDFLAGS = -version-info 1:0:1 ${libiptc_LDFLAGS2} +libip6tc_la_LDFLAGS = -version-info 2:0:0 ${libiptc_LDFLAGS2} all: all-am .SUFFIXES: diff --git a/libiptc/libiptc.c b/libiptc/libiptc.c index 9ecec581e119ed9e18c0264472bb1d961983b6a5..f4fb09fb509e54f71af35c1c30b3c1563766fc4d 100644 --- a/libiptc/libiptc.c +++ b/libiptc/libiptc.c @@ -2751,11 +2751,15 @@ TC_STRERROR(int err) const struct xtc_ops TC_OPS = { .commit = TC_COMMIT, + .init = TC_INIT, .free = TC_FREE, .builtin = TC_BUILTIN, .is_chain = TC_IS_CHAIN, .flush_entries = TC_FLUSH_ENTRIES, .create_chain = TC_CREATE_CHAIN, + .first_chain = TC_FIRST_CHAIN, + .next_chain = TC_NEXT_CHAIN, + .get_policy = TC_GET_POLICY, .set_policy = TC_SET_POLICY, .strerror = TC_STRERROR, }; diff --git a/libxtables/xtables.c b/libxtables/xtables.c index ea9bb102c8eb4abb3c1250481d1da8c0e6f1932d..895f6988eaf57048d54458274728a5ce9d318234 100644 --- a/libxtables/xtables.c +++ b/libxtables/xtables.c @@ -756,8 +756,24 @@ xtables_find_target(const char *name, enum xtables_tryload tryload) } for (ptr = xtables_targets; ptr; ptr = ptr->next) { - if (extension_cmp(name, ptr->name, ptr->family)) + if (extension_cmp(name, ptr->name, ptr->family)) { + struct xtables_target *clone; + + /* First target of this type: */ + if (ptr->t == NULL) + break; + + /* Second and subsequent clones */ + clone = xtables_malloc(sizeof(struct xtables_target)); + memcpy(clone, ptr, sizeof(struct xtables_target)); + clone->udata = NULL; + clone->tflags = 0; + /* This is a clone: */ + clone->next = clone; + + ptr = clone; break; + } } #ifndef NO_SHARED_LIBS diff --git a/release.sh b/release.sh deleted file mode 100644 index 7c76423ebdaf7de7e7f4237af2e936ca8f176876..0000000000000000000000000000000000000000 --- a/release.sh +++ /dev/null @@ -1,31 +0,0 @@ -#! /bin/sh -# -set -e - -VERSION=1.4.7 -PREV_VERSION=1.4.6 -TMPDIR=/tmp/ipt-release -IPTDIR="$TMPDIR/iptables-$VERSION" - -PATCH="patch-iptables-$PREV_VERSION-$VERSION.bz2"; -TARBALL="iptables-$VERSION.tar.bz2"; -CHANGELOG="changes-iptables-$PREV_VERSION-$VERSION.txt"; - -mkdir -p "$TMPDIR" -git shortlog "v$PREV_VERSION..v$VERSION" > "$TMPDIR/$CHANGELOG" -git diff "v$PREV_VERSION..v$VERSION" | bzip2 > "$TMPDIR/$PATCH" -git archive --prefix="iptables-$VERSION/" "v$VERSION" | tar -xC "$TMPDIR/" - -cd "$IPTDIR" && { - sh autogen.sh - cd .. -} - -tar -cjf "$TARBALL" "iptables-$VERSION"; -gpg -u "Netfilter Core Team" -sb "$TARBALL"; -md5sum "$TARBALL" >"$TARBALL.md5sum"; -sha1sum "$TARBALL" >"$TARBALL.sha1sum"; - -gpg -u "Netfilter Core Team" -sb "$PATCH"; -md5sum "$PATCH" >"$PATCH.md5sum"; -sha1sum "$PATCH" >"$PATCH.sha1sum"; diff --git a/utils/.gitignore b/utils/.gitignore index 7c6afbf4e6a527949be6e549a13040d36e3fe4fa..6300812b1701bae7b29e0fc3182e5703bca2bfda 100644 --- a/utils/.gitignore +++ b/utils/.gitignore @@ -1,3 +1,4 @@ /nfnl_osf /nfnl_osf.8 /nfbpf_compile +/nfbpf_compile.8 diff --git a/utils/Makefile.am b/utils/Makefile.am index 80029e303ff3b801bdb3d60cd8619be54cd98a0f..d09a69749b85fbf0ef650d345dcd6a75262d0fbd 100644 --- a/utils/Makefile.am +++ b/utils/Makefile.am @@ -17,6 +17,7 @@ nfnl_osf_LDADD = ${libnfnetlink_LIBS} endif if ENABLE_BPFC +man_MANS += nfbpf_compile.8 sbin_PROGRAMS += nfbpf_compile nfbpf_compile_LDADD = -lpcap endif @@ -26,4 +27,4 @@ sbin_PROGRAMS += nfsynproxy nfsynproxy_LDADD = -lpcap endif -CLEANFILES = nfnl_osf.8 +CLEANFILES = nfnl_osf.8 nfbpf_compile.8 diff --git a/utils/Makefile.in b/utils/Makefile.in index 25faeeb2d3865a0c5be0854109ef360e3f18fc4e..c85887313c7238bb134cc44bb096947c989fdef3 100644 --- a/utils/Makefile.in +++ b/utils/Makefile.in @@ -94,8 +94,9 @@ sbin_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) @HAVE_LIBNFNETLINK_TRUE@am__append_1 = nfnl_osf.8 @HAVE_LIBNFNETLINK_TRUE@am__append_2 = nfnl_osf @HAVE_LIBNFNETLINK_TRUE@am__append_3 = pf.os -@ENABLE_BPFC_TRUE@am__append_4 = nfbpf_compile -@ENABLE_SYNCONF_TRUE@am__append_5 = nfsynproxy +@ENABLE_BPFC_TRUE@am__append_4 = nfbpf_compile.8 +@ENABLE_BPFC_TRUE@am__append_5 = nfbpf_compile +@ENABLE_SYNCONF_TRUE@am__append_6 = nfsynproxy subdir = utils ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_linker_flags.m4 \ @@ -107,7 +108,7 @@ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h -CONFIG_CLEAN_FILES = nfnl_osf.8 +CONFIG_CLEAN_FILES = nfnl_osf.8 nfbpf_compile.8 CONFIG_CLEAN_VPATH_FILES = @HAVE_LIBNFNETLINK_TRUE@am__EXEEXT_1 = nfnl_osf$(EXEEXT) @ENABLE_BPFC_TRUE@am__EXEEXT_2 = nfbpf_compile$(EXEEXT) @@ -220,8 +221,8 @@ am__define_uniq_tagged_files = \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags -am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/nfnl_osf.8.in \ - $(top_srcdir)/build-aux/depcomp +am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/nfbpf_compile.8.in \ + $(srcdir)/nfnl_osf.8.in $(top_srcdir)/build-aux/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) pkgdatadir = @pkgdatadir@ ACLOCAL = @ACLOCAL@ @@ -379,11 +380,11 @@ AM_CPPFLAGS = ${regular_CPPFLAGS} -I${top_builddir}/include \ -I${top_srcdir}/include ${libnfnetlink_CFLAGS} pkgdata_DATA = $(am__append_3) -man_MANS = $(am__append_1) +man_MANS = $(am__append_1) $(am__append_4) @HAVE_LIBNFNETLINK_TRUE@nfnl_osf_LDADD = ${libnfnetlink_LIBS} @ENABLE_BPFC_TRUE@nfbpf_compile_LDADD = -lpcap @ENABLE_SYNCONF_TRUE@nfsynproxy_LDADD = -lpcap -CLEANFILES = nfnl_osf.8 +CLEANFILES = nfnl_osf.8 nfbpf_compile.8 all: all-am .SUFFIXES: @@ -419,6 +420,8 @@ $(ACLOCAL_M4): $(am__aclocal_m4_deps) $(am__aclocal_m4_deps): nfnl_osf.8: $(top_builddir)/config.status $(srcdir)/nfnl_osf.8.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +nfbpf_compile.8: $(top_builddir)/config.status $(srcdir)/nfbpf_compile.8.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ diff --git a/utils/nfbpf_compile.8.in b/utils/nfbpf_compile.8.in new file mode 100644 index 0000000000000000000000000000000000000000..d02979a5143ef1ff5a19b8941563eaf04de99185 --- /dev/null +++ b/utils/nfbpf_compile.8.in @@ -0,0 +1,70 @@ +.TH NFBPF_COMPILE 8 "" "@PACKAGE_STRING@" "@PACKAGE_STRING@" + +.SH NAME +nfbpf_compile \- generate bytecode for use with xt_bpf +.SH SYNOPSIS + +.ad l +.in +8 +.ti -8 +.B nfbpf_compile +[ +.I LLTYPE +] +.I PROGRAM + +.ti -8 +.I LLTYPE +:= { +.BR EN10MB " | " RAW " | " SLIP " | " +.I ... +} + +.SH DESCRIPTION +The +.B nfbpf_compile +utility aids in generating BPF byte code suitable for passing to +the iptables +.B bpf +match. + +.SH OPTIONS + +.TP +.I LLTYPE +Link-layer header type to operate on. This is a name as defined in +.RB < pcap/dlt.h > +but with the leading +.B DLT_ +prefix stripped. For use with iptables, +.B RAW +should be the right choice (it's also the default if not specified). + +.TP +.I PROGRAM +The BPF expression to compile, see +.BR pcap-filter (7) +for a description of the language. + +.SH EXIT STATUS +The program returns 0 on success, 1 otherwise. + +.SH EXAMPLE +Match incoming TCP packets with size bigger than 100 bytes: +.P +.in +8 +.EE +bpf=$(nfbpf_compile 'tcp and greater 100') +.br +iptables -A INPUT -m bpf --bytecode "$bpf" -j ACCEPT +.RE +.P +The description of +.B bpf +match in +.BR iptables-extensions (8) +lists a few more examples. + +.SH SEE ALSO +.BR iptables-extensions (8), +.BR pcap-filter (7) diff --git a/xlate-test.py b/xlate-test.py index f365a700bdf537d9ac86eb624ec5e7cf1c1a106f..4c014f9bd269a6a6052cd81da51790212ff8e3da 100755 --- a/xlate-test.py +++ b/xlate-test.py @@ -8,6 +8,7 @@ import argparse from subprocess import Popen, PIPE keywords = ("iptables-translate", "ip6tables-translate", "ebtables-translate") +xtables_nft_multi = 'xtables-nft-multi' if sys.stdout.isatty(): colors = {"magenta": "\033[95m", "green": "\033[92m", "yellow": "\033[93m", @@ -33,6 +34,7 @@ def green(string): def run_test(name, payload): + global xtables_nft_multi test_passed = True tests = passed = failed = errors = 0 result = [] @@ -40,7 +42,7 @@ def run_test(name, payload): for line in payload: if line.startswith(keywords): tests += 1 - process = Popen([ os.path.abspath(os.path.curdir) + "/iptables/xtables-nft-multi" ] + shlex.split(line), stdout=PIPE, stderr=PIPE) + process = Popen([ xtables_nft_multi ] + shlex.split(line), stdout=PIPE, stderr=PIPE) (output, error) = process.communicate() if process.returncode == 0: translation = output.decode("utf-8").rstrip(" \n") @@ -86,8 +88,12 @@ def load_test_files(): print("%d test files, %d tests, %d tests passed, %d tests failed, %d errors" % (test_files, total_tests, total_passed, total_failed, total_error)) def main(): - os.putenv("XTABLES_LIBDIR", os.path.abspath("extensions")) - os.putenv("PATH", "%s/iptables:%s" % (os.path.abspath(os.path.curdir), os.getenv("PATH"))) + global xtables_nft_multi + if not args.host: + os.putenv("XTABLES_LIBDIR", os.path.abspath("extensions")) + xtables_nft_multi = os.path.abspath(os.path.curdir) \ + + '/iptables/' + xtables_nft_multi + if args.test: if not args.test.endswith(".txlate"): args.test += ".txlate" @@ -101,6 +107,8 @@ def main(): parser = argparse.ArgumentParser() +parser.add_argument('-H', '--host', action='store_true', + help='Run tests against installed binaries') parser.add_argument("test", nargs="?", help="run only the specified test file") args = parser.parse_args() main()