aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorandroid-build-team Robot <android-build-team-robot@google.com>2021-06-19 12:01:59 +0000
committerandroid-build-team Robot <android-build-team-robot@google.com>2021-06-19 12:01:59 +0000
commitc0f3bbf7f4aaa21c37dbba7f939bd644358cceb7 (patch)
treed3b12fcc78b5ad0e8e25c7e3f068be047b461d91
parent735bd681a5ee12a17c67917603467acaf4a58f33 (diff)
parentfae46950c0c0818cac1b37a7042b86fb03a75511 (diff)
downloadiptables-android12-mainline-media-swcodec-release.tar.gz
Change-Id: I1d998418c5855999498995ff455ab0d13d3e43d4
-rw-r--r--.gitignore3
-rw-r--r--Android.bp34
-rw-r--r--METADATA4
-rw-r--r--config.h6
-rw-r--r--configure.ac9
-rw-r--r--extensions/Android.bp10
-rw-r--r--extensions/GNUmakefile.in15
-rw-r--r--extensions/generic.txlate16
-rw-r--r--extensions/libarpt_mangle.c13
-rw-r--r--extensions/libebt_among.c12
-rw-r--r--extensions/libebt_among.t2
-rw-r--r--extensions/libebt_arp.c50
-rw-r--r--extensions/libebt_stp.c60
-rw-r--r--extensions/libip6t_DNPT.man2
-rw-r--r--extensions/libip6t_REJECT.man20
-rw-r--r--extensions/libip6t_SNPT.man2
-rw-r--r--extensions/libip6t_srh.t4
-rw-r--r--extensions/libipt_CLUSTERIP.man3
-rw-r--r--extensions/libipt_ECN.man2
-rw-r--r--extensions/libipt_REJECT.man20
-rw-r--r--extensions/libipt_icmp.c5
-rw-r--r--extensions/libipt_icmp.txlate3
-rw-r--r--extensions/libxt_AUDIT.man2
-rw-r--r--extensions/libxt_CHECKSUM.man2
-rw-r--r--extensions/libxt_CT.c16
-rw-r--r--extensions/libxt_CT.man2
-rw-r--r--extensions/libxt_DSCP.man2
-rw-r--r--extensions/libxt_HMARK.man2
-rw-r--r--extensions/libxt_IDLETIMER.c113
-rw-r--r--extensions/libxt_IDLETIMER.man4
-rw-r--r--extensions/libxt_IDLETIMER.t1
-rw-r--r--extensions/libxt_MARK.man4
-rw-r--r--extensions/libxt_NOTRACK.t3
-rw-r--r--extensions/libxt_NOTRACK.txlate2
-rw-r--r--extensions/libxt_SET.man2
-rw-r--r--extensions/libxt_TCPMSS.man2
-rw-r--r--extensions/libxt_TOS.man2
-rw-r--r--extensions/libxt_bpf.man2
-rw-r--r--extensions/libxt_cluster.c2
-rw-r--r--extensions/libxt_cluster.man2
-rw-r--r--extensions/libxt_connlabel.c7
-rw-r--r--extensions/libxt_conntrack.c18
-rw-r--r--extensions/libxt_conntrack.txlate7
-rw-r--r--extensions/libxt_dccp.c58
-rw-r--r--extensions/libxt_dccp.txlate12
-rw-r--r--extensions/libxt_mac.c15
-rw-r--r--extensions/libxt_osf.c2
-rw-r--r--extensions/libxt_osf.man6
-rw-r--r--extensions/libxt_policy.man2
-rw-r--r--extensions/libxt_sctp.man1
-rw-r--r--extensions/libxt_set.man2
-rw-r--r--extensions/libxt_string.man2
-rw-r--r--extensions/libxt_time.c74
-rw-r--r--extensions/libxt_time.txlate26
-rw-r--r--include/Makefile.am5
-rw-r--r--include/linux/netfilter/xt_IDLETIMER.h15
-rw-r--r--include/linux/netfilter/xt_sctp.h6
-rw-r--r--include/xtables.h4
-rwxr-xr-xiptables-test.py18
-rw-r--r--iptables/Android.bp17
-rw-r--r--iptables/Makefile.am36
-rw-r--r--iptables/ebtables-nft.84
-rw-r--r--iptables/ip6tables-apply.81
-rw-r--r--iptables/ip6tables-standalone.c2
-rw-r--r--iptables/ip6tables.c79
-rwxr-xr-xiptables/iptables-apply302
-rw-r--r--iptables/iptables-apply.8.in46
-rw-r--r--iptables/iptables-restore.8.in2
-rw-r--r--iptables/iptables-restore.c14
-rw-r--r--iptables/iptables-save.8.in2
-rw-r--r--iptables/iptables-save.c14
-rw-r--r--iptables/iptables-standalone.c2
-rw-r--r--iptables/iptables.8.in12
-rw-r--r--iptables/iptables.c80
-rw-r--r--iptables/nft-arp.c144
-rw-r--r--iptables/nft-arp.h7
-rw-r--r--iptables/nft-bridge.c109
-rw-r--r--iptables/nft-cache.c574
-rw-r--r--iptables/nft-cache.h18
-rw-r--r--iptables/nft-chain.c59
-rw-r--r--iptables/nft-chain.h29
-rw-r--r--iptables/nft-cmd.c395
-rw-r--r--iptables/nft-cmd.h79
-rw-r--r--iptables/nft-ipv4.c16
-rw-r--r--iptables/nft-ipv6.c16
-rw-r--r--iptables/nft-shared.c62
-rw-r--r--iptables/nft-shared.h16
-rw-r--r--iptables/nft.c1212
-rw-r--r--iptables/nft.h87
-rwxr-xr-xiptables/tests/shell/run-tests.sh66
-rwxr-xr-xiptables/tests/shell/testcases/arptables/0001-arptables-save-restore_02
-rwxr-xr-xiptables/tests/shell/testcases/arptables/0002-arptables-restore-defaults_02
-rwxr-xr-xiptables/tests/shell/testcases/arptables/0003-arptables-verbose-output_02
-rwxr-xr-xiptables/tests/shell/testcases/ebtables/0001-ebtables-basic_0143
-rwxr-xr-xiptables/tests/shell/testcases/ebtables/0002-ebtables-save-restore_04
-rwxr-xr-xiptables/tests/shell/testcases/ebtables/0003-ebtables-restore-defaults_02
-rwxr-xr-xiptables/tests/shell/testcases/ebtables/0004-save-counters_02
-rwxr-xr-xiptables/tests/shell/testcases/ebtables/0005-ifnamechecks_02
-rwxr-xr-xiptables/tests/shell/testcases/firewalld-restore/0001-firewalld_017
-rwxr-xr-xiptables/tests/shell/testcases/ip6tables/0004-return-codes_038
-rwxr-xr-xiptables/tests/shell/testcases/ipt-restore/0001load-specific-table_02
-rwxr-xr-xiptables/tests/shell/testcases/ipt-restore/0004-restore-race_07
-rwxr-xr-xiptables/tests/shell/testcases/ipt-restore/0007-flush-noflush_04
-rwxr-xr-xiptables/tests/shell/testcases/ipt-restore/0010-noflush-new-chain_011
-rwxr-xr-xiptables/tests/shell/testcases/ipt-restore/0011-noflush-empty-line_016
-rwxr-xr-xiptables/tests/shell/testcases/ipt-restore/0012-dash-F_012
-rwxr-xr-xiptables/tests/shell/testcases/ipt-restore/0013-test-mode_07
-rwxr-xr-xiptables/tests/shell/testcases/ipt-restore/0014-verbose-restore_076
-rwxr-xr-xiptables/tests/shell/testcases/ipt-restore/0016-concurrent-restores_067
-rwxr-xr-xiptables/tests/shell/testcases/ipt-restore/0017-pointless-compat-checks_025
-rw-r--r--iptables/tests/shell/testcases/ipt-save/dumps/ipt-save-filter.txt4
-rwxr-xr-xiptables/tests/shell/testcases/iptables/0004-return-codes_0107
-rwxr-xr-xiptables/tests/shell/testcases/iptables/0006-46-args_088
-rwxr-xr-xiptables/tests/shell/testcases/nft-only/0001compat_015
-rwxr-xr-xiptables/tests/shell/testcases/nft-only/0002invflags_02
-rwxr-xr-xiptables/tests/shell/testcases/nft-only/0003delete-with-comment_02
-rwxr-xr-xiptables/tests/shell/testcases/nft-only/0006-policy-override_029
-rwxr-xr-xiptables/tests/shell/testcases/nft-only/0007-mid-restore-flush_023
-rwxr-xr-xiptables/tests/shell/testcases/nft-only/0008-basechain-policy_029
-rwxr-xr-xiptables/tests/shell/testcases/nft-only/0009-needless-bitwise_0346
-rw-r--r--iptables/xshared.c86
-rw-r--r--iptables/xshared.h20
-rw-r--r--iptables/xtables-arp-standalone.c1
-rw-r--r--iptables/xtables-arp.c135
-rw-r--r--iptables/xtables-eb-standalone.c2
-rw-r--r--iptables/xtables-eb-translate.c8
-rw-r--r--iptables/xtables-eb.c115
-rw-r--r--iptables/xtables-monitor.c79
-rw-r--r--iptables/xtables-restore.c148
-rw-r--r--iptables/xtables-save.c32
-rw-r--r--iptables/xtables-standalone.c19
-rw-r--r--iptables/xtables-translate.c47
-rw-r--r--iptables/xtables.c175
-rw-r--r--libipq/ipq_set_verdict.32
-rw-r--r--libiptc/Android.bp9
-rw-r--r--libiptc/libiptc.c2
-rw-r--r--libxtables/Android.bp10
-rw-r--r--libxtables/xtables.c342
-rw-r--r--utils/Makefile.am5
-rw-r--r--utils/nfnl_osf.c21
140 files changed, 4204 insertions, 2382 deletions
diff --git a/.gitignore b/.gitignore
index 4b554256..6c156da7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,3 +22,6 @@ Makefile.in
/iptables/xtables-multi
/iptables/xtables-compat-multi
+
+# vim/nano swap file
+*.swp
diff --git a/Android.bp b/Android.bp
index 3808573c..cec28515 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,3 +1,37 @@
+package {
+ default_applicable_licenses: ["external_iptables_license"],
+}
+
+// Added automatically by a large-scale-change that took the approach of
+// 'apply every license found to every target'. While this makes sure we respect
+// every license restriction, it may not be entirely correct.
+//
+// e.g. GPL in an MIT project might only apply to the contrib/ directory.
+//
+// Please consider splitting the single license below into multiple licenses,
+// taking care not to lose any license_kind information, and overriding the
+// default license using the 'licenses: [...]' property on targets as needed.
+//
+// For unused files, consider creating a 'fileGroup' with "//visibility:private"
+// to attach the license to, and including a comment whether the files may be
+// used in the current project.
+// See: http://go/android-license-faq
+license {
+ name: "external_iptables_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "SPDX-license-identifier-Artistic",
+ "SPDX-license-identifier-Artistic-2.0",
+ "SPDX-license-identifier-GPL",
+ "SPDX-license-identifier-GPL-2.0",
+ "SPDX-license-identifier-LGPL",
+ "SPDX-license-identifier-MIT",
+ ],
+ license_text: [
+ "COPYING",
+ ],
+}
+
cc_library_headers {
name: "iptables_headers",
export_include_dirs: ["include"],
diff --git a/METADATA b/METADATA
index c56e4c9c..d5267994 100644
--- a/METADATA
+++ b/METADATA
@@ -11,7 +11,7 @@ third_party {
type: GIT
value: "git://git.netfilter.org/iptables"
}
- version: "v1.8.4"
- last_upgrade_date { year: 2020 month: 4 day: 15 }
+ version: "v1.8.7"
+ last_upgrade_date { year: 2021 month: 3 day: 23 }
license_type: RESTRICTED
}
diff --git a/config.h b/config.h
index 9c304c18..f4a827d6 100644
--- a/config.h
+++ b/config.h
@@ -62,7 +62,7 @@
#define PACKAGE_NAME "iptables"
/* Define to the full name and version of this package. */
-#define PACKAGE_STRING "iptables 1.8.4"
+#define PACKAGE_STRING "iptables 1.8.7"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "iptables"
@@ -71,7 +71,7 @@
#define PACKAGE_URL ""
/* Define to the version of this package. */
-#define PACKAGE_VERSION "1.8.4"
+#define PACKAGE_VERSION "1.8.7"
/* The size of `struct ip6_hdr', as computed by sizeof. */
#define SIZEOF_STRUCT_IP6_HDR 40
@@ -80,7 +80,7 @@
#define STDC_HEADERS 1
/* Version number of package */
-#define VERSION "1.8.4"
+#define VERSION "1.8.7"
/* Location of the iptables lock file */
#define XT_LOCK_NAME "/system/etc/xtables.lock"
diff --git a/configure.ac b/configure.ac
index cab77a48..6864378a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,9 +1,9 @@
-AC_INIT([iptables], [1.8.4])
+AC_INIT([iptables], [1.8.7])
# See libtool.info "Libtool's versioning system"
-libxtables_vcurrent=14
-libxtables_vage=2
+libxtables_vcurrent=16
+libxtables_vage=4
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_HEADERS([config.h])
@@ -131,7 +131,7 @@ if test "x$enable_nftables" = "xyes"; then
exit 1
fi
- PKG_CHECK_MODULES([libnftnl], [libnftnl >= 1.1.3], [nftables=1], [nftables=0])
+ PKG_CHECK_MODULES([libnftnl], [libnftnl >= 1.1.6], [nftables=1], [nftables=0])
if test "$nftables" = 0;
then
@@ -219,6 +219,7 @@ AC_SUBST([libxtables_vmajor])
AC_DEFINE_UNQUOTED([XT_LOCK_NAME], "${xt_lock_name}",
[Location of the iptables lock file])
+AC_SUBST([XT_LOCK_NAME], "${xt_lock_name}")
AC_CONFIG_FILES([Makefile extensions/GNUmakefile include/Makefile
iptables/Makefile iptables/xtables.pc
diff --git a/extensions/Android.bp b/extensions/Android.bp
index 6296db98..8a6b6e99 100644
--- a/extensions/Android.bp
+++ b/extensions/Android.bp
@@ -1,3 +1,13 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "external_iptables_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-GPL
+ // SPDX-license-identifier-GPL-2.0
+ default_applicable_licenses: ["external_iptables_license"],
+}
+
cc_defaults {
name: "libext_defaults",
defaults: ["iptables_defaults"],
diff --git a/extensions/GNUmakefile.in b/extensions/GNUmakefile.in
index 0842a553..956ccb38 100644
--- a/extensions/GNUmakefile.in
+++ b/extensions/GNUmakefile.in
@@ -79,7 +79,7 @@ targets_install :=
.SECONDARY:
-.PHONY: all install clean distclean FORCE
+.PHONY: all install uninstall clean distclean FORCE
all: ${targets}
@@ -92,6 +92,19 @@ install: ${targets_install} ${symlinks_install}
cp -P ${symlinks_install} "${DESTDIR}${xtlibdir}/"; \
fi;
+uninstall:
+ dir=${DESTDIR}${xtlibdir}; { \
+ test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; \
+ } || { \
+ test -z "${targets_install}" || ( \
+ cd "$$dir" && rm -f ${targets_install} \
+ ); \
+ test -z "${symlinks_install}" || ( \
+ cd "$$dir" && rm -f ${symlinks_install} \
+ ); \
+ rmdir -p --ignore-fail-on-non-empty "$$dir"; \
+ }
+
clean:
rm -f *.o *.oo *.so *.a {matches,targets}.man initext.c initext4.c initext6.c initextb.c initexta.c;
rm -f .*.d .*.dd;
diff --git a/extensions/generic.txlate b/extensions/generic.txlate
index b38fbd1f..0e256c37 100644
--- a/extensions/generic.txlate
+++ b/extensions/generic.txlate
@@ -18,3 +18,19 @@ nft add rule bridge filter FORWARD iifname != "iname" meta ibrname "ilogname" oi
ebtables-translate -I INPUT -p ip -d 1:2:3:4:5:6/ff:ff:ff:ff:00:00
nft insert rule bridge filter INPUT ether type 0x800 ether daddr 01:02:03:04:00:00 and ff:ff:ff:ff:00:00 == 01:02:03:04:00:00 counter
+
+# asterisk is not special in iptables and it is even a valid interface name
+iptables-translate -A FORWARD -i '*' -o 'eth*foo'
+nft add rule ip filter FORWARD iifname "\*" oifname "eth\*foo" counter
+
+# escape all asterisks but translate only the first plus character
+iptables-translate -A FORWARD -i 'eth*foo*+' -o 'eth++'
+nft add rule ip filter FORWARD iifname "eth\*foo\**" oifname "eth+*" counter
+
+# skip for always matching interface names
+iptables-translate -A FORWARD -i '+'
+nft add rule ip filter FORWARD counter
+
+# match against invalid interface name to simulate never matching rule
+iptables-translate -A FORWARD ! -i '+'
+nft add rule ip filter FORWARD iifname "INVAL/D" counter
diff --git a/extensions/libarpt_mangle.c b/extensions/libarpt_mangle.c
index 2fea6185..a2378a8b 100644
--- a/extensions/libarpt_mangle.c
+++ b/extensions/libarpt_mangle.c
@@ -130,15 +130,6 @@ static void arpmangle_final_check(unsigned int flags)
{
}
-static void print_mac(const unsigned char *mac, int l)
-{
- int j;
-
- for (j = 0; j < l; j++)
- printf("%02x%s", mac[j],
- (j==l-1) ? "" : ":");
-}
-
static const char *ipaddr_to(const struct in_addr *addrp, int numeric)
{
if (numeric)
@@ -159,7 +150,7 @@ arpmangle_print(const void *ip, const struct xt_entry_target *target,
}
if (m->flags & ARPT_MANGLE_SDEV) {
printf(" --mangle-mac-s ");
- print_mac((unsigned char *)m->src_devaddr, 6);
+ xtables_print_mac((unsigned char *)m->src_devaddr);
}
if (m->flags & ARPT_MANGLE_TIP) {
printf(" --mangle-ip-d %s",
@@ -167,7 +158,7 @@ arpmangle_print(const void *ip, const struct xt_entry_target *target,
}
if (m->flags & ARPT_MANGLE_TDEV) {
printf(" --mangle-mac-d ");
- print_mac((unsigned char *)m->tgt_devaddr, 6);
+ xtables_print_mac((unsigned char *)m->tgt_devaddr);
}
if (m->target != NF_ACCEPT) {
printf(" --mangle-target %s",
diff --git a/extensions/libebt_among.c b/extensions/libebt_among.c
index 2e87db3b..2b9a1b65 100644
--- a/extensions/libebt_among.c
+++ b/extensions/libebt_among.c
@@ -6,6 +6,7 @@
* August, 2003
*/
+#include <errno.h>
#include <ctype.h>
#include <fcntl.h>
#include <getopt.h>
@@ -62,10 +63,6 @@ parse_nft_among_pair(char *buf, struct nft_among_pair *pair, bool have_ip)
char *sep = index(buf, '=');
struct ether_addr *ether;
- if (have_ip ^ !!sep)
- xtables_error(PARAMETER_PROBLEM,
- "among: Mixed MAC and MAC=IP not allowed.");
-
if (sep) {
*sep = '\0';
@@ -137,7 +134,10 @@ static int bramong_parse(int c, char **argv, int invert,
if ((fd = open(optarg, O_RDONLY)) == -1)
xtables_error(PARAMETER_PROBLEM,
"Couldn't open file '%s'", optarg);
- fstat(fd, &stats);
+ if (fstat(fd, &stats) < 0)
+ xtables_error(PARAMETER_PROBLEM,
+ "fstat(%s) failed: '%s'",
+ optarg, strerror(errno));
flen = stats.st_size;
/* use mmap because the file will probably be big */
optarg = mmap(0, flen, PROT_READ | PROT_WRITE,
@@ -201,7 +201,7 @@ static void __bramong_print(struct nft_among_pair *pairs,
isep = ",";
printf("%s", ether_ntoa(&pairs[i].ether));
- if (have_ip)
+ if (pairs[i].in.s_addr != INADDR_ANY)
printf("=%s", inet_ntoa(pairs[i].in));
}
printf(" ");
diff --git a/extensions/libebt_among.t b/extensions/libebt_among.t
index 56b29916..a02206f3 100644
--- a/extensions/libebt_among.t
+++ b/extensions/libebt_among.t
@@ -13,4 +13,4 @@
--among-src;=;FAIL
--among-src 00:11=10.0.0.1;=;FAIL
--among-src de:ad:0:be:ee:ff=10.256.0.1;=;FAIL
---among-src de:ad:0:be:ee:ff,c0:ff:ee:0:ba:be=192.168.1.1;=;FAIL
+--among-src c0:ff:ee:0:ba:be=192.168.1.1,de:ad:0:be:ee:ff;=;OK
diff --git a/extensions/libebt_arp.c b/extensions/libebt_arp.c
index a062b7e7..d5035b95 100644
--- a/extensions/libebt_arp.c
+++ b/extensions/libebt_arp.c
@@ -161,54 +161,6 @@ static void ebt_parse_ip_address(char *address, uint32_t *addr, uint32_t *msk)
*addr = *addr & *msk;
}
-static int brarp_get_mac_and_mask(const char *from, unsigned char *to, unsigned char *mask)
-{
- char *p;
- int i;
- struct ether_addr *addr = NULL;
-
- static const unsigned char mac_type_unicast[ETH_ALEN];
- static const unsigned char msk_type_unicast[ETH_ALEN] = {1,0,0,0,0,0};
- static const unsigned char mac_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
- static const unsigned char mac_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
- static const unsigned char mac_type_bridge_group[ETH_ALEN] = {0x01,0x80,0xc2,0,0,0};
- static const unsigned char msk_type_bridge_group[ETH_ALEN] = {255,255,255,255,255,255};
-
- if (strcasecmp(from, "Unicast") == 0) {
- memcpy(to, mac_type_unicast, ETH_ALEN);
- memcpy(mask, msk_type_unicast, ETH_ALEN);
- return 0;
- }
- if (strcasecmp(from, "Multicast") == 0) {
- memcpy(to, mac_type_multicast, ETH_ALEN);
- memcpy(mask, mac_type_multicast, ETH_ALEN);
- return 0;
- }
- if (strcasecmp(from, "Broadcast") == 0) {
- memcpy(to, mac_type_broadcast, ETH_ALEN);
- memcpy(mask, mac_type_broadcast, ETH_ALEN);
- return 0;
- }
- if (strcasecmp(from, "BGA") == 0) {
- memcpy(to, mac_type_bridge_group, ETH_ALEN);
- memcpy(mask, msk_type_bridge_group, ETH_ALEN);
- return 0;
- }
- if ( (p = strrchr(from, '/')) != NULL) {
- *p = '\0';
- if (!(addr = ether_aton(p + 1)))
- return -1;
- memcpy(mask, addr, ETH_ALEN);
- } else
- memset(mask, 0xff, ETH_ALEN);
- if (!(addr = ether_aton(from)))
- return -1;
- memcpy(to, addr, ETH_ALEN);
- for (i = 0; i < ETH_ALEN; i++)
- to[i] &= mask[i];
- return 0;
-}
-
static int
brarp_parse(int c, char **argv, int invert, unsigned int *flags,
const void *entry, struct xt_entry_match **match)
@@ -317,7 +269,7 @@ brarp_parse(int c, char **argv, int invert, unsigned int *flags,
else
arpinfo->invflags |= EBT_ARP_DST_MAC;
}
- if (brarp_get_mac_and_mask(optarg, maddr, mmask))
+ if (xtables_parse_mac_and_mask(optarg, maddr, mmask))
xtables_error(PARAMETER_PROBLEM, "Problem with ARP MAC address argument");
break;
case ARP_GRAT:
diff --git a/extensions/libebt_stp.c b/extensions/libebt_stp.c
index 06cf93b8..81ba572c 100644
--- a/extensions/libebt_stp.c
+++ b/extensions/libebt_stp.c
@@ -150,54 +150,6 @@ static void print_range(unsigned int l, unsigned int u)
printf("%u:%u ", l, u);
}
-static int brstp_get_mac_and_mask(const char *from, unsigned char *to, unsigned char *mask)
-{
- char *p;
- int i;
- struct ether_addr *addr = NULL;
-
- static const unsigned char mac_type_unicast[ETH_ALEN];
- static const unsigned char msk_type_unicast[ETH_ALEN] = {1,0,0,0,0,0};
- static const unsigned char mac_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
- static const unsigned char mac_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
- static const unsigned char mac_type_bridge_group[ETH_ALEN] = {0x01,0x80,0xc2,0,0,0};
- static const unsigned char msk_type_bridge_group[ETH_ALEN] = {255,255,255,255,255,255};
-
- if (strcasecmp(from, "Unicast") == 0) {
- memcpy(to, mac_type_unicast, ETH_ALEN);
- memcpy(mask, msk_type_unicast, ETH_ALEN);
- return 0;
- }
- if (strcasecmp(from, "Multicast") == 0) {
- memcpy(to, mac_type_multicast, ETH_ALEN);
- memcpy(mask, mac_type_multicast, ETH_ALEN);
- return 0;
- }
- if (strcasecmp(from, "Broadcast") == 0) {
- memcpy(to, mac_type_broadcast, ETH_ALEN);
- memcpy(mask, mac_type_broadcast, ETH_ALEN);
- return 0;
- }
- if (strcasecmp(from, "BGA") == 0) {
- memcpy(to, mac_type_bridge_group, ETH_ALEN);
- memcpy(mask, msk_type_bridge_group, ETH_ALEN);
- return 0;
- }
- if ( (p = strrchr(from, '/')) != NULL) {
- *p = '\0';
- if (!(addr = ether_aton(p + 1)))
- return -1;
- memcpy(mask, addr, ETH_ALEN);
- } else
- memset(mask, 0xff, ETH_ALEN);
- if (!(addr = ether_aton(from)))
- return -1;
- memcpy(to, addr, ETH_ALEN);
- for (i = 0; i < ETH_ALEN; i++)
- to[i] &= mask[i];
- return 0;
-}
-
static int
brstp_parse(int c, char **argv, int invert, unsigned int *flags,
const void *entry, struct xt_entry_match **match)
@@ -280,15 +232,15 @@ brstp_parse(int c, char **argv, int invert, unsigned int *flags,
xtables_error(PARAMETER_PROBLEM, "Bad --stp-forward-delay range");
break;
case EBT_STP_ROOTADDR:
- if (brstp_get_mac_and_mask(argv[optind-1],
- (unsigned char *)stpinfo->config.root_addr,
- (unsigned char *)stpinfo->config.root_addrmsk))
+ if (xtables_parse_mac_and_mask(argv[optind-1],
+ stpinfo->config.root_addr,
+ stpinfo->config.root_addrmsk))
xtables_error(PARAMETER_PROBLEM, "Bad --stp-root-addr address");
break;
case EBT_STP_SENDERADDR:
- if (brstp_get_mac_and_mask(argv[optind-1],
- (unsigned char *)stpinfo->config.sender_addr,
- (unsigned char *)stpinfo->config.sender_addrmsk))
+ if (xtables_parse_mac_and_mask(argv[optind-1],
+ stpinfo->config.sender_addr,
+ stpinfo->config.sender_addrmsk))
xtables_error(PARAMETER_PROBLEM, "Bad --stp-sender-addr address");
break;
default:
diff --git a/extensions/libip6t_DNPT.man b/extensions/libip6t_DNPT.man
index 61beeee8..9b060f5b 100644
--- a/extensions/libip6t_DNPT.man
+++ b/extensions/libip6t_DNPT.man
@@ -23,7 +23,7 @@ ip6tables \-t mangle \-I PREROUTING \-i wlan0 \-d 2001:e20:2000:40f::/64
.PP
You may need to enable IPv6 neighbor proxy:
.IP
-sysctl -w net.ipv6.conf.all.proxy_ndp=1
+sysctl \-w net.ipv6.conf.all.proxy_ndp=1
.PP
You also have to use the
.B NOTRACK
diff --git a/extensions/libip6t_REJECT.man b/extensions/libip6t_REJECT.man
index 0030a51f..3c42768e 100644
--- a/extensions/libip6t_REJECT.man
+++ b/extensions/libip6t_REJECT.man
@@ -30,3 +30,23 @@ TCP RST packet to be sent back. This is mainly useful for blocking
hosts (which won't accept your mail otherwise).
\fBtcp\-reset\fP
can only be used with kernel versions 2.6.14 or later.
+.PP
+\fIWarning:\fP You should not indiscriminately apply the REJECT target to
+packets whose connection state is classified as INVALID; instead, you should
+only DROP these.
+.PP
+Consider a source host transmitting a packet P, with P experiencing so much
+delay along its path that the source host issues a retransmission, P_2, with
+P_2 being successful in reaching its destination and advancing the connection
+state normally. It is conceivable that the late-arriving P may be considered
+not to be associated with any connection tracking entry. Generating a reject
+response for a packet so classed would then terminate the healthy connection.
+.PP
+So, instead of:
+.PP
+-A INPUT ... -j REJECT
+.PP
+do consider using:
+.PP
+-A INPUT ... -m conntrack --ctstate INVALID -j DROP
+-A INPUT ... -j REJECT
diff --git a/extensions/libip6t_SNPT.man b/extensions/libip6t_SNPT.man
index 78d644a7..97e0071b 100644
--- a/extensions/libip6t_SNPT.man
+++ b/extensions/libip6t_SNPT.man
@@ -23,7 +23,7 @@ ip6tables \-t mangle \-I PREROUTING \-i wlan0 \-d 2001:e20:2000:40f::/64
.PP
You may need to enable IPv6 neighbor proxy:
.IP
-sysctl -w net.ipv6.conf.all.proxy_ndp=1
+sysctl \-w net.ipv6.conf.all.proxy_ndp=1
.PP
You also have to use the
.B NOTRACK
diff --git a/extensions/libip6t_srh.t b/extensions/libip6t_srh.t
index 07b54031..5b02a71b 100644
--- a/extensions/libip6t_srh.t
+++ b/extensions/libip6t_srh.t
@@ -23,6 +23,6 @@
-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 --srh-psid a::/64 --srh-nsid b::/128 --srh-lsid c::/0;=;OK
+-m srh ! --srh-psid a::/64 ! --srh-nsid b::/128 ! --srh-lsid c::/0;=;OK
-m srh;=;OK
diff --git a/extensions/libipt_CLUSTERIP.man b/extensions/libipt_CLUSTERIP.man
index 8ec6d6b6..768bb23e 100644
--- a/extensions/libipt_CLUSTERIP.man
+++ b/extensions/libipt_CLUSTERIP.man
@@ -2,6 +2,9 @@ This module allows you to configure a simple cluster of nodes that share
a certain IP and MAC address without an explicit load balancer in front of
them. Connections are statically distributed between the nodes in this
cluster.
+.PP
+Please note that CLUSTERIP target is considered deprecated in favour of cluster
+match which is more flexible and not limited to IPv4.
.TP
\fB\-\-new\fP
Create a new ClusterIP. You always have to set this on the first rule
diff --git a/extensions/libipt_ECN.man b/extensions/libipt_ECN.man
index a9cbe109..8ae7996e 100644
--- a/extensions/libipt_ECN.man
+++ b/extensions/libipt_ECN.man
@@ -1,4 +1,4 @@
-This target allows to selectively work around known ECN blackholes.
+This target selectively works around known ECN blackholes.
It can only be used in the mangle table.
.TP
\fB\-\-ecn\-tcp\-remove\fP
diff --git a/extensions/libipt_REJECT.man b/extensions/libipt_REJECT.man
index 8a360ce7..cc47aead 100644
--- a/extensions/libipt_REJECT.man
+++ b/extensions/libipt_REJECT.man
@@ -30,3 +30,23 @@ TCP RST packet to be sent back. This is mainly useful for blocking
hosts (which won't accept your mail otherwise).
.IP
(*) Using icmp\-admin\-prohibited with kernels that do not support it will result in a plain DROP instead of REJECT
+.PP
+\fIWarning:\fP You should not indiscriminately apply the REJECT target to
+packets whose connection state is classified as INVALID; instead, you should
+only DROP these.
+.PP
+Consider a source host transmitting a packet P, with P experiencing so much
+delay along its path that the source host issues a retransmission, P_2, with
+P_2 being successful in reaching its destination and advancing the connection
+state normally. It is conceivable that the late-arriving P may be considered
+not to be associated with any connection tracking entry. Generating a reject
+response for a packet so classed would then terminate the healthy connection.
+.PP
+So, instead of:
+.PP
+-A INPUT ... -j REJECT
+.PP
+do consider using:
+.PP
+-A INPUT ... -m conntrack --ctstate INVALID -j DROP
+-A INPUT ... -j REJECT
diff --git a/extensions/libipt_icmp.c b/extensions/libipt_icmp.c
index e76257c5..e5e23661 100644
--- a/extensions/libipt_icmp.c
+++ b/extensions/libipt_icmp.c
@@ -256,6 +256,11 @@ static int icmp_xlate(struct xt_xlate *xl,
if (!type_xlate_print(xl, info->type, info->code[0],
info->code[1]))
return 0;
+ } else {
+ /* '-m icmp --icmp-type any' is a noop by itself,
+ * but it eats a (mandatory) previous '-p icmp' so
+ * emit it here */
+ xt_xlate_add(xl, "ip protocol icmp");
}
return 1;
}
diff --git a/extensions/libipt_icmp.txlate b/extensions/libipt_icmp.txlate
index 434f8cc4..a2aec8e2 100644
--- a/extensions/libipt_icmp.txlate
+++ b/extensions/libipt_icmp.txlate
@@ -6,3 +6,6 @@ nft add rule ip filter INPUT icmp type destination-unreachable counter accept
iptables-translate -t filter -A INPUT -m icmp ! --icmp-type 3 -j ACCEPT
nft add rule ip filter INPUT icmp type != destination-unreachable counter accept
+
+iptables-translate -t filter -A INPUT -m icmp --icmp-type any -j ACCEPT
+nft add rule ip filter INPUT ip protocol icmp counter accept
diff --git a/extensions/libxt_AUDIT.man b/extensions/libxt_AUDIT.man
index 4f5562e8..8c513d22 100644
--- a/extensions/libxt_AUDIT.man
+++ b/extensions/libxt_AUDIT.man
@@ -1,4 +1,4 @@
-This target allows to create audit records for packets hitting the target.
+This target creates audit records for packets hitting the target.
It can be used to record accepted, dropped, and rejected packets. See
auditd(8) for additional details.
.TP
diff --git a/extensions/libxt_CHECKSUM.man b/extensions/libxt_CHECKSUM.man
index 92ae700f..726f4ea6 100644
--- a/extensions/libxt_CHECKSUM.man
+++ b/extensions/libxt_CHECKSUM.man
@@ -1,4 +1,4 @@
-This target allows to selectively work around broken/old applications.
+This target selectively works around broken/old applications.
It can only be used in the mangle table.
.TP
\fB\-\-checksum\-fill\fP
diff --git a/extensions/libxt_CT.c b/extensions/libxt_CT.c
index 371b2176..fbbbe266 100644
--- a/extensions/libxt_CT.c
+++ b/extensions/libxt_CT.c
@@ -348,6 +348,20 @@ static void notrack_ct2_tg_init(struct xt_entry_target *target)
info->flags = XT_CT_NOTRACK | XT_CT_NOTRACK_ALIAS;
}
+static int xlate_ct1_tg(struct xt_xlate *xl,
+ const struct xt_xlate_tg_params *params)
+{
+ struct xt_ct_target_info_v1 *info =
+ (struct xt_ct_target_info_v1 *)params->target->data;
+
+ if (info->flags & XT_CT_NOTRACK)
+ xt_xlate_add(xl, "notrack");
+ else
+ return 0;
+
+ return 1;
+}
+
static struct xtables_target ct_target_reg[] = {
{
.family = NFPROTO_UNSPEC,
@@ -387,6 +401,7 @@ static struct xtables_target ct_target_reg[] = {
.alias = ct_print_name_alias,
.x6_parse = ct_parse_v1,
.x6_options = ct_opts_v1,
+ .xlate = xlate_ct1_tg,
},
{
.family = NFPROTO_UNSPEC,
@@ -418,6 +433,7 @@ static struct xtables_target ct_target_reg[] = {
.size = XT_ALIGN(sizeof(struct xt_ct_target_info_v1)),
.userspacesize = offsetof(struct xt_ct_target_info_v1, ct),
.init = notrack_ct2_tg_init,
+ .xlate = xlate_ct1_tg,
},
{
.family = NFPROTO_UNSPEC,
diff --git a/extensions/libxt_CT.man b/extensions/libxt_CT.man
index e992120a..fc692f9a 100644
--- a/extensions/libxt_CT.man
+++ b/extensions/libxt_CT.man
@@ -1,4 +1,4 @@
-The CT target allows to set parameters for a packet or its associated
+The CT target sets parameters for a packet or its associated
connection. The target attaches a "template" connection tracking entry to
the packet, which is then used by the conntrack core when initializing
a new ct entry. This target is thus only valid in the "raw" table.
diff --git a/extensions/libxt_DSCP.man b/extensions/libxt_DSCP.man
index 551ba2e1..5385c97a 100644
--- a/extensions/libxt_DSCP.man
+++ b/extensions/libxt_DSCP.man
@@ -1,4 +1,4 @@
-This target allows to alter the value of the DSCP bits within the TOS
+This target alters the value of the DSCP bits within the TOS
header of the IPv4 packet. As this manipulates a packet, it can only
be used in the mangle table.
.TP
diff --git a/extensions/libxt_HMARK.man b/extensions/libxt_HMARK.man
index e7b5426d..cd7ffd54 100644
--- a/extensions/libxt_HMARK.man
+++ b/extensions/libxt_HMARK.man
@@ -56,5 +56,5 @@ iptables \-t mangle \-A PREROUTING \-m conntrack \-\-ctstate NEW
\-j HMARK \-\-hmark-tuple ct,src,dst,proto \-\-hmark-offset 10000
\-\-hmark\-mod 10 \-\-hmark\-rnd 0xfeedcafe
.PP
-iptables \-t mangle \-A PREROUTING -j HMARK \-\-hmark\-offset 10000
+iptables \-t mangle \-A PREROUTING \-j HMARK \-\-hmark\-offset 10000
\-\-hmark-tuple src,dst,proto \-\-hmark-mod 10 \-\-hmark\-rnd 0xdeafbeef
diff --git a/extensions/libxt_IDLETIMER.c b/extensions/libxt_IDLETIMER.c
index 5f1b9fe7..c414801c 100644
--- a/extensions/libxt_IDLETIMER.c
+++ b/extensions/libxt_IDLETIMER.c
@@ -27,6 +27,7 @@
enum {
O_TIMEOUT = 0,
O_LABEL,
+ O_ALARM,
O_NETLINK,
};
@@ -36,8 +37,18 @@ static const struct xt_option_entry idletimer_tg_opts[] = {
.flags = XTOPT_MAND | XTOPT_PUT, XTOPT_POINTER(s, timeout)},
{.name = "label", .id = O_LABEL, .type = XTTYPE_STRING,
.flags = XTOPT_MAND | XTOPT_PUT, XTOPT_POINTER(s, label)},
- {.name = "send_nl_msg", .id = O_NETLINK, .type = XTTYPE_UINT8,
- .flags = XTOPT_PUT, XTOPT_POINTER(s, send_nl_msg)},
+ XTOPT_TABLEEND,
+};
+#undef s
+
+#define s struct idletimer_tg_info_v1
+static const struct xt_option_entry idletimer_tg_opts_v1[] = {
+ {.name = "timeout", .id = O_TIMEOUT, .type = XTTYPE_UINT32,
+ .flags = XTOPT_MAND | XTOPT_PUT, XTOPT_POINTER(s, timeout)},
+ {.name = "label", .id = O_LABEL, .type = XTTYPE_STRING,
+ .flags = XTOPT_MAND | XTOPT_PUT, XTOPT_POINTER(s, label)},
+ {.name = "alarm", .id = O_ALARM, .type = XTTYPE_NONE},
+ {.name = "send_nl_msg", .id = O_NETLINK, .type = XTTYPE_NONE},
XTOPT_TABLEEND,
};
#undef s
@@ -48,8 +59,17 @@ static void idletimer_tg_help(void)
"IDLETIMER target options:\n"
" --timeout time Timeout until the notification is sent (in seconds)\n"
" --label string Unique rule identifier\n"
-" --send_nl_msg (0/1) Enable netlink messages,"
- " and show remaining time in sysfs. Defaults to 0.\n"
+"\n");
+}
+
+static void idletimer_tg_help_v1(void)
+{
+ printf(
+"IDLETIMER target options:\n"
+" --timeout time Timeout until the notification is sent (in seconds)\n"
+" --label string Unique rule identifier\n"
+" --alarm Use alarm instead of default timer\n"
+" --send_nl_msg Enable netlink messages and show remaining time in sysfs.\n"
"\n");
}
@@ -62,9 +82,24 @@ static void idletimer_tg_print(const void *ip,
printf(" timeout:%u", info->timeout);
printf(" label:%s", info->label);
- printf(" send_nl_msg:%u", info->send_nl_msg);
}
+static void idletimer_tg_print_v1(const void *ip,
+ const struct xt_entry_target *target,
+ int numeric)
+{
+ struct idletimer_tg_info_v1 *info =
+ (struct idletimer_tg_info_v1 *) target->data;
+
+ printf(" timeout:%u", info->timeout);
+ printf(" label:%s", info->label);
+ if (info->timer_type == XT_IDLETIMER_ALARM)
+ printf(" alarm");
+ if (info->send_nl_msg)
+ printf(" send_nl_msg");
+}
+
+
static void idletimer_tg_save(const void *ip,
const struct xt_entry_target *target)
{
@@ -73,24 +108,64 @@ static void idletimer_tg_save(const void *ip,
printf(" --timeout %u", info->timeout);
printf(" --label %s", info->label);
- printf(" --send_nl_msg %u", info->send_nl_msg);
}
-static struct xtables_target idletimer_tg_reg = {
- .family = NFPROTO_UNSPEC,
- .name = "IDLETIMER",
- .version = XTABLES_VERSION,
- .revision = 1,
- .size = XT_ALIGN(sizeof(struct idletimer_tg_info)),
- .userspacesize = offsetof(struct idletimer_tg_info, timer),
- .help = idletimer_tg_help,
- .x6_parse = xtables_option_parse,
- .print = idletimer_tg_print,
- .save = idletimer_tg_save,
- .x6_options = idletimer_tg_opts,
+static void idletimer_tg_save_v1(const void *ip,
+ const struct xt_entry_target *target)
+{
+ struct idletimer_tg_info_v1 *info =
+ (struct idletimer_tg_info_v1 *) target->data;
+
+ printf(" --timeout %u", info->timeout);
+ printf(" --label %s", info->label);
+ if (info->timer_type == XT_IDLETIMER_ALARM)
+ printf(" --alarm");
+ if (info->send_nl_msg)
+ printf(" --send_nl_msg");
+}
+
+static void idletimer_tg_parse_v1(struct xt_option_call *cb)
+{
+ struct idletimer_tg_info_v1 *info = cb->data;
+
+ xtables_option_parse(cb);
+ if (cb->entry->id == O_ALARM)
+ info->timer_type = XT_IDLETIMER_ALARM;
+ if (cb->entry->id == O_NETLINK)
+ info->send_nl_msg = 1;
+}
+
+static struct xtables_target idletimer_tg_reg[] = {
+ {
+ .family = NFPROTO_UNSPEC,
+ .name = "IDLETIMER",
+ .version = XTABLES_VERSION,
+ .revision = 0,
+ .size = XT_ALIGN(sizeof(struct idletimer_tg_info)),
+ .userspacesize = offsetof(struct idletimer_tg_info, timer),
+ .help = idletimer_tg_help,
+ .x6_parse = xtables_option_parse,
+ .print = idletimer_tg_print,
+ .save = idletimer_tg_save,
+ .x6_options = idletimer_tg_opts,
+ },
+ {
+ .family = NFPROTO_UNSPEC,
+ .name = "IDLETIMER",
+ .version = XTABLES_VERSION,
+ .revision = 1,
+ .size = XT_ALIGN(sizeof(struct idletimer_tg_info_v1)),
+ .userspacesize = offsetof(struct idletimer_tg_info_v1, timer),
+ .help = idletimer_tg_help_v1,
+ .x6_parse = idletimer_tg_parse_v1,
+ .print = idletimer_tg_print_v1,
+ .save = idletimer_tg_save_v1,
+ .x6_options = idletimer_tg_opts_v1,
+ },
+
};
void _init(void)
{
- xtables_register_target(&idletimer_tg_reg);
+ xtables_register_targets(idletimer_tg_reg, ARRAY_SIZE(idletimer_tg_reg));
}
diff --git a/extensions/libxt_IDLETIMER.man b/extensions/libxt_IDLETIMER.man
index 3b5188d9..bd4add9b 100644
--- a/extensions/libxt_IDLETIMER.man
+++ b/extensions/libxt_IDLETIMER.man
@@ -19,6 +19,6 @@ This is the time in seconds that will trigger the notification.
This is a unique identifier for the timer. The maximum length for the
label string is 27 characters.
.TP
-\fB\-\---send_nl_msg\fP \fI(0/1)\fP
+\fB\-\---send_nl_msg\fP
Send netlink messages in addition to sysfs notifications and show remaining
-time. Defaults to 0.
+time.
diff --git a/extensions/libxt_IDLETIMER.t b/extensions/libxt_IDLETIMER.t
index 6afd92c1..e8f306d2 100644
--- a/extensions/libxt_IDLETIMER.t
+++ b/extensions/libxt_IDLETIMER.t
@@ -2,3 +2,4 @@
-j IDLETIMER --timeout;;FAIL
-j IDLETIMER --timeout 42;;FAIL
-j IDLETIMER --timeout 42 --label foo;=;OK
+-j IDLETIMER --timeout 42 --label foo --alarm;;OK
diff --git a/extensions/libxt_MARK.man b/extensions/libxt_MARK.man
index 712fb76f..b2408597 100644
--- a/extensions/libxt_MARK.man
+++ b/extensions/libxt_MARK.man
@@ -1,7 +1,7 @@
This target is used to set the Netfilter mark value associated with the packet.
It can, for example, be used in conjunction with routing based on fwmark (needs
-iproute2). If you plan on doing so, note that the mark needs to be set in the
-PREROUTING chain of the mangle table to affect routing.
+iproute2). If you plan on doing so, note that the mark needs to be set in
+either the PREROUTING or the OUTPUT chain of the mangle table to affect routing.
The mark field is 32 bits wide.
.TP
\fB\-\-set\-xmark\fP \fIvalue\fP[\fB/\fP\fImask\fP]
diff --git a/extensions/libxt_NOTRACK.t b/extensions/libxt_NOTRACK.t
index 585be82d..27c4734f 100644
--- a/extensions/libxt_NOTRACK.t
+++ b/extensions/libxt_NOTRACK.t
@@ -1,4 +1,3 @@
:PREROUTING,OUTPUT
*raw
-# ERROR: cannot find: iptables -I PREROUTING -t raw -j NOTRACK
-#-j NOTRACK;=;OK
+-j NOTRACK;=;OK
diff --git a/extensions/libxt_NOTRACK.txlate b/extensions/libxt_NOTRACK.txlate
new file mode 100644
index 00000000..9d35619d
--- /dev/null
+++ b/extensions/libxt_NOTRACK.txlate
@@ -0,0 +1,2 @@
+iptables-translate -A PREROUTING -t raw -j NOTRACK
+nft add rule ip raw PREROUTING counter notrack
diff --git a/extensions/libxt_SET.man b/extensions/libxt_SET.man
index 78a9ae0f..c4713378 100644
--- a/extensions/libxt_SET.man
+++ b/extensions/libxt_SET.man
@@ -42,5 +42,5 @@ and
\fB\-\-map\-queue\fP
flags can be used in the OUTPUT, FORWARD and POSTROUTING chains.
.PP
-Use of -j SET requires that ipset kernel support is provided, which, for
+Use of \-j SET requires that ipset kernel support is provided, which, for
standard kernels, is the case since Linux 2.6.39.
diff --git a/extensions/libxt_TCPMSS.man b/extensions/libxt_TCPMSS.man
index 8da8e761..25b480dd 100644
--- a/extensions/libxt_TCPMSS.man
+++ b/extensions/libxt_TCPMSS.man
@@ -1,4 +1,4 @@
-This target allows to alter the MSS value of TCP SYN packets, to control
+This target alters the MSS value of TCP SYN packets, to control
the maximum size for that connection (usually limiting it to your
outgoing interface's MTU minus 40 for IPv4 or 60 for IPv6, respectively).
Of course, it can only be used
diff --git a/extensions/libxt_TOS.man b/extensions/libxt_TOS.man
index 58118ec2..de2d22dc 100644
--- a/extensions/libxt_TOS.man
+++ b/extensions/libxt_TOS.man
@@ -32,5 +32,5 @@ longterm releases 2.6.32 (>=.42), 2.6.33 (>=.15), and 2.6.35 (>=.14), there is
a bug whereby IPv6 TOS mangling does not behave as documented and differs from
the IPv4 version. The TOS mask indicates the bits one wants to zero out, so it
needs to be inverted before applying it to the original TOS field. However, the
-aformentioned kernels forgo the inversion which breaks --set-tos and its
+aformentioned kernels forgo the inversion which breaks \-\-set\-tos and its
mnemonics.
diff --git a/extensions/libxt_bpf.man b/extensions/libxt_bpf.man
index 1d2aa9e6..d6da2043 100644
--- a/extensions/libxt_bpf.man
+++ b/extensions/libxt_bpf.man
@@ -17,7 +17,7 @@ iptables \-A OUTPUT \-m bpf \-\-object\-pinned ${BPF_MOUNT}/{PINNED_PATH} \-j AC
\fB\-\-bytecode\fP \fIcode\fP
Pass the BPF byte code format as generated by the \fBnfbpf_compile\fP utility.
.PP
-The code format is similar to the output of the tcpdump -ddd command: one line
+The code format is similar to the output of the tcpdump \-ddd command: one line
that stores the number of instructions, followed by one line for each
instruction. Instruction lines follow the pattern 'u16 u8 u8 u32' in decimal
notation. Fields encode the operation, jump offset if true, jump offset if
diff --git a/extensions/libxt_cluster.c b/extensions/libxt_cluster.c
index c9c35ee2..d164bf69 100644
--- a/extensions/libxt_cluster.c
+++ b/extensions/libxt_cluster.c
@@ -156,7 +156,7 @@ static int cluster_xlate(struct xt_xlate *xl,
xt_xlate_add(xl, "%s %u seed 0x%08x ", jhash_st,
info->total_nodes, info->hash_seed);
for (node = 0; node < 32; node++) {
- if (info->node_mask & (1 << node)) {
+ if (info->node_mask & (1u << node)) {
if (needs_set == 0) {
xt_xlate_add(xl, "{ ");
needs_set = 1;
diff --git a/extensions/libxt_cluster.man b/extensions/libxt_cluster.man
index 94b4b205..23448e26 100644
--- a/extensions/libxt_cluster.man
+++ b/extensions/libxt_cluster.man
@@ -27,7 +27,7 @@ iptables \-A PREROUTING \-t mangle \-i eth1 \-m cluster
iptables \-A PREROUTING \-t mangle \-i eth2 \-m cluster
\-\-cluster\-total\-nodes 2 \-\-cluster\-local\-node 1
\-\-cluster\-hash\-seed 0xdeadbeef
-\-j MARK -\-set\-mark 0xffff
+\-j MARK \-\-set\-mark 0xffff
.IP
iptables \-A PREROUTING \-t mangle \-i eth1
\-m mark ! \-\-mark 0xffff \-j DROP
diff --git a/extensions/libxt_connlabel.c b/extensions/libxt_connlabel.c
index 5a01fe72..565b8c79 100644
--- a/extensions/libxt_connlabel.c
+++ b/extensions/libxt_connlabel.c
@@ -70,18 +70,15 @@ static int connlabel_value_parse(const char *in)
static void connlabel_mt_parse(struct xt_option_call *cb)
{
struct xt_connlabel_mtinfo *info = cb->data;
- bool have_labelmap = !connlabel_open();
int tmp;
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_LABEL:
- if (have_labelmap)
+ tmp = connlabel_value_parse(cb->arg);
+ if (tmp < 0 && !connlabel_open())
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 or invalid value",
diff --git a/extensions/libxt_conntrack.c b/extensions/libxt_conntrack.c
index 6f350393..7734509c 100644
--- a/extensions/libxt_conntrack.c
+++ b/extensions/libxt_conntrack.c
@@ -1249,11 +1249,19 @@ static int _conntrack3_mt_xlate(struct xt_xlate *xl,
}
if (sinfo->match_flags & XT_CONNTRACK_STATE) {
- xt_xlate_add(xl, "%sct state %s", space,
- sinfo->invert_flags & XT_CONNTRACK_STATE ?
- "!= " : "");
- state_xlate_print(xl, sinfo->state_mask);
- space = " ";
+ if ((sinfo->state_mask & XT_CONNTRACK_STATE_SNAT) ||
+ (sinfo->state_mask & XT_CONNTRACK_STATE_DNAT)) {
+ xt_xlate_add(xl, "%sct status %s%s", space,
+ sinfo->invert_flags & XT_CONNTRACK_STATUS ? "!=" : "",
+ sinfo->state_mask & XT_CONNTRACK_STATE_SNAT ? "snat" : "dnat");
+ space = " ";
+ } else {
+ xt_xlate_add(xl, "%sct state %s", space,
+ sinfo->invert_flags & XT_CONNTRACK_STATE ?
+ "!= " : "");
+ state_xlate_print(xl, sinfo->state_mask);
+ space = " ";
+ }
}
if (sinfo->match_flags & XT_CONNTRACK_STATUS) {
diff --git a/extensions/libxt_conntrack.txlate b/extensions/libxt_conntrack.txlate
index 8a3d0181..d374f8a0 100644
--- a/extensions/libxt_conntrack.txlate
+++ b/extensions/libxt_conntrack.txlate
@@ -42,3 +42,10 @@ nft add rule ip filter INPUT ct direction original counter accept
iptables-translate -t filter -A INPUT -m conntrack --ctstate NEW --ctproto tcp --ctorigsrc 192.168.0.1 --ctorigdst 192.168.0.1 --ctreplsrc 192.168.0.1 --ctrepldst 192.168.0.1 --ctorigsrcport 12 --ctorigdstport 14 --ctreplsrcport 16 --ctrepldstport 18 --ctexpire 10 --ctstatus SEEN_REPLY --ctdir ORIGINAL -j ACCEPT
nft add rule ip filter INPUT ct direction original ct original protocol 6 ct state new ct status seen-reply ct expiration 10 ct original saddr 192.168.0.1 ct original daddr 192.168.0.1 ct reply saddr 192.168.0.1 ct reply daddr 192.168.0.1 ct original proto-src 12 ct original proto-dst 14 ct reply proto-src 16 ct reply proto-dst 18 counter accept
+
+iptables-translate -t filter -A INPUT -m conntrack --ctstate SNAT -j ACCEPT
+nft add rule ip filter INPUT ct status snat counter accept
+
+iptables-translate -t filter -A INPUT -m conntrack --ctstate DNAT -j ACCEPT
+nft add rule ip filter INPUT ct status dnat counter accept
+
diff --git a/extensions/libxt_dccp.c b/extensions/libxt_dccp.c
index 5e67c264..aea3e20b 100644
--- a/extensions/libxt_dccp.c
+++ b/extensions/libxt_dccp.c
@@ -76,6 +76,9 @@ static const char *const dccp_pkt_types[] = {
[DCCP_PKT_INVALID] = "INVALID",
};
+/* Bits for type values 11-15 */
+#define INVALID_OTHER_TYPE_MASK 0xf800
+
static uint16_t
parse_dccp_types(const char *typestring)
{
@@ -95,6 +98,9 @@ parse_dccp_types(const char *typestring)
xtables_error(PARAMETER_PROBLEM,
"Unknown DCCP type `%s'", ptr);
}
+ if (typemask & (1 << DCCP_PKT_INVALID))
+ typemask |= INVALID_OTHER_TYPE_MASK;
+
free(buffer);
return typemask;
@@ -193,9 +199,13 @@ print_types(uint16_t types, int inverted, int numeric)
if (numeric)
printf("%u", i);
- else
+ else {
printf("%s", dccp_pkt_types[i]);
+ if (i == DCCP_PKT_INVALID)
+ break;
+ }
+
types &= ~(1 << i);
}
}
@@ -288,6 +298,7 @@ static const char *const dccp_pkt_types_xlate[] = {
[DCCP_PKT_RESET] = "reset",
[DCCP_PKT_SYNC] = "sync",
[DCCP_PKT_SYNCACK] = "syncack",
+ [DCCP_PKT_INVALID] = "10-15",
};
static int dccp_type_xlate(const struct xt_dccp_info *einfo,
@@ -296,10 +307,10 @@ static int dccp_type_xlate(const struct xt_dccp_info *einfo,
bool have_type = false, set_need = false;
uint16_t types = einfo->typemask;
- if (types & (1 << DCCP_PKT_INVALID))
- return 0;
-
- xt_xlate_add(xl, " dccp type%s ", einfo->invflags ? " !=" : "");
+ if (types & INVALID_OTHER_TYPE_MASK) {
+ types &= ~INVALID_OTHER_TYPE_MASK;
+ types |= 1 << DCCP_PKT_INVALID;
+ }
if ((types != 0) && !(types == (types & -types))) {
xt_xlate_add(xl, "{");
@@ -335,34 +346,37 @@ static int dccp_xlate(struct xt_xlate *xl,
char *space = "";
int ret = 1;
- xt_xlate_add(xl, "dccp ");
-
if (einfo->flags & XT_DCCP_SRC_PORTS) {
+ xt_xlate_add(xl, "dccp sport%s %u",
+ einfo->invflags & XT_DCCP_SRC_PORTS ? " !=" : "",
+ einfo->spts[0]);
+
if (einfo->spts[0] != einfo->spts[1])
- xt_xlate_add(xl, "sport%s %u-%u",
- einfo->invflags & XT_DCCP_SRC_PORTS ? " !=" : "",
- einfo->spts[0], einfo->spts[1]);
- else
- xt_xlate_add(xl, "sport%s %u",
- einfo->invflags & XT_DCCP_SRC_PORTS ? " !=" : "",
- einfo->spts[0]);
+ xt_xlate_add(xl, "-%u", einfo->spts[1]);
+
space = " ";
}
if (einfo->flags & XT_DCCP_DEST_PORTS) {
+ xt_xlate_add(xl, "%sdccp dport%s %u", space,
+ einfo->invflags & XT_DCCP_DEST_PORTS ? " !=" : "",
+ einfo->dpts[0]);
+
if (einfo->dpts[0] != einfo->dpts[1])
- xt_xlate_add(xl, "%sdport%s %u-%u", space,
- einfo->invflags & XT_DCCP_DEST_PORTS ? " !=" : "",
- einfo->dpts[0], einfo->dpts[1]);
- else
- xt_xlate_add(xl, "%sdport%s %u", space,
- einfo->invflags & XT_DCCP_DEST_PORTS ? " !=" : "",
- einfo->dpts[0]);
+ xt_xlate_add(xl, "-%u", einfo->dpts[1]);
+
+ space = " ";
}
- if (einfo->flags & XT_DCCP_TYPE)
+ if (einfo->flags & XT_DCCP_TYPE && einfo->typemask) {
+ xt_xlate_add(xl, "%sdccp type%s ", space,
+ einfo->invflags & XT_DCCP_TYPE ? " !=" : "");
ret = dccp_type_xlate(einfo, xl);
+ space = " ";
+ }
+
+ /* FIXME: no dccp option support in nftables yet */
if (einfo->flags & XT_DCCP_OPTION)
ret = 0;
diff --git a/extensions/libxt_dccp.txlate b/extensions/libxt_dccp.txlate
index b47dc65f..ea853f6a 100644
--- a/extensions/libxt_dccp.txlate
+++ b/extensions/libxt_dccp.txlate
@@ -7,8 +7,14 @@ nft add rule ip filter INPUT dccp dport 100-200 counter
iptables-translate -A INPUT -p dccp -m dccp ! --dport 100
nft add rule ip filter INPUT dccp dport != 100 counter
-iptables-translate -A INPUT -p dccp -m dccp --dport 100 --dccp-types REQUEST,RESPONSE,DATA,ACK,DATAACK,CLOSEREQ,CLOSE,SYNC,SYNCACK
-nft add rule ip filter INPUT dccp dport 100 dccp type {request, response, data, ack, dataack, closereq, close, sync, syncack} counter
+iptables-translate -A INPUT -p dccp -m dccp --dccp-types CLOSE
+nft add rule ip filter INPUT dccp type close counter
+
+iptables-translate -A INPUT -p dccp -m dccp --dccp-types INVALID
+nft add rule ip filter INPUT dccp type 10-15 counter
+
+iptables-translate -A INPUT -p dccp -m dccp --dport 100 --dccp-types REQUEST,RESPONSE,DATA,ACK,DATAACK,CLOSEREQ,CLOSE,SYNC,SYNCACK,INVALID
+nft add rule ip filter INPUT dccp dport 100 dccp type {request, response, data, ack, dataack, closereq, close, sync, syncack, 10-15} counter
iptables-translate -A INPUT -p dccp -m dccp --sport 200 --dport 100
-nft add rule ip filter INPUT dccp sport 200 dport 100 counter
+nft add rule ip filter INPUT dccp sport 200 dccp dport 100 counter
diff --git a/extensions/libxt_mac.c b/extensions/libxt_mac.c
index b6d717bc..b90eef20 100644
--- a/extensions/libxt_mac.c
+++ b/extensions/libxt_mac.c
@@ -37,15 +37,6 @@ static void mac_parse(struct xt_option_call *cb)
macinfo->invert = 1;
}
-static void print_mac(const unsigned char *macaddress)
-{
- unsigned int i;
-
- printf(" %02X", macaddress[0]);
- for (i = 1; i < ETH_ALEN; ++i)
- printf(":%02X", macaddress[i]);
-}
-
static void
mac_print(const void *ip, const struct xt_entry_match *match, int numeric)
{
@@ -56,7 +47,7 @@ mac_print(const void *ip, const struct xt_entry_match *match, int numeric)
if (info->invert)
printf(" !");
- print_mac(info->srcaddr);
+ xtables_print_mac(info->srcaddr);
}
static void mac_save(const void *ip, const struct xt_entry_match *match)
@@ -66,8 +57,8 @@ static void mac_save(const void *ip, const struct xt_entry_match *match)
if (info->invert)
printf(" !");
- printf(" --mac-source");
- print_mac(info->srcaddr);
+ printf(" --mac-source ");
+ xtables_print_mac(info->srcaddr);
}
static void print_mac_xlate(const unsigned char *macaddress,
diff --git a/extensions/libxt_osf.c b/extensions/libxt_osf.c
index 496b4805..c567d9e0 100644
--- a/extensions/libxt_osf.c
+++ b/extensions/libxt_osf.c
@@ -40,7 +40,7 @@ static void osf_help(void)
"--ttl level Use some TTL check extensions to determine OS:\n"
" 0 true ip and fingerprint TTL comparison. Works for LAN.\n"
" 1 check if ip TTL is less than fingerprint one. Works for global addresses.\n"
- " 2 do not compare TTL at all. Allows to detect NMAP, but can produce false results.\n"
+ " 2 do not compare TTL at all. This allows NMAP detection, but can produce false results.\n"
"--log level Log determined genres into dmesg even if they do not match desired one:\n"
" 0 log all matched or unknown signatures.\n"
" 1 log only first one.\n"
diff --git a/extensions/libxt_osf.man b/extensions/libxt_osf.man
index 5ba92ce0..41103f29 100644
--- a/extensions/libxt_osf.man
+++ b/extensions/libxt_osf.man
@@ -1,4 +1,4 @@
-The osf module does passive operating system fingerprinting. This modules
+The osf module does passive operating system fingerprinting. This module
compares some data (Window Size, MSS, options and their order, TTL, DF,
and others) from packets with the SYN bit set.
.TP
@@ -35,11 +35,11 @@ Windows [2000:SP3:Windows XP Pro SP1, 2000 SP3]: 11.22.33.55:4024 ->
OS fingerprints are loadable using the \fBnfnl_osf\fP program. To load
fingerprints from a file, use:
.PP
-\fBnfnl_osf -f /usr/share/xtables/pf.os\fP
+\fBnfnl_osf \-f /usr/share/xtables/pf.os\fP
.PP
To remove them again,
.PP
-\fBnfnl_osf -f /usr/share/xtables/pf.os -d\fP
+\fBnfnl_osf \-f /usr/share/xtables/pf.os \-d\fP
.PP
The fingerprint database can be downloaded from
http://www.openbsd.org/cgi-bin/cvsweb/src/etc/pf.os .
diff --git a/extensions/libxt_policy.man b/extensions/libxt_policy.man
index 1b834fa0..12c01b43 100644
--- a/extensions/libxt_policy.man
+++ b/extensions/libxt_policy.man
@@ -1,4 +1,4 @@
-This modules matches the policy used by IPsec for handling a packet.
+This module matches the policy used by IPsec for handling a packet.
.TP
\fB\-\-dir\fP {\fBin\fP|\fBout\fP}
Used to select whether to match the policy used for decapsulation or the
diff --git a/extensions/libxt_sctp.man b/extensions/libxt_sctp.man
index 9c0bd8c3..3779d05a 100644
--- a/extensions/libxt_sctp.man
+++ b/extensions/libxt_sctp.man
@@ -1,3 +1,4 @@
+This module matches Stream Control Transmission Protocol headers.
.TP
[\fB!\fP] \fB\-\-source\-port\fP,\fB\-\-sport\fP \fIport\fP[\fB:\fP\fIport\fP]
.TP
diff --git a/extensions/libxt_set.man b/extensions/libxt_set.man
index dbc1586b..5c6f64e3 100644
--- a/extensions/libxt_set.man
+++ b/extensions/libxt_set.man
@@ -61,5 +61,5 @@ when the set was defined without counter support.
The option \fB\-\-match\-set\fP can be replaced by \fB\-\-set\fP if that does
not clash with an option of other extensions.
.PP
-Use of -m set requires that ipset kernel support is provided, which, for
+Use of \-m set requires that ipset kernel support is provided, which, for
standard kernels, is the case since Linux 2.6.39.
diff --git a/extensions/libxt_string.man b/extensions/libxt_string.man
index 54c03a3a..5f1a993c 100644
--- a/extensions/libxt_string.man
+++ b/extensions/libxt_string.man
@@ -1,4 +1,4 @@
-This modules matches a given string by using some pattern matching strategy. It requires a linux kernel >= 2.6.14.
+This module matches a given string by using some pattern matching strategy. It requires a linux kernel >= 2.6.14.
.TP
\fB\-\-algo\fP {\fBbm\fP|\fBkmp\fP}
Select the pattern matching strategy. (bm = Boyer-Moore, kmp = Knuth-Pratt-Morris)
diff --git a/extensions/libxt_time.c b/extensions/libxt_time.c
index 5a8cc5de..d27d84ca 100644
--- a/extensions/libxt_time.c
+++ b/extensions/libxt_time.c
@@ -258,6 +258,16 @@ static unsigned int time_parse_weekdays(const char *arg)
return ret;
}
+static unsigned int time_count_weekdays(unsigned int weekdays_mask)
+{
+ unsigned int ret;
+
+ for (ret = 0; weekdays_mask; weekdays_mask >>= 1)
+ ret += weekdays_mask & 1;
+
+ return ret;
+}
+
static void time_parse(struct xt_option_call *cb)
{
struct xt_time_info *info = cb->data;
@@ -330,7 +340,7 @@ static void time_print_monthdays(uint32_t mask, bool human_readable)
printf(" ");
for (i = 1; i <= 31; ++i)
- if (mask & (1 << i)) {
+ if (mask & (1u << i)) {
if (nbdays++ > 0)
printf(",");
printf("%u", i);
@@ -450,6 +460,67 @@ static void time_check(struct xt_fcheck_call *cb)
"time: --contiguous only makes sense when stoptime is smaller than starttime");
}
+static int time_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ const struct xt_time_info *info =
+ (const struct xt_time_info *)params->match->data;
+ unsigned int h, m, s,
+ i, sep, mask, count;
+ time_t tt_start, tt_stop;
+ struct tm *t_start, *t_stop;
+
+ if (info->date_start != 0 ||
+ info->date_stop != INT_MAX) {
+ tt_start = (time_t) info->date_start;
+ tt_stop = (time_t) info->date_stop;
+
+ xt_xlate_add(xl, "meta time ");
+ t_start = gmtime(&tt_start);
+ xt_xlate_add(xl, "\"%04u-%02u-%02u %02u:%02u:%02u\"",
+ t_start->tm_year + 1900, t_start->tm_mon + 1,
+ t_start->tm_mday, t_start->tm_hour,
+ t_start->tm_min, t_start->tm_sec);
+ t_stop = gmtime(&tt_stop);
+ xt_xlate_add(xl, "-\"%04u-%02u-%02u %02u:%02u:%02u\"",
+ t_stop->tm_year + 1900, t_stop->tm_mon + 1,
+ t_stop->tm_mday, t_stop->tm_hour,
+ t_stop->tm_min, t_stop->tm_sec);
+ }
+ if (info->daytime_start != XT_TIME_MIN_DAYTIME ||
+ info->daytime_stop != XT_TIME_MAX_DAYTIME) {
+ divide_time(info->daytime_start, &h, &m, &s);
+ xt_xlate_add(xl, " meta hour \"%02u:%02u:%02u\"", h, m, s);
+ divide_time(info->daytime_stop, &h, &m, &s);
+ xt_xlate_add(xl, "-\"%02u:%02u:%02u\"", h, m, s);
+ }
+ /* nft_time does not support --monthdays */
+ if (info->monthdays_match != XT_TIME_ALL_MONTHDAYS)
+ return 0;
+ if (info->weekdays_match != XT_TIME_ALL_WEEKDAYS) {
+ sep = 0;
+ mask = info->weekdays_match;
+ count = time_count_weekdays(mask);
+
+ xt_xlate_add(xl, " meta day ");
+ if (count > 1)
+ xt_xlate_add(xl, "{");
+ for (i = 1; i <= 7; ++i)
+ if (mask & (1 << i)) {
+ if (sep)
+ xt_xlate_add(xl, ",%u", i%7);
+ else {
+ xt_xlate_add(xl, "%u", i%7);
+ ++sep;
+ }
+ }
+ if (count > 1)
+ xt_xlate_add(xl, "}");
+ }
+
+ return 1;
+}
+
static struct xtables_match time_match = {
.name = "time",
.family = NFPROTO_UNSPEC,
@@ -463,6 +534,7 @@ static struct xtables_match time_match = {
.x6_parse = time_parse,
.x6_fcheck = time_check,
.x6_options = time_opts,
+ .xlate = time_xlate,
};
void _init(void)
diff --git a/extensions/libxt_time.txlate b/extensions/libxt_time.txlate
new file mode 100644
index 00000000..ff4a7b88
--- /dev/null
+++ b/extensions/libxt_time.txlate
@@ -0,0 +1,26 @@
+iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --weekdays Sa,Su -j REJECT
+nft add rule ip filter INPUT icmp type echo-request meta day {6,0} counter reject
+
+iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --timestart 12:00 -j REJECT
+nft add rule ip filter INPUT icmp type echo-request meta hour "12:00:00"-"23:59:59" counter reject
+
+iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --timestop 12:00 -j REJECT
+nft add rule ip filter INPUT icmp type echo-request meta hour "00:00:00"-"12:00:00" counter reject
+
+iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --datestart 2021 -j REJECT
+nft add rule ip filter INPUT icmp type echo-request meta time "2021-01-01 00:00:00"-"2038-01-19 03:14:07" counter reject
+
+iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --datestop 2021 -j REJECT
+nft add rule ip filter INPUT icmp type echo-request meta time "1970-01-01 00:00:00"-"2021-01-01 00:00:00" counter reject
+
+iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --datestop 2021-01-29T00:00:00 -j REJECT
+nft add rule ip filter INPUT icmp type echo-request meta time "1970-01-01 00:00:00"-"2021-01-29 00:00:00" counter reject
+
+iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --datestart 2020-01-29T00:00:00 --timestart 12:00 -j REJECT
+nft add rule ip filter INPUT icmp type echo-request meta time "2020-01-29 00:00:00"-"2038-01-19 03:14:07" meta hour "12:00:00"-"23:59:59" counter reject
+
+iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --datestart 2020-01-29T00:00:00 --timestart 12:00 --timestop 19:00 --weekdays Mon,Tue,Wed,Thu,Fri -j REJECT
+nft add rule ip filter INPUT icmp type echo-request meta time "2020-01-29 00:00:00"-"2038-01-19 03:14:07" meta hour "12:00:00"-"19:00:00" meta day {1,2,3,4,5} counter reject
+
+iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --datestart 2020-01-29T00:00:00 --timestart 12:00 --timestop 19:00 ! --weekdays Mon,Tue,Wed,Thu,Fri -j REJECT
+nft add rule ip filter INPUT icmp type echo-request meta time "2020-01-29 00:00:00"-"2038-01-19 03:14:07" meta hour "12:00:00"-"19:00:00" meta day {6,0} counter reject
diff --git a/include/Makefile.am b/include/Makefile.am
index e6951209..ea34c2fe 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -10,3 +10,8 @@ endif
nobase_include_HEADERS += \
libiptc/ipt_kernel_headers.h libiptc/libiptc.h \
libiptc/libip6tc.h libiptc/libxtc.h libiptc/xtcshared.h
+
+uninstall-hook:
+ dir=${includedir}/libiptc; { \
+ test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; \
+ } || rmdir -p --ignore-fail-on-non-empty "$$dir"
diff --git a/include/linux/netfilter/xt_IDLETIMER.h b/include/linux/netfilter/xt_IDLETIMER.h
index ec96e4a3..49ddcdc6 100644
--- a/include/linux/netfilter/xt_IDLETIMER.h
+++ b/include/linux/netfilter/xt_IDLETIMER.h
@@ -32,17 +32,26 @@
#include <linux/types.h>
#define MAX_IDLETIMER_LABEL_SIZE 28
+#define XT_IDLETIMER_ALARM 0x01
struct idletimer_tg_info {
__u32 timeout;
char label[MAX_IDLETIMER_LABEL_SIZE];
- /* Use netlink messages for notification in addition to sysfs */
- __u8 send_nl_msg;
-
/* for kernel module internal use only */
struct idletimer_tg *timer __attribute__((aligned(8)));
};
+struct idletimer_tg_info_v1 {
+ __u32 timeout;
+
+ char label[MAX_IDLETIMER_LABEL_SIZE];
+
+ __u8 send_nl_msg; /* unused: for compatibility with Android */
+ __u8 timer_type;
+
+ /* for kernel module internal use only */
+ struct idletimer_tg *timer __attribute__((aligned(8)));
+};
#endif
diff --git a/include/linux/netfilter/xt_sctp.h b/include/linux/netfilter/xt_sctp.h
index a501e619..5b28525a 100644
--- a/include/linux/netfilter/xt_sctp.h
+++ b/include/linux/netfilter/xt_sctp.h
@@ -40,19 +40,19 @@ struct xt_sctp_info {
#define SCTP_CHUNKMAP_SET(chunkmap, type) \
do { \
(chunkmap)[type / bytes(__u32)] |= \
- 1 << (type % bytes(__u32)); \
+ 1u << (type % bytes(__u32)); \
} while (0)
#define SCTP_CHUNKMAP_CLEAR(chunkmap, type) \
do { \
(chunkmap)[type / bytes(__u32)] &= \
- ~(1 << (type % bytes(__u32))); \
+ ~(1u << (type % bytes(__u32))); \
} while (0)
#define SCTP_CHUNKMAP_IS_SET(chunkmap, type) \
({ \
((chunkmap)[type / bytes (__u32)] & \
- (1 << (type % bytes (__u32)))) ? 1: 0; \
+ (1u << (type % bytes (__u32)))) ? 1: 0; \
})
#define SCTP_CHUNKMAP_RESET(chunkmap) \
diff --git a/include/xtables.h b/include/xtables.h
index 4aa084a1..df1eaee3 100644
--- a/include/xtables.h
+++ b/include/xtables.h
@@ -448,6 +448,7 @@ extern struct xtables_match *xtables_matches;
extern struct xtables_target *xtables_targets;
extern void xtables_init(void);
+extern void xtables_fini(void);
extern void xtables_set_nfproto(uint8_t);
extern void *xtables_calloc(size_t, size_t);
extern void *xtables_malloc(size_t);
@@ -556,6 +557,9 @@ extern void xtables_save_string(const char *value);
#define FMT(tab,notab) ((format) & FMT_NOTABLE ? (notab) : (tab))
extern void xtables_print_num(uint64_t number, unsigned int format);
+extern int xtables_parse_mac_and_mask(const char *from, void *to, void *mask);
+extern int xtables_print_well_known_mac_and_mask(const void *mac,
+ const void *mask);
extern void xtables_print_mac(const unsigned char *macaddress);
extern void xtables_print_mac_and_mask(const unsigned char *mac,
const unsigned char *mask);
diff --git a/iptables-test.py b/iptables-test.py
index fdb4e6a3..ca5efb1b 100755
--- a/iptables-test.py
+++ b/iptables-test.py
@@ -119,8 +119,7 @@ def run_test(iptables, rule, rule_save, res, filename, lineno, netns):
elif splitted[0] == EBTABLES:
command = EBTABLES_SAVE
- path = os.path.abspath(os.path.curdir) + "/iptables/" + EXECUTEABLE
- command = path + " " + command
+ command = EXECUTEABLE + " " + command
if netns:
command = "ip netns exec ____iptables-container-test " + command
@@ -165,7 +164,7 @@ def execute_cmd(cmd, filename, lineno):
'''
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
+ cmd = EXECUTEABLE + " " + cmd
print("command: {}".format(cmd), file=log_file)
ret = subprocess.call(cmd, shell=True, universal_newlines=True,
@@ -222,7 +221,7 @@ def run_test_file(filename, netns):
execute_cmd("ip netns add ____iptables-container-test", filename, 0)
for lineno, line in enumerate(f):
- if line[0] == "#":
+ if line[0] == "#" or len(line.strip()) == 0:
continue
if line[0] == ":":
@@ -311,7 +310,7 @@ def show_missing():
#
def main():
parser = argparse.ArgumentParser(description='Run iptables tests')
- parser.add_argument('filename', nargs='?',
+ parser.add_argument('filename', nargs='*',
metavar='path/to/file.t',
help='Run only this test')
parser.add_argument('-H', '--host', action='store_true',
@@ -360,13 +359,20 @@ def main():
return
if args.filename:
- file_list = [args.filename]
+ file_list = args.filename
else:
file_list = [os.path.join(EXTENSIONS_PATH, i)
for i in os.listdir(EXTENSIONS_PATH)
if i.endswith('.t')]
file_list.sort()
+ if not args.netns:
+ try:
+ import unshare
+ unshare.unshare(unshare.CLONE_NEWNET)
+ except:
+ print("Cannot run in own namespace, connectivity might break")
+
for filename in file_list:
file_tests, file_passed = run_test_file(filename, args.netns)
if file_tests:
diff --git a/iptables/Android.bp b/iptables/Android.bp
index 91bcb71f..7a23995e 100644
--- a/iptables/Android.bp
+++ b/iptables/Android.bp
@@ -1,3 +1,16 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "external_iptables_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Artistic
+ // SPDX-license-identifier-Artistic-2.0
+ // SPDX-license-identifier-GPL
+ // SPDX-license-identifier-GPL-2.0
+ // SPDX-license-identifier-LGPL
+ default_applicable_licenses: ["external_iptables_license"],
+}
+
cc_defaults {
name: "iptables_cmd_defaults",
defaults: ["iptables_defaults"],
@@ -65,6 +78,10 @@ cc_binary {
"ip6tables-save",
"ip6tables-restore",
],
+
+ sanitize: {
+ memtag_heap: true,
+ },
}
//----------------------------------------------------------------
diff --git a/iptables/Makefile.am b/iptables/Makefile.am
index fc834e0f..f7895210 100644
--- a/iptables/Makefile.am
+++ b/iptables/Makefile.am
@@ -38,7 +38,7 @@ xtables_nft_multi_SOURCES += xtables-save.c xtables-restore.c \
nft-shared.c nft-ipv4.c nft-ipv6.c nft-arp.c \
xtables-monitor.c nft-cache.c \
xtables-arp-standalone.c xtables-arp.c \
- nft-bridge.c \
+ nft-bridge.c nft-cmd.c nft-chain.c \
xtables-eb-standalone.c xtables-eb.c \
xtables-eb-translate.c \
xtables-translate.c
@@ -53,7 +53,11 @@ sbin_PROGRAMS += xtables-nft-multi
endif
man_MANS = iptables.8 iptables-restore.8 iptables-save.8 \
iptables-xml.1 ip6tables.8 ip6tables-restore.8 \
- ip6tables-save.8 iptables-extensions.8
+ ip6tables-save.8 iptables-extensions.8 \
+ iptables-apply.8 ip6tables-apply.8
+
+sbin_SCRIPTS = iptables-apply
+
if ENABLE_NFTABLES
man_MANS += xtables-nft.8 xtables-translate.8 xtables-legacy.8 \
iptables-translate.8 ip6tables-translate.8 \
@@ -63,6 +67,10 @@ man_MANS += xtables-nft.8 xtables-translate.8 xtables-legacy.8 \
ebtables-nft.8
endif
CLEANFILES = iptables.8 xtables-monitor.8 \
+ iptables-xml.1 iptables-apply.8 \
+ iptables-extensions.8 iptables-extensions.8.tmpl \
+ iptables-restore.8 iptables-save.8 \
+ iptables-restore-translate.8 ip6tables-restore-translate.8 \
iptables-translate.8 ip6tables-translate.8
vx_bin_links = iptables-xml
@@ -106,3 +114,27 @@ install-exec-hook:
for i in ${v4_sbin_links}; do ${LN_S} -f xtables-legacy-multi "${DESTDIR}${sbindir}/$$i"; done;
for i in ${v6_sbin_links}; do ${LN_S} -f xtables-legacy-multi "${DESTDIR}${sbindir}/$$i"; done;
for i in ${x_sbin_links}; do ${LN_S} -f xtables-nft-multi "${DESTDIR}${sbindir}/$$i"; done;
+ ${LN_S} -f iptables-apply "${DESTDIR}${sbindir}/ip6tables-apply"
+
+uninstall-hook:
+ dir=${DESTDIR}${bindir}; { \
+ test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; \
+ } || { \
+ test -z "${vx_bin_links}" || ( \
+ cd "$$dir" && rm -f ${vx_bin_links} \
+ ) \
+ }
+ dir=${DESTDIR}${sbindir}; { \
+ test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; \
+ } || { \
+ test -z "${v4_sbin_links}" || ( \
+ cd "$$dir" && rm -f ${v4_sbin_links} \
+ ); \
+ test -z "${v6_sbin_links}" || ( \
+ cd "$$dir" && rm -f ${v6_sbin_links} \
+ ); \
+ test -z "${x_sbin_links}" || ( \
+ cd "$$dir" && rm -f ${x_sbin_links} \
+ ); \
+ ( cd "$$dir" && rm -f ip6tables-apply ); \
+ }
diff --git a/iptables/ebtables-nft.8 b/iptables/ebtables-nft.8
index a91f0c1a..1fa5ad93 100644
--- a/iptables/ebtables-nft.8
+++ b/iptables/ebtables-nft.8
@@ -551,10 +551,6 @@ Same as
.BR "--among-src-file " "[!] \fIfile\fP"
Same as
.BR --among-src " but the list is read in from the specified file."
-.PP
-Note that in this implementation of ebtables, among lists uses must be
-internally homogeneous regarding whether IP addresses are present or not. Mixed
-use of MAC addresses and MAC/IP address pairs is not supported yet.
.SS arp
Specify (R)ARP fields. The protocol must be specified as
.IR ARP " or " RARP .
diff --git a/iptables/ip6tables-apply.8 b/iptables/ip6tables-apply.8
new file mode 100644
index 00000000..994b487a
--- /dev/null
+++ b/iptables/ip6tables-apply.8
@@ -0,0 +1 @@
+.so man8/iptables-apply.8
diff --git a/iptables/ip6tables-standalone.c b/iptables/ip6tables-standalone.c
index 35d2d9a5..105b83ba 100644
--- a/iptables/ip6tables-standalone.c
+++ b/iptables/ip6tables-standalone.c
@@ -64,6 +64,8 @@ ip6tables_main(int argc, char *argv[])
ip6tc_free(handle);
}
+ xtables_fini();
+
if (!ret) {
if (errno == EINVAL) {
fprintf(stderr, "ip6tables: %s. "
diff --git a/iptables/ip6tables.c b/iptables/ip6tables.c
index 576c2cf8..c95355b0 100644
--- a/iptables/ip6tables.c
+++ b/iptables/ip6tables.c
@@ -45,10 +45,6 @@
#include "ip6tables-multi.h"
#include "xshared.h"
-#define NUMBER_OF_OPT ARRAY_SIZE(optflags)
-static const char optflags[]
-= { 'n', 's', 'd', 'p', 'j', 'v', 'x', 'i', 'o', '0', 'c'};
-
static const char unsupported_rev[] = " [unsupported revision]";
static struct option original_opts[] = {
@@ -100,36 +96,6 @@ struct xtables_globals ip6tables_globals = {
.compat_rev = xtables_compatible_revision,
};
-/* Table of legal combinations of commands and options. If any of the
- * given commands make an option legal, that option is legal (applies to
- * CMD_LIST and CMD_ZERO only).
- * Key:
- * + compulsory
- * x illegal
- * optional
- */
-
-static const char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] =
-/* Well, it's better than "Re: Linux vs FreeBSD" */
-{
- /* -n -s -d -p -j -v -x -i -o --line -c */
-/*INSERT*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' '},
-/*DELETE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x','x'},
-/*DELETE_NUM*/{'x','x','x','x','x',' ','x','x','x','x','x'},
-/*REPLACE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' '},
-/*APPEND*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' '},
-/*LIST*/ {' ','x','x','x','x',' ',' ','x','x',' ','x'},
-/*FLUSH*/ {'x','x','x','x','x',' ','x','x','x','x','x'},
-/*ZERO*/ {'x','x','x','x','x',' ','x','x','x','x','x'},
-/*NEW_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x'},
-/*DEL_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x'},
-/*SET_POLICY*/{'x','x','x','x','x',' ','x','x','x','x',' '},
-/*RENAME*/ {'x','x','x','x','x',' ','x','x','x','x','x'},
-/*LIST_RULES*/{'x','x','x','x','x',' ','x','x','x','x','x'},
-/*ZERO_NUM*/ {'x','x','x','x','x',' ','x','x','x','x','x'},
-/*CHECK*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x','x'},
-};
-
static const unsigned int inverse_for_options[NUMBER_OF_OPT] =
{
/* -n */ 0,
@@ -264,51 +230,6 @@ ip6tables_exit_error(enum xtables_exittype status, const char *msg, ...)
exit(status);
}
-static void
-generic_opt_check(int command, int options)
-{
- int i, j, legal = 0;
-
- /* Check that commands are valid with options. Complicated by the
- * fact that if an option is legal with *any* command given, it is
- * legal overall (ie. -z and -l).
- */
- for (i = 0; i < NUMBER_OF_OPT; i++) {
- legal = 0; /* -1 => illegal, 1 => legal, 0 => undecided. */
-
- for (j = 0; j < NUMBER_OF_CMD; j++) {
- if (!(command & (1<<j)))
- continue;
-
- if (!(options & (1<<i))) {
- if (commands_v_options[j][i] == '+')
- xtables_error(PARAMETER_PROBLEM,
- "You need to supply the `-%c' "
- "option for this command\n",
- optflags[i]);
- } else {
- if (commands_v_options[j][i] != 'x')
- legal = 1;
- else if (legal == 0)
- legal = -1;
- }
- }
- if (legal == -1)
- xtables_error(PARAMETER_PROBLEM,
- "Illegal option `-%c' with this command\n",
- optflags[i]);
- }
-}
-
-static char
-opt2char(int option)
-{
- const char *ptr;
- for (ptr = optflags; option > 1; option >>= 1, ptr++);
-
- return *ptr;
-}
-
/*
* All functions starting with "parse" should succeed, otherwise
* the program fails.
diff --git a/iptables/iptables-apply b/iptables/iptables-apply
index 819ca4a4..4683b1b4 100755
--- a/iptables/iptables-apply
+++ b/iptables/iptables-apply
@@ -1,174 +1,294 @@
#!/bin/bash
-#
# iptables-apply -- a safer way to update iptables remotely
#
-# Copyright © Martin F. Krafft <madduck@madduck.net>
+# Usage:
+# iptables-apply [-hV] [-t timeout] [-w savefile] {[rulesfile]|-c [runcmd]}
+#
+# Versions:
+# * 1.0 Copyright 2006 Martin F. Krafft <madduck@madduck.net>
+# Original version
+# * 1.1 Copyright 2010 GW <gw.2010@tnode.com or http://gw.tnode.com/>
+# Added parameter -c (run command)
+# Added parameter -w (save successfully applied rules to file)
+# Major code cleanup
+#
# Released under the terms of the Artistic Licence 2.0
#
set -eu
-PROGNAME="${0##*/}";
-VERSION=1.0
+PROGNAME="${0##*/}"
+VERSION=1.1
+
+
+### Default settings
+
+DEF_TIMEOUT=10
+
+MODE=0 # apply rulesfile mode
+# MODE=1 # run command mode
+
+case "$PROGNAME" in
+ (*6*)
+ SAVE=ip6tables-save
+ RESTORE=ip6tables-restore
+ DEF_RULESFILE="/etc/network/ip6tables.up.rules"
+ DEF_SAVEFILE="$DEF_RULESFILE"
+ DEF_RUNCMD="/etc/network/ip6tables.up.run"
+ ;;
+ (*)
+ SAVE=iptables-save
+ RESTORE=iptables-restore
+ DEF_RULESFILE="/etc/network/iptables.up.rules"
+ DEF_SAVEFILE="$DEF_RULESFILE"
+ DEF_RUNCMD="/etc/network/iptables.up.run"
+ ;;
+esac
+
-TIMEOUT=10
+### Functions
-function blurb()
-{
- cat <<-_eof
+function blurb() {
+ cat <<-__EOF__
$PROGNAME $VERSION -- a safer way to update iptables remotely
- _eof
+ __EOF__
}
-function copyright()
-{
- cat <<-_eof
- $PROGNAME is C Martin F. Krafft <madduck@madduck.net>.
+function copyright() {
+ cat <<-__EOF__
+ $PROGNAME has been published under the terms of the Artistic Licence 2.0.
- The program has been published under the terms of the Artistic Licence 2.0
- _eof
+ Original version - Copyright 2006 Martin F. Krafft <madduck@madduck.net>.
+ Version 1.1 - Copyright 2010 GW <gw.2010@tnode.com or http://gw.tnode.com/>.
+ __EOF__
}
-function about()
-{
+function about() {
blurb
echo
copyright
}
-function usage()
-{
- cat <<-_eof
- Usage: $PROGNAME [options] ruleset
+function usage() {
+ blurb
+ echo
+ cat <<-__EOF__
+ Usage:
+ $PROGNAME [-hV] [-t timeout] [-w savefile] {[rulesfile]|-c [runcmd]}
+
+ The script will try to apply a new rulesfile (as output by iptables-save,
+ read by iptables-restore) or run a command to configure iptables and then
+ prompt the user whether the changes are okay. If the new iptables rules cut
+ the existing connection, the user will not be able to answer affirmatively.
+ In this case, the script rolls back to the previous working iptables rules
+ after the timeout expires.
+
+ Successfully applied rules can also be written to savefile and later used
+ to roll back to this state. This can be used to implement a store last good
+ configuration mechanism when experimenting with an iptables setup script:
+ $PROGNAME -w $DEF_SAVEFILE -c $DEF_RUNCMD
- The script will try to apply a new ruleset (as output by iptables-save/read
- by iptables-restore) to iptables, then prompt the user whether the changes
- are okay. If the new ruleset cut the existing connection, the user will not
- be able to answer affirmatively. In this case, the script rolls back to the
- previous ruleset.
+ When called as ip6tables-apply, the script will use ip6tables-save/-restore
+ and IPv6 default values instead. Default value for rulesfile is
+ '$DEF_RULESFILE'.
+
+ Options:
+
+ -t seconds, --timeout seconds
+ Specify the timeout in seconds (default: $DEF_TIMEOUT).
+ -w savefile, --write savefile
+ Specify the savefile where successfully applied rules will be written to
+ (default if empty string is given: $DEF_SAVEFILE).
+ -c runcmd, --command runcmd
+ Run command runcmd to configure iptables instead of applying a rulesfile
+ (default: $DEF_RUNCMD).
+ -h, --help
+ Display this help text.
+ -V, --version
+ Display version information.
+
+ __EOF__
+}
- The following options may be specified, using standard conventions:
+function checkcommands() {
+ for cmd in "${COMMANDS[@]}"; do
+ if ! command -v "$cmd" >/dev/null; then
+ echo "Error: needed command not found: $cmd" >&2
+ exit 127
+ fi
+ done
+}
- -t | --timeout Specify the timeout in seconds (default: $TIMEOUT)
- -V | --version Display version information
- -h | --help Display this help text
- _eof
+function revertrules() {
+ echo -n "Reverting to old iptables rules... "
+ "$RESTORE" <"$TMPFILE"
+ echo "done."
}
-SHORTOPTS="t:Vh";
-LONGOPTS="timeout:,version,help";
+
+### Parsing and checking parameters
+
+TIMEOUT="$DEF_TIMEOUT"
+SAVEFILE=""
+
+SHORTOPTS="t:w:chV";
+LONGOPTS="timeout:,write:,command,help,version";
OPTS=$(getopt -s bash -o "$SHORTOPTS" -l "$LONGOPTS" -n "$PROGNAME" -- "$@") || exit $?
for opt in $OPTS; do
case "$opt" in
- (-*) unset OPT_STATE;;
+ (-*)
+ unset OPT_STATE
+ ;;
(*)
case "${OPT_STATE:-}" in
- (SET_TIMEOUT)
- eval TIMEOUT=$opt
- case "$TIMEOUT" in
- ([0-9]*) :;;
- (*)
- echo "E: non-numeric timeout value." >&2
- exit 1
- ;;
- esac
+ (SET_TIMEOUT) eval TIMEOUT=$opt;;
+ (SET_SAVEFILE)
+ eval SAVEFILE=$opt
+ [ -z "$SAVEFILE" ] && SAVEFILE="$DEF_SAVEFILE"
;;
esac
;;
esac
case "$opt" in
+ (-t|--timeout) OPT_STATE="SET_TIMEOUT";;
+ (-w|--write) OPT_STATE="SET_SAVEFILE";;
+ (-c|--command) MODE=1;;
(-h|--help) usage >&2; exit 0;;
(-V|--version) about >&2; exit 0;;
- (-t|--timeout) OPT_STATE=SET_TIMEOUT;;
(--) break;;
esac
shift
done
-case "$PROGNAME" in
- (*6*)
- SAVE=ip6tables-save
- RESTORE=ip6tables-restore
- DEFAULT_FILE=/etc/network/ip6tables
- ;;
- (*)
- SAVE=iptables-save
- RESTORE=iptables-restore
- DEFAULT_FILE=/etc/network/iptables
- ;;
-esac
-
-FILE="${1:-$DEFAULT_FILE}";
-
-if [[ -z "$FILE" ]]; then
- echo "E: missing file argument." >&2
+# Validate parameters
+if [ "$TIMEOUT" -ge 0 ] 2>/dev/null; then
+ TIMEOUT=$(($TIMEOUT))
+else
+ echo "Error: timeout must be a positive number" >&2
exit 1
fi
-if [[ ! -r "$FILE" ]]; then
- echo "E: cannot read $FILE" >&2
- exit 2
+if [ -n "$SAVEFILE" -a -e "$SAVEFILE" -a ! -w "$SAVEFILE" ]; then
+ echo "Error: savefile not writable: $SAVEFILE" >&2
+ exit 8
fi
-COMMANDS=(tempfile "$SAVE" "$RESTORE")
+case "$MODE" in
+ (1)
+ # Treat parameter as runcmd (run command mode)
+ RUNCMD="${1:-$DEF_RUNCMD}"
+ if [ ! -x "$RUNCMD" ]; then
+ echo "Error: runcmd not executable: $RUNCMD" >&2
+ exit 6
+ fi
+
+ # Needed commands
+ COMMANDS=(mktemp "$SAVE" "$RESTORE" "$RUNCMD")
+ checkcommands
+ ;;
+ (*)
+ # Treat parameter as rulesfile (apply rulesfile mode)
+ RULESFILE="${1:-$DEF_RULESFILE}";
+ if [ ! -r "$RULESFILE" ]; then
+ echo "Error: rulesfile not readable: $RULESFILE" >&2
+ exit 2
+ fi
+
+ # Needed commands
+ COMMANDS=(mktemp "$SAVE" "$RESTORE")
+ checkcommands
+ ;;
+esac
-for cmd in "${COMMANDS[@]}"; do
- if ! command -v $cmd >/dev/null; then
- echo "E: command not found: $cmd" >&2
- exit 127
- fi
-done
-umask 0700
+### Begin work
-TMPFILE=$(tempfile -p iptap)
+# Store old iptables rules to temporary file
+TMPFILE=`mktemp /tmp/$PROGNAME-XXXXXXXX`
trap "rm -f $TMPFILE" EXIT HUP INT QUIT ILL TRAP ABRT BUS \
FPE USR1 SEGV USR2 PIPE ALRM TERM
if ! "$SAVE" >"$TMPFILE"; then
+ # An error occured
if ! grep -q ipt /proc/modules 2>/dev/null; then
- echo "E: iptables support lacking from the kernel." >&2
+ echo "Error: iptables support lacking from the kernel" >&2
exit 3
else
- echo "E: unknown error saving current iptables ruleset." >&2
+ echo "Error: unknown error saving old iptables rules: $TMPFILE" >&2
exit 4
fi
fi
+# Legacy to stop the fail2ban daemon if present
[ -x /etc/init.d/fail2ban ] && /etc/init.d/fail2ban stop
-echo -n "Applying new ruleset... "
-if ! "$RESTORE" <"$FILE"; then
- echo "failed."
- echo "E: unknown error applying new iptables ruleset." >&2
- exit 5
-else
- echo "done."
-fi
+# Configure iptables
+case "$MODE" in
+ (1)
+ # Run command in background and kill it if it times out
+ echo -n "Running command '$RUNCMD'... "
+ "$RUNCMD" &
+ CMD_PID=$!
+ ( sleep "$TIMEOUT"; kill "$CMD_PID" 2>/dev/null; exit 0 ) &
+ CMDTIMEOUT_PID=$!
+ if ! wait "$CMD_PID"; then
+ echo "failed."
+ echo "Error: unknown error running command: $RUNCMD" >&2
+ revertrules
+ exit 7
+ else
+ echo "done."
+ fi
+ ;;
+ (*)
+ # Apply iptables rulesfile
+ echo -n "Applying new iptables rules from '$RULESFILE'... "
+ if ! "$RESTORE" <"$RULESFILE"; then
+ echo "failed."
+ echo "Error: unknown error applying new iptables rules: $RULESFILE" >&2
+ revertrules
+ exit 5
+ else
+ echo "done."
+ fi
+ ;;
+esac
+# Prompt user for confirmation
echo -n "Can you establish NEW connections to the machine? (y/N) "
-read -n1 -t "${TIMEOUT:-15}" ret 2>&1 || :
+read -n1 -t "$TIMEOUT" ret 2>&1 || :
case "${ret:-}" in
(y*|Y*)
+ # Success
echo
+
+ if [ ! -z "$SAVEFILE" ]; then
+ # Write successfully applied rules to the savefile
+ echo "Writing successfully applied rules to '$SAVEFILE'..."
+ if ! "$SAVE" >"$SAVEFILE"; then
+ echo "Error: unknown error writing successfully applied rules: $SAVEFILE" >&2
+ exit 9
+ fi
+ fi
+
echo "... then my job is done. See you next time."
;;
(*)
- if [[ -z "${ret:-}" ]]; then
- echo "apparently not..."
+ # Failed
+ echo
+ if [ -z "${ret:-}" ]; then
+ echo "Timeout! Something happened (or did not). Better play it safe..."
else
- echo
+ echo "No affirmative response! Better play it safe..."
fi
- echo "Timeout. Something happened (or did not). Better play it safe..."
- echo -n "Reverting to old ruleset... "
- "$RESTORE" <"$TMPFILE";
- echo "done."
+ revertrules
exit 255
;;
esac
+# Legacy to start the fail2ban daemon again
[ -x /etc/init.d/fail2ban ] && /etc/init.d/fail2ban start
exit 0
diff --git a/iptables/iptables-apply.8.in b/iptables/iptables-apply.8.in
index cdc9c447..f0ed4e5f 100644
--- a/iptables/iptables-apply.8.in
+++ b/iptables/iptables-apply.8.in
@@ -1,6 +1,6 @@
.\" Title: iptables-apply
-.\" Author: Martin F. Krafft
-.\" Date: Jun 04, 2006
+.\" Author: Martin F. Krafft, GW
+.\" Date: May 10, 2010
.\"
.TH IPTABLES\-APPLY 8 "" "@PACKAGE_STRING@" "@PACKAGE_STRING@"
.\" disable hyphenation
@@ -8,23 +8,37 @@
.SH NAME
iptables-apply \- a safer way to update iptables remotely
.SH SYNOPSIS
-\fBiptables\-apply\fP [\-\fBhV\fP] [\fB-t\fP \fItimeout\fP] \fIruleset\-file\fP
+\fBiptables\-apply\fP [\-\fBhV\fP] [\fB-t\fP \fItimeout\fP] [\fB-w\fP \fIsavefile\fP] {[\fIrulesfile]|-c [runcmd]}\fP
.SH "DESCRIPTION"
.PP
-iptables\-apply will try to apply a new ruleset (as output by
-iptables\-save/read by iptables\-restore) to iptables, then prompt the
-user whether the changes are okay. If the new ruleset cut the existing
-connection, the user will not be able to answer affirmatively. In this
-case, the script rolls back to the previous ruleset after the timeout
-expired. The timeout can be set with \fB\-t\fP.
+iptables\-apply will try to apply a new rulesfile (as output by
+iptables-save, read by iptables-restore) or run a command to configure
+iptables and then prompt the user whether the changes are okay. If the
+new iptables rules cut the existing connection, the user will not be
+able to answer affirmatively. In this case, the script rolls back to
+the previous working iptables rules after the timeout expires.
.PP
-When called as \fBip6tables\-apply\fP, the script will use
-ip6tables\-save/\-restore instead.
+Successfully applied rules can also be written to savefile and later used
+to roll back to this state. This can be used to implement a store last good
+configuration mechanism when experimenting with an iptables setup script:
+iptables-apply \-w /etc/network/iptables.up.rules \-c /etc/network/iptables.up.run
+.PP
+When called as ip6tables\-apply, the script will use
+ip6tables\-save/\-restore and IPv6 default values instead. Default
+value for rulesfile is '/etc/network/iptables.up.rules'.
.SH OPTIONS
.TP
\fB\-t\fP \fIseconds\fR, \fB\-\-timeout\fP \fIseconds\fR
-Sets the timeout after which the script will roll back to the previous
-ruleset.
+Sets the timeout in seconds after which the script will roll back
+to the previous ruleset (default: 10).
+.TP
+\fB\-w\fP \fIsavefile\fR, \fB\-\-write\fP \fIsavefile\fR
+Specify the savefile where successfully applied rules will be written to
+(default if empty string is given: /etc/network/iptables.up.rules).
+.TP
+\fB\-c\fP \fIruncmd\fR, \fB\-\-command\fP \fIruncmd\fR
+Run command runcmd to configure iptables instead of applying a rulesfile
+(default: /etc/network/iptables.up.run).
.TP
\fB\-h\fP, \fB\-\-help\fP
Display usage information.
@@ -36,9 +50,11 @@ Display version information.
\fBiptables-restore\fP(8), \fBiptables-save\fP(8), \fBiptables\fR(8).
.SH LEGALESE
.PP
-iptables\-apply is copyright by Martin F. Krafft.
+Original iptables-apply - Copyright 2006 Martin F. Krafft <madduck@madduck.net>.
+Version 1.1 - Copyright 2010 GW <gw.2010@tnode.com or http://gw.tnode.com/>.
.PP
-This manual page was written by Martin F. Krafft <madduck@madduck.net>
+This manual page was written by Martin F. Krafft <madduck@madduck.net> and
+extended by GW <gw.2010@tnode.com or http://gw.tnode.com/>.
.PP
Permission is granted to copy, distribute and/or modify this document
under the terms of the Artistic License 2.0.
diff --git a/iptables/iptables-restore.8.in b/iptables/iptables-restore.8.in
index f751492d..b4b62f92 100644
--- a/iptables/iptables-restore.8.in
+++ b/iptables/iptables-restore.8.in
@@ -87,7 +87,7 @@ from Rusty Russell.
.br
Andras Kis-Szabo <kisza@sch.bme.hu> contributed ip6tables-restore.
.SH SEE ALSO
-\fBiptables\-save\fP(8), \fBiptables\fP(8)
+\fBiptables\-apply\fP(8),\fBiptables\-save\fP(8), \fBiptables\fP(8)
.PP
The iptables-HOWTO, which details more iptables usage, the NAT-HOWTO,
which details NAT, and the netfilter-hacking-HOWTO which details the
diff --git a/iptables/iptables-restore.c b/iptables/iptables-restore.c
index fea04842..cc2c2b8b 100644
--- a/iptables/iptables-restore.c
+++ b/iptables/iptables-restore.c
@@ -372,7 +372,7 @@ static const struct iptables_restore_cb ipt_restore_cb = {
int
iptables_restore_main(int argc, char *argv[])
{
- int c;
+ int c, ret;
iptables_globals.program_name = "iptables-restore";
c = xtables_init_all(&iptables_globals, NFPROTO_IPV4);
@@ -387,7 +387,10 @@ iptables_restore_main(int argc, char *argv[])
init_extensions4();
#endif
- return ip46tables_restore_main(&ipt_restore_cb, argc, argv);
+ ret = ip46tables_restore_main(&ipt_restore_cb, argc, argv);
+
+ xtables_fini();
+ return ret;
}
#endif
@@ -403,7 +406,7 @@ static const struct iptables_restore_cb ip6t_restore_cb = {
int
ip6tables_restore_main(int argc, char *argv[])
{
- int c;
+ int c, ret;
ip6tables_globals.program_name = "ip6tables-restore";
c = xtables_init_all(&ip6tables_globals, NFPROTO_IPV6);
@@ -418,6 +421,9 @@ ip6tables_restore_main(int argc, char *argv[])
init_extensions6();
#endif
- return ip46tables_restore_main(&ip6t_restore_cb, argc, argv);
+ ret = ip46tables_restore_main(&ip6t_restore_cb, argc, argv);
+
+ xtables_fini();
+ return ret;
}
#endif
diff --git a/iptables/iptables-save.8.in b/iptables/iptables-save.8.in
index 29ef2829..7683fd37 100644
--- a/iptables/iptables-save.8.in
+++ b/iptables/iptables-save.8.in
@@ -62,7 +62,7 @@ Rusty Russell <rusty@rustcorp.com.au>
.br
Andras Kis-Szabo <kisza@sch.bme.hu> contributed ip6tables-save.
.SH SEE ALSO
-\fBiptables\-restore\fP(8), \fBiptables\fP(8)
+\fBiptables\-apply\fP(8),\fBiptables\-restore\fP(8), \fBiptables\fP(8)
.PP
The iptables-HOWTO, which details more iptables usage, the NAT-HOWTO,
which details NAT, and the netfilter-hacking-HOWTO which details the
diff --git a/iptables/iptables-save.c b/iptables/iptables-save.c
index c7251e35..4efd6667 100644
--- a/iptables/iptables-save.c
+++ b/iptables/iptables-save.c
@@ -218,6 +218,8 @@ struct iptables_save_cb ipt_save_cb = {
int
iptables_save_main(int argc, char *argv[])
{
+ int ret;
+
iptables_globals.program_name = "iptables-save";
if (xtables_init_all(&iptables_globals, NFPROTO_IPV4) < 0) {
fprintf(stderr, "%s/%s Failed to initialize xtables\n",
@@ -230,7 +232,10 @@ iptables_save_main(int argc, char *argv[])
init_extensions4();
#endif
- return do_iptables_save(&ipt_save_cb, argc, argv);
+ ret = do_iptables_save(&ipt_save_cb, argc, argv);
+
+ xtables_fini();
+ return ret;
}
#endif /* ENABLE_IPV4 */
@@ -259,6 +264,8 @@ struct iptables_save_cb ip6t_save_cb = {
int
ip6tables_save_main(int argc, char *argv[])
{
+ int ret;
+
ip6tables_globals.program_name = "ip6tables-save";
if (xtables_init_all(&ip6tables_globals, NFPROTO_IPV6) < 0) {
fprintf(stderr, "%s/%s Failed to initialize xtables\n",
@@ -271,6 +278,9 @@ ip6tables_save_main(int argc, char *argv[])
init_extensions6();
#endif
- return do_iptables_save(&ip6t_save_cb, argc, argv);
+ ret = do_iptables_save(&ip6t_save_cb, argc, argv);
+
+ xtables_fini();
+ return ret;
}
#endif /* ENABLE_IPV6 */
diff --git a/iptables/iptables-standalone.c b/iptables/iptables-standalone.c
index 3a4d5e37..3c8af60d 100644
--- a/iptables/iptables-standalone.c
+++ b/iptables/iptables-standalone.c
@@ -67,6 +67,8 @@ iptables_main(int argc, char *argv[])
iptc_free(handle);
}
+ xtables_fini();
+
if (!ret) {
if (errno == EINVAL) {
fprintf(stderr, "iptables: %s. "
diff --git a/iptables/iptables.8.in b/iptables/iptables.8.in
index 78df8f08..999cf339 100644
--- a/iptables/iptables.8.in
+++ b/iptables/iptables.8.in
@@ -245,13 +245,13 @@ add, delete, insert, replace and append commands).
This option has no effect in iptables and iptables-restore.
If a rule using the \fB\-4\fP option is inserted with (and only with)
ip6tables-restore, it will be silently ignored. Any other uses will throw an
-error. This option allows to put both IPv4 and IPv6 rules in a single rule file
+error. This option allows IPv4 and IPv6 rules in a single rule file
for use with both iptables-restore and ip6tables-restore.
.TP
\fB\-6\fP, \fB\-\-ipv6\fP
If a rule using the \fB\-6\fP option is inserted with (and only with)
iptables-restore, it will be silently ignored. Any other uses will throw an
-error. This option allows to put both IPv4 and IPv6 rules in a single rule file
+error. This option allows IPv4 and IPv6 rules in a single rule file
for use with both iptables-restore and ip6tables-restore.
This option has no effect in ip6tables and ip6tables-restore.
.TP
@@ -397,6 +397,14 @@ corresponding to that rule's position in the chain.
\fB\-\-modprobe=\fP\fIcommand\fP
When adding or inserting rules into a chain, use \fIcommand\fP
to load any necessary modules (targets, match extensions, etc).
+
+.SH LOCK FILE
+iptables uses the \fI@XT_LOCK_NAME@\fP file to take an exclusive lock at
+launch.
+
+The \fBXTABLES_LOCKFILE\fP environment variable can be used to override
+the default setting.
+
.SH MATCH AND TARGET EXTENSIONS
.PP
iptables can use extended packet matching and target modules.
diff --git a/iptables/iptables.c b/iptables/iptables.c
index 88ef6cf6..7d618311 100644
--- a/iptables/iptables.c
+++ b/iptables/iptables.c
@@ -41,11 +41,6 @@
#include <fcntl.h>
#include "xshared.h"
-#define OPT_FRAGMENT 0x00800U
-#define NUMBER_OF_OPT ARRAY_SIZE(optflags)
-static const char optflags[]
-= { 'n', 's', 'd', 'p', 'j', 'v', 'x', 'i', 'o', '0', 'c', 'f'};
-
static const char unsupported_rev[] = " [unsupported revision]";
static struct option original_opts[] = {
@@ -99,36 +94,6 @@ struct xtables_globals iptables_globals = {
.compat_rev = xtables_compatible_revision,
};
-/* Table of legal combinations of commands and options. If any of the
- * given commands make an option legal, that option is legal (applies to
- * CMD_LIST and CMD_ZERO only).
- * Key:
- * + compulsory
- * x illegal
- * optional
- */
-
-static const char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] =
-/* Well, it's better than "Re: Linux vs FreeBSD" */
-{
- /* -n -s -d -p -j -v -x -i -o --line -c -f */
-/*INSERT*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' ',' '},
-/*DELETE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x','x',' '},
-/*DELETE_NUM*/{'x','x','x','x','x',' ','x','x','x','x','x','x'},
-/*REPLACE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' ',' '},
-/*APPEND*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' ',' '},
-/*LIST*/ {' ','x','x','x','x',' ',' ','x','x',' ','x','x'},
-/*FLUSH*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
-/*ZERO*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
-/*NEW_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
-/*DEL_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
-/*SET_POLICY*/{'x','x','x','x','x',' ','x','x','x','x',' ','x'},
-/*RENAME*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
-/*LIST_RULES*/{'x','x','x','x','x',' ','x','x','x','x','x','x'},
-/*ZERO_NUM*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
-/*CHECK*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x','x',' '},
-};
-
static const int inverse_for_options[NUMBER_OF_OPT] =
{
/* -n */ 0,
@@ -263,51 +228,6 @@ iptables_exit_error(enum xtables_exittype status, const char *msg, ...)
exit(status);
}
-static void
-generic_opt_check(int command, int options)
-{
- int i, j, legal = 0;
-
- /* Check that commands are valid with options. Complicated by the
- * fact that if an option is legal with *any* command given, it is
- * legal overall (ie. -z and -l).
- */
- for (i = 0; i < NUMBER_OF_OPT; i++) {
- legal = 0; /* -1 => illegal, 1 => legal, 0 => undecided. */
-
- for (j = 0; j < NUMBER_OF_CMD; j++) {
- if (!(command & (1<<j)))
- continue;
-
- if (!(options & (1<<i))) {
- if (commands_v_options[j][i] == '+')
- xtables_error(PARAMETER_PROBLEM,
- "You need to supply the `-%c' "
- "option for this command\n",
- optflags[i]);
- } else {
- if (commands_v_options[j][i] != 'x')
- legal = 1;
- else if (legal == 0)
- legal = -1;
- }
- }
- if (legal == -1)
- xtables_error(PARAMETER_PROBLEM,
- "Illegal option `-%c' with this command\n",
- optflags[i]);
- }
-}
-
-static char
-opt2char(int option)
-{
- const char *ptr;
- for (ptr = optflags; option > 1; option >>= 1, ptr++);
-
- return *ptr;
-}
-
/*
* All functions starting with "parse" should succeed, otherwise
* the program fails.
diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c
index d4a86610..c82ffdc9 100644
--- a/iptables/nft-arp.c
+++ b/iptables/nft-arp.c
@@ -134,34 +134,34 @@ static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
int ret = 0;
if (fw->arp.iniface[0] != '\0') {
- op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_VIA_IN);
+ op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_VIA_IN);
add_iniface(r, fw->arp.iniface, op);
}
if (fw->arp.outiface[0] != '\0') {
- op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_VIA_OUT);
+ op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_VIA_OUT);
add_outiface(r, fw->arp.outiface, op);
}
if (fw->arp.arhrd != 0 ||
- fw->arp.invflags & ARPT_INV_ARPHRD) {
- op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_ARPHRD);
+ fw->arp.invflags & IPT_INV_ARPHRD) {
+ op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_ARPHRD);
add_payload(r, offsetof(struct arphdr, ar_hrd), 2,
NFT_PAYLOAD_NETWORK_HEADER);
add_cmp_u16(r, fw->arp.arhrd, op);
}
if (fw->arp.arpro != 0 ||
- fw->arp.invflags & ARPT_INV_ARPPRO) {
- op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_ARPPRO);
+ fw->arp.invflags & IPT_INV_PROTO) {
+ op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_PROTO);
add_payload(r, offsetof(struct arphdr, ar_pro), 2,
NFT_PAYLOAD_NETWORK_HEADER);
add_cmp_u16(r, fw->arp.arpro, op);
}
if (fw->arp.arhln != 0 ||
- fw->arp.invflags & ARPT_INV_ARPHLN) {
- op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_ARPHLN);
+ fw->arp.invflags & IPT_INV_ARPHLN) {
+ op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_ARPHLN);
add_proto(r, offsetof(struct arphdr, ar_hln), 1,
fw->arp.arhln, op);
}
@@ -169,16 +169,17 @@ static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
add_proto(r, offsetof(struct arphdr, ar_pln), 1, 4, NFT_CMP_EQ);
if (fw->arp.arpop != 0 ||
- fw->arp.invflags & ARPT_INV_ARPOP) {
- op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_ARPOP);
+ fw->arp.invflags & IPT_INV_ARPOP) {
+ op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_ARPOP);
add_payload(r, offsetof(struct arphdr, ar_op), 2,
NFT_PAYLOAD_NETWORK_HEADER);
add_cmp_u16(r, fw->arp.arpop, op);
}
if (need_devaddr(&fw->arp.src_devaddr)) {
- op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_SRCDEVADDR);
- add_addr(r, sizeof(struct arphdr),
+ op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_SRCDEVADDR);
+ add_addr(r, NFT_PAYLOAD_NETWORK_HEADER,
+ sizeof(struct arphdr),
&fw->arp.src_devaddr.addr,
&fw->arp.src_devaddr.mask,
fw->arp.arhln, op);
@@ -187,17 +188,19 @@ static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
if (fw->arp.src.s_addr != 0 ||
fw->arp.smsk.s_addr != 0 ||
- fw->arp.invflags & ARPT_INV_SRCIP) {
- op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_SRCIP);
- add_addr(r, sizeof(struct arphdr) + fw->arp.arhln,
+ fw->arp.invflags & IPT_INV_SRCIP) {
+ op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_SRCIP);
+ add_addr(r, NFT_PAYLOAD_NETWORK_HEADER,
+ sizeof(struct arphdr) + fw->arp.arhln,
&fw->arp.src.s_addr, &fw->arp.smsk.s_addr,
sizeof(struct in_addr), op);
}
if (need_devaddr(&fw->arp.tgt_devaddr)) {
- op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_TGTDEVADDR);
- add_addr(r, sizeof(struct arphdr) + fw->arp.arhln + sizeof(struct in_addr),
+ op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_TGTDEVADDR);
+ add_addr(r, NFT_PAYLOAD_NETWORK_HEADER,
+ sizeof(struct arphdr) + fw->arp.arhln + sizeof(struct in_addr),
&fw->arp.tgt_devaddr.addr,
&fw->arp.tgt_devaddr.mask,
fw->arp.arhln, op);
@@ -205,9 +208,10 @@ static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
if (fw->arp.tgt.s_addr != 0 ||
fw->arp.tmsk.s_addr != 0 ||
- fw->arp.invflags & ARPT_INV_TGTIP) {
- op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_TGTIP);
- add_addr(r, sizeof(struct arphdr) + fw->arp.arhln + sizeof(struct in_addr) + fw->arp.arhln,
+ fw->arp.invflags & IPT_INV_DSTIP) {
+ op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_DSTIP);
+ add_addr(r, NFT_PAYLOAD_NETWORK_HEADER,
+ sizeof(struct arphdr) + fw->arp.arhln + sizeof(struct in_addr) + fw->arp.arhln,
&fw->arp.tgt.s_addr, &fw->arp.tmsk.s_addr,
sizeof(struct in_addr), op);
}
@@ -236,28 +240,6 @@ static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
return ret;
}
-static uint16_t ipt_to_arpt_flags(uint8_t invflags)
-{
- uint16_t result = 0;
-
- if (invflags & IPT_INV_VIA_IN)
- result |= ARPT_INV_VIA_IN;
-
- if (invflags & IPT_INV_VIA_OUT)
- result |= ARPT_INV_VIA_OUT;
-
- if (invflags & IPT_INV_SRCIP)
- result |= ARPT_INV_SRCIP;
-
- if (invflags & IPT_INV_DSTIP)
- result |= ARPT_INV_TGTIP;
-
- if (invflags & IPT_INV_PROTO)
- result |= ARPT_INV_ARPPRO;
-
- return result;
-}
-
static void nft_arp_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e,
void *data)
{
@@ -269,7 +251,7 @@ static void nft_arp_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e,
fw->arp.outiface, fw->arp.outiface_mask,
&flags);
- fw->arp.invflags |= ipt_to_arpt_flags(flags);
+ fw->arp.invflags |= flags;
}
static void nft_arp_parse_immediate(const char *jumpto, bool nft_goto,
@@ -303,7 +285,8 @@ static bool nft_arp_parse_devaddr(struct nft_xt_ctx *ctx,
memcpy(info->mask, ctx->bitwise.mask, ETH_ALEN);
ctx->flags &= ~NFT_XT_CTX_BITWISE;
} else {
- memset(info->mask, 0xff, ETH_ALEN);
+ memset(info->mask, 0xff,
+ min(ctx->payload.len, ETH_ALEN));
}
return inv;
@@ -325,33 +308,33 @@ static void nft_arp_parse_payload(struct nft_xt_ctx *ctx,
fw->arp.arhrd = ar_hrd;
fw->arp.arhrd_mask = 0xffff;
if (inv)
- fw->arp.invflags |= ARPT_INV_ARPHRD;
+ fw->arp.invflags |= IPT_INV_ARPHRD;
break;
case offsetof(struct arphdr, ar_pro):
get_cmp_data(e, &ar_pro, sizeof(ar_pro), &inv);
fw->arp.arpro = ar_pro;
fw->arp.arpro_mask = 0xffff;
if (inv)
- fw->arp.invflags |= ARPT_INV_ARPPRO;
+ fw->arp.invflags |= IPT_INV_PROTO;
break;
case offsetof(struct arphdr, ar_op):
get_cmp_data(e, &ar_op, sizeof(ar_op), &inv);
fw->arp.arpop = ar_op;
fw->arp.arpop_mask = 0xffff;
if (inv)
- fw->arp.invflags |= ARPT_INV_ARPOP;
+ fw->arp.invflags |= IPT_INV_ARPOP;
break;
case offsetof(struct arphdr, ar_hln):
get_cmp_data(e, &ar_hln, sizeof(ar_hln), &inv);
fw->arp.arhln = ar_hln;
fw->arp.arhln_mask = 0xff;
if (inv)
- fw->arp.invflags |= ARPT_INV_ARPOP;
+ fw->arp.invflags |= IPT_INV_ARPOP;
break;
default:
if (ctx->payload.offset == sizeof(struct arphdr)) {
if (nft_arp_parse_devaddr(ctx, e, &fw->arp.src_devaddr))
- fw->arp.invflags |= ARPT_INV_SRCDEVADDR;
+ fw->arp.invflags |= IPT_INV_SRCDEVADDR;
} else if (ctx->payload.offset == sizeof(struct arphdr) +
fw->arp.arhln) {
get_cmp_data(e, &addr, sizeof(addr), &inv);
@@ -360,16 +343,18 @@ static void nft_arp_parse_payload(struct nft_xt_ctx *ctx,
parse_mask_ipv4(ctx, &fw->arp.smsk);
ctx->flags &= ~NFT_XT_CTX_BITWISE;
} else {
- fw->arp.smsk.s_addr = 0xffffffff;
+ memset(&fw->arp.smsk, 0xff,
+ min(ctx->payload.len,
+ sizeof(struct in_addr)));
}
if (inv)
- fw->arp.invflags |= ARPT_INV_SRCIP;
+ fw->arp.invflags |= IPT_INV_SRCIP;
} else if (ctx->payload.offset == sizeof(struct arphdr) +
fw->arp.arhln +
sizeof(struct in_addr)) {
if (nft_arp_parse_devaddr(ctx, e, &fw->arp.tgt_devaddr))
- fw->arp.invflags |= ARPT_INV_TGTDEVADDR;
+ fw->arp.invflags |= IPT_INV_TGTDEVADDR;
} else if (ctx->payload.offset == sizeof(struct arphdr) +
fw->arp.arhln +
sizeof(struct in_addr) +
@@ -380,11 +365,13 @@ static void nft_arp_parse_payload(struct nft_xt_ctx *ctx,
parse_mask_ipv4(ctx, &fw->arp.tmsk);
ctx->flags &= ~NFT_XT_CTX_BITWISE;
} else {
- fw->arp.tmsk.s_addr = 0xffffffff;
+ memset(&fw->arp.tmsk, 0xff,
+ min(ctx->payload.len,
+ sizeof(struct in_addr)));
}
if (inv)
- fw->arp.invflags |= ARPT_INV_TGTIP;
+ fw->arp.invflags |= IPT_INV_DSTIP;
}
break;
}
@@ -439,7 +426,7 @@ static void nft_arp_print_rule_details(const struct iptables_command_state *cs,
else strcat(iface, "any");
}
if (print_iface) {
- printf("%s%s-i %s", sep, fw->arp.invflags & ARPT_INV_VIA_IN ?
+ printf("%s%s-i %s", sep, fw->arp.invflags & IPT_INV_VIA_IN ?
"! " : "", iface);
sep = " ";
}
@@ -457,13 +444,13 @@ static void nft_arp_print_rule_details(const struct iptables_command_state *cs,
else strcat(iface, "any");
}
if (print_iface) {
- printf("%s%s-o %s", sep, fw->arp.invflags & ARPT_INV_VIA_OUT ?
+ printf("%s%s-o %s", sep, fw->arp.invflags & IPT_INV_VIA_OUT ?
"! " : "", iface);
sep = " ";
}
if (fw->arp.smsk.s_addr != 0L) {
- printf("%s%s", sep, fw->arp.invflags & ARPT_INV_SRCIP
+ printf("%s%s", sep, fw->arp.invflags & IPT_INV_SRCIP
? "! " : "");
if (format & FMT_NUMERIC)
sprintf(buf, "%s", addr_to_dotted(&(fw->arp.src)));
@@ -480,7 +467,7 @@ static void nft_arp_print_rule_details(const struct iptables_command_state *cs,
break;
if (i == ARPT_DEV_ADDR_LEN_MAX)
goto after_devsrc;
- printf("%s%s", sep, fw->arp.invflags & ARPT_INV_SRCDEVADDR
+ printf("%s%s", sep, fw->arp.invflags & IPT_INV_SRCDEVADDR
? "! " : "");
printf("--src-mac ");
xtables_print_mac_and_mask((unsigned char *)fw->arp.src_devaddr.addr,
@@ -489,7 +476,7 @@ static void nft_arp_print_rule_details(const struct iptables_command_state *cs,
after_devsrc:
if (fw->arp.tmsk.s_addr != 0L) {
- printf("%s%s", sep, fw->arp.invflags & ARPT_INV_TGTIP
+ printf("%s%s", sep, fw->arp.invflags & IPT_INV_DSTIP
? "! " : "");
if (format & FMT_NUMERIC)
sprintf(buf, "%s", addr_to_dotted(&(fw->arp.tgt)));
@@ -506,7 +493,7 @@ after_devsrc:
break;
if (i == ARPT_DEV_ADDR_LEN_MAX)
goto after_devdst;
- printf("%s%s", sep, fw->arp.invflags & ARPT_INV_TGTDEVADDR
+ printf("%s%s", sep, fw->arp.invflags & IPT_INV_TGTDEVADDR
? "! " : "");
printf("--dst-mac ");
xtables_print_mac_and_mask((unsigned char *)fw->arp.tgt_devaddr.addr,
@@ -516,7 +503,7 @@ after_devsrc:
after_devdst:
if (fw->arp.arhln_mask != 255 || fw->arp.arhln != 6) {
- printf("%s%s", sep, fw->arp.invflags & ARPT_INV_ARPHLN
+ printf("%s%s", sep, fw->arp.invflags & IPT_INV_ARPHLN
? "! " : "");
printf("--h-length %d", fw->arp.arhln);
if (fw->arp.arhln_mask != 255)
@@ -527,7 +514,7 @@ after_devdst:
if (fw->arp.arpop_mask != 0) {
int tmp = ntohs(fw->arp.arpop);
- printf("%s%s", sep, fw->arp.invflags & ARPT_INV_ARPOP
+ printf("%s%s", sep, fw->arp.invflags & IPT_INV_ARPOP
? "! " : "");
if (tmp <= NUMOPCODES && !(format & FMT_NUMERIC))
printf("--opcode %s", arp_opcodes[tmp-1]);
@@ -542,7 +529,7 @@ after_devdst:
if (fw->arp.arhrd_mask != 65535 || fw->arp.arhrd != htons(1)) {
uint16_t tmp = ntohs(fw->arp.arhrd);
- printf("%s%s", sep, fw->arp.invflags & ARPT_INV_ARPHRD
+ printf("%s%s", sep, fw->arp.invflags & IPT_INV_ARPHRD
? "! " : "");
if (tmp == 1 && !(format & FMT_NUMERIC))
printf("--h-type %s", "Ethernet");
@@ -556,7 +543,7 @@ after_devdst:
if (fw->arp.arpro_mask != 0) {
int tmp = ntohs(fw->arp.arpro);
- printf("%s%s", sep, fw->arp.invflags & ARPT_INV_ARPPRO
+ printf("%s%s", sep, fw->arp.invflags & IPT_INV_PROTO
? "! " : "");
if (tmp == 0x0800 && !(format & FMT_NUMERIC))
printf("--proto-type %s", "IPv4");
@@ -604,6 +591,8 @@ nft_arp_print_rule(struct nft_handle *h, struct nftnl_rule *r,
if (!(format & FMT_NONEWLINE))
fputc('\n', stdout);
+
+ nft_clear_iptables_command_state(&cs);
}
static bool nft_arp_is_same(const void *data_a,
@@ -633,31 +622,6 @@ static bool nft_arp_is_same(const void *data_a,
(unsigned char *)b->arp.outiface_mask);
}
-static bool nft_arp_rule_find(struct nft_handle *h, struct nftnl_rule *r,
- void *data)
-{
- const struct iptables_command_state *cs = data;
- struct iptables_command_state this = {};
- bool ret = false;
-
- /* Delete by matching rule case */
- nft_rule_to_iptables_command_state(h, r, &this);
-
- if (!nft_arp_is_same(&cs->arp, &this.arp))
- goto out;
-
- if (!compare_targets(cs->target, this.target))
- goto out;
-
- if (this.jumpto && strcmp(cs->jumpto, this.jumpto) != 0)
- goto out;
-
- ret = true;
-out:
- h->ops->clear_cs(&this);
- return ret;
-}
-
static void nft_arp_save_chain(const struct nftnl_chain *c, const char *policy)
{
const char *chain = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
@@ -675,11 +639,9 @@ 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 = save_counters,
.save_chain = nft_arp_save_chain,
.post_parse = NULL,
.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 3411fc3d..0d93a31f 100644
--- a/iptables/nft-arp.h
+++ b/iptables/nft-arp.h
@@ -4,4 +4,11 @@
extern char *arp_opcodes[];
#define NUMOPCODES 9
+/* define invflags which won't collide with IPT ones */
+#define IPT_INV_SRCDEVADDR 0x0080
+#define IPT_INV_TGTDEVADDR 0x0100
+#define IPT_INV_ARPHLN 0x0200
+#define IPT_INV_ARPOP 0x0400
+#define IPT_INV_ARPHRD 0x0800
+
#endif
diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c
index 3f85cbbf..d98fd527 100644
--- a/iptables/nft-bridge.c
+++ b/iptables/nft-bridge.c
@@ -58,44 +58,11 @@ void ebt_cs_clean(struct iptables_command_state *cs)
}
}
-static void ebt_print_mac(const unsigned char *mac)
-{
- int j;
-
- for (j = 0; j < ETH_ALEN; j++)
- printf("%02x%s", mac[j], (j==ETH_ALEN-1) ? "" : ":");
-}
-
-static bool mac_all_ones(const unsigned char *mac)
-{
- static const char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
-
- return memcmp(mac, hlpmsk, sizeof(hlpmsk)) == 0;
-}
-
/* Put the mac address into 6 (ETH_ALEN) bytes returns 0 on success. */
static void ebt_print_mac_and_mask(const unsigned char *mac, const unsigned char *mask)
{
-
- if (!memcmp(mac, eb_mac_type_unicast, 6) &&
- !memcmp(mask, eb_msk_type_unicast, 6))
- printf("Unicast");
- else if (!memcmp(mac, eb_mac_type_multicast, 6) &&
- !memcmp(mask, eb_msk_type_multicast, 6))
- printf("Multicast");
- else if (!memcmp(mac, eb_mac_type_broadcast, 6) &&
- !memcmp(mask, eb_msk_type_broadcast, 6))
- printf("Broadcast");
- else if (!memcmp(mac, eb_mac_type_bridge_group, 6) &&
- !memcmp(mask, eb_msk_type_bridge_group, 6))
- printf("BGA");
- else {
- ebt_print_mac(mac);
- if (!mac_all_ones(mask)) {
- printf("/");
- ebt_print_mac(mask);
- }
- }
+ if (xtables_print_well_known_mac_and_mask(mac, mask))
+ xtables_print_mac_and_mask(mac, mask);
}
static void add_logical_iniface(struct nftnl_rule *r, char *iface, uint32_t op)
@@ -159,20 +126,16 @@ static int nft_bridge_add(struct nft_handle *h,
if (fw->bitmask & EBT_ISOURCE) {
op = nft_invflags2cmp(fw->invflags, EBT_ISOURCE);
- add_payload(r, offsetof(struct ethhdr, h_source), 6,
- NFT_PAYLOAD_LL_HEADER);
- if (!mac_all_ones(fw->sourcemsk))
- add_bitwise(r, fw->sourcemsk, 6);
- add_cmp_ptr(r, op, fw->sourcemac, 6);
+ add_addr(r, NFT_PAYLOAD_LL_HEADER,
+ offsetof(struct ethhdr, h_source),
+ fw->sourcemac, fw->sourcemsk, ETH_ALEN, op);
}
if (fw->bitmask & EBT_IDEST) {
op = nft_invflags2cmp(fw->invflags, EBT_IDEST);
- add_payload(r, offsetof(struct ethhdr, h_dest), 6,
- NFT_PAYLOAD_LL_HEADER);
- if (!mac_all_ones(fw->destmsk))
- add_bitwise(r, fw->destmsk, 6);
- add_cmp_ptr(r, op, fw->destmac, 6);
+ add_addr(r, NFT_PAYLOAD_LL_HEADER,
+ offsetof(struct ethhdr, h_dest),
+ fw->destmac, fw->destmsk, ETH_ALEN, op);
}
if ((fw->bitmask & EBT_NOPROTO) == 0) {
@@ -258,7 +221,8 @@ static void nft_bridge_parse_payload(struct nft_xt_ctx *ctx,
memcpy(fw->destmsk, ctx->bitwise.mask, ETH_ALEN);
ctx->flags &= ~NFT_XT_CTX_BITWISE;
} else {
- memset(&fw->destmsk, 0xff, ETH_ALEN);
+ memset(&fw->destmsk, 0xff,
+ min(ctx->payload.len, ETH_ALEN));
}
fw->bitmask |= EBT_IDEST;
break;
@@ -272,7 +236,8 @@ static void nft_bridge_parse_payload(struct nft_xt_ctx *ctx,
memcpy(fw->sourcemsk, ctx->bitwise.mask, ETH_ALEN);
ctx->flags &= ~NFT_XT_CTX_BITWISE;
} else {
- memset(&fw->sourcemsk, 0xff, ETH_ALEN);
+ memset(&fw->sourcemsk, 0xff,
+ min(ctx->payload.len, ETH_ALEN));
}
fw->bitmask |= EBT_ISOURCE;
break;
@@ -421,11 +386,20 @@ static struct nftnl_set *set_from_lookup_expr(struct nft_xt_ctx *ctx,
const struct nftnl_expr *e)
{
const char *set_name = nftnl_expr_get_str(e, NFTNL_EXPR_LOOKUP_SET);
+ uint32_t set_id = nftnl_expr_get_u32(e, NFTNL_EXPR_LOOKUP_SET_ID);
struct nftnl_set_list *slist;
+ struct nftnl_set *set;
slist = nft_set_list_get(ctx->h, ctx->table, set_name);
- if (slist)
- return nftnl_set_list_lookup_byname(slist, set_name);
+ if (slist) {
+ set = nftnl_set_list_lookup_byname(slist, set_name);
+ if (set)
+ return set;
+
+ set = nft_set_batch_lookup_byid(ctx->h, set_id);
+ if (set)
+ return set;
+ }
return NULL;
}
@@ -747,41 +721,6 @@ static bool nft_bridge_is_same(const void *data_a, const void *data_b)
return strcmp(a->in, b->in) == 0 && strcmp(a->out, b->out) == 0;
}
-static bool nft_bridge_rule_find(struct nft_handle *h, struct nftnl_rule *r,
- void *data)
-{
- struct iptables_command_state *cs = data;
- struct iptables_command_state this = {};
- bool ret = false;
-
- nft_rule_to_ebtables_command_state(h, r, &this);
-
- DEBUGP("comparing with... ");
-
- if (!nft_bridge_is_same(cs, &this))
- goto out;
-
- if (!compare_matches(cs->matches, this.matches)) {
- DEBUGP("Different matches\n");
- goto out;
- }
-
- if (!compare_targets(cs->target, this.target)) {
- DEBUGP("Different target\n");
- goto out;
- }
-
- if (cs->jumpto != NULL && strcmp(cs->jumpto, this.jumpto) != 0) {
- DEBUGP("Different verdict\n");
- goto out;
- }
-
- ret = true;
-out:
- h->ops->clear_cs(&this);
- return ret;
-}
-
static int xlate_ebmatches(const struct iptables_command_state *cs, struct xt_xlate *xl)
{
int ret = 1, numeric = cs->options & OPT_NUMERIC;
@@ -958,11 +897,9 @@ struct nft_family_ops nft_family_ops_bridge = {
.print_header = nft_bridge_print_header,
.print_rule = nft_bridge_print_rule,
.save_rule = nft_bridge_save_rule,
- .save_counters = save_counters,
.save_chain = nft_bridge_save_chain,
.post_parse = NULL,
.rule_to_cs = nft_rule_to_ebtables_command_state,
.clear_cs = ebt_cs_clean,
- .rule_find = nft_bridge_rule_find,
.xlate = nft_bridge_xlate,
};
diff --git a/iptables/nft-cache.c b/iptables/nft-cache.c
index 7345a27e..6b6e6da4 100644
--- a/iptables/nft-cache.c
+++ b/iptables/nft-cache.c
@@ -11,6 +11,7 @@
#include <assert.h>
#include <errno.h>
+#include <stdlib.h>
#include <string.h>
#include <xtables.h>
@@ -23,6 +24,53 @@
#include "nft.h"
#include "nft-cache.h"
+#include "nft-chain.h"
+
+static void cache_chain_list_insert(struct list_head *list, const char *name)
+{
+ struct cache_chain *pos = NULL, *new;
+
+ list_for_each_entry(pos, list, head) {
+ int cmp = strcmp(pos->name, name);
+
+ if (!cmp)
+ return;
+ if (cmp > 0)
+ break;
+ }
+
+ new = xtables_malloc(sizeof(*new));
+ new->name = strdup(name);
+ list_add_tail(&new->head, pos ? &pos->head : list);
+}
+
+void nft_cache_level_set(struct nft_handle *h, int level,
+ const struct nft_cmd *cmd)
+{
+ struct nft_cache_req *req = &h->cache_req;
+
+ if (level > req->level)
+ req->level = level;
+
+ if (!cmd || !cmd->table || req->all_chains)
+ return;
+
+ if (!req->table)
+ req->table = strdup(cmd->table);
+ else
+ assert(!strcmp(req->table, cmd->table));
+
+ if (!cmd->chain) {
+ req->all_chains = true;
+ return;
+ }
+
+ cache_chain_list_insert(&req->chain_list, cmd->chain);
+ if (cmd->rename)
+ cache_chain_list_insert(&req->chain_list, cmd->rename);
+ if (cmd->jumpto)
+ cache_chain_list_insert(&req->chain_list, cmd->jumpto);
+}
static int genid_cb(const struct nlmsghdr *nlh, void *data)
{
@@ -62,51 +110,137 @@ static void mnl_genid_get(struct nft_handle *h, uint32_t *genid)
static int nftnl_table_list_cb(const struct nlmsghdr *nlh, void *data)
{
- struct nftnl_table *t;
- struct nftnl_table_list *list = data;
+ struct nftnl_table *nftnl = nftnl_table_alloc();
+ const struct builtin_table *t;
+ struct nft_handle *h = data;
+ const char *name;
- t = nftnl_table_alloc();
- if (t == NULL)
- goto err;
+ if (!nftnl)
+ return MNL_CB_OK;
- if (nftnl_table_nlmsg_parse(nlh, t) < 0)
+ if (nftnl_table_nlmsg_parse(nlh, nftnl) < 0)
goto out;
- nftnl_table_list_add_tail(t, list);
+ name = nftnl_table_get_str(nftnl, NFTNL_TABLE_NAME);
+ if (!name)
+ goto out;
- return MNL_CB_OK;
+ t = nft_table_builtin_find(h, name);
+ if (!t)
+ goto out;
+
+ h->cache->table[t->type].exists = true;
out:
- nftnl_table_free(t);
-err:
+ nftnl_table_free(nftnl);
return MNL_CB_OK;
}
static int fetch_table_cache(struct nft_handle *h)
{
- char buf[16536];
struct nlmsghdr *nlh;
- struct nftnl_table_list *list;
- int ret;
-
- if (h->cache->tables)
- return 0;
-
- list = nftnl_table_list_alloc();
- if (list == NULL)
- return 0;
+ char buf[16536];
+ int i, ret;
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);
+ ret = mnl_talk(h, nlh, nftnl_table_list_cb, h);
if (ret < 0 && errno == EINTR)
assert(nft_restart(h) >= 0);
- h->cache->tables = list;
+ 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 = nft_chain_list_alloc();
+
+ h->cache->table[type].sets = nftnl_set_list_alloc();
+ if (!h->cache->table[type].sets)
+ return 0;
+ }
return 1;
}
+static uint32_t djb_hash(const char *key)
+{
+ uint32_t i, hash = 5381;
+
+ for (i = 0; i < strlen(key); i++)
+ hash = ((hash << 5) + hash) + key[i];
+
+ return hash;
+}
+
+static struct hlist_head *chain_name_hlist(struct nft_handle *h,
+ const struct builtin_table *t,
+ const char *chain)
+{
+ int key = djb_hash(chain) % CHAIN_NAME_HSIZE;
+
+ return &h->cache->table[t->type].chains->names[key];
+}
+
+struct nft_chain *
+nft_chain_find(struct nft_handle *h, const char *table, const char *chain)
+{
+ const struct builtin_table *t;
+ struct hlist_node *node;
+ struct nft_chain *c;
+
+ t = nft_table_builtin_find(h, table);
+ if (!t)
+ return NULL;
+
+ hlist_for_each_entry(c, node, chain_name_hlist(h, t, chain), hnode) {
+ if (!strcmp(nftnl_chain_get_str(c->nftnl, NFTNL_CHAIN_NAME),
+ chain))
+ return c;
+ }
+ return NULL;
+}
+
+int nft_cache_add_chain(struct nft_handle *h, const struct builtin_table *t,
+ struct nftnl_chain *c)
+{
+ const char *cname = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
+ struct nft_chain *nc = nft_chain_alloc(c);
+
+ if (nftnl_chain_is_set(c, NFTNL_CHAIN_HOOKNUM)) {
+ uint32_t hooknum = nftnl_chain_get_u32(c, NFTNL_CHAIN_HOOKNUM);
+
+ if (hooknum >= NF_INET_NUMHOOKS) {
+ nft_chain_free(nc);
+ return -EINVAL;
+ }
+
+ if (h->cache->table[t->type].base_chains[hooknum]) {
+ nft_chain_free(nc);
+ return -EEXIST;
+ }
+
+ h->cache->table[t->type].base_chains[hooknum] = nc;
+ } else {
+ struct nft_chain_list *clist = h->cache->table[t->type].chains;
+ struct list_head *pos = &clist->list;
+ struct nft_chain *cur;
+ const char *n;
+
+ list_for_each_entry(cur, &clist->list, head) {
+ n = nftnl_chain_get_str(cur->nftnl, NFTNL_CHAIN_NAME);
+ if (strcmp(cname, n) <= 0) {
+ pos = &cur->head;
+ break;
+ }
+ }
+ list_add_tail(&nc->head, pos);
+ }
+ hlist_add_head(&nc->hnode, chain_name_hlist(h, t, cname));
+ return 0;
+}
+
struct nftnl_chain_list_cb_data {
struct nft_handle *h;
const struct builtin_table *t;
@@ -116,10 +250,9 @@ static int nftnl_chain_list_cb(const struct nlmsghdr *nlh, void *data)
{
struct nftnl_chain_list_cb_data *d = data;
const struct builtin_table *t = d->t;
- struct nftnl_chain_list *list;
struct nft_handle *h = d->h;
- const char *tname, *cname;
struct nftnl_chain *c;
+ const char *tname;
c = nftnl_chain_alloc();
if (c == NULL)
@@ -138,14 +271,9 @@ static int nftnl_chain_list_cb(const struct nlmsghdr *nlh, void *data)
goto out;
}
- list = h->cache->table[t->type].chains;
- cname = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
-
- if (nftnl_chain_list_lookup_byname(list, cname))
+ if (nft_cache_add_chain(h, t, c))
goto out;
- nftnl_chain_list_add_tail(c, list);
-
return MNL_CB_OK;
out:
nftnl_chain_free(c);
@@ -239,40 +367,31 @@ static int fetch_set_cache(struct nft_handle *h,
.h = h,
.t = t,
};
+ uint16_t flags = NLM_F_DUMP;
+ struct nftnl_set *s = NULL;
struct nlmsghdr *nlh;
char buf[16536];
int i, ret;
- if (!t) {
- for (i = 0; i < NFT_TABLE_MAX; i++) {
- enum nft_table_type type = h->tables[i].type;
+ if (t) {
+ s = nftnl_set_alloc();
+ if (!s)
+ return -1;
- if (!h->tables[i].name)
- continue;
+ nftnl_set_set_str(s, NFTNL_SET_TABLE, t->name);
- h->cache->table[type].sets = nftnl_set_list_alloc();
- if (!h->cache->table[type].sets)
- return -1;
+ if (set) {
+ nftnl_set_set_str(s, NFTNL_SET_NAME, set);
+ flags = NLM_F_ACK;
}
- } else if (!h->cache->table[t->type].sets) {
- h->cache->table[t->type].sets = nftnl_set_list_alloc();
}
- if (t && set) {
- struct nftnl_set *s = nftnl_set_alloc();
-
- if (!s)
- return -1;
+ nlh = nftnl_set_nlmsg_build_hdr(buf, NFT_MSG_GETSET,
+ h->family, flags, h->seq);
- nlh = nftnl_set_nlmsg_build_hdr(buf, NFT_MSG_GETSET, h->family,
- NLM_F_ACK, h->seq);
- nftnl_set_set_str(s, NFTNL_SET_TABLE, t->name);
- nftnl_set_set_str(s, NFTNL_SET_NAME, set);
+ if (s) {
nftnl_set_nlmsg_build_payload(nlh, s);
nftnl_set_free(s);
- } else {
- nlh = nftnl_set_nlmsg_build_hdr(buf, NFT_MSG_GETSET, h->family,
- NLM_F_DUMP, h->seq);
}
ret = mnl_talk(h, nlh, nftnl_set_list_cb, &d);
@@ -281,13 +400,7 @@ static int fetch_set_cache(struct nft_handle *h,
return ret;
}
- if (t && set) {
- struct nftnl_set *s;
-
- s = nftnl_set_list_lookup_byname(h->cache->table[t->type].sets,
- set);
- set_fetch_elem_cb(s, h);
- } else if (t) {
+ if (t) {
nftnl_set_list_foreach(h->cache->table[t->type].sets,
set_fetch_elem_cb, h);
} else {
@@ -304,9 +417,9 @@ static int fetch_set_cache(struct nft_handle *h,
return ret;
}
-static int fetch_chain_cache(struct nft_handle *h,
- const struct builtin_table *t,
- const char *chain)
+static int __fetch_chain_cache(struct nft_handle *h,
+ const struct builtin_table *t,
+ const struct nftnl_chain *c)
{
struct nftnl_chain_list_cb_data d = {
.h = h,
@@ -314,51 +427,47 @@ static int fetch_chain_cache(struct nft_handle *h,
};
char buf[16536];
struct nlmsghdr *nlh;
- int i, ret;
+ int ret;
- if (!t) {
- for (i = 0; i < NFT_TABLE_MAX; i++) {
- enum nft_table_type type = h->tables[i].type;
+ nlh = nftnl_chain_nlmsg_build_hdr(buf, NFT_MSG_GETCHAIN, h->family,
+ c ? NLM_F_ACK : NLM_F_DUMP, h->seq);
+ if (c)
+ nftnl_chain_nlmsg_build_payload(nlh, c);
- if (!h->tables[i].name)
- continue;
+ ret = mnl_talk(h, nlh, nftnl_chain_list_cb, &d);
+ if (ret < 0 && errno == EINTR)
+ assert(nft_restart(h) >= 0);
- if (h->cache->table[type].chains)
- continue;
+ return ret;
+}
- h->cache->table[type].chains = nftnl_chain_list_alloc();
- if (!h->cache->table[type].chains)
- return -1;
- }
- } else if (!h->cache->table[t->type].chains) {
- h->cache->table[t->type].chains = nftnl_chain_list_alloc();
- if (!h->cache->table[t->type].chains)
- return -1;
- }
+static int fetch_chain_cache(struct nft_handle *h,
+ const struct builtin_table *t,
+ struct list_head *chains)
+{
+ struct cache_chain *cc;
+ struct nftnl_chain *c;
+ int rc, ret = 0;
- if (t && chain) {
- struct nftnl_chain *c = nftnl_chain_alloc();
+ if (!chains)
+ return __fetch_chain_cache(h, t, NULL);
- if (!c)
- return -1;
+ assert(t);
- nlh = nftnl_chain_nlmsg_build_hdr(buf, NFT_MSG_GETCHAIN,
- h->family, NLM_F_ACK,
- h->seq);
- nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, t->name);
- nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, chain);
- nftnl_chain_nlmsg_build_payload(nlh, c);
- nftnl_chain_free(c);
- } else {
- nlh = nftnl_chain_nlmsg_build_hdr(buf, NFT_MSG_GETCHAIN,
- h->family, NLM_F_DUMP,
- h->seq);
- }
+ c = nftnl_chain_alloc();
+ if (!c)
+ return -1;
- ret = mnl_talk(h, nlh, nftnl_chain_list_cb, &d);
- if (ret < 0 && errno == EINTR)
- assert(nft_restart(h) >= 0);
+ nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, t->name);
+ list_for_each_entry(cc, chains, head) {
+ nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, cc->name);
+ rc = __fetch_chain_cache(h, t, c);
+ if (rc)
+ ret = rc;
+ }
+
+ nftnl_chain_free(c);
return ret;
}
@@ -380,8 +489,9 @@ static int nftnl_rule_list_cb(const struct nlmsghdr *nlh, void *data)
return MNL_CB_OK;
}
-static int nft_rule_list_update(struct nftnl_chain *c, void *data)
+static int nft_rule_list_update(struct nft_chain *nc, void *data)
{
+ struct nftnl_chain *c = nc->nftnl;
struct nft_handle *h = data;
char buf[16536];
struct nlmsghdr *nlh;
@@ -417,119 +527,65 @@ static int nft_rule_list_update(struct nftnl_chain *c, void *data)
}
static int fetch_rule_cache(struct nft_handle *h,
- const struct builtin_table *t, const char *chain)
+ const struct builtin_table *t)
{
int i;
- if (t) {
- struct nftnl_chain_list *list;
- struct nftnl_chain *c;
-
- list = h->cache->table[t->type].chains;
-
- if (chain) {
- c = nftnl_chain_list_lookup_byname(list, chain);
- return nft_rule_list_update(c, h);
- }
- return nftnl_chain_list_foreach(list, nft_rule_list_update, h);
- }
+ if (t)
+ return nft_chain_foreach(h, t->name, nft_rule_list_update, h);
for (i = 0; i < NFT_TABLE_MAX; i++) {
- enum nft_table_type type = h->tables[i].type;
if (!h->tables[i].name)
continue;
- if (nftnl_chain_list_foreach(h->cache->table[type].chains,
- nft_rule_list_update, h))
+ if (nft_chain_foreach(h, h->tables[i].name,
+ nft_rule_list_update, h))
return -1;
}
return 0;
}
+static int flush_cache(struct nft_handle *h, struct nft_cache *c,
+ const char *tablename);
+
static void
-__nft_build_cache(struct nft_handle *h, enum nft_cache_level level,
- const struct builtin_table *t, const char *set,
- const char *chain)
+__nft_build_cache(struct nft_handle *h)
{
- uint32_t genid_start, genid_stop;
+ struct nft_cache_req *req = &h->cache_req;
+ const struct builtin_table *t = NULL;
+ struct list_head *chains = NULL;
+ uint32_t genid_check;
- if (level <= h->cache_level)
+ if (h->cache_init)
return;
-retry:
- mnl_genid_get(h, &genid_start);
-
- if (h->cache_level && genid_start != h->nft_genid)
- flush_chain_cache(h, NULL);
-
- switch (h->cache_level) {
- case NFT_CL_NONE:
- fetch_table_cache(h);
- if (level == NFT_CL_TABLES)
- break;
- /* fall through */
- case NFT_CL_TABLES:
- fetch_chain_cache(h, t, chain);
- if (level == NFT_CL_CHAINS)
- break;
- /* fall through */
- case NFT_CL_CHAINS:
- fetch_set_cache(h, t, set);
- if (level == NFT_CL_SETS)
- break;
- /* fall through */
- case NFT_CL_SETS:
- fetch_rule_cache(h, t, chain);
- if (level == NFT_CL_RULES)
- break;
- /* fall through */
- case NFT_CL_RULES:
- break;
- }
- mnl_genid_get(h, &genid_stop);
- if (genid_start != genid_stop) {
- flush_chain_cache(h, NULL);
- goto retry;
+ if (req->table) {
+ t = nft_table_builtin_find(h, req->table);
+ if (!req->all_chains)
+ chains = &req->chain_list;
}
- if (!t && !chain)
- h->cache_level = level;
- else if (h->cache_level < NFT_CL_TABLES)
- h->cache_level = NFT_CL_TABLES;
-
- h->nft_genid = genid_start;
-}
-
-void nft_build_cache(struct nft_handle *h, struct nftnl_chain *c)
-{
- const struct builtin_table *t;
- const char *table, *chain;
-
- if (!c)
- return __nft_build_cache(h, NFT_CL_RULES, NULL, NULL, NULL);
-
- table = nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE);
- chain = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
- t = nft_table_builtin_find(h, table);
- __nft_build_cache(h, NFT_CL_RULES, t, NULL, chain);
-}
-
-void nft_fake_cache(struct nft_handle *h)
-{
- int i;
-
- 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_init = true;
+retry:
+ mnl_genid_get(h, &h->nft_genid);
- h->cache->table[type].chains = nftnl_chain_list_alloc();
+ if (req->level >= NFT_CL_TABLES)
+ fetch_table_cache(h);
+ if (req->level == NFT_CL_FAKE)
+ goto genid_check;
+ if (req->level >= NFT_CL_CHAINS)
+ fetch_chain_cache(h, t, chains);
+ if (req->level >= NFT_CL_SETS)
+ fetch_set_cache(h, t, NULL);
+ if (req->level >= NFT_CL_RULES)
+ fetch_rule_cache(h, t);
+genid_check:
+ mnl_genid_get(h, &genid_check);
+ if (h->nft_genid != genid_check) {
+ flush_cache(h, h->cache, NULL);
+ goto retry;
}
- h->cache_level = NFT_CL_RULES;
- mnl_genid_get(h, &h->nft_genid);
}
static void __nft_flush_cache(struct nft_handle *h)
@@ -550,31 +606,25 @@ static int ____flush_rule_cache(struct nftnl_rule *r, void *data)
return 0;
}
-static int __flush_rule_cache(struct nftnl_chain *c, void *data)
+static int __flush_rule_cache(struct nft_chain *c, void *data)
{
- return nftnl_rule_foreach(c, ____flush_rule_cache, NULL);
+ return nftnl_rule_foreach(c->nftnl, ____flush_rule_cache, NULL);
}
int flush_rule_cache(struct nft_handle *h, const char *table,
- struct nftnl_chain *c)
+ struct nft_chain *c)
{
- const struct builtin_table *t;
-
if (c)
return __flush_rule_cache(c, NULL);
- t = nft_table_builtin_find(h, table);
- if (!t || !h->cache->table[t->type].chains)
- return 0;
-
- return nftnl_chain_list_foreach(h->cache->table[t->type].chains,
- __flush_rule_cache, NULL);
+ nft_chain_foreach(h, table, __flush_rule_cache, NULL);
+ return 0;
}
-static int __flush_chain_cache(struct nftnl_chain *c, void *data)
+static int __flush_chain_cache(struct nft_chain *c, void *data)
{
- nftnl_chain_list_del(c);
- nftnl_chain_free(c);
+ nft_chain_list_del(c);
+ nft_chain_free(c);
return 0;
}
@@ -587,6 +637,19 @@ static int __flush_set_cache(struct nftnl_set *s, void *data)
return 0;
}
+static void flush_base_chain_cache(struct nft_chain **base_chains)
+{
+ int i;
+
+ for (i = 0; i < NF_INET_NUMHOOKS; i++) {
+ if (!base_chains[i])
+ continue;
+ hlist_del(&base_chains[i]->hnode);
+ nft_chain_free(base_chains[i]);
+ base_chains[i] = NULL;
+ }
+}
+
static int flush_cache(struct nft_handle *h, struct nft_cache *c,
const char *tablename)
{
@@ -597,9 +660,10 @@ static int flush_cache(struct nft_handle *h, struct nft_cache *c,
table = nft_table_builtin_find(h, tablename);
if (!table)
return 0;
- if (c->table[table->type].chains)
- nftnl_chain_list_foreach(c->table[table->type].chains,
- __flush_chain_cache, NULL);
+
+ flush_base_chain_cache(c->table[table->type].base_chains);
+ nft_chain_foreach(h, tablename, __flush_chain_cache, NULL);
+
if (c->table[table->type].sets)
nftnl_set_list_foreach(c->table[table->type].sets,
__flush_set_cache, NULL);
@@ -610,52 +674,89 @@ static int flush_cache(struct nft_handle *h, struct nft_cache *c,
if (h->tables[i].name == NULL)
continue;
- if (!c->table[i].chains)
- continue;
+ flush_base_chain_cache(c->table[i].base_chains);
+ if (c->table[i].chains) {
+ nft_chain_list_free(c->table[i].chains);
+ c->table[i].chains = NULL;
+ }
- nftnl_chain_list_free(c->table[i].chains);
- c->table[i].chains = NULL;
- if (c->table[i].sets)
+ if (c->table[i].sets) {
nftnl_set_list_free(c->table[i].sets);
- c->table[i].sets = NULL;
+ c->table[i].sets = NULL;
+ }
+
+ c->table[i].exists = false;
}
- nftnl_table_list_free(c->tables);
- c->tables = NULL;
return 1;
}
void flush_chain_cache(struct nft_handle *h, const char *tablename)
{
- if (!h->cache_level)
+ if (!h->cache_init)
return;
if (flush_cache(h, h->cache, tablename))
- h->cache_level = NFT_CL_NONE;
+ h->cache_init = false;
}
void nft_rebuild_cache(struct nft_handle *h)
{
- enum nft_cache_level level = h->cache_level;
-
- if (h->cache_level)
+ if (h->cache_init) {
__nft_flush_cache(h);
+ h->cache_init = false;
+ }
- h->cache_level = NFT_CL_NONE;
- __nft_build_cache(h, level, NULL, NULL, NULL);
+ __nft_build_cache(h);
}
-void nft_release_cache(struct nft_handle *h)
+void nft_cache_build(struct nft_handle *h)
{
- if (h->cache_index)
- flush_cache(h, &h->__cache[0], NULL);
+ struct nft_cache_req *req = &h->cache_req;
+ const struct builtin_table *t = NULL;
+ int i;
+
+ if (req->table)
+ t = nft_table_builtin_find(h, req->table);
+
+ /* fetch builtin chains as well (if existing) so nft_xt_builtin_init()
+ * doesn't override policies by accident */
+ if (t && !req->all_chains) {
+ for (i = 0; i < NF_INET_NUMHOOKS; i++) {
+ const char *cname = t->chains[i].name;
+
+ if (!cname)
+ break;
+ cache_chain_list_insert(&req->chain_list, cname);
+ }
+ }
+
+ __nft_build_cache(h);
}
-struct nftnl_table_list *nftnl_table_list_get(struct nft_handle *h)
+void nft_release_cache(struct nft_handle *h)
{
- __nft_build_cache(h, NFT_CL_TABLES, NULL, NULL, NULL);
-
- return h->cache->tables;
+ struct nft_cache_req *req = &h->cache_req;
+ struct cache_chain *cc, *cc_tmp;
+
+ while (h->cache_index)
+ flush_cache(h, &h->__cache[h->cache_index--], NULL);
+ flush_cache(h, &h->__cache[0], NULL);
+ h->cache = &h->__cache[0];
+ h->cache_init = false;
+
+ if (req->level != NFT_CL_FAKE)
+ req->level = NFT_CL_TABLES;
+ if (req->table) {
+ free(req->table);
+ req->table = NULL;
+ }
+ req->all_chains = false;
+ list_for_each_entry_safe(cc, cc_tmp, &req->chain_list, head) {
+ list_del(&cc->head);
+ free(cc->name);
+ free(cc);
+ }
}
struct nftnl_set_list *
@@ -667,22 +768,5 @@ nft_set_list_get(struct nft_handle *h, const char *table, const char *set)
if (!t)
return NULL;
- __nft_build_cache(h, NFT_CL_RULES, t, set, NULL);
-
return h->cache->table[t->type].sets;
}
-
-struct nftnl_chain_list *
-nft_chain_list_get(struct nft_handle *h, const char *table, const char *chain)
-{
- const struct builtin_table *t;
-
- t = nft_table_builtin_find(h, table);
- if (!t)
- return NULL;
-
- __nft_build_cache(h, NFT_CL_CHAINS, t, NULL, chain);
-
- return h->cache->table[t->type].chains;
-}
-
diff --git a/iptables/nft-cache.h b/iptables/nft-cache.h
index ed498835..20d96bee 100644
--- a/iptables/nft-cache.h
+++ b/iptables/nft-cache.h
@@ -2,19 +2,25 @@
#define _NFT_CACHE_H_
struct nft_handle;
+struct nft_chain;
+struct nft_cmd;
+struct builtin_table;
-void nft_fake_cache(struct nft_handle *h);
-void nft_build_cache(struct nft_handle *h, struct nftnl_chain *c);
+void nft_cache_level_set(struct nft_handle *h, int level,
+ const struct nft_cmd *cmd);
void nft_rebuild_cache(struct nft_handle *h);
void nft_release_cache(struct nft_handle *h);
void flush_chain_cache(struct nft_handle *h, const char *tablename);
int flush_rule_cache(struct nft_handle *h, const char *table,
- struct nftnl_chain *c);
+ struct nft_chain *c);
+void nft_cache_build(struct nft_handle *h);
+int nft_cache_add_chain(struct nft_handle *h, const struct builtin_table *t,
+ struct nftnl_chain *c);
+
+struct nft_chain *
+nft_chain_find(struct nft_handle *h, const char *table, const char *chain);
-struct nftnl_chain_list *
-nft_chain_list_get(struct nft_handle *h, const char *table, const char *chain);
struct nftnl_set_list *
nft_set_list_get(struct nft_handle *h, const char *table, const char *set);
-struct nftnl_table_list *nftnl_table_list_get(struct nft_handle *h);
#endif /* _NFT_CACHE_H_ */
diff --git a/iptables/nft-chain.c b/iptables/nft-chain.c
new file mode 100644
index 00000000..e954170f
--- /dev/null
+++ b/iptables/nft-chain.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2020 Red Hat GmbH. Author: Phil Sutter <phil@nwl.cc>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <stdlib.h>
+#include <xtables.h>
+
+#include "nft-chain.h"
+
+struct nft_chain *nft_chain_alloc(struct nftnl_chain *nftnl)
+{
+ struct nft_chain *c = xtables_malloc(sizeof(*c));
+
+ INIT_LIST_HEAD(&c->head);
+ c->nftnl = nftnl;
+
+ return c;
+}
+
+void nft_chain_free(struct nft_chain *c)
+{
+ if (c->nftnl)
+ nftnl_chain_free(c->nftnl);
+ free(c);
+}
+
+struct nft_chain_list *nft_chain_list_alloc(void)
+{
+ struct nft_chain_list *list = xtables_malloc(sizeof(*list));
+ int i;
+
+ INIT_LIST_HEAD(&list->list);
+ for (i = 0; i < CHAIN_NAME_HSIZE; i++)
+ INIT_HLIST_HEAD(&list->names[i]);
+
+ return list;
+}
+
+void nft_chain_list_del(struct nft_chain *c)
+{
+ list_del(&c->head);
+ hlist_del(&c->hnode);
+}
+
+void nft_chain_list_free(struct nft_chain_list *list)
+{
+ struct nft_chain *c, *c2;
+
+ list_for_each_entry_safe(c, c2, &list->list, head) {
+ nft_chain_list_del(c);
+ nft_chain_free(c);
+ }
+ free(list);
+}
diff --git a/iptables/nft-chain.h b/iptables/nft-chain.h
new file mode 100644
index 00000000..137f4b7f
--- /dev/null
+++ b/iptables/nft-chain.h
@@ -0,0 +1,29 @@
+#ifndef _NFT_CHAIN_H_
+#define _NFT_CHAIN_H_
+
+#include <libnftnl/chain.h>
+#include <libiptc/linux_list.h>
+
+struct nft_handle;
+
+struct nft_chain {
+ struct list_head head;
+ struct hlist_node hnode;
+ struct nftnl_chain *nftnl;
+};
+
+#define CHAIN_NAME_HSIZE 512
+
+struct nft_chain_list {
+ struct list_head list;
+ struct hlist_head names[CHAIN_NAME_HSIZE];
+};
+
+struct nft_chain *nft_chain_alloc(struct nftnl_chain *nftnl);
+void nft_chain_free(struct nft_chain *c);
+
+struct nft_chain_list *nft_chain_list_alloc(void);
+void nft_chain_list_free(struct nft_chain_list *list);
+void nft_chain_list_del(struct nft_chain *c);
+
+#endif /* _NFT_CHAIN_H_ */
diff --git a/iptables/nft-cmd.c b/iptables/nft-cmd.c
new file mode 100644
index 00000000..5d33f1f0
--- /dev/null
+++ b/iptables/nft-cmd.c
@@ -0,0 +1,395 @@
+/*
+ * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This code has been sponsored by Sophos Astaro <http://www.sophos.com>
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "nft.h"
+#include "nft-cmd.h"
+
+struct nft_cmd *nft_cmd_new(struct nft_handle *h, int command,
+ const char *table, const char *chain,
+ struct iptables_command_state *state,
+ int rulenum, bool verbose)
+{
+ struct nftnl_rule *rule;
+ struct nft_cmd *cmd;
+
+ cmd = calloc(1, sizeof(struct nft_cmd));
+ if (!cmd)
+ return NULL;
+
+ cmd->command = command;
+ cmd->table = strdup(table);
+ if (chain)
+ cmd->chain = strdup(chain);
+ cmd->rulenum = rulenum;
+ cmd->verbose = verbose;
+
+ if (state) {
+ rule = nft_rule_new(h, chain, table, state);
+ if (!rule)
+ return NULL;
+
+ cmd->obj.rule = rule;
+
+ if (!state->target && strlen(state->jumpto) > 0)
+ cmd->jumpto = strdup(state->jumpto);
+ }
+
+ list_add_tail(&cmd->head, &h->cmd_list);
+
+ return cmd;
+}
+
+void nft_cmd_free(struct nft_cmd *cmd)
+{
+ free((void *)cmd->table);
+ free((void *)cmd->chain);
+ free((void *)cmd->policy);
+ free((void *)cmd->rename);
+ free((void *)cmd->jumpto);
+
+ switch (cmd->command) {
+ case NFT_COMPAT_RULE_CHECK:
+ case NFT_COMPAT_RULE_DELETE:
+ if (cmd->obj.rule)
+ nftnl_rule_free(cmd->obj.rule);
+ break;
+ default:
+ break;
+ }
+
+ list_del(&cmd->head);
+ free(cmd);
+}
+
+static void nft_cmd_rule_bridge(struct nft_handle *h, const struct nft_cmd *cmd)
+{
+ const struct builtin_table *t;
+
+ t = nft_table_builtin_find(h, cmd->table);
+ if (!t)
+ return;
+
+ /* Since ebtables user-defined chain policies are implemented as last
+ * rule in nftables, rule cache is required here to treat them right.
+ */
+ if (h->family == NFPROTO_BRIDGE &&
+ !nft_chain_builtin_find(t, cmd->chain))
+ nft_cache_level_set(h, NFT_CL_RULES, cmd);
+ else
+ nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
+}
+
+int nft_cmd_rule_append(struct nft_handle *h, const char *chain,
+ const char *table, struct iptables_command_state *state,
+ void *ref, bool verbose)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_RULE_APPEND, table, chain, state, -1,
+ verbose);
+ if (!cmd)
+ return 0;
+
+ nft_cmd_rule_bridge(h, cmd);
+
+ return 1;
+}
+
+int nft_cmd_rule_insert(struct nft_handle *h, const char *chain,
+ const char *table, struct iptables_command_state *state,
+ int rulenum, bool verbose)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_RULE_INSERT, table, chain, state,
+ rulenum, verbose);
+ if (!cmd)
+ return 0;
+
+ nft_cmd_rule_bridge(h, cmd);
+
+ if (cmd->rulenum > 0)
+ nft_cache_level_set(h, NFT_CL_RULES, cmd);
+ else
+ nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
+
+ return 1;
+}
+
+int nft_cmd_rule_delete(struct nft_handle *h, const char *chain,
+ const char *table, struct iptables_command_state *state,
+ bool verbose)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_RULE_DELETE, table, chain, state,
+ -1, verbose);
+ if (!cmd)
+ return 0;
+
+ nft_cache_level_set(h, NFT_CL_RULES, cmd);
+
+ return 1;
+}
+
+int nft_cmd_rule_delete_num(struct nft_handle *h, const char *chain,
+ const char *table, int rulenum, bool verbose)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_RULE_DELETE, table, chain, NULL,
+ rulenum, verbose);
+ if (!cmd)
+ return 0;
+
+ nft_cache_level_set(h, NFT_CL_RULES, cmd);
+
+ return 1;
+}
+
+int nft_cmd_rule_flush(struct nft_handle *h, const char *chain,
+ const char *table, bool verbose)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_RULE_FLUSH, table, chain, NULL, -1,
+ verbose);
+ if (!cmd)
+ return 0;
+
+ if (chain || verbose)
+ nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
+ else
+ nft_cache_level_set(h, NFT_CL_TABLES, cmd);
+
+ return 1;
+}
+
+int nft_cmd_chain_zero_counters(struct nft_handle *h, const char *chain,
+ const char *table, bool verbose)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_CHAIN_ZERO, table, chain, NULL, -1,
+ verbose);
+ if (!cmd)
+ return 0;
+
+ nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
+
+ return 1;
+}
+
+int nft_cmd_chain_user_add(struct nft_handle *h, const char *chain,
+ const char *table)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_CHAIN_USER_ADD, table, chain, NULL, -1,
+ false);
+ if (!cmd)
+ return 0;
+
+ nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
+
+ return 1;
+}
+
+int nft_cmd_chain_user_del(struct nft_handle *h, const char *chain,
+ const char *table, bool verbose)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_CHAIN_USER_DEL, table, chain, NULL, -1,
+ verbose);
+ if (!cmd)
+ return 0;
+
+ /* This triggers nft_bridge_chain_postprocess() when fetching the
+ * rule cache.
+ */
+ if (h->family == NFPROTO_BRIDGE)
+ nft_cache_level_set(h, NFT_CL_RULES, cmd);
+ else
+ nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
+
+ return 1;
+}
+
+int nft_cmd_chain_user_rename(struct nft_handle *h,const char *chain,
+ const char *table, const char *newname)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_CHAIN_RENAME, table, chain, NULL, -1,
+ false);
+ if (!cmd)
+ return 0;
+
+ cmd->rename = strdup(newname);
+
+ nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
+
+ return 1;
+}
+
+int nft_cmd_rule_list(struct nft_handle *h, const char *chain,
+ const char *table, int rulenum, unsigned int format)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_RULE_LIST, table, chain, NULL, rulenum,
+ false);
+ if (!cmd)
+ return 0;
+
+ cmd->format = format;
+
+ nft_cache_level_set(h, NFT_CL_RULES, cmd);
+
+ return 1;
+}
+
+int nft_cmd_rule_replace(struct nft_handle *h, const char *chain,
+ const char *table, void *data, int rulenum,
+ bool verbose)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_RULE_REPLACE, table, chain, data,
+ rulenum, verbose);
+ if (!cmd)
+ return 0;
+
+ nft_cache_level_set(h, NFT_CL_RULES, cmd);
+
+ return 1;
+}
+
+int nft_cmd_rule_check(struct nft_handle *h, const char *chain,
+ const char *table, void *data, bool verbose)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_RULE_CHECK, table, chain, data, -1,
+ verbose);
+ if (!cmd)
+ return 0;
+
+ nft_cache_level_set(h, NFT_CL_RULES, cmd);
+
+ return 1;
+}
+
+int nft_cmd_chain_set(struct nft_handle *h, const char *table,
+ const char *chain, const char *policy,
+ const struct xt_counters *counters)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_CHAIN_UPDATE, table, chain, NULL, -1,
+ false);
+ if (!cmd)
+ return 0;
+
+ cmd->policy = strdup(policy);
+ if (counters)
+ cmd->counters = *counters;
+
+ nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
+
+ return 1;
+}
+
+int nft_cmd_table_flush(struct nft_handle *h, const char *table, bool verbose)
+{
+ struct nft_cmd *cmd;
+
+ if (verbose) {
+ return nft_cmd_rule_flush(h, NULL, table, verbose) &&
+ nft_cmd_chain_user_del(h, NULL, table, verbose);
+ }
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_TABLE_FLUSH, table, NULL, NULL, -1,
+ false);
+ if (!cmd)
+ return 0;
+
+ nft_cache_level_set(h, NFT_CL_TABLES, cmd);
+
+ return 1;
+}
+
+int nft_cmd_chain_restore(struct nft_handle *h, const char *chain,
+ const char *table)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_CHAIN_RESTORE, table, chain, NULL, -1,
+ false);
+ if (!cmd)
+ return 0;
+
+ nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
+
+ return 1;
+}
+
+int nft_cmd_rule_zero_counters(struct nft_handle *h, const char *chain,
+ const char *table, int rulenum)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_RULE_ZERO, table, chain, NULL, rulenum,
+ false);
+ if (!cmd)
+ return 0;
+
+ nft_cache_level_set(h, NFT_CL_RULES, cmd);
+
+ return 1;
+}
+
+int nft_cmd_rule_list_save(struct nft_handle *h, const char *chain,
+ const char *table, int rulenum, int counters)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_RULE_SAVE, table, chain, NULL, rulenum,
+ false);
+ if (!cmd)
+ return 0;
+
+ cmd->counters_save = counters;
+
+ nft_cache_level_set(h, NFT_CL_RULES, cmd);
+
+ return 1;
+}
+
+int ebt_cmd_user_chain_policy(struct nft_handle *h, const char *table,
+ const char *chain, const char *policy)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE, table, chain,
+ NULL, -1, false);
+ if (!cmd)
+ return 0;
+
+ cmd->policy = strdup(policy);
+
+ nft_cache_level_set(h, NFT_CL_RULES, cmd);
+
+ return 1;
+}
diff --git a/iptables/nft-cmd.h b/iptables/nft-cmd.h
new file mode 100644
index 00000000..ecf7655a
--- /dev/null
+++ b/iptables/nft-cmd.h
@@ -0,0 +1,79 @@
+#ifndef _NFT_CMD_H_
+#define _NFT_CMD_H_
+
+#include <libiptc/linux_list.h>
+#include <stdbool.h>
+#include "nft.h"
+
+struct nftnl_rule;
+
+struct nft_cmd {
+ struct list_head head;
+ int command;
+ const char *table;
+ const char *chain;
+ const char *jumpto;
+ int rulenum;
+ bool verbose;
+ unsigned int format;
+ struct {
+ struct nftnl_rule *rule;
+ struct nftnl_set *set;
+ } obj;
+ const char *policy;
+ struct xt_counters counters;
+ const char *rename;
+ int counters_save;
+};
+
+struct nft_cmd *nft_cmd_new(struct nft_handle *h, int command,
+ const char *table, const char *chain,
+ struct iptables_command_state *state,
+ int rulenum, bool verbose);
+void nft_cmd_free(struct nft_cmd *cmd);
+
+int nft_cmd_rule_append(struct nft_handle *h, const char *chain,
+ const char *table, struct iptables_command_state *state,
+ void *ref, bool verbose);
+int nft_cmd_rule_insert(struct nft_handle *h, const char *chain,
+ const char *table, struct iptables_command_state *state,
+ int rulenum, bool verbose);
+int nft_cmd_rule_delete(struct nft_handle *h, const char *chain,
+ const char *table, struct iptables_command_state *state,
+ bool verbose);
+int nft_cmd_rule_delete_num(struct nft_handle *h, const char *chain,
+ const char *table, int rulenum, bool verbose);
+int nft_cmd_rule_flush(struct nft_handle *h, const char *chain,
+ const char *table, bool verbose);
+int nft_cmd_zero_counters(struct nft_handle *h, const char *chain,
+ const char *table, bool verbose);
+int nft_cmd_chain_user_add(struct nft_handle *h, const char *chain,
+ const char *table);
+int nft_cmd_chain_user_del(struct nft_handle *h, const char *chain,
+ const char *table, bool verbose);
+int nft_cmd_chain_zero_counters(struct nft_handle *h, const char *chain,
+ const char *table, bool verbose);
+int nft_cmd_rule_list(struct nft_handle *h, const char *chain,
+ const char *table, int rulenum, unsigned int format);
+int nft_cmd_rule_check(struct nft_handle *h, const char *chain,
+ const char *table, void *data, bool verbose);
+int nft_cmd_chain_set(struct nft_handle *h, const char *table,
+ const char *chain, const char *policy,
+ const struct xt_counters *counters);
+int nft_cmd_chain_user_rename(struct nft_handle *h,const char *chain,
+ const char *table, const char *newname);
+int nft_cmd_rule_replace(struct nft_handle *h, const char *chain,
+ const char *table, void *data, int rulenum,
+ bool verbose);
+int nft_cmd_table_flush(struct nft_handle *h, const char *table, bool verbose);
+int nft_cmd_chain_restore(struct nft_handle *h, const char *chain,
+ const char *table);
+int nft_cmd_rule_zero_counters(struct nft_handle *h, const char *chain,
+ const char *table, int rulenum);
+int nft_cmd_rule_list_save(struct nft_handle *h, const char *chain,
+ const char *table, int rulenum, int counters);
+int ebt_cmd_user_chain_policy(struct nft_handle *h, const char *table,
+ const char *chain, const char *policy);
+void nft_cmd_table_new(struct nft_handle *h, const char *table);
+
+#endif /* _NFT_CMD_H_ */
diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c
index 70634f8f..fdc15c6f 100644
--- a/iptables/nft-ipv4.c
+++ b/iptables/nft-ipv4.c
@@ -50,13 +50,15 @@ static int nft_ipv4_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
if (cs->fw.ip.src.s_addr || cs->fw.ip.smsk.s_addr || cs->fw.ip.invflags & IPT_INV_SRCIP) {
op = nft_invflags2cmp(cs->fw.ip.invflags, IPT_INV_SRCIP);
- add_addr(r, offsetof(struct iphdr, saddr),
+ add_addr(r, NFT_PAYLOAD_NETWORK_HEADER,
+ offsetof(struct iphdr, saddr),
&cs->fw.ip.src.s_addr, &cs->fw.ip.smsk.s_addr,
sizeof(struct in_addr), op);
}
if (cs->fw.ip.dst.s_addr || cs->fw.ip.dmsk.s_addr || cs->fw.ip.invflags & IPT_INV_DSTIP) {
op = nft_invflags2cmp(cs->fw.ip.invflags, IPT_INV_DSTIP);
- add_addr(r, offsetof(struct iphdr, daddr),
+ add_addr(r, NFT_PAYLOAD_NETWORK_HEADER,
+ offsetof(struct iphdr, daddr),
&cs->fw.ip.dst.s_addr, &cs->fw.ip.dmsk.s_addr,
sizeof(struct in_addr), op);
}
@@ -199,7 +201,8 @@ static void nft_ipv4_parse_payload(struct nft_xt_ctx *ctx,
parse_mask_ipv4(ctx, &cs->fw.ip.smsk);
ctx->flags &= ~NFT_XT_CTX_BITWISE;
} else {
- cs->fw.ip.smsk.s_addr = 0xffffffff;
+ memset(&cs->fw.ip.smsk, 0xff,
+ min(ctx->payload.len, sizeof(struct in_addr)));
}
if (inv)
@@ -212,7 +215,8 @@ static void nft_ipv4_parse_payload(struct nft_xt_ctx *ctx,
parse_mask_ipv4(ctx, &cs->fw.ip.dmsk);
ctx->flags &= ~NFT_XT_CTX_BITWISE;
} else {
- cs->fw.ip.dmsk.s_addr = 0xffffffff;
+ memset(&cs->fw.ip.dmsk, 0xff,
+ min(ctx->payload.len, sizeof(struct in_addr)));
}
if (inv)
@@ -288,7 +292,7 @@ static void nft_ipv4_print_rule(struct nft_handle *h, struct nftnl_rule *r,
if (!(format & FMT_NONEWLINE))
fputc('\n', stdout);
- xtables_rule_matches_free(&cs.matches);
+ nft_clear_iptables_command_state(&cs);
}
static void save_ipv4_addr(char letter, const struct in_addr *addr,
@@ -450,13 +454,11 @@ struct nft_family_ops nft_family_ops_ipv4 = {
.print_header = print_header,
.print_rule = nft_ipv4_print_rule,
.save_rule = nft_ipv4_save_rule,
- .save_counters = save_counters,
.save_chain = nft_ipv46_save_chain,
.proto_parse = nft_ipv4_proto_parse,
.post_parse = nft_ipv4_post_parse,
.parse_target = nft_ipv46_parse_target,
.rule_to_cs = nft_rule_to_iptables_command_state,
.clear_cs = nft_clear_iptables_command_state,
- .rule_find = nft_ipv46_rule_find,
.xlate = nft_ipv4_xlate,
};
diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c
index d01491bf..130ad3e6 100644
--- a/iptables/nft-ipv6.c
+++ b/iptables/nft-ipv6.c
@@ -51,7 +51,8 @@ static int nft_ipv6_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
!IN6_IS_ADDR_UNSPECIFIED(&cs->fw6.ipv6.smsk) ||
(cs->fw6.ipv6.invflags & IPT_INV_SRCIP)) {
op = nft_invflags2cmp(cs->fw6.ipv6.invflags, IPT_INV_SRCIP);
- add_addr(r, offsetof(struct ip6_hdr, ip6_src),
+ add_addr(r, NFT_PAYLOAD_NETWORK_HEADER,
+ offsetof(struct ip6_hdr, ip6_src),
&cs->fw6.ipv6.src, &cs->fw6.ipv6.smsk,
sizeof(struct in6_addr), op);
}
@@ -59,7 +60,8 @@ static int nft_ipv6_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
!IN6_IS_ADDR_UNSPECIFIED(&cs->fw6.ipv6.dmsk) ||
(cs->fw6.ipv6.invflags & IPT_INV_DSTIP)) {
op = nft_invflags2cmp(cs->fw6.ipv6.invflags, IPT_INV_DSTIP);
- add_addr(r, offsetof(struct ip6_hdr, ip6_dst),
+ add_addr(r, NFT_PAYLOAD_NETWORK_HEADER,
+ offsetof(struct ip6_hdr, ip6_dst),
&cs->fw6.ipv6.dst, &cs->fw6.ipv6.dmsk,
sizeof(struct in6_addr), op);
}
@@ -146,7 +148,8 @@ static void nft_ipv6_parse_payload(struct nft_xt_ctx *ctx,
parse_mask_ipv6(ctx, &cs->fw6.ipv6.smsk);
ctx->flags &= ~NFT_XT_CTX_BITWISE;
} else {
- memset(&cs->fw6.ipv6.smsk, 0xff, sizeof(struct in6_addr));
+ memset(&cs->fw6.ipv6.smsk, 0xff,
+ min(ctx->payload.len, sizeof(struct in6_addr)));
}
if (inv)
@@ -159,7 +162,8 @@ static void nft_ipv6_parse_payload(struct nft_xt_ctx *ctx,
parse_mask_ipv6(ctx, &cs->fw6.ipv6.dmsk);
ctx->flags &= ~NFT_XT_CTX_BITWISE;
} else {
- memset(&cs->fw6.ipv6.dmsk, 0xff, sizeof(struct in6_addr));
+ memset(&cs->fw6.ipv6.dmsk, 0xff,
+ min(ctx->payload.len, sizeof(struct in6_addr)));
}
if (inv)
@@ -217,7 +221,7 @@ static void nft_ipv6_print_rule(struct nft_handle *h, struct nftnl_rule *r,
if (!(format & FMT_NONEWLINE))
fputc('\n', stdout);
- xtables_rule_matches_free(&cs.matches);
+ nft_clear_iptables_command_state(&cs);
}
static void save_ipv6_addr(char letter, const struct in6_addr *addr,
@@ -402,13 +406,11 @@ struct nft_family_ops nft_family_ops_ipv6 = {
.print_header = print_header,
.print_rule = nft_ipv6_print_rule,
.save_rule = nft_ipv6_save_rule,
- .save_counters = save_counters,
.save_chain = nft_ipv46_save_chain,
.proto_parse = nft_ipv6_proto_parse,
.post_parse = nft_ipv6_post_parse,
.parse_target = nft_ipv46_parse_target,
.rule_to_cs = nft_rule_to_iptables_command_state,
.clear_cs = nft_clear_iptables_command_state,
- .rule_find = nft_ipv46_rule_find,
.xlate = nft_ipv6_xlate,
};
diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c
index 78e42278..10553ab2 100644
--- a/iptables/nft-shared.c
+++ b/iptables/nft-shared.c
@@ -20,7 +20,6 @@
#include <xtables.h>
-#include <linux/netfilter/nf_tables.h>
#include <linux/netfilter/xt_comment.h>
#include <linux/netfilter/xt_limit.h>
@@ -162,20 +161,26 @@ void add_outiface(struct nftnl_rule *r, char *iface, uint32_t op)
add_cmp_ptr(r, op, iface, iface_len + 1);
}
-void add_addr(struct nftnl_rule *r, int offset,
+void add_addr(struct nftnl_rule *r, enum nft_payload_bases base, int offset,
void *data, void *mask, size_t len, uint32_t op)
{
- const char *m = mask;
+ const unsigned char *m = mask;
+ bool bitwise = false;
int i;
- add_payload(r, offset, len, NFT_PAYLOAD_NETWORK_HEADER);
-
for (i = 0; i < len; i++) {
- if (m[i] != 0xff)
+ if (m[i] != 0xff) {
+ bitwise = m[i] != 0;
break;
+ }
}
- if (i != len)
+ if (!bitwise)
+ len = i;
+
+ add_payload(r, offset, len, base);
+
+ if (bitwise)
add_bitwise(r, mask, len);
add_cmp_ptr(r, op, data, len);
@@ -831,14 +836,6 @@ void save_rule_details(const struct iptables_command_state *cs,
}
}
-void save_counters(const void *data)
-{
- const struct iptables_command_state *cs = data;
-
- printf("[%llu:%llu] ", (unsigned long long)cs->counters.pcnt,
- (unsigned long long)cs->counters.bcnt);
-}
-
void nft_ipv46_save_chain(const struct nftnl_chain *c, const char *policy)
{
const char *chain = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
@@ -989,41 +986,6 @@ void nft_ipv46_parse_target(struct xtables_target *t, void *data)
cs->target = t;
}
-bool nft_ipv46_rule_find(struct nft_handle *h, struct nftnl_rule *r, void *data)
-{
- struct iptables_command_state *cs = data, this = {};
- bool ret = false;
-
- nft_rule_to_iptables_command_state(h, r, &this);
-
- DEBUGP("comparing with... ");
-#ifdef DEBUG_DEL
- nft_rule_print_save(r, NFT_RULE_APPEND, 0);
-#endif
- if (!h->ops->is_same(cs, &this))
- goto out;
-
- if (!compare_matches(cs->matches, this.matches)) {
- DEBUGP("Different matches\n");
- goto out;
- }
-
- if (!compare_targets(cs->target, this.target)) {
- DEBUGP("Different target\n");
- goto out;
- }
-
- if (strcmp(cs->jumpto, this.jumpto) != 0) {
- DEBUGP("Different verdict\n");
- goto out;
- }
-
- ret = true;
-out:
- h->ops->clear_cs(&this);
- return ret;
-}
-
void nft_check_xt_legacy(int family, bool is_ipt_save)
{
static const char tables6[] = "/proc/net/ip6_tables_names";
diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h
index bee99a7d..da4ba9d2 100644
--- a/iptables/nft-shared.h
+++ b/iptables/nft-shared.h
@@ -8,6 +8,7 @@
#include <libnftnl/chain.h>
#include <linux/netfilter_arp/arp_tables.h>
+#include <linux/netfilter/nf_tables.h>
#include "xshared.h"
@@ -98,7 +99,6 @@ struct nft_family_ops {
void (*print_rule)(struct nft_handle *h, struct nftnl_rule *r,
unsigned int num, unsigned int format);
void (*save_rule)(const void *data, unsigned int format);
- void (*save_counters)(const void *data);
void (*save_chain)(const struct nftnl_chain *c, const char *policy);
void (*proto_parse)(struct iptables_command_state *cs,
struct xtables_args *args);
@@ -109,8 +109,6 @@ struct nft_family_ops {
void (*rule_to_cs)(struct nft_handle *h, const struct nftnl_rule *r,
struct iptables_command_state *cs);
void (*clear_cs)(struct iptables_command_state *cs);
- bool (*rule_find)(struct nft_handle *h, struct nftnl_rule *r,
- void *data);
int (*xlate)(const void *data, struct xt_xlate *xl);
};
@@ -124,7 +122,7 @@ void add_cmp_u16(struct nftnl_rule *r, uint16_t val, uint32_t op);
void add_cmp_u32(struct nftnl_rule *r, uint32_t val, uint32_t op);
void add_iniface(struct nftnl_rule *r, char *iface, uint32_t op);
void add_outiface(struct nftnl_rule *r, char *iface, uint32_t op);
-void add_addr(struct nftnl_rule *r, int offset,
+void add_addr(struct nftnl_rule *r, enum nft_payload_bases base, int offset,
void *data, void *mask, size_t len, uint32_t op);
void add_proto(struct nftnl_rule *r, int offset, size_t len,
uint8_t proto, uint32_t op);
@@ -162,7 +160,6 @@ void save_rule_details(const struct iptables_command_state *cs,
unsigned const char *iniface_mask,
const char *outiface,
unsigned const char *outiface_mask);
-void save_counters(const void *data);
void nft_ipv46_save_chain(const struct nftnl_chain *c, const char *policy);
void save_matches_and_target(const struct iptables_command_state *cs,
bool goto_flag, const void *fw,
@@ -171,8 +168,6 @@ void save_matches_and_target(const struct iptables_command_state *cs,
struct nft_family_ops *nft_family_ops_lookup(int family);
void nft_ipv46_parse_target(struct xtables_target *t, void *data);
-bool nft_ipv46_rule_find(struct nft_handle *h, struct nftnl_rule *r,
- void *data);
bool compare_matches(struct xtables_rule_match *mt1, struct xtables_rule_match *mt2);
bool compare_targets(struct xtables_target *tg1, struct xtables_target *tg2);
@@ -231,7 +226,8 @@ struct nft_xt_restore_cb {
int (*chain_restore)(struct nft_handle *h, const char *chain,
const char *table);
- int (*table_flush)(struct nft_handle *h, const char *table);
+ int (*table_flush)(struct nft_handle *h, const char *table,
+ bool verbose);
int (*do_command)(struct nft_handle *h, int argc, char *argv[],
char **table, bool restore);
@@ -252,4 +248,8 @@ void xtables_restore_parse(struct nft_handle *h,
const struct nft_xt_restore_parse *p);
void nft_check_xt_legacy(int family, bool is_ipt_save);
+
+#define min(x, y) ((x) < (y) ? (x) : (y))
+#define max(x, y) ((x) > (y) ? (x) : (y))
+
#endif
diff --git a/iptables/nft.c b/iptables/nft.c
index 3f2a62ae..bde4ca72 100644
--- a/iptables/nft.c
+++ b/iptables/nft.c
@@ -256,24 +256,6 @@ static int mnl_batch_talk(struct nft_handle *h, int numcmds)
return err;
}
-enum obj_update_type {
- NFT_COMPAT_TABLE_ADD,
- NFT_COMPAT_TABLE_FLUSH,
- NFT_COMPAT_CHAIN_ADD,
- NFT_COMPAT_CHAIN_USER_ADD,
- NFT_COMPAT_CHAIN_USER_DEL,
- NFT_COMPAT_CHAIN_USER_FLUSH,
- NFT_COMPAT_CHAIN_UPDATE,
- NFT_COMPAT_CHAIN_RENAME,
- NFT_COMPAT_CHAIN_ZERO,
- NFT_COMPAT_RULE_APPEND,
- NFT_COMPAT_RULE_INSERT,
- NFT_COMPAT_RULE_REPLACE,
- NFT_COMPAT_RULE_DELETE,
- NFT_COMPAT_RULE_FLUSH,
- NFT_COMPAT_SET_ADD,
-};
-
enum obj_action {
NFT_COMPAT_COMMIT,
NFT_COMPAT_ABORT,
@@ -283,7 +265,6 @@ struct obj_update {
struct list_head head;
enum obj_update_type type:8;
uint8_t skip:1;
- uint8_t implicit:1;
unsigned int seq;
union {
struct nftnl_table *table;
@@ -362,6 +343,14 @@ static int mnl_append_error(const struct nft_handle *h,
snprintf(tcr, sizeof(tcr), "set %s",
nftnl_set_get_str(o->set, NFTNL_SET_NAME));
break;
+ case NFT_COMPAT_RULE_LIST:
+ case NFT_COMPAT_RULE_CHECK:
+ case NFT_COMPAT_CHAIN_RESTORE:
+ case NFT_COMPAT_RULE_SAVE:
+ case NFT_COMPAT_RULE_ZERO:
+ case NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE:
+ assert(0);
+ break;
}
return snprintf(buf, len, "%s: %s", errmsg, tcr);
@@ -398,10 +387,11 @@ batch_set_add(struct nft_handle *h, enum obj_update_type type,
return batch_add(h, type, s);
}
-static int batch_chain_add(struct nft_handle *h, enum obj_update_type type,
+static struct obj_update *
+batch_chain_add(struct nft_handle *h, enum obj_update_type type,
struct nftnl_chain *c)
{
- return batch_add(h, type, c) ? 0 : -1;
+ return batch_add(h, type, c);
}
static struct obj_update *
@@ -411,6 +401,38 @@ batch_rule_add(struct nft_handle *h, enum obj_update_type type,
return batch_add(h, type, r);
}
+static void batch_obj_del(struct nft_handle *h, struct obj_update *o);
+
+static void batch_chain_flush(struct nft_handle *h,
+ const char *table, const char *chain)
+{
+ struct obj_update *obj, *tmp;
+
+ list_for_each_entry_safe(obj, tmp, &h->obj_list, head) {
+ struct nftnl_rule *r = obj->ptr;
+
+ switch (obj->type) {
+ case NFT_COMPAT_RULE_APPEND:
+ case NFT_COMPAT_RULE_INSERT:
+ case NFT_COMPAT_RULE_REPLACE:
+ case NFT_COMPAT_RULE_DELETE:
+ break;
+ default:
+ continue;
+ }
+
+ if (table &&
+ strcmp(table, nftnl_rule_get_str(r, NFTNL_RULE_TABLE)))
+ continue;
+
+ if (chain &&
+ strcmp(chain, nftnl_rule_get_str(r, NFTNL_RULE_CHAIN)))
+ continue;
+
+ batch_obj_del(h, obj);
+ }
+}
+
const struct builtin_table xtables_ipv4[NFT_TABLE_MAX] = {
[NFT_TABLE_RAW] = {
.name = "raw",
@@ -622,19 +644,13 @@ const 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,
const struct builtin_table *_t)
{
struct nftnl_table *t;
int ret;
- if (nft_table_initialized(h, _t->type))
+ if (h->cache->table[_t->type].exists)
return 0;
t = nftnl_table_alloc();
@@ -662,7 +678,9 @@ nft_chain_builtin_alloc(const struct builtin_table *table,
nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, chain->name);
nftnl_chain_set_u32(c, NFTNL_CHAIN_HOOKNUM, chain->hook);
nftnl_chain_set_u32(c, NFTNL_CHAIN_PRIO, chain->prio);
- nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, policy);
+ if (policy >= 0)
+ nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, policy);
+
nftnl_chain_set_str(c, NFTNL_CHAIN_TYPE, chain->type);
return c;
@@ -670,7 +688,8 @@ nft_chain_builtin_alloc(const struct builtin_table *table,
static void nft_chain_builtin_add(struct nft_handle *h,
const struct builtin_table *table,
- const struct builtin_chain *chain)
+ const struct builtin_chain *chain,
+ bool fake)
{
struct nftnl_chain *c;
@@ -678,8 +697,9 @@ static void nft_chain_builtin_add(struct nft_handle *h,
if (c == NULL)
return;
- batch_chain_add(h, NFT_COMPAT_CHAIN_ADD, c);
- nftnl_chain_list_add_tail(c, h->cache->table[table->type].chains);
+ if (!fake)
+ batch_chain_add(h, NFT_COMPAT_CHAIN_ADD, c);
+ nft_cache_add_chain(h, table, c);
}
/* find if built-in table already exists */
@@ -723,43 +743,64 @@ nft_chain_builtin_find(const struct builtin_table *t, const char *chain)
static void nft_chain_builtin_init(struct nft_handle *h,
const struct builtin_table *table)
{
- struct nftnl_chain_list *list;
- struct nftnl_chain *c;
int i;
/* Initialize built-in chains if they don't exist yet */
for (i=0; i < NF_INET_NUMHOOKS && table->chains[i].name != NULL; i++) {
- list = nft_chain_list_get(h, table->name,
- table->chains[i].name);
- if (!list)
- continue;
-
- c = nftnl_chain_list_lookup_byname(list, table->chains[i].name);
- if (c != NULL)
+ if (nft_chain_find(h, table->name, table->chains[i].name))
continue;
- nft_chain_builtin_add(h, table, &table->chains[i]);
+ nft_chain_builtin_add(h, table, &table->chains[i], false);
}
}
-static int nft_xt_builtin_init(struct nft_handle *h, const char *table)
+static const struct builtin_table *
+nft_xt_builtin_table_init(struct nft_handle *h, const char *table)
{
const struct builtin_table *t;
+ if (!h->cache_init)
+ return NULL;
+
t = nft_table_builtin_find(h, table);
if (t == NULL)
- return -1;
+ return NULL;
- if (nft_table_initialized(h, t->type))
+ if (nft_table_builtin_add(h, t) < 0)
+ return NULL;
+
+ return t;
+}
+
+static int nft_xt_builtin_init(struct nft_handle *h, const char *table,
+ const char *chain)
+{
+ const struct builtin_table *t;
+ const struct builtin_chain *c;
+
+ if (!h->cache_init)
return 0;
- if (nft_table_builtin_add(h, t) < 0)
+ t = nft_xt_builtin_table_init(h, table);
+ if (!t)
return -1;
- nft_chain_builtin_init(h, t);
+ if (h->cache_req.level < NFT_CL_CHAINS)
+ return 0;
+
+ if (!chain) {
+ nft_chain_builtin_init(h, t);
+ return 0;
+ }
+
+ c = nft_chain_builtin_find(t, chain);
+ if (!c)
+ return -1;
- h->cache->table[t->type].initialized = true;
+ if (h->cache->table[t->type].base_chains[c->hook])
+ return 0;
+ nft_chain_builtin_add(h, t, c, false);
return 0;
}
@@ -771,6 +812,40 @@ static bool nft_chain_builtin(struct nftnl_chain *c)
return nftnl_chain_get(c, NFTNL_CHAIN_HOOKNUM) != NULL;
}
+static int __nft_xt_fake_builtin_chains(struct nft_handle *h,
+ const char *table, void *data)
+{
+ const char *chain = data ? *(const char **)data : NULL;
+ const struct builtin_table *t;
+ struct nft_chain **bcp;
+ int i;
+
+ t = nft_table_builtin_find(h, table);
+ if (!t)
+ return -1;
+
+ bcp = h->cache->table[t->type].base_chains;
+ for (i = 0; i < NF_INET_NUMHOOKS && t->chains[i].name; i++) {
+ if (bcp[t->chains[i].hook])
+ continue;
+
+ if (chain && strcmp(chain, t->chains[i].name))
+ continue;
+
+ nft_chain_builtin_add(h, t, &t->chains[i], true);
+ }
+ return 0;
+}
+
+int nft_xt_fake_builtin_chains(struct nft_handle *h,
+ const char *table, const char *chain)
+{
+ if (table)
+ return __nft_xt_fake_builtin_chains(h, table, &chain);
+
+ return nft_for_each_table(h, __nft_xt_fake_builtin_chains, &chain);
+}
+
int nft_restart(struct nft_handle *h)
{
mnl_socket_close(h->nl);
@@ -789,8 +864,10 @@ int nft_restart(struct nft_handle *h)
return 0;
}
-int nft_init(struct nft_handle *h, const struct builtin_table *t)
+int nft_init(struct nft_handle *h, int family, const struct builtin_table *t)
{
+ memset(h, 0, sizeof(*h));
+
h->nl = mnl_socket_open(NETLINK_NETFILTER);
if (h->nl == NULL)
return -1;
@@ -800,19 +877,37 @@ int nft_init(struct nft_handle *h, const struct builtin_table *t)
return -1;
}
+ h->ops = nft_family_ops_lookup(family);
+ if (!h->ops)
+ xtables_error(PARAMETER_PROBLEM, "Unknown family");
+
h->portid = mnl_socket_get_portid(h->nl);
h->tables = t;
h->cache = &h->__cache[0];
+ h->family = family;
INIT_LIST_HEAD(&h->obj_list);
INIT_LIST_HEAD(&h->err_list);
+ INIT_LIST_HEAD(&h->cmd_list);
+ INIT_LIST_HEAD(&h->cache_req.chain_list);
return 0;
}
void nft_fini(struct nft_handle *h)
{
- flush_chain_cache(h, NULL);
+ struct list_head *pos, *n;
+
+ list_for_each_safe(pos, n, &h->cmd_list)
+ nft_cmd_free(list_entry(pos, struct nft_cmd, head));
+
+ list_for_each_safe(pos, n, &h->obj_list)
+ batch_obj_del(h, list_entry(pos, struct obj_update, head));
+
+ list_for_each_safe(pos, n, &h->err_list)
+ mnl_err_list_free(list_entry(pos, struct mnl_err, head));
+
+ nft_release_cache(h);
mnl_socket_close(h->nl);
}
@@ -843,7 +938,7 @@ static struct nftnl_chain *nft_chain_new(struct nft_handle *h,
}
/* if this built-in table does not exists, create it */
- nft_table_builtin_add(h, _t);
+ nft_xt_builtin_init(h, table, chain);
_c = nft_chain_builtin_find(_t, chain);
if (_c != NULL) {
@@ -871,7 +966,6 @@ int nft_chain_set(struct nft_handle *h, const char *table,
const struct xt_counters *counters)
{
struct nftnl_chain *c = NULL;
- int ret;
nft_fn = nft_chain_set;
@@ -879,16 +973,19 @@ int nft_chain_set(struct nft_handle *h, const char *table,
c = nft_chain_new(h, table, chain, NF_DROP, counters);
else if (strcmp(policy, "ACCEPT") == 0)
c = nft_chain_new(h, table, chain, NF_ACCEPT, counters);
+ else if (strcmp(policy, "-") == 0)
+ c = nft_chain_new(h, table, chain, -1, counters);
else
errno = EINVAL;
if (c == NULL)
return 0;
- ret = batch_chain_add(h, NFT_COMPAT_CHAIN_UPDATE, c);
+ if (!batch_chain_add(h, NFT_COMPAT_CHAIN_UPDATE, c))
+ return 0;
/* the core expects 1 for success and 0 for error */
- return ret == 0 ? 1 : 0;
+ return 1;
}
static int __add_match(struct nftnl_expr *e, struct xt_entry_match *m)
@@ -950,6 +1047,7 @@ static struct nftnl_set *add_anon_set(struct nft_handle *h, const char *table,
{
static uint32_t set_id = 0;
struct nftnl_set *s;
+ struct nft_cmd *cmd;
s = nftnl_set_alloc();
if (!s)
@@ -965,7 +1063,14 @@ static struct nftnl_set *add_anon_set(struct nft_handle *h, const char *table,
nftnl_set_set_u32(s, NFTNL_SET_KEY_LEN, key_len);
nftnl_set_set_u32(s, NFTNL_SET_DESC_SIZE, size);
- return batch_set_add(h, NFT_COMPAT_SET_ADD, s) ? s : NULL;
+ cmd = nft_cmd_new(h, NFT_COMPAT_SET_ADD, table, NULL, NULL, -1, false);
+ if (!cmd) {
+ nftnl_set_free(s);
+ return NULL;
+ }
+ cmd->obj.set = s;
+
+ return s;
}
static struct nftnl_expr *
@@ -1022,19 +1127,28 @@ static int __add_nft_among(struct nft_handle *h, const char *table,
};
struct nftnl_expr *e;
struct nftnl_set *s;
+ uint32_t flags = 0;
int idx = 0;
if (ip) {
type = type << CONCAT_TYPE_BITS | NFT_DATATYPE_IPADDR;
len += sizeof(struct in_addr) + NETLINK_ALIGN - 1;
len &= ~(NETLINK_ALIGN - 1);
+ flags = NFT_SET_INTERVAL;
}
- s = add_anon_set(h, table, 0, type, len, cnt);
+ s = add_anon_set(h, table, flags, type, len, cnt);
if (!s)
return -ENOMEM;
set_id = nftnl_set_get_u32(s, NFTNL_SET_ID);
+ if (ip) {
+ uint8_t field_len[2] = { ETH_ALEN, sizeof(struct in_addr) };
+
+ nftnl_set_set_data(s, NFTNL_SET_DESC_CONCAT,
+ field_len, sizeof(field_len));
+ }
+
for (idx = 0; idx < cnt; idx++) {
struct nftnl_set_elem *elem = nftnl_set_elem_alloc();
@@ -1042,6 +1156,15 @@ static int __add_nft_among(struct nft_handle *h, const char *table,
return -ENOMEM;
nftnl_set_elem_set(elem, NFTNL_SET_ELEM_KEY,
&pairs[idx], len);
+ if (ip) {
+ struct in_addr tmp = pairs[idx].in;
+
+ if (tmp.s_addr == INADDR_ANY)
+ pairs[idx].in.s_addr = INADDR_BROADCAST;
+ nftnl_set_elem_set(elem, NFTNL_SET_ELEM_KEY_END,
+ &pairs[idx], len);
+ pairs[idx].in = tmp;
+ }
nftnl_set_elem_add(s, elem);
}
@@ -1302,7 +1425,7 @@ void add_compat(struct nftnl_rule *r, uint32_t proto, bool inv)
inv ? NFT_RULE_COMPAT_F_INV : 0);
}
-static struct nftnl_rule *
+struct nftnl_rule *
nft_rule_new(struct nft_handle *h, const char *chain, const char *table,
void *data)
{
@@ -1325,33 +1448,17 @@ err:
return NULL;
}
-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, struct nftnl_rule *ref, bool verbose)
+ struct nftnl_rule *r, struct nftnl_rule *ref, bool verbose)
{
- struct nftnl_chain *c;
- struct nftnl_rule *r;
+ struct nft_chain *c;
int type;
- nft_xt_builtin_init(h, table);
-
- /* Since ebtables user-defined chain policies are implemented as last
- * rule in nftables, rule cache is required here to treat them right. */
- if (h->family == NFPROTO_BRIDGE) {
- c = nft_chain_find(h, table, chain);
- if (c && !nft_chain_builtin(c))
- nft_build_cache(h, c);
- }
+ nft_xt_builtin_init(h, table, chain);
nft_fn = nft_rule_append;
- r = nft_rule_new(h, chain, table, data);
- if (r == NULL)
- return 0;
-
if (ref) {
nftnl_rule_set_u64(r, NFTNL_RULE_HANDLE,
nftnl_rule_get_u64(ref, NFTNL_RULE_HANDLE));
@@ -1359,24 +1466,23 @@ nft_rule_append(struct nft_handle *h, const char *chain, const char *table,
} else
type = NFT_COMPAT_RULE_APPEND;
- if (batch_rule_add(h, type, r) == NULL) {
- nftnl_rule_free(r);
+ if (batch_rule_add(h, type, r) == NULL)
return 0;
- }
if (verbose)
h->ops->print_rule(h, r, 0, FMT_PRINT_RULE);
if (ref) {
nftnl_chain_rule_insert_at(r, ref);
- nftnl_chain_rule_del(r);
+ nftnl_chain_rule_del(ref);
+ nftnl_rule_free(ref);
} else {
c = nft_chain_find(h, table, chain);
if (!c) {
errno = ENOENT;
return 0;
}
- nftnl_chain_rule_add_tail(r, c);
+ nftnl_chain_rule_add_tail(r, c->nftnl);
}
return 1;
@@ -1392,8 +1498,9 @@ nft_rule_print_save(struct nft_handle *h, const struct nftnl_rule *r,
ops->rule_to_cs(h, r, &cs);
- if (!(format & (FMT_NOCOUNTS | FMT_C_COUNTS)) && ops->save_counters)
- ops->save_counters(&cs);
+ if (!(format & (FMT_NOCOUNTS | FMT_C_COUNTS)))
+ printf("[%llu:%llu] ", (unsigned long long)cs.counters.pcnt,
+ (unsigned long long)cs.counters.bcnt);
/* print chain name */
switch(type) {
@@ -1497,61 +1604,44 @@ static const char *policy_name[NF_ACCEPT+1] = {
[NF_ACCEPT] = "ACCEPT",
};
-int nft_chain_save(struct nft_handle *h, struct nftnl_chain_list *list)
+int nft_chain_save(struct nft_chain *nc, void *data)
{
- struct nft_family_ops *ops = h->ops;
- struct nftnl_chain_list_iter *iter;
- struct nftnl_chain *c;
-
- iter = nftnl_chain_list_iter_create(list);
- if (iter == NULL)
- return 0;
-
- 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);
+ struct nftnl_chain *c = nc->nftnl;
+ struct nft_handle *h = data;
+ const char *policy = NULL;
- c = nftnl_chain_list_iter_next(iter);
+ if (nftnl_chain_is_set(c, NFTNL_CHAIN_POLICY)) {
+ policy = policy_name[nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY)];
+ } else if (nft_chain_builtin(c)) {
+ policy = "ACCEPT";
+ } else if (h->family == NFPROTO_BRIDGE) {
+ policy = "RETURN";
}
- nftnl_chain_list_iter_destroy(iter);
+ if (h->ops->save_chain)
+ h->ops->save_chain(c, policy);
- return 1;
+ return 0;
}
-static int nft_chain_save_rules(struct nft_handle *h,
- struct nftnl_chain *c, unsigned int format)
+struct nft_rule_save_data {
+ struct nft_handle *h;
+ unsigned int format;
+};
+
+static int nft_rule_save_cb(struct nft_chain *c, void *data)
{
+ struct nft_rule_save_data *d = data;
struct nftnl_rule_iter *iter;
struct nftnl_rule *r;
- iter = nftnl_rule_iter_create(c);
+ iter = nftnl_rule_iter_create(c->nftnl);
if (iter == NULL)
return 1;
r = nftnl_rule_iter_next(iter);
while (r != NULL) {
- nft_rule_print_save(h, r, NFT_RULE_APPEND, format);
+ nft_rule_print_save(d->h, r, NFT_RULE_APPEND, d->format);
r = nftnl_rule_iter_next(iter);
}
@@ -1561,38 +1651,35 @@ static int nft_chain_save_rules(struct nft_handle *h,
int nft_rule_save(struct nft_handle *h, const char *table, unsigned int format)
{
- struct nftnl_chain_list_iter *iter;
- struct nftnl_chain_list *list;
- struct nftnl_chain *c;
- int ret = 0;
+ struct nft_rule_save_data d = {
+ .h = h,
+ .format = format,
+ };
+ int ret;
- list = nft_chain_list_get(h, table, NULL);
- if (!list)
- return 0;
+ ret = nft_chain_foreach(h, table, nft_rule_save_cb, &d);
- iter = nftnl_chain_list_iter_create(list);
- if (!iter)
- return 0;
+ /* the core expects 1 for success and 0 for error */
+ return ret == 0 ? 1 : 0;
+}
- c = nftnl_chain_list_iter_next(iter);
- while (c) {
- nft_build_cache(h, c);
- ret = nft_chain_save_rules(h, c, format);
- if (ret != 0)
- break;
+struct nftnl_set *nft_set_batch_lookup_byid(struct nft_handle *h,
+ uint32_t set_id)
+{
+ struct obj_update *n;
- c = nftnl_chain_list_iter_next(iter);
+ list_for_each_entry(n, &h->obj_list, head) {
+ if (n->type == NFT_COMPAT_SET_ADD &&
+ nftnl_set_get_u32(n->set, NFTNL_SET_ID) == set_id)
+ return n->set;
}
- nftnl_chain_list_iter_destroy(iter);
-
- /* the core expects 1 for success and 0 for error */
- return ret == 0 ? 1 : 0;
+ return NULL;
}
static void
__nft_rule_flush(struct nft_handle *h, const char *table,
- const char *chain, bool verbose, bool implicit)
+ const char *chain, bool verbose, bool skip)
{
struct obj_update *obj;
struct nftnl_rule *r;
@@ -1614,31 +1701,46 @@ __nft_rule_flush(struct nft_handle *h, const char *table,
return;
}
- obj->implicit = implicit;
+ obj->skip = skip;
+}
+
+struct nft_rule_flush_data {
+ struct nft_handle *h;
+ const char *table;
+ bool verbose;
+};
+
+static int nft_rule_flush_cb(struct nft_chain *c, void *data)
+{
+ const char *chain = nftnl_chain_get_str(c->nftnl, NFTNL_CHAIN_NAME);
+ struct nft_rule_flush_data *d = data;
+
+ batch_chain_flush(d->h, d->table, chain);
+ __nft_rule_flush(d->h, d->table, chain, d->verbose, false);
+ flush_rule_cache(d->h, d->table, c);
+ return 0;
}
int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table,
bool verbose)
{
- struct nftnl_chain_list_iter *iter;
- struct nftnl_chain_list *list;
- struct nftnl_chain *c = NULL;
+ struct nft_rule_flush_data d = {
+ .h = h,
+ .table = table,
+ .verbose = verbose,
+ };
+ struct nft_chain *c = NULL;
int ret = 0;
- nft_xt_builtin_init(h, table);
-
nft_fn = nft_rule_flush;
- if (chain || verbose) {
- list = nft_chain_list_get(h, table, chain);
- if (list == NULL) {
- ret = 1;
- goto err;
- }
- }
+ if (chain || verbose)
+ nft_xt_builtin_init(h, table, chain);
+ else if (!nft_table_find(h, table))
+ return 1;
if (chain) {
- c = nftnl_chain_list_lookup_byname(list, chain);
+ c = nft_chain_find(h, table, chain);
if (!c) {
errno = ENOENT;
return 0;
@@ -1646,40 +1748,26 @@ int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table,
}
if (chain || !verbose) {
+ batch_chain_flush(h, table, chain);
__nft_rule_flush(h, table, chain, verbose, false);
flush_rule_cache(h, table, c);
return 1;
}
- iter = nftnl_chain_list_iter_create(list);
- if (iter == NULL) {
- ret = 1;
- goto err;
- }
+ ret = nft_chain_foreach(h, table, nft_rule_flush_cb, &d);
- c = nftnl_chain_list_iter_next(iter);
- while (c != NULL) {
- chain = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
-
- __nft_rule_flush(h, table, chain, verbose, false);
- flush_rule_cache(h, table, c);
- c = nftnl_chain_list_iter_next(iter);
- }
- nftnl_chain_list_iter_destroy(iter);
-err:
/* the core expects 1 for success and 0 for error */
return ret == 0 ? 1 : 0;
}
int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *table)
{
- struct nftnl_chain_list *list;
+ const struct builtin_table *t;
struct nftnl_chain *c;
- int ret;
nft_fn = nft_chain_user_add;
- nft_xt_builtin_init(h, table);
+ t = nft_xt_builtin_table_init(h, table);
if (nft_chain_exists(h, table, chain)) {
errno = EEXIST;
@@ -1695,53 +1783,57 @@ int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *tabl
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);
+ if (!batch_chain_add(h, NFT_COMPAT_CHAIN_USER_ADD, c))
+ return 0;
- list = nft_chain_list_get(h, table, chain);
- if (list)
- nftnl_chain_list_add(c, list);
+ nft_cache_add_chain(h, t, c);
/* the core expects 1 for success and 0 for error */
- return ret == 0 ? 1 : 0;
+ return 1;
}
int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table)
{
- struct nftnl_chain_list *list;
+ const struct builtin_table *t;
+ struct obj_update *obj;
struct nftnl_chain *c;
+ struct nft_chain *nc;
bool created = false;
- int ret;
- 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 {
+ t = nft_xt_builtin_table_init(h, table);
+
+ nc = nft_chain_find(h, table, chain);
+ if (!nc) {
c = nftnl_chain_alloc();
if (!c)
- return -1;
+ return 0;
nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, table);
nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, chain);
created = true;
+
+ nft_cache_add_chain(h, t, c);
+ } else {
+ c = nc->nftnl;
+
+ /* If the chain should vanish meanwhile, kernel genid changes
+ * and the transaction is refreshed enabling the chain add
+ * object. With the handle still set, kernel interprets it as a
+ * chain replace job and errors since it is not found anymore.
+ */
+ nftnl_chain_unset(c, NFTNL_CHAIN_HANDLE);
}
- if (h->family == NFPROTO_BRIDGE)
- nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, NF_ACCEPT);
+ __nft_rule_flush(h, table, chain, false, created);
- if (!created)
+ obj = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_ADD, c);
+ if (!obj)
return 0;
- ret = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_ADD, c);
+ obj->skip = !created;
- list = nft_chain_list_get(h, table, chain);
- if (list)
- nftnl_chain_list_add(c, list);
-
- return ret;
+ /* the core expects 1 for success and 0 for error */
+ return 1;
}
/* From linux/netlink.h */
@@ -1755,11 +1847,11 @@ struct chain_user_del_data {
int builtin_err;
};
-static int __nft_chain_user_del(struct nftnl_chain *c, void *data)
+static int __nft_chain_user_del(struct nft_chain *nc, void *data)
{
struct chain_user_del_data *d = data;
+ struct nftnl_chain *c = nc->nftnl;
struct nft_handle *h = d->handle;
- int ret;
/* don't delete built-in chain */
if (nft_chain_builtin(c))
@@ -1769,17 +1861,17 @@ static int __nft_chain_user_del(struct nftnl_chain *c, void *data)
fprintf(stdout, "Deleting chain `%s'\n",
nftnl_chain_get_str(c, NFTNL_CHAIN_NAME));
- /* This triggers required policy rule deletion. */
- if (h->family == NFPROTO_BRIDGE)
- nft_build_cache(h, c);
/* 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)
+ if (!batch_chain_add(h, NFT_COMPAT_CHAIN_USER_DEL, c))
return -1;
- nftnl_chain_list_del(c);
+ /* nftnl_chain is freed when deleting the batch object */
+ nc->nftnl = NULL;
+
+ nft_chain_list_del(nc);
+ nft_chain_free(nc);
return 0;
}
@@ -1790,18 +1882,13 @@ int nft_chain_user_del(struct nft_handle *h, const char *chain,
.handle = h,
.verbose = verbose,
};
- struct nftnl_chain_list *list;
- struct nftnl_chain *c;
+ struct nft_chain *c;
int ret = 0;
nft_fn = nft_chain_user_del;
- list = nft_chain_list_get(h, table, chain);
- if (list == NULL)
- return 0;
-
if (chain) {
- c = nftnl_chain_list_lookup_byname(list, chain);
+ c = nft_chain_find(h, table, chain);
if (!c) {
errno = ENOENT;
return 0;
@@ -1813,24 +1900,12 @@ int nft_chain_user_del(struct nft_handle *h, const char *chain,
goto out;
}
- ret = nftnl_chain_list_foreach(list, __nft_chain_user_del, &d);
+ ret = nft_chain_foreach(h, table, __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 *
-nft_chain_find(struct nft_handle *h, const char *table, const char *chain)
-{
- struct nftnl_chain_list *list;
-
- list = nft_chain_list_get(h, table, chain);
- if (list == NULL)
- return NULL;
-
- return nftnl_chain_list_lookup_byname(list, chain);
-}
-
bool nft_chain_exists(struct nft_handle *h,
const char *table, const char *chain)
{
@@ -1850,8 +1925,8 @@ int nft_chain_user_rename(struct nft_handle *h,const char *chain,
const char *table, const char *newname)
{
struct nftnl_chain *c;
+ struct nft_chain *nc;
uint64_t handle;
- int ret;
nft_fn = nft_chain_user_rename;
@@ -1860,18 +1935,13 @@ int nft_chain_user_rename(struct nft_handle *h,const char *chain,
return 0;
}
- nft_xt_builtin_init(h, table);
-
- /* Config load changed errno. Ensure genuine info for our callers. */
- errno = 0;
-
/* Find the old chain to be renamed */
- c = nft_chain_find(h, table, chain);
- if (c == NULL) {
+ nc = nft_chain_find(h, table, chain);
+ if (nc == NULL) {
errno = ENOENT;
return 0;
}
- handle = nftnl_chain_get_u64(c, NFTNL_CHAIN_HANDLE);
+ handle = nftnl_chain_get_u64(nc->nftnl, NFTNL_CHAIN_HANDLE);
/* Now prepare the new name for the chain */
c = nftnl_chain_alloc();
@@ -1882,73 +1952,37 @@ int nft_chain_user_rename(struct nft_handle *h,const char *chain,
nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, newname);
nftnl_chain_set_u64(c, NFTNL_CHAIN_HANDLE, handle);
- ret = batch_chain_add(h, NFT_COMPAT_CHAIN_RENAME, c);
+ if (!batch_chain_add(h, NFT_COMPAT_CHAIN_RENAME, c))
+ return 0;
/* the core expects 1 for success and 0 for error */
- return ret == 0 ? 1 : 0;
+ return 1;
}
bool nft_table_find(struct nft_handle *h, const char *tablename)
{
- struct nftnl_table_list_iter *iter;
- struct nftnl_table_list *list;
- struct nftnl_table *t;
- bool ret = false;
-
- list = nftnl_table_list_get(h);
- if (list == NULL)
- goto err;
-
- iter = nftnl_table_list_iter_create(list);
- if (iter == NULL)
- goto err;
-
- t = nftnl_table_list_iter_next(iter);
- while (t != NULL) {
- const char *this_tablename =
- nftnl_table_get(t, NFTNL_TABLE_NAME);
-
- if (strcmp(tablename, this_tablename) == 0) {
- ret = true;
- break;
- }
-
- t = nftnl_table_list_iter_next(iter);
- }
-
- nftnl_table_list_iter_destroy(iter);
+ const struct builtin_table *t;
-err:
- return ret;
+ t = nft_table_builtin_find(h, tablename);
+ return t ? h->cache->table[t->type].exists : false;
}
int nft_for_each_table(struct nft_handle *h,
int (*func)(struct nft_handle *h, const char *tablename, void *data),
void *data)
{
- struct nftnl_table_list *list;
- struct nftnl_table_list_iter *iter;
- struct nftnl_table *t;
-
- list = nftnl_table_list_get(h);
- if (list == NULL)
- return -1;
-
- iter = nftnl_table_list_iter_create(list);
- if (iter == NULL)
- return -1;
+ int i;
- t = nftnl_table_list_iter_next(iter);
- while (t != NULL) {
- const char *tablename =
- nftnl_table_get(t, NFTNL_TABLE_NAME);
+ for (i = 0; i < NFT_TABLE_MAX; i++) {
+ if (h->tables[i].name == NULL)
+ continue;
- func(h, tablename, data);
+ if (!h->cache->table[h->tables[i].type].exists)
+ continue;
- t = nftnl_table_list_iter_next(iter);
+ func(h, h->tables[i].name, data);
}
- nftnl_table_list_iter_destroy(iter);
return 0;
}
@@ -1975,7 +2009,7 @@ static int __nft_table_flush(struct nft_handle *h, const char *table, bool exist
_t = nft_table_builtin_find(h, table);
assert(_t);
- h->cache->table[_t->type].initialized = false;
+ h->cache->table[_t->type].exists = false;
flush_chain_cache(h, table);
@@ -1984,52 +2018,21 @@ static int __nft_table_flush(struct nft_handle *h, const char *table, bool exist
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;
+ const struct builtin_table *t;
int ret = 0;
nft_fn = nft_table_flush;
- list = nftnl_table_list_get(h);
- if (list == NULL) {
- ret = -1;
- goto err_out;
- }
-
- iter = nftnl_table_list_iter_create(list);
- if (iter == NULL) {
- ret = -1;
- goto err_table_list;
- }
-
- t = nftnl_table_list_iter_next(iter);
- while (t != NULL) {
- const char *table_name =
- nftnl_table_get_str(t, NFTNL_TABLE_NAME);
-
- if (strcmp(table_name, table) == 0) {
- exists = true;
- break;
- }
+ t = nft_table_builtin_find(h, table);
+ if (!t)
+ return 0;
- t = nftnl_table_list_iter_next(iter);
- }
+ ret = __nft_table_flush(h, table, h->cache->table[t->type].exists);
- ret = __nft_table_flush(h, table, exists);
- nftnl_table_list_iter_destroy(iter);
-err_table_list:
-err_out:
/* the core expects 1 for success and 0 for error */
return ret == 0 ? 1 : 0;
}
-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 *r)
{
struct obj_update *obj;
@@ -2047,15 +2050,54 @@ static int __nft_rule_del(struct nft_handle *h, struct nftnl_rule *r)
return 1;
}
+static bool nft_rule_cmp(struct nft_handle *h, struct nftnl_rule *r,
+ struct nftnl_rule *rule)
+{
+ struct iptables_command_state _cs = {}, this = {}, *cs = &_cs;
+ bool ret = false;
+
+ h->ops->rule_to_cs(h, r, &this);
+ h->ops->rule_to_cs(h, rule, cs);
+
+ DEBUGP("comparing with... ");
+#ifdef DEBUG_DEL
+ nft_rule_print_save(h, r, NFT_RULE_APPEND, 0);
+#endif
+ if (!h->ops->is_same(cs, &this))
+ goto out;
+
+ if (!compare_matches(cs->matches, this.matches)) {
+ DEBUGP("Different matches\n");
+ goto out;
+ }
+
+ if (!compare_targets(cs->target, this.target)) {
+ DEBUGP("Different target\n");
+ goto out;
+ }
+
+ if ((!cs->target || !this.target) &&
+ strcmp(cs->jumpto, this.jumpto) != 0) {
+ DEBUGP("Different verdict\n");
+ goto out;
+ }
+
+ ret = true;
+out:
+ h->ops->clear_cs(&this);
+ h->ops->clear_cs(cs);
+ return ret;
+}
+
static struct nftnl_rule *
-nft_rule_find(struct nft_handle *h, struct nftnl_chain *c, void *data, int rulenum)
+nft_rule_find(struct nft_handle *h, struct nft_chain *nc,
+ struct nftnl_rule *rule, int rulenum)
{
+ struct nftnl_chain *c = nc->nftnl;
struct nftnl_rule *r;
struct nftnl_rule_iter *iter;
bool found = false;
- nft_build_cache(h, c);
-
if (rulenum >= 0)
/* Delete by rule number case */
return nftnl_rule_lookup_byindex(c, rulenum);
@@ -2066,7 +2108,7 @@ nft_rule_find(struct nft_handle *h, struct nftnl_chain *c, void *data, int rulen
r = nftnl_rule_iter_next(iter);
while (r != NULL) {
- found = h->ops->rule_find(h, r, data);
+ found = nft_rule_cmp(h, r, rule);
if (found)
break;
r = nftnl_rule_iter_next(iter);
@@ -2078,10 +2120,10 @@ nft_rule_find(struct nft_handle *h, struct nftnl_chain *c, void *data, int rulen
}
int nft_rule_check(struct nft_handle *h, const char *chain,
- const char *table, void *data, bool verbose)
+ const char *table, struct nftnl_rule *rule, bool verbose)
{
- struct nftnl_chain *c;
struct nftnl_rule *r;
+ struct nft_chain *c;
nft_fn = nft_rule_check;
@@ -2089,7 +2131,7 @@ int nft_rule_check(struct nft_handle *h, const char *chain,
if (!c)
goto fail_enoent;
- r = nft_rule_find(h, c, data, -1);
+ r = nft_rule_find(h, c, rule, -1);
if (r == NULL)
goto fail_enoent;
@@ -2103,11 +2145,11 @@ fail_enoent:
}
int nft_rule_delete(struct nft_handle *h, const char *chain,
- const char *table, void *data, bool verbose)
+ const char *table, struct nftnl_rule *rule, bool verbose)
{
int ret = 0;
- struct nftnl_chain *c;
struct nftnl_rule *r;
+ struct nft_chain *c;
nft_fn = nft_rule_delete;
@@ -2117,7 +2159,7 @@ int nft_rule_delete(struct nft_handle *h, const char *chain,
return 0;
}
- r = nft_rule_find(h, c, data, -1);
+ r = nft_rule_find(h, c, rule, -1);
if (r != NULL) {
ret =__nft_rule_del(h, r);
if (ret < 0)
@@ -2132,16 +2174,11 @@ 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,
+ const char *table, struct nftnl_rule *r,
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 (ref) {
ref_id = nftnl_rule_get_u64(ref, NFTNL_RULE_HANDLE);
if (ref_id > 0) {
@@ -2158,10 +2195,8 @@ nft_rule_add(struct nft_handle *h, const char *chain,
}
}
- if (!batch_rule_add(h, NFT_COMPAT_RULE_INSERT, r)) {
- nftnl_rule_free(r);
+ if (!batch_rule_add(h, NFT_COMPAT_RULE_INSERT, r))
return NULL;
- }
if (verbose)
h->ops->print_rule(h, r, 0, FMT_PRINT_RULE);
@@ -2170,12 +2205,13 @@ 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)
+ const char *table, struct nftnl_rule *new_rule, int rulenum,
+ bool verbose)
{
- struct nftnl_rule *r = NULL, *new_rule;
- struct nftnl_chain *c;
+ struct nftnl_rule *r = NULL;
+ struct nft_chain *c;
- nft_xt_builtin_init(h, table);
+ nft_xt_builtin_init(h, table, chain);
nft_fn = nft_rule_insert;
@@ -2186,29 +2222,29 @@ int nft_rule_insert(struct nft_handle *h, const char *chain,
}
if (rulenum > 0) {
- r = nft_rule_find(h, c, data, rulenum);
+ r = nft_rule_find(h, c, new_rule, rulenum);
if (r == NULL) {
/* special case: iptables allows to insert into
* rule_count + 1 position.
*/
- r = nft_rule_find(h, c, data, rulenum - 1);
+ r = nft_rule_find(h, c, new_rule, rulenum - 1);
if (r != NULL)
- return nft_rule_append(h, chain, table, data,
- NULL, verbose);
+ return nft_rule_append(h, chain, table,
+ new_rule, NULL, verbose);
errno = E2BIG;
goto err;
}
}
- new_rule = nft_rule_add(h, chain, table, data, r, verbose);
+ new_rule = nft_rule_add(h, chain, table, new_rule, r, verbose);
if (!new_rule)
goto err;
if (r)
nftnl_chain_rule_insert_at(new_rule, r);
else
- nftnl_chain_rule_add(new_rule, c);
+ nftnl_chain_rule_add(new_rule, c->nftnl);
return 1;
err:
@@ -2219,8 +2255,8 @@ 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 nft_chain *c;
nft_fn = nft_rule_delete_num;
@@ -2243,11 +2279,12 @@ int nft_rule_delete_num(struct nft_handle *h, const char *chain,
}
int nft_rule_replace(struct nft_handle *h, const char *chain,
- const char *table, void *data, int rulenum, bool verbose)
+ const char *table, struct nftnl_rule *rule,
+ int rulenum, bool verbose)
{
int ret = 0;
- struct nftnl_chain *c;
struct nftnl_rule *r;
+ struct nft_chain *c;
nft_fn = nft_rule_replace;
@@ -2257,13 +2294,13 @@ int nft_rule_replace(struct nft_handle *h, const char *chain,
return 0;
}
- r = nft_rule_find(h, c, data, rulenum);
+ r = nft_rule_find(h, c, rule, rulenum);
if (r != NULL) {
DEBUGP("replacing rule with handle=%llu\n",
(unsigned long long)
nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE));
- ret = nft_rule_append(h, chain, table, data, r, verbose);
+ ret = nft_rule_append(h, chain, table, rule, r, verbose);
} else
errno = E2BIG;
@@ -2326,8 +2363,9 @@ static int nft_rule_count(struct nft_handle *h, struct nftnl_chain *c)
}
static void __nft_print_header(struct nft_handle *h,
- struct nftnl_chain *c, unsigned int format)
+ struct nft_chain *nc, unsigned int format)
{
+ struct nftnl_chain *c = nc->nftnl;
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);
@@ -2345,55 +2383,64 @@ static void __nft_print_header(struct nft_handle *h,
&ctrs, basechain, refs - entries, entries);
}
+struct nft_rule_list_cb_data {
+ struct nft_handle *h;
+ unsigned int format;
+ int rulenum;
+ bool found;
+ bool save_fmt;
+ void (*cb)(struct nft_handle *h, struct nftnl_rule *r,
+ unsigned int num, unsigned int format);
+};
+
+static int nft_rule_list_cb(struct nft_chain *c, void *data)
+{
+ struct nft_rule_list_cb_data *d = data;
+
+ if (!d->save_fmt) {
+ if (d->found)
+ printf("\n");
+ d->found = true;
+
+ __nft_print_header(d->h, c, d->format);
+ }
+
+ return __nft_rule_list(d->h, c->nftnl, d->rulenum, d->format, d->cb);
+}
+
int nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
int rulenum, unsigned int format)
{
const struct nft_family_ops *ops = h->ops;
- struct nftnl_chain_list *list;
- struct nftnl_chain_list_iter *iter;
- struct nftnl_chain *c;
- bool found = false;
+ struct nft_rule_list_cb_data d = {
+ .h = h,
+ .format = format,
+ .rulenum = rulenum,
+ .cb = ops->print_rule,
+ };
+ struct nft_chain *c;
- nft_xt_builtin_init(h, table);
+ nft_xt_fake_builtin_chains(h, table, chain);
nft_assert_table_compatible(h, table, chain);
- list = nft_chain_list_get(h, table, chain);
- if (!list)
- return 0;
-
if (chain) {
- c = nftnl_chain_list_lookup_byname(list, chain);
+ c = nft_chain_find(h, table, chain);
if (!c)
return 0;
- if (!rulenum) {
- if (ops->print_table_header)
- ops->print_table_header(table);
- __nft_print_header(h, c, format);
- }
- __nft_rule_list(h, c, rulenum, format, ops->print_rule);
+ if (rulenum)
+ d.save_fmt = true; /* skip header printing */
+ else if (ops->print_table_header)
+ ops->print_table_header(table);
+
+ nft_rule_list_cb(c, &d);
return 1;
}
- iter = nftnl_chain_list_iter_create(list);
- if (iter == NULL)
- return 0;
-
if (ops->print_table_header)
ops->print_table_header(table);
- c = nftnl_chain_list_iter_next(iter);
- while (c != NULL) {
- if (found)
- printf("\n");
-
- __nft_print_header(h, c, format);
- __nft_rule_list(h, c, rulenum, format, ops->print_rule);
-
- found = true;
- c = nftnl_chain_list_iter_next(iter);
- }
- nftnl_chain_list_iter_destroy(iter);
+ nft_chain_foreach(h, table, nft_rule_list_cb, &d);
return 1;
}
@@ -2404,8 +2451,44 @@ list_save(struct nft_handle *h, struct nftnl_rule *r,
nft_rule_print_save(h, r, NFT_RULE_APPEND, format);
}
-static int __nftnl_rule_list_chain_save(struct nftnl_chain *c, void *data)
+int nft_chain_foreach(struct nft_handle *h, const char *table,
+ int (*cb)(struct nft_chain *c, void *data),
+ void *data)
+{
+ const struct builtin_table *t;
+ struct nft_chain_list *list;
+ struct nft_chain *c, *c_bak;
+ int i, ret;
+
+ t = nft_table_builtin_find(h, table);
+ if (!t)
+ return -1;
+
+ for (i = 0; i < NF_INET_NUMHOOKS; i++) {
+ c = h->cache->table[t->type].base_chains[i];
+ if (!c)
+ continue;
+
+ ret = cb(c, data);
+ if (ret < 0)
+ return ret;
+ }
+
+ list = h->cache->table[t->type].chains;
+ if (!list)
+ return -1;
+
+ list_for_each_entry_safe(c, c_bak, &list->list, head) {
+ ret = cb(c, data);
+ if (ret < 0)
+ return ret;
+ }
+ return 0;
+}
+
+static int nft_rule_list_chain_save(struct nft_chain *nc, void *data)
{
+ struct nftnl_chain *c = nc->nftnl;
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;
@@ -2426,78 +2509,51 @@ static int __nftnl_rule_list_chain_save(struct nftnl_chain *c, void *data)
return 0;
}
-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;
-
- 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;
-}
-
int nft_rule_list_save(struct nft_handle *h, const char *chain,
const char *table, int rulenum, int counters)
{
- struct nftnl_chain_list *list;
- struct nftnl_chain_list_iter *iter;
- unsigned int format = 0;
- struct nftnl_chain *c;
+ struct nft_rule_list_cb_data d = {
+ .h = h,
+ .rulenum = rulenum,
+ .save_fmt = true,
+ .cb = list_save,
+ };
+ struct nft_chain *c;
int ret = 0;
- nft_xt_builtin_init(h, table);
+ nft_xt_fake_builtin_chains(h, table, chain);
nft_assert_table_compatible(h, table, chain);
- list = nft_chain_list_get(h, table, chain);
- 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;
+ d.format = FMT_C_COUNTS;
else if (counters == 0)
- format = FMT_NOCOUNTS;
+ d.format = FMT_NOCOUNTS;
if (chain) {
- c = nftnl_chain_list_lookup_byname(list, chain);
+ c = nft_chain_find(h, table, chain);
if (!c)
return 0;
- return __nft_rule_list(h, c, rulenum, format, list_save);
+ if (!rulenum)
+ nft_rule_list_chain_save(c, &counters);
+
+ return nft_rule_list_cb(c, &d);
}
- /* Now dump out rules in this table */
- iter = nftnl_chain_list_iter_create(list);
- if (iter == NULL)
- return 0;
+ /* Dump policies and custom chains first */
+ nft_chain_foreach(h, table, nft_rule_list_chain_save, &counters);
- 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);
- return ret;
+ /* Now dump out rules in this table */
+ ret = nft_chain_foreach(h, table, nft_rule_list_cb, &d);
+ return ret == 0 ? 1 : 0;
}
int nft_rule_zero_counters(struct nft_handle *h, const char *chain,
const char *table, int rulenum)
{
struct iptables_command_state cs = {};
- struct nftnl_chain *c;
- struct nftnl_rule *r;
+ struct nftnl_rule *r, *new_rule;
+ struct nft_chain *c;
int ret = 0;
nft_fn = nft_rule_delete;
@@ -2516,8 +2572,11 @@ int nft_rule_zero_counters(struct nft_handle *h, const char *chain,
nft_rule_to_iptables_command_state(h, r, &cs);
cs.counters.pcnt = cs.counters.bcnt = 0;
+ new_rule = nft_rule_new(h, chain, table, &cs);
+ if (!new_rule)
+ return 1;
- ret = nft_rule_append(h, chain, table, &cs, r, false);
+ ret = nft_rule_append(h, chain, table, new_rule, r, false);
error:
return ret;
@@ -2611,14 +2670,22 @@ static void batch_obj_del(struct nft_handle *h, struct obj_update *o)
case NFT_COMPAT_RULE_APPEND:
case NFT_COMPAT_RULE_INSERT:
case NFT_COMPAT_RULE_REPLACE:
- case NFT_COMPAT_RULE_DELETE:
break;
+ case NFT_COMPAT_RULE_DELETE:
case NFT_COMPAT_RULE_FLUSH:
nftnl_rule_free(o->rule);
break;
case NFT_COMPAT_SET_ADD:
nftnl_set_free(o->set);
break;
+ case NFT_COMPAT_RULE_LIST:
+ case NFT_COMPAT_RULE_CHECK:
+ case NFT_COMPAT_CHAIN_RESTORE:
+ case NFT_COMPAT_RULE_SAVE:
+ case NFT_COMPAT_RULE_ZERO:
+ case NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE:
+ assert(0);
+ break;
}
h->obj_list_num--;
list_del(&o->head);
@@ -2628,18 +2695,13 @@ static void batch_obj_del(struct nft_handle *h, struct obj_update *o)
static void nft_refresh_transaction(struct nft_handle *h)
{
const char *tablename, *chainname;
- const struct nftnl_chain *c;
+ const struct nft_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);
@@ -2665,14 +2727,22 @@ static void nft_refresh_transaction(struct nft_handle *h)
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_RULE_FLUSH:
+ tablename = nftnl_rule_get_str(n->rule, NFTNL_RULE_TABLE);
+ if (!tablename)
+ continue;
+
+ chainname = nftnl_rule_get_str(n->rule, NFTNL_RULE_CHAIN);
+ if (!chainname)
+ continue;
+
+ n->skip = !nft_chain_find(h, tablename, chainname);
+ break;
case NFT_COMPAT_TABLE_ADD:
case NFT_COMPAT_CHAIN_ADD:
case NFT_COMPAT_CHAIN_ZERO:
@@ -2684,8 +2754,13 @@ static void nft_refresh_transaction(struct nft_handle *h)
case NFT_COMPAT_RULE_INSERT:
case NFT_COMPAT_RULE_REPLACE:
case NFT_COMPAT_RULE_DELETE:
- case NFT_COMPAT_RULE_FLUSH:
case NFT_COMPAT_SET_ADD:
+ case NFT_COMPAT_RULE_LIST:
+ case NFT_COMPAT_RULE_CHECK:
+ case NFT_COMPAT_CHAIN_RESTORE:
+ case NFT_COMPAT_RULE_SAVE:
+ case NFT_COMPAT_RULE_ZERO:
+ case NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE:
break;
}
}
@@ -2709,9 +2784,10 @@ retry:
h->nft_genid++;
list_for_each_entry(n, &h->obj_list, head) {
-
- if (n->skip)
+ if (n->skip) {
+ n->seq = 0;
continue;
+ }
n->seq = seq++;
switch (n->type) {
@@ -2783,6 +2859,13 @@ retry:
NLM_F_CREATE, &n->seq, n->set);
seq = n->seq;
break;
+ case NFT_COMPAT_RULE_LIST:
+ case NFT_COMPAT_RULE_CHECK:
+ case NFT_COMPAT_CHAIN_RESTORE:
+ case NFT_COMPAT_RULE_SAVE:
+ case NFT_COMPAT_RULE_ZERO:
+ case NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE:
+ assert(0);
}
mnl_nft_batch_continue(h->batch);
@@ -2803,7 +2886,6 @@ retry:
nft_refresh_transaction(h);
- i=0;
list_for_each_entry_safe(err, ne, &h->err_list, head)
mnl_err_list_free(err);
@@ -2878,33 +2960,39 @@ static int ebt_add_policy_rule(struct nftnl_chain *c, void *data)
r = nft_rule_new(h, nftnl_chain_get_str(c, NFTNL_CHAIN_NAME),
nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE), &cs);
+ ebt_cs_clean(&cs);
+
if (!r)
return -1;
udata = nftnl_udata_buf_alloc(NFT_USERDATA_MAXLEN);
if (!udata)
- return -1;
+ goto err_free_rule;
if (!nftnl_udata_put_u32(udata, UDATA_TYPE_EBTABLES_POLICY, 1))
- return -1;
+ goto err_free_rule;
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;
- }
+ if (!batch_rule_add(h, NFT_COMPAT_RULE_APPEND, r))
+ goto err_free_rule;
+
+ /* add the rule to chain so it is freed later */
+ nftnl_chain_rule_add_tail(r, c);
return 0;
+err_free_rule:
+ nftnl_rule_free(r);
+ return -1;
}
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);
+ struct nft_chain *c = nft_chain_find(h, table, chain);
int pval;
if (!c)
@@ -2919,16 +3007,15 @@ int ebt_set_user_chain_policy(struct nft_handle *h, const char *table,
else
return 0;
- nft_build_cache(h, c);
-
- nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, pval);
+ nftnl_chain_set_u32(c->nftnl, 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;
+ struct nft_chain_list *list;
+ struct nft_chain *c;
int i;
for (i = 0; i < NFT_TABLE_MAX; i++) {
@@ -2941,45 +3028,154 @@ static void nft_bridge_commit_prepare(struct nft_handle *h)
if (!list)
continue;
- nftnl_chain_list_foreach(list, ebt_add_policy_rule, h);
+ list_for_each_entry(c, &list->list, head) {
+ ebt_add_policy_rule(c->nftnl, h);
+ }
}
}
-int nft_commit(struct nft_handle *h)
+static void assert_chain_exists(struct nft_handle *h,
+ const char *table, const char *chain)
{
- return nft_action(h, NFT_COMPAT_COMMIT);
+ if (chain && !nft_chain_exists(h, table, chain))
+ xtables_error(PARAMETER_PROBLEM,
+ "Chain '%s' does not exist", chain);
}
-int nft_bridge_commit(struct nft_handle *h)
+static int nft_prepare(struct nft_handle *h)
{
- nft_bridge_commit_prepare(h);
- return nft_commit(h);
+ struct nft_cmd *cmd, *next;
+ int ret = 1;
+
+ nft_cache_build(h);
+
+ list_for_each_entry_safe(cmd, next, &h->cmd_list, head) {
+ switch (cmd->command) {
+ case NFT_COMPAT_TABLE_FLUSH:
+ ret = nft_table_flush(h, cmd->table);
+ break;
+ case NFT_COMPAT_CHAIN_USER_ADD:
+ ret = nft_chain_user_add(h, cmd->chain, cmd->table);
+ break;
+ case NFT_COMPAT_CHAIN_USER_DEL:
+ ret = nft_chain_user_del(h, cmd->chain, cmd->table,
+ cmd->verbose);
+ break;
+ case NFT_COMPAT_CHAIN_RESTORE:
+ ret = nft_chain_restore(h, cmd->chain, cmd->table);
+ break;
+ case NFT_COMPAT_CHAIN_UPDATE:
+ ret = nft_chain_set(h, cmd->table, cmd->chain,
+ cmd->policy, &cmd->counters);
+ break;
+ case NFT_COMPAT_CHAIN_RENAME:
+ ret = nft_chain_user_rename(h, cmd->chain, cmd->table,
+ cmd->rename);
+ break;
+ case NFT_COMPAT_CHAIN_ZERO:
+ ret = nft_chain_zero_counters(h, cmd->chain, cmd->table,
+ cmd->verbose);
+ break;
+ case NFT_COMPAT_RULE_APPEND:
+ assert_chain_exists(h, cmd->table, cmd->jumpto);
+ ret = nft_rule_append(h, cmd->chain, cmd->table,
+ cmd->obj.rule, NULL, cmd->verbose);
+ break;
+ case NFT_COMPAT_RULE_INSERT:
+ assert_chain_exists(h, cmd->table, cmd->jumpto);
+ ret = nft_rule_insert(h, cmd->chain, cmd->table,
+ cmd->obj.rule, cmd->rulenum,
+ cmd->verbose);
+ break;
+ case NFT_COMPAT_RULE_REPLACE:
+ assert_chain_exists(h, cmd->table, cmd->jumpto);
+ ret = nft_rule_replace(h, cmd->chain, cmd->table,
+ cmd->obj.rule, cmd->rulenum,
+ cmd->verbose);
+ break;
+ case NFT_COMPAT_RULE_DELETE:
+ assert_chain_exists(h, cmd->table, cmd->jumpto);
+ if (cmd->rulenum >= 0)
+ ret = nft_rule_delete_num(h, cmd->chain,
+ cmd->table,
+ cmd->rulenum,
+ cmd->verbose);
+ else
+ ret = nft_rule_delete(h, cmd->chain, cmd->table,
+ cmd->obj.rule, cmd->verbose);
+ break;
+ case NFT_COMPAT_RULE_FLUSH:
+ ret = nft_rule_flush(h, cmd->chain, cmd->table,
+ cmd->verbose);
+ break;
+ case NFT_COMPAT_RULE_LIST:
+ ret = nft_rule_list(h, cmd->chain, cmd->table,
+ cmd->rulenum, cmd->format);
+ break;
+ case NFT_COMPAT_RULE_CHECK:
+ assert_chain_exists(h, cmd->table, cmd->jumpto);
+ ret = nft_rule_check(h, cmd->chain, cmd->table,
+ cmd->obj.rule, cmd->rulenum);
+ break;
+ case NFT_COMPAT_RULE_ZERO:
+ ret = nft_rule_zero_counters(h, cmd->chain, cmd->table,
+ cmd->rulenum);
+ break;
+ case NFT_COMPAT_RULE_SAVE:
+ ret = nft_rule_list_save(h, cmd->chain, cmd->table,
+ cmd->rulenum,
+ cmd->counters_save);
+ break;
+ case NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE:
+ ret = ebt_set_user_chain_policy(h, cmd->table,
+ cmd->chain, cmd->policy);
+ break;
+ case NFT_COMPAT_SET_ADD:
+ nft_xt_builtin_table_init(h, cmd->table);
+ batch_set_add(h, NFT_COMPAT_SET_ADD, cmd->obj.set);
+ ret = 1;
+ break;
+ case NFT_COMPAT_TABLE_ADD:
+ case NFT_COMPAT_CHAIN_ADD:
+ assert(0);
+ break;
+ }
+
+ nft_cmd_free(cmd);
+
+ if (ret == 0)
+ return 0;
+ }
+
+ return 1;
}
-int nft_abort(struct nft_handle *h)
+int nft_commit(struct nft_handle *h)
{
- return nft_action(h, NFT_COMPAT_ABORT);
+ if (!nft_prepare(h))
+ return 0;
+
+ return nft_action(h, NFT_COMPAT_COMMIT);
}
-int nft_abort_policy_rule(struct nft_handle *h, const char *table)
+int nft_bridge_commit(struct nft_handle *h)
{
- struct obj_update *n, *tmp;
+ if (!nft_prepare(h))
+ return 0;
- 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;
+ nft_bridge_commit_prepare(h);
- if (strcmp(table,
- nftnl_rule_get_str(n->rule, NFTNL_RULE_TABLE)))
- continue;
+ return nft_action(h, NFT_COMPAT_COMMIT);
+}
- if (!nft_rule_is_policy_rule(n->rule))
- continue;
+int nft_abort(struct nft_handle *h)
+{
+ struct nft_cmd *cmd, *next;
- batch_obj_del(h, n);
- }
- return 0;
+ list_for_each_entry_safe(cmd, next, &h->cmd_list, head)
+ nft_cmd_free(cmd);
+
+ return nft_action(h, NFT_COMPAT_ABORT);
}
int nft_compatible_revision(const char *name, uint8_t rev, int opt)
@@ -3142,8 +3338,9 @@ struct chain_zero_data {
bool verbose;
};
-static int __nft_chain_zero_counters(struct nftnl_chain *c, void *data)
+static int __nft_chain_zero_counters(struct nft_chain *nc, void *data)
{
+ struct nftnl_chain *c = nc->nftnl;
struct chain_zero_data *d = data;
struct nft_handle *h = d->handle;
struct nftnl_rule_iter *iter;
@@ -3151,19 +3348,17 @@ static int __nft_chain_zero_counters(struct nftnl_chain *c, void *data)
if (d->verbose)
fprintf(stdout, "Zeroing chain `%s'\n",
- nftnl_chain_get_str(c, NFTNL_CHAIN_NAME));
+ 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))
+ if (!batch_chain_add(h, NFT_COMPAT_CHAIN_ZERO, c))
return -1;
}
- nft_build_cache(h, c);
-
iter = nftnl_rule_iter_create(c);
if (iter == NULL)
return -1;
@@ -3218,20 +3413,15 @@ static int __nft_chain_zero_counters(struct nftnl_chain *c, void *data)
int nft_chain_zero_counters(struct nft_handle *h, const char *chain,
const char *table, bool verbose)
{
- struct nftnl_chain_list *list;
struct chain_zero_data d = {
.handle = h,
.verbose = verbose,
};
- struct nftnl_chain *c;
+ struct nft_chain *c;
int ret = 0;
- list = nft_chain_list_get(h, table, chain);
- if (list == NULL)
- goto err;
-
if (chain) {
- c = nftnl_chain_list_lookup_byname(list, chain);
+ c = nft_chain_find(h, table, chain);
if (!c) {
errno = ENOENT;
return 0;
@@ -3241,7 +3431,7 @@ int nft_chain_zero_counters(struct nft_handle *h, const char *chain,
goto err;
}
- ret = nftnl_chain_list_foreach(list, __nft_chain_zero_counters, &d);
+ ret = nft_chain_foreach(h, table, __nft_chain_zero_counters, &d);
err:
/* the core expects 1 for success and 0 for error */
return ret == 0 ? 1 : 0;
@@ -3291,8 +3481,9 @@ static int nft_is_rule_compatible(struct nftnl_rule *rule, void *data)
return nftnl_expr_foreach(rule, nft_is_expr_compatible, NULL);
}
-static int nft_is_chain_compatible(struct nftnl_chain *c, void *data)
+static int nft_is_chain_compatible(struct nft_chain *nc, void *data)
{
+ struct nftnl_chain *c = nc->nftnl;
const struct builtin_table *table;
const struct builtin_chain *chain;
const char *tname, *cname, *type;
@@ -3300,8 +3491,6 @@ static int nft_is_chain_compatible(struct nftnl_chain *c, void *data)
enum nf_inet_hooks hook;
int prio;
- nft_build_cache(h, c);
-
if (nftnl_rule_foreach(c, nft_is_rule_compatible, NULL))
return -1;
@@ -3332,16 +3521,13 @@ static int nft_is_chain_compatible(struct nftnl_chain *c, void *data)
bool nft_is_table_compatible(struct nft_handle *h,
const char *table, const char *chain)
{
- struct nftnl_chain_list *clist;
-
- clist = nft_chain_list_get(h, table, chain);
- if (clist == NULL)
- return false;
+ if (chain) {
+ struct nft_chain *c = nft_chain_find(h, table, chain);
- if (nftnl_chain_list_foreach(clist, nft_is_chain_compatible, h))
- return false;
+ return c && !nft_is_chain_compatible(c, h);
+ }
- return true;
+ return !nft_chain_foreach(h, table, nft_is_chain_compatible, h);
}
void nft_assert_table_compatible(struct nft_handle *h,
diff --git a/iptables/nft.h b/iptables/nft.h
index 51b56603..0910f82a 100644
--- a/iptables/nft.h
+++ b/iptables/nft.h
@@ -3,13 +3,16 @@
#include "xshared.h"
#include "nft-shared.h"
+#include "nft-cache.h"
+#include "nft-chain.h"
+#include "nft-cmd.h"
#include <libiptc/linux_list.h>
enum nft_table_type {
- NFT_TABLE_FILTER = 0,
- NFT_TABLE_MANGLE,
- NFT_TABLE_RAW,
+ NFT_TABLE_MANGLE = 0,
NFT_TABLE_SECURITY,
+ NFT_TABLE_RAW,
+ NFT_TABLE_FILTER,
NFT_TABLE_NAT,
};
#define NFT_TABLE_MAX (NFT_TABLE_NAT + 1)
@@ -28,22 +31,58 @@ struct builtin_table {
};
enum nft_cache_level {
- NFT_CL_NONE,
NFT_CL_TABLES,
NFT_CL_CHAINS,
NFT_CL_SETS,
- NFT_CL_RULES
+ NFT_CL_RULES,
+ NFT_CL_FAKE /* must be last entry */
};
struct nft_cache {
- struct nftnl_table_list *tables;
struct {
- struct nftnl_chain_list *chains;
+ struct nft_chain *base_chains[NF_INET_NUMHOOKS];
+ struct nft_chain_list *chains;
struct nftnl_set_list *sets;
- bool initialized;
+ bool exists;
} table[NFT_TABLE_MAX];
};
+enum obj_update_type {
+ NFT_COMPAT_TABLE_ADD,
+ NFT_COMPAT_TABLE_FLUSH,
+ NFT_COMPAT_CHAIN_ADD,
+ NFT_COMPAT_CHAIN_USER_ADD,
+ NFT_COMPAT_CHAIN_USER_DEL,
+ NFT_COMPAT_CHAIN_USER_FLUSH,
+ NFT_COMPAT_CHAIN_UPDATE,
+ NFT_COMPAT_CHAIN_RENAME,
+ NFT_COMPAT_CHAIN_ZERO,
+ NFT_COMPAT_RULE_APPEND,
+ NFT_COMPAT_RULE_INSERT,
+ NFT_COMPAT_RULE_REPLACE,
+ NFT_COMPAT_RULE_DELETE,
+ NFT_COMPAT_RULE_FLUSH,
+ NFT_COMPAT_SET_ADD,
+ NFT_COMPAT_RULE_LIST,
+ NFT_COMPAT_RULE_CHECK,
+ NFT_COMPAT_CHAIN_RESTORE,
+ NFT_COMPAT_RULE_SAVE,
+ NFT_COMPAT_RULE_ZERO,
+ NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE,
+};
+
+struct cache_chain {
+ struct list_head head;
+ char *name;
+};
+
+struct nft_cache_req {
+ enum nft_cache_level level;
+ char *table;
+ bool all_chains;
+ struct list_head chain_list;
+};
+
struct nft_handle {
int family;
struct mnl_socket *nl;
@@ -62,10 +101,12 @@ struct nft_handle {
unsigned int cache_index;
struct nft_cache __cache[2];
struct nft_cache *cache;
- enum nft_cache_level cache_level;
+ struct nft_cache_req cache_req;
bool restore;
bool noflush;
int8_t config_done;
+ struct list_head cmd_list;
+ bool cache_init;
/* meta data, for error reporting */
struct {
@@ -80,7 +121,7 @@ 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, const struct builtin_table *t);
+int nft_init(struct nft_handle *h, int family, const struct builtin_table *t);
void nft_fini(struct nft_handle *h);
int nft_restart(struct nft_handle *h);
@@ -94,8 +135,8 @@ int nft_for_each_table(struct nft_handle *h, int (*func)(struct nft_handle *h, c
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);
const struct builtin_table *nft_table_builtin_find(struct nft_handle *h, const char *table);
+int nft_xt_fake_builtin_chains(struct nft_handle *h, const char *table, const char *chain);
/*
* Operations with chains.
@@ -103,7 +144,7 @@ const struct builtin_table *nft_table_builtin_find(struct nft_handle *h, const c
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);
-int nft_chain_save(struct nft_handle *h, struct nftnl_chain_list *list);
+int nft_chain_save(struct nft_chain *c, void *data);
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_restore(struct nft_handle *h, const char *chain, const char *table);
@@ -113,19 +154,29 @@ const struct builtin_chain *nft_chain_builtin_find(const struct builtin_table *t
bool nft_chain_exists(struct nft_handle *h, const char *table, const char *chain);
void nft_bridge_chain_postprocess(struct nft_handle *h,
struct nftnl_chain *c);
+int nft_chain_foreach(struct nft_handle *h, const char *table,
+ int (*cb)(struct nft_chain *c, void *data),
+ void *data);
+
+/*
+ * Operations with sets.
+ */
+struct nftnl_set *nft_set_batch_lookup_byid(struct nft_handle *h,
+ uint32_t set_id);
/*
* Operations with rule-set.
*/
struct nftnl_rule;
-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);
+struct nftnl_rule *nft_rule_new(struct nft_handle *h, const char *chain, const char *table, void *data);
+int nft_rule_append(struct nft_handle *h, const char *chain, const char *table, struct nftnl_rule *r, struct nftnl_rule *ref, bool verbose);
+int nft_rule_insert(struct nft_handle *h, const char *chain, const char *table, struct nftnl_rule *r, int rulenum, bool verbose);
+int nft_rule_check(struct nft_handle *h, const char *chain, const char *table, struct nftnl_rule *r, bool verbose);
+int nft_rule_delete(struct nft_handle *h, const char *chain, const char *table, struct nftnl_rule *r, bool verbose);
int nft_rule_delete_num(struct nft_handle *h, const char *chain, const char *table, int rulenum, bool verbose);
-int nft_rule_replace(struct nft_handle *h, const char *chain, const char *table, void *data, int rulenum, bool verbose);
+int nft_rule_replace(struct nft_handle *h, const char *chain, const char *table, struct nftnl_rule *r, int rulenum, bool verbose);
int nft_rule_list(struct nft_handle *h, const char *chain, const char *table, int rulenum, unsigned int format);
int nft_rule_list_save(struct nft_handle *h, const char *chain, const char *table, int rulenum, int counters);
int nft_rule_save(struct nft_handle *h, const char *table, unsigned int format);
@@ -159,7 +210,6 @@ uint32_t nft_invflags2cmp(uint32_t invflags, uint32_t flag);
int nft_commit(struct nft_handle *h);
int nft_bridge_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.
@@ -178,6 +228,7 @@ int nft_init_arp(struct nft_handle *h, const char *pname);
int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table, bool restore);
/* For xtables-eb.c */
int nft_init_eb(struct nft_handle *h, const char *pname);
+void nft_fini_eb(struct nft_handle *h);
int ebt_get_current_chain(const char *chain);
int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table, bool restore);
diff --git a/iptables/tests/shell/run-tests.sh b/iptables/tests/shell/run-tests.sh
index d71c1372..65c37adb 100755
--- a/iptables/tests/shell/run-tests.sh
+++ b/iptables/tests/shell/run-tests.sh
@@ -4,6 +4,21 @@
TESTDIR="./$(dirname $0)/"
RETURNCODE_SEPARATOR="_"
+usage() {
+ cat <<EOF
+Usage: $(basename $0) [-v|--verbose] [-H|--host] [-V|--valgrind]
+ [[-l|--legacy]|[-n|--nft]] [testscript ...]
+
+-v | --verbose Enable verbose mode (do not drop testscript output).
+-H | --host Run tests against installed binaries in \$PATH,
+ not those built in this source tree.
+-V | --valgrind Enable leak checking via valgrind.
+-l | --legacy Test legacy variant only. Conflicts with --nft.
+-n | --nft Test nft variant only. Conflicts with --legacy.
+testscript Run only specific test(s). Implies --verbose.
+EOF
+}
+
msg_error() {
echo "E: $1 ..." >&2
exit 1
@@ -46,6 +61,14 @@ while [ -n "$1" ]; do
NFT_ONLY=y
shift
;;
+ -V|--valgrind)
+ VALGRIND=y
+ shift
+ ;;
+ -h|--help)
+ usage
+ exit 0
+ ;;
*${RETURNCODE_SEPARATOR}+([0-9]))
SINGLE+=" $1"
VERBOSE=y
@@ -67,6 +90,49 @@ else
XTABLES_LEGACY_MULTI="xtables-legacy-multi"
fi
+printscript() { # (cmd, tmpd)
+ cat <<EOF
+#!/bin/bash
+
+CMD="$1"
+
+# note: valgrind man page warns about --log-file with --trace-children, the
+# last child executed overwrites previous reports unless %p or %q is used.
+# Since libtool wrapper calls exec but none of the iptables tools do, this is
+# perfect for us as it effectively hides bash-related errors
+
+valgrind --log-file=$2/valgrind.log --trace-children=yes \
+ --leak-check=full --show-leak-kinds=all \$CMD "\$@"
+RC=\$?
+
+# don't keep uninteresting logs
+if grep -q 'no leaks are possible' $2/valgrind.log; then
+ rm $2/valgrind.log
+else
+ mv $2/valgrind.log $2/valgrind_\$\$.log
+fi
+
+# drop logs for failing commands for now
+[ \$RC -eq 0 ] || rm $2/valgrind_\$\$.log
+
+exit \$RC
+EOF
+}
+
+if [ "$VALGRIND" == "y" ]; then
+ tmpd=$(mktemp -d)
+ msg_info "writing valgrind logs to $tmpd"
+ chmod a+rx $tmpd
+ printscript "$XTABLES_NFT_MULTI" "$tmpd" >${tmpd}/xtables-nft-multi
+ printscript "$XTABLES_LEGACY_MULTI" "$tmpd" >${tmpd}/xtables-legacy-multi
+ trap "rm ${tmpd}/xtables-*-multi" EXIT
+ chmod a+x ${tmpd}/xtables-nft-multi ${tmpd}/xtables-legacy-multi
+
+ XTABLES_NFT_MULTI="${tmpd}/xtables-nft-multi"
+ XTABLES_LEGACY_MULTI="${tmpd}/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 bf04dc0a..e64e9142 100755
--- a/iptables/tests/shell/testcases/arptables/0001-arptables-save-restore_0
+++ b/iptables/tests/shell/testcases/arptables/0001-arptables-save-restore_0
@@ -4,7 +4,7 @@ set -e
#set -x
# there is no legacy backend to test
-[[ $XT_MULTI == */xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
+[[ $XT_MULTI == *xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
# fill arptables manually
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 38d387f3..afd0fcb4 100755
--- a/iptables/tests/shell/testcases/arptables/0002-arptables-restore-defaults_0
+++ b/iptables/tests/shell/testcases/arptables/0002-arptables-restore-defaults_0
@@ -3,7 +3,7 @@
set -e
# there is no legacy backend to test
-[[ $XT_MULTI == */xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
+[[ $XT_MULTI == *xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
# arptables-restore reuses preloaded targets and matches, make sure defaults
# apply to consecutive rules using the same target/match as a previous one
diff --git a/iptables/tests/shell/testcases/arptables/0003-arptables-verbose-output_0 b/iptables/tests/shell/testcases/arptables/0003-arptables-verbose-output_0
index 10c5ec33..952cfa78 100755
--- a/iptables/tests/shell/testcases/arptables/0003-arptables-verbose-output_0
+++ b/iptables/tests/shell/testcases/arptables/0003-arptables-verbose-output_0
@@ -4,7 +4,7 @@ set -e
set -x
# there is no legacy backend to test
-[[ $XT_MULTI == */xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
+[[ $XT_MULTI == *xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
$XT_MULTI arptables -N foo
diff --git a/iptables/tests/shell/testcases/ebtables/0001-ebtables-basic_0 b/iptables/tests/shell/testcases/ebtables/0001-ebtables-basic_0
index c7f24a38..6f11bd12 100755
--- a/iptables/tests/shell/testcases/ebtables/0001-ebtables-basic_0
+++ b/iptables/tests/shell/testcases/ebtables/0001-ebtables-basic_0
@@ -1,86 +1,93 @@
#!/bin/sh
+case "$XT_MULTI" in
+*xtables-nft-multi)
+ ;;
+*)
+ echo "skip $XT_MULTI"
+ exit 0
+ ;;
+esac
+
get_entries_count() { # (chain)
$XT_MULTI ebtables -L $1 | sed -n 's/.*entries: \([0-9]*\).*/\1/p'
}
set -x
-case "$XT_MULTI" in
-*/xtables-nft-multi)
- for t in filter nat;do
- $XT_MULTI ebtables -t $t -L || exit 1
- $XT_MULTI ebtables -t $t -X || exit 1
- $XT_MULTI ebtables -t $t -F || exit 1
- done
-
- for t in broute foobar ;do
- $XT_MULTI ebtables -t $t -L &&
- $XT_MULTI ebtables -t $t -X &&
- $XT_MULTI ebtables -t $t -F
- if [ $? -eq 0 ]; then
- echo "Expect nonzero return for unsupported table"
- exit 1
- fi
- done
-
-
- $XT_MULTI ebtables -t filter -N FOO || exit 1
- $XT_MULTI ebtables -t filter -N FOO
+
+for t in filter nat;do
+ $XT_MULTI ebtables -t $t -L || exit 1
+ $XT_MULTI ebtables -t $t -X || exit 1
+ $XT_MULTI ebtables -t $t -F || exit 1
+done
+
+for t in broute foobar ;do
+ $XT_MULTI ebtables -t $t -L &&
+ $XT_MULTI ebtables -t $t -X &&
+ $XT_MULTI ebtables -t $t -F
if [ $? -eq 0 ]; then
- echo "Duplicate chain FOO"
- $XT_MULTI ebtables -t filter -L
+ echo "Expect nonzero return for unsupported table"
exit 1
fi
+done
- entries=$(get_entries_count FOO)
- if [ $entries -ne 0 ]; then
- echo "Unexpected entries count in empty unreferenced chain (expected 0, have $entries)"
- $XT_MULTI ebtables -L
- exit 1
- fi
- $XT_MULTI ebtables -A FORWARD -j FOO
- entries=$(get_entries_count FORWARD)
- if [ $entries -ne 1 ]; then
- echo "Unexpected entries count in FORWARD chain (expected 1, have $entries)"
- $XT_MULTI ebtables -L
- exit 1
- fi
+$XT_MULTI ebtables -t filter -N FOO || exit 1
+$XT_MULTI ebtables -t filter -N FOO
+if [ $? -eq 0 ]; then
+ echo "Duplicate chain FOO"
+ $XT_MULTI ebtables -t filter -L
+ exit 1
+fi
- entries=$(get_entries_count FOO)
- if [ $entries -ne 0 ]; then
- echo "Unexpected entries count in empty referenced chain (expected 0, have $entries)"
- $XT_MULTI ebtables -L
- exit 1
- fi
+entries=$(get_entries_count FOO)
+if [ $entries -ne 0 ]; then
+ echo "Unexpected entries count in empty unreferenced chain (expected 0, have $entries)"
+ $XT_MULTI ebtables -L
+ exit 1
+fi
- $XT_MULTI ebtables -A FOO -j ACCEPT
- entries=$(get_entries_count FOO)
- if [ $entries -ne 1 ]; then
- echo "Unexpected entries count in non-empty referenced chain (expected 1, have $entries)"
- $XT_MULTI ebtables -L
- exit 1
- fi
+$XT_MULTI ebtables -A FORWARD -j FOO
+entries=$(get_entries_count FORWARD)
+if [ $entries -ne 1 ]; then
+ echo "Unexpected entries count in FORWARD chain (expected 1, have $entries)"
+ $XT_MULTI ebtables -L
+ exit 1
+fi
- $XT_MULTI ebtables -t filter -N BAR || exit 1
- $XT_MULTI ebtables -t filter -N BAZ || exit 1
+entries=$(get_entries_count FOO)
+if [ $entries -ne 0 ]; then
+ echo "Unexpected entries count in empty referenced chain (expected 0, have $entries)"
+ $XT_MULTI ebtables -L
+ exit 1
+fi
- $XT_MULTI ebtables -t filter -L | grep -q FOO || exit 1
- $XT_MULTI ebtables -t filter -L | grep -q BAR || exit 1
- $XT_MULTI ebtables -t filter -L | grep -q BAZ || exit 1
+$XT_MULTI ebtables -A FOO -j ACCEPT
+entries=$(get_entries_count FOO)
+if [ $entries -ne 1 ]; then
+ echo "Unexpected entries count in non-empty referenced chain (expected 1, have $entries)"
+ $XT_MULTI ebtables -L
+ exit 1
+fi
- $XT_MULTI ebtables -t filter -L BAZ || exit 1
- $XT_MULTI ebtables -t filter -X BAZ || exit 1
- $XT_MULTI ebtables -t filter -L BAZ | grep -q BAZ
- if [ $? -eq 0 ]; then
- echo "Deleted chain -L BAZ ok, expected failure"
- $XT_MULTI ebtables -t filter -L
- exit 1
- fi
+$XT_MULTI ebtables -t filter -N BAR || exit 1
+$XT_MULTI ebtables -t filter -N BAZ || exit 1
- $XT_MULTI ebtables -t $t -F || exit 0
- ;;
-*)
- echo "skip $XT_MULTI"
- ;;
-esac
+$XT_MULTI ebtables -t filter -L | grep -q FOO || exit 1
+$XT_MULTI ebtables -t filter -L | grep -q BAR || exit 1
+$XT_MULTI ebtables -t filter -L | grep -q BAZ || exit 1
+
+$XT_MULTI ebtables -t filter -L BAZ || exit 1
+$XT_MULTI ebtables -t filter -X BAZ || exit 1
+$XT_MULTI ebtables -t filter -L BAZ | grep -q BAZ
+if [ $? -eq 0 ]; then
+ echo "Deleted chain -L BAZ ok, expected failure"
+ $XT_MULTI ebtables -t filter -L
+ exit 1
+fi
+
+$XT_MULTI ebtables -t filter -E FOO BAZ || exit 1
+$XT_MULTI ebtables -t filter -L | grep -q FOO && exit 1
+$XT_MULTI ebtables -t filter -L | grep -q BAZ || exit 1
+
+$XT_MULTI ebtables -t $t -F || exit 0
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 e18d4655..ccdef19c 100755
--- a/iptables/tests/shell/testcases/ebtables/0002-ebtables-save-restore_0
+++ b/iptables/tests/shell/testcases/ebtables/0002-ebtables-save-restore_0
@@ -4,7 +4,7 @@ set -e
#set -x
# there is no legacy backend to test
-[[ $XT_MULTI == */xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
+[[ $XT_MULTI == *xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
# fill ebtables manually
@@ -70,8 +70,8 @@ DUMP='*filter
:INPUT ACCEPT
:FORWARD DROP
:OUTPUT ACCEPT
-:foo ACCEPT
:bar RETURN
+:foo ACCEPT
-A INPUT -p IPv4 -i lo -j ACCEPT
-A FORWARD -j foo
-A OUTPUT -s Broadcast -j DROP
diff --git a/iptables/tests/shell/testcases/ebtables/0003-ebtables-restore-defaults_0 b/iptables/tests/shell/testcases/ebtables/0003-ebtables-restore-defaults_0
index 62d22413..63891c1b 100755
--- a/iptables/tests/shell/testcases/ebtables/0003-ebtables-restore-defaults_0
+++ b/iptables/tests/shell/testcases/ebtables/0003-ebtables-restore-defaults_0
@@ -3,7 +3,7 @@
set -e
# there is no legacy backend to test
-[[ $XT_MULTI == */xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
+[[ $XT_MULTI == *xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
# ebtables-restore reuses preloaded targets and matches, make sure defaults
# apply to consecutive rules using the same target/match as a previous one
diff --git a/iptables/tests/shell/testcases/ebtables/0004-save-counters_0 b/iptables/tests/shell/testcases/ebtables/0004-save-counters_0
index 46966f43..d52db900 100755
--- a/iptables/tests/shell/testcases/ebtables/0004-save-counters_0
+++ b/iptables/tests/shell/testcases/ebtables/0004-save-counters_0
@@ -3,7 +3,7 @@
set -e
# there is no legacy backend to test
-[[ $XT_MULTI == */xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
+[[ $XT_MULTI == *xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
$XT_MULTI ebtables --init-table
$XT_MULTI ebtables -A FORWARD -i nodev123 -o nodev432 -j ACCEPT
diff --git a/iptables/tests/shell/testcases/ebtables/0005-ifnamechecks_0 b/iptables/tests/shell/testcases/ebtables/0005-ifnamechecks_0
index 2163d364..0b3acfd7 100755
--- a/iptables/tests/shell/testcases/ebtables/0005-ifnamechecks_0
+++ b/iptables/tests/shell/testcases/ebtables/0005-ifnamechecks_0
@@ -3,7 +3,7 @@
set -e
# there is no legacy backend to test
-[[ $XT_MULTI == */xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
+[[ $XT_MULTI == *xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
EXPECT='*filter
:INPUT ACCEPT
diff --git a/iptables/tests/shell/testcases/firewalld-restore/0001-firewalld_0 b/iptables/tests/shell/testcases/firewalld-restore/0001-firewalld_0
index 8bf0c2c6..4900554e 100755
--- a/iptables/tests/shell/testcases/firewalld-restore/0001-firewalld_0
+++ b/iptables/tests/shell/testcases/firewalld-restore/0001-firewalld_0
@@ -230,21 +230,8 @@ for table in nat mangle raw filter;do
$XT_MULTI iptables-save -t $table | grep -v '^#' >> "$tmpfile"
done
-case "$XT_MULTI" in
-*/xtables-nft-multi)
- # nft-multi displays chain names in different order, work around this for now
- tmpfile2=$(mktemp)
- sort "$tmpfile" > "$tmpfile2"
- sort $(dirname "$0")/dumps/ipt-save-completed.txt > "$tmpfile"
- diff -u $tmpfile $tmpfile2
- RET=$?
- rm -f "$tmpfile2"
- ;;
-*)
- diff -u $tmpfile $(dirname "$0")/dumps/ipt-save-completed.txt
- RET=$?
- ;;
-esac
+diff -u $tmpfile $(dirname "$0")/dumps/ipt-save-completed.txt
+RET=$?
rm -f "$tmpfile"
diff --git a/iptables/tests/shell/testcases/ip6tables/0004-return-codes_0 b/iptables/tests/shell/testcases/ip6tables/0004-return-codes_0
deleted file mode 100755
index f023b791..00000000
--- a/iptables/tests/shell/testcases/ip6tables/0004-return-codes_0
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/bin/sh
-
-# make sure error return codes are as expected useful cases
-# (e.g. commands to check ruleset state)
-
-global_rc=0
-
-cmd() { # (rc, cmd, [args ...])
- rc_exp=$1; shift
-
- $XT_MULTI "$@"
- rc=$?
-
- [ $rc -eq $rc_exp ] || {
- echo "---> expected $rc_exp, got $rc for command '$@'"
- global_rc=1
- }
-}
-
-# test chain creation
-cmd 0 ip6tables -N foo
-cmd 1 ip6tables -N foo
-# iptables-nft allows this - bug or feature?
-#cmd 2 ip6tables -N "invalid name"
-
-# test rule adding
-cmd 0 ip6tables -A INPUT -j ACCEPT
-cmd 1 ip6tables -A noexist -j ACCEPT
-
-# test rule checking
-cmd 0 ip6tables -C INPUT -j ACCEPT
-cmd 1 ip6tables -C FORWARD -j ACCEPT
-cmd 1 ip6tables -C nonexist -j ACCEPT
-cmd 2 ip6tables -C INPUT -j foobar
-cmd 2 ip6tables -C INPUT -m foobar -j ACCEPT
-cmd 3 ip6tables -t foobar -C INPUT -j ACCEPT
-
-exit $global_rc
diff --git a/iptables/tests/shell/testcases/ipt-restore/0001load-specific-table_0 b/iptables/tests/shell/testcases/ipt-restore/0001load-specific-table_0
index ce3bef3a..3f443a98 100755
--- a/iptables/tests/shell/testcases/ipt-restore/0001load-specific-table_0
+++ b/iptables/tests/shell/testcases/ipt-restore/0001load-specific-table_0
@@ -22,7 +22,7 @@ do_simple()
table="${2}"
dumpfile="$(dirname "${0}")/dumps/${iptables}.dump"
- "$XT_MULTI" "${iptables}-restore" --table="${table}" <"${dumpfile}"; rv=$?
+ "$XT_MULTI" "${iptables}-restore" --table="${table}" "${dumpfile}"; rv=$?
if [ "${rv}" -ne 0 ]; then
RET=1
diff --git a/iptables/tests/shell/testcases/ipt-restore/0004-restore-race_0 b/iptables/tests/shell/testcases/ipt-restore/0004-restore-race_0
index 96a5e66d..a7fae41d 100755
--- a/iptables/tests/shell/testcases/ipt-restore/0004-restore-race_0
+++ b/iptables/tests/shell/testcases/ipt-restore/0004-restore-race_0
@@ -45,8 +45,7 @@ get_target()
make_dummy_rules()
{
-
- echo "*filter"
+ echo "*${1:-filter}"
echo ":INPUT ACCEPT [0:0]"
echo ":FORWARD ACCEPT [0:0]"
echo ":OUTPUT ACCEPT [0:0]"
@@ -74,7 +73,7 @@ make_dummy_rules()
tmpfile=$(mktemp) || exit 1
dumpfile=$(mktemp) || exit 1
-make_dummy_rules > $dumpfile
+(make_dummy_rules; make_dummy_rules security) > $dumpfile
$XT_MULTI iptables-restore -w < $dumpfile
LINES1=$(wc -l < $dumpfile)
$XT_MULTI iptables-save | grep -v '^#' > $dumpfile
@@ -86,7 +85,7 @@ if [ $LINES1 -ne $LINES2 ]; then
fi
case "$XT_MULTI" in
-*/xtables-nft-multi)
+*xtables-nft-multi)
attempts=$((RANDOM%10))
attempts=$((attempts+1))
;;
diff --git a/iptables/tests/shell/testcases/ipt-restore/0007-flush-noflush_0 b/iptables/tests/shell/testcases/ipt-restore/0007-flush-noflush_0
index 029db223..e705b28c 100755
--- a/iptables/tests/shell/testcases/ipt-restore/0007-flush-noflush_0
+++ b/iptables/tests/shell/testcases/ipt-restore/0007-flush-noflush_0
@@ -18,7 +18,7 @@ EXPECT="*nat
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -j ACCEPT
COMMIT"
-diff -u -Z <(echo -e "$EXPECT" | sort) <($XT_MULTI iptables-save | grep -v '^#' | sort)
+diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI iptables-save | grep -v '^#')
$XT_MULTI iptables-restore <<EOF
*filter
@@ -39,4 +39,4 @@ COMMIT
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -j ACCEPT
COMMIT"
-diff -u -Z <(echo -e "$EXPECT" | sort) <($XT_MULTI iptables-save | grep -v '^#' | sort)
+diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI iptables-save | grep -v '^#')
diff --git a/iptables/tests/shell/testcases/ipt-restore/0010-noflush-new-chain_0 b/iptables/tests/shell/testcases/ipt-restore/0010-noflush-new-chain_0
new file mode 100755
index 00000000..2817376e
--- /dev/null
+++ b/iptables/tests/shell/testcases/ipt-restore/0010-noflush-new-chain_0
@@ -0,0 +1,11 @@
+#!/bin/sh -e
+
+# assert input feed from buffer doesn't trip over
+# added nul-chars from parsing chain line.
+
+$XT_MULTI iptables-restore --noflush <<EOF
+*filter
+:foobar - [0:0]
+-A foobar -j ACCEPT
+COMMIT
+EOF
diff --git a/iptables/tests/shell/testcases/ipt-restore/0011-noflush-empty-line_0 b/iptables/tests/shell/testcases/ipt-restore/0011-noflush-empty-line_0
new file mode 100755
index 00000000..bea1a690
--- /dev/null
+++ b/iptables/tests/shell/testcases/ipt-restore/0011-noflush-empty-line_0
@@ -0,0 +1,16 @@
+#!/bin/bash -e
+
+# make sure empty lines won't break --noflush
+
+cat <<EOF | $XT_MULTI iptables-restore --noflush
+# just a comment followed by innocent empty line
+
+*filter
+-A FORWARD -j ACCEPT
+COMMIT
+EOF
+
+EXPECT='Chain FORWARD (policy ACCEPT)
+target prot opt source destination
+ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 '
+diff -u <(echo "$EXPECT") <($XT_MULTI iptables -n -L FORWARD)
diff --git a/iptables/tests/shell/testcases/ipt-restore/0012-dash-F_0 b/iptables/tests/shell/testcases/ipt-restore/0012-dash-F_0
new file mode 100755
index 00000000..fd82afa1
--- /dev/null
+++ b/iptables/tests/shell/testcases/ipt-restore/0012-dash-F_0
@@ -0,0 +1,12 @@
+#!/bin/bash -e
+
+# make sure -F lines don't cause segfaults
+
+RULESET='*nat
+-F PREROUTING
+-A PREROUTING -j ACCEPT
+-F PREROUTING
+COMMIT'
+
+echo -e "$RULESET" | $XT_MULTI iptables-restore
+echo -e "$RULESET" | $XT_MULTI iptables-restore -n
diff --git a/iptables/tests/shell/testcases/ipt-restore/0013-test-mode_0 b/iptables/tests/shell/testcases/ipt-restore/0013-test-mode_0
new file mode 100755
index 00000000..65c3b9a1
--- /dev/null
+++ b/iptables/tests/shell/testcases/ipt-restore/0013-test-mode_0
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+set -e
+
+# segfault with --test reported in nfbz#1391
+
+printf '%s\nCOMMIT\n' '*nat' '*raw' '*filter' | $XT_MULTI iptables-restore --test
diff --git a/iptables/tests/shell/testcases/ipt-restore/0014-verbose-restore_0 b/iptables/tests/shell/testcases/ipt-restore/0014-verbose-restore_0
new file mode 100755
index 00000000..fc8559c5
--- /dev/null
+++ b/iptables/tests/shell/testcases/ipt-restore/0014-verbose-restore_0
@@ -0,0 +1,76 @@
+#!/bin/bash
+
+set -e
+
+DUMP="*filter
+:foo - [0:0]
+:bar - [0:0]
+-A foo -j ACCEPT
+COMMIT
+*nat
+:natfoo - [0:0]
+:natbar - [0:0]
+-A natfoo -j ACCEPT
+COMMIT
+*raw
+:rawfoo - [0:0]
+COMMIT
+*mangle
+:manglefoo - [0:0]
+COMMIT
+*security
+:secfoo - [0:0]
+COMMIT
+"
+
+$XT_MULTI iptables-restore <<< "$DUMP"
+$XT_MULTI ip6tables-restore <<< "$DUMP"
+
+EXPECT="Flushing chain \`INPUT'
+Flushing chain \`FORWARD'
+Flushing chain \`OUTPUT'
+Flushing chain \`bar'
+Flushing chain \`foo'
+Deleting chain \`bar'
+Deleting chain \`foo'
+Flushing chain \`PREROUTING'
+Flushing chain \`INPUT'
+Flushing chain \`OUTPUT'
+Flushing chain \`POSTROUTING'
+Flushing chain \`natbar'
+Flushing chain \`natfoo'
+Deleting chain \`natbar'
+Deleting chain \`natfoo'
+Flushing chain \`PREROUTING'
+Flushing chain \`OUTPUT'
+Flushing chain \`rawfoo'
+Deleting chain \`rawfoo'
+Flushing chain \`PREROUTING'
+Flushing chain \`INPUT'
+Flushing chain \`FORWARD'
+Flushing chain \`OUTPUT'
+Flushing chain \`POSTROUTING'
+Flushing chain \`manglefoo'
+Deleting chain \`manglefoo'
+Flushing chain \`INPUT'
+Flushing chain \`FORWARD'
+Flushing chain \`OUTPUT'
+Flushing chain \`secfoo'
+Deleting chain \`secfoo'"
+
+for ipt in iptables-restore ip6tables-restore; do
+ diff -u -Z <(echo "$EXPECT") <($XT_MULTI $ipt -v <<< "$DUMP")
+done
+
+DUMP="*filter
+:baz - [0:0]
+-F foo
+-X bar
+-A foo -j ACCEPT
+COMMIT
+"
+
+EXPECT=""
+for ipt in iptables-restore ip6tables-restore; do
+ diff -u -Z <(echo -ne "$EXPECT") <($XT_MULTI $ipt -v --noflush <<< "$DUMP")
+done
diff --git a/iptables/tests/shell/testcases/ipt-restore/0016-concurrent-restores_0 b/iptables/tests/shell/testcases/ipt-restore/0016-concurrent-restores_0
new file mode 100755
index 00000000..aa746ab4
--- /dev/null
+++ b/iptables/tests/shell/testcases/ipt-restore/0016-concurrent-restores_0
@@ -0,0 +1,67 @@
+#!/bin/bash
+
+# test for iptables-restore --noflush skipping an explicitly requested chain
+# flush because the chain did not exist when cache was fetched. In order to
+# expect for that chain to appear when refreshing the transaction (due to a
+# concurrent ruleset change), the chain flush job has to be present in batch
+# job list (although disabled at first).
+# The input line requesting chain flush is ':FOO - [0:0]'. RS1 and RS2 contents
+# are crafted to cause EBUSY when deleting the BAR* chains if FOO is not
+# flushed in the same transaction.
+
+set -e
+
+RS="*filter
+:INPUT ACCEPT [12024:3123388]
+:FORWARD ACCEPT [0:0]
+:OUTPUT ACCEPT [12840:2144421]
+:FOO - [0:0]
+:BAR0 - [0:0]
+:BAR1 - [0:0]
+:BAR2 - [0:0]
+:BAR3 - [0:0]
+:BAR4 - [0:0]
+:BAR5 - [0:0]
+:BAR6 - [0:0]
+:BAR7 - [0:0]
+:BAR8 - [0:0]
+:BAR9 - [0:0]
+"
+
+RS1="$RS
+-X BAR3
+-X BAR6
+-X BAR9
+-A FOO -s 9.9.0.1/32 -j BAR1
+-A FOO -s 9.9.0.2/32 -j BAR2
+-A FOO -s 9.9.0.4/32 -j BAR4
+-A FOO -s 9.9.0.5/32 -j BAR5
+-A FOO -s 9.9.0.7/32 -j BAR7
+-A FOO -s 9.9.0.8/32 -j BAR8
+COMMIT
+"
+
+RS2="$RS
+-X BAR2
+-X BAR5
+-X BAR7
+-A FOO -s 9.9.0.1/32 -j BAR1
+-A FOO -s 9.9.0.3/32 -j BAR3
+-A FOO -s 9.9.0.4/32 -j BAR4
+-A FOO -s 9.9.0.6/32 -j BAR6
+-A FOO -s 9.9.0.8/32 -j BAR8
+-A FOO -s 9.9.0.9/32 -j BAR9
+COMMIT
+"
+
+NORS="*filter
+COMMIT
+"
+
+for n in $(seq 1 10); do
+ $XT_MULTI iptables-restore <<< "$NORS"
+ $XT_MULTI iptables-restore --noflush -w <<< "$RS1" &
+ $XT_MULTI iptables-restore --noflush -w <<< "$RS2" &
+ wait -n
+ wait -n
+done
diff --git a/iptables/tests/shell/testcases/ipt-restore/0017-pointless-compat-checks_0 b/iptables/tests/shell/testcases/ipt-restore/0017-pointless-compat-checks_0
new file mode 100755
index 00000000..cf73de32
--- /dev/null
+++ b/iptables/tests/shell/testcases/ipt-restore/0017-pointless-compat-checks_0
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+# A bug in extension registration would leave unsupported older extension
+# revisions in pending list and get compatibility checked again for each rule
+# using them. With SELinux enabled, the resulting socket() call per rule leads
+# to significant slowdown (~50% performance in worst cases).
+
+set -e
+
+strace --version >/dev/null || { echo "skip for missing strace"; exit 0; }
+
+RULESET="$(
+ echo "*filter"
+ for ((i = 0; i < 100; i++)); do
+ echo "-A FORWARD -m conntrack --ctstate NEW"
+ done
+ echo "COMMIT"
+)"
+
+cmd="$XT_MULTI iptables-restore"
+socketcount=$(strace -esocket $cmd <<< "$RULESET" 2>&1 | wc -l)
+
+# unpatched iptables-restore would open 111 sockets,
+# patched only 12 but keep a certain margin for future changes
+[[ $socketcount -lt 20 ]]
diff --git a/iptables/tests/shell/testcases/ipt-save/dumps/ipt-save-filter.txt b/iptables/tests/shell/testcases/ipt-save/dumps/ipt-save-filter.txt
index bfb6bdda..6e42de78 100644
--- a/iptables/tests/shell/testcases/ipt-save/dumps/ipt-save-filter.txt
+++ b/iptables/tests/shell/testcases/ipt-save/dumps/ipt-save-filter.txt
@@ -40,8 +40,8 @@
-A OUTPUT -s 127.0.0.1/32 -d 127.0.0.1/32 -o lo -j ACCEPT
-A OUTPUT -o wlan0 -j wlanout
-A OUTPUT -j block
--A WLAN -s 192.168.200.4/32 -m mac --mac-source 00:00:F1:05:A0:E0 -j RETURN
--A WLAN -s 192.168.200.9/32 -m mac --mac-source 00:00:F1:05:99:85 -j RETURN
+-A WLAN -s 192.168.200.4/32 -m mac --mac-source 00:00:f1:05:a0:e0 -j RETURN
+-A WLAN -s 192.168.200.9/32 -m mac --mac-source 00:00:f1:05:99:85 -j RETURN
-A WLAN -m limit --limit 12/min -j LOG --log-prefix "UNKNOWN WLAN dropped:"
-A WLAN -j DROP
-A accept_log -i ppp0 -p tcp -m tcp --tcp-flags SYN,RST,ACK SYN -m limit --limit 1/sec -j LOG --log-prefix "TCPConnect on ppp0:"
diff --git a/iptables/tests/shell/testcases/iptables/0004-return-codes_0 b/iptables/tests/shell/testcases/iptables/0004-return-codes_0
index ce02e0bc..dcd9dfd3 100755
--- a/iptables/tests/shell/testcases/iptables/0004-return-codes_0
+++ b/iptables/tests/shell/testcases/iptables/0004-return-codes_0
@@ -13,69 +13,84 @@ cmd() { # (rc, msg, cmd, [args ...])
msg_exp="$1"; shift
}
- msg="$($XT_MULTI "$@" 2>&1 >/dev/null)"
- rc=$?
+ for ipt in iptables ip6tables; do
+ msg="$($XT_MULTI $ipt "$@" 2>&1 >/dev/null)"
+ rc=$?
- [ $rc -eq $rc_exp ] || {
- echo "---> expected return code $rc_exp, got $rc for command '$@'"
- global_rc=1
- }
+ [ $rc -eq $rc_exp ] || {
+ echo "---> expected return code $rc_exp, got $rc for command '$ipt $@'"
+ 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
- }
+ [ -n "$msg_exp" ] || continue
+ msg_exp_full="${ipt}$msg_exp"
+ grep -q "$msg_exp_full" <<< $msg || {
+ echo "---> expected error message '$msg_exp_full', got '$msg' for command '$ipt $@'"
+ global_rc=1
+ }
+ done
}
-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"
+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=" v[0-9\.]* [^ ]*: Couldn't load target \`foobar':No such file or directory"
+ENOMTH=" v[0-9\.]* [^ ]*: 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 "$EEXIST" iptables -N foo
+cmd 0 -N foo
+cmd 1 "$EEXIST" -N foo
# iptables-nft allows this - bug or feature?
-#cmd 2 iptables -N "invalid name"
+#cmd 2 -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
+cmd 0 -F foo
+cmd 0 -Z foo
+cmd 1 "$ENOENT" -F bar
+cmd 1 "$ENOENT" -Z bar
# test chain rename
-cmd 0 iptables -E foo bar
-cmd 1 "$EEXIST_F" iptables -E foo bar
+cmd 0 -E foo bar
+cmd 1 "$EEXIST_F" -E foo bar
+cmd 1 "$ENOENT" -E foo bar2
+cmd 0 -N foo2
+cmd 1 "$EEXIST_F" -E foo2 bar
# test rule adding
-cmd 0 iptables -A INPUT -j ACCEPT
-cmd 1 "$ENOENT" iptables -A noexist -j ACCEPT
+cmd 0 -A INPUT -j ACCEPT
+cmd 1 "$ENOENT" -A noexist -j ACCEPT
+# next three differ:
+# legacy: Couldn't load target `foobar':No such file or directory
+# nft: Chain 'foobar' does not exist
+cmd 2 "" -I INPUT -j foobar
+cmd 2 "" -R INPUT 1 -j foobar
+cmd 2 "" -D INPUT -j foobar
+cmd 1 "$EBADRULE" -D INPUT -p tcp --dport 22 -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
+cmd 1 "$E2BIG_I" -I INPUT 23 -j ACCEPT
+cmd 1 "$E2BIG_D" -D INPUT 23
+cmd 1 "$E2BIG_R" -R INPUT 23 -j ACCEPT
+cmd 1 "$ENOENT" -I nonexist 23 -j ACCEPT
+cmd 1 "$ENOENT" -D nonexist 23
+cmd 1 "$ENOENT" -R nonexist 23 -j ACCEPT
# test rule checking
-cmd 0 iptables -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
+cmd 0 -C INPUT -j ACCEPT
+cmd 1 "$EBADRULE" -C FORWARD -j ACCEPT
+cmd 1 "$BADRULE" -C nonexist -j ACCEPT
+cmd 2 "$ENOMTH" -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
+# legacy: Couldn't load target `foobar':No such file or directory
+# nft: Chain 'foobar' does not exist
+cmd 2 "" -C INPUT -j foobar
+# legacy: can't initialize ip6tables table `foobar': Table does not exist (do you need to insmod?)
+# nft: table 'foobar' does not exist
+cmd 3 "" -t foobar -C INPUT -j ACCEPT
exit $global_rc
diff --git a/iptables/tests/shell/testcases/iptables/0006-46-args_0 b/iptables/tests/shell/testcases/iptables/0006-46-args_0
new file mode 100755
index 00000000..17a0a018
--- /dev/null
+++ b/iptables/tests/shell/testcases/iptables/0006-46-args_0
@@ -0,0 +1,88 @@
+#!/bin/bash
+
+RC=0
+
+$XT_MULTI iptables -6 -A FORWARD -j ACCEPT
+rc=$?
+if [[ $rc -ne 2 ]]; then
+ echo "'iptables -6' returned $rc instead of 2"
+ RC=1
+fi
+
+$XT_MULTI ip6tables -4 -A FORWARD -j ACCEPT
+rc=$?
+if [[ $rc -ne 2 ]]; then
+ echo "'ip6tables -4' returned $rc instead of 2"
+ RC=1
+fi
+
+RULESET='*filter
+-4 -A FORWARD -d 10.0.0.1 -j ACCEPT
+-6 -A FORWARD -d fec0:10::1 -j ACCEPT
+COMMIT
+'
+EXPECT4='-P FORWARD ACCEPT
+-A FORWARD -d 10.0.0.1/32 -j ACCEPT'
+EXPECT6='-P FORWARD ACCEPT
+-A FORWARD -d fec0:10::1/128 -j ACCEPT'
+EXPECT_EMPTY='-P FORWARD ACCEPT'
+
+echo "$RULESET" | $XT_MULTI iptables-restore || {
+ echo "iptables-restore failed!"
+ RC=1
+}
+diff -u -Z <(echo -e "$EXPECT4") <($XT_MULTI iptables -S FORWARD) || {
+ echo "unexpected iptables ruleset"
+ RC=1
+}
+diff -u -Z <(echo -e "$EXPECT_EMPTY") <($XT_MULTI ip6tables -S FORWARD) || {
+ echo "unexpected non-empty ip6tables ruleset"
+ RC=1
+}
+
+$XT_MULTI iptables -F FORWARD
+
+echo "$RULESET" | $XT_MULTI ip6tables-restore || {
+ echo "ip6tables-restore failed!"
+ RC=1
+}
+diff -u -Z <(echo -e "$EXPECT6") <($XT_MULTI ip6tables -S FORWARD) || {
+ echo "unexpected ip6tables ruleset"
+ RC=1
+}
+diff -u -Z <(echo -e "$EXPECT_EMPTY") <($XT_MULTI iptables -S FORWARD) || {
+ echo "unexpected non-empty iptables ruleset"
+ RC=1
+}
+
+$XT_MULTI ip6tables -F FORWARD
+
+$XT_MULTI iptables -4 -A FORWARD -d 10.0.0.1 -j ACCEPT || {
+ echo "iptables failed!"
+ RC=1
+}
+diff -u -Z <(echo -e "$EXPECT4") <($XT_MULTI iptables -S FORWARD) || {
+ echo "unexpected iptables ruleset"
+ RC=1
+}
+diff -u -Z <(echo -e "$EXPECT_EMPTY") <($XT_MULTI ip6tables -S FORWARD) || {
+ echo "unexpected non-empty ip6tables ruleset"
+ RC=1
+}
+
+$XT_MULTI iptables -F FORWARD
+
+$XT_MULTI ip6tables -6 -A FORWARD -d fec0:10::1 -j ACCEPT || {
+ echo "ip6tables failed!"
+ RC=1
+}
+diff -u -Z <(echo -e "$EXPECT6") <($XT_MULTI ip6tables -S FORWARD) || {
+ echo "unexpected ip6tables ruleset"
+ RC=1
+}
+diff -u -Z <(echo -e "$EXPECT_EMPTY") <($XT_MULTI iptables -S FORWARD) || {
+ echo "unexpected non-empty iptables ruleset"
+ RC=1
+}
+
+exit $RC
diff --git a/iptables/tests/shell/testcases/nft-only/0001compat_0 b/iptables/tests/shell/testcases/nft-only/0001compat_0
index 4319ea5a..a617c52f 100755
--- a/iptables/tests/shell/testcases/nft-only/0001compat_0
+++ b/iptables/tests/shell/testcases/nft-only/0001compat_0
@@ -5,17 +5,18 @@
# xtables: avoid bogus 'is incompatible' warning
case "$XT_MULTI" in
-*/xtables-nft-multi)
- nft -v >/dev/null || exit 0
- nft 'add table ip nft-test; add chain ip nft-test foobar { type filter hook forward priority 42; }' || exit 1
- nft 'add table ip6 nft-test; add chain ip6 nft-test foobar { type filter hook forward priority 42; }' || exit 1
-
- $XT_MULTI iptables -L -t filter || exit 1
- $XT_MULTI ip6tables -L -t filter || exit 1
+*xtables-nft-multi)
;;
*)
echo skip $XT_MULTI
+ exit 0
;;
esac
+nft -v >/dev/null || exit 0
+nft 'add table ip nft-test; add chain ip nft-test foobar { type filter hook forward priority 42; }' || exit 1
+nft 'add table ip6 nft-test; add chain ip6 nft-test foobar { type filter hook forward priority 42; }' || exit 1
+
+$XT_MULTI iptables -L -t filter || exit 1
+$XT_MULTI ip6tables -L -t filter || exit 1
exit 0
diff --git a/iptables/tests/shell/testcases/nft-only/0002invflags_0 b/iptables/tests/shell/testcases/nft-only/0002invflags_0
index 406b6081..fe33874d 100755
--- a/iptables/tests/shell/testcases/nft-only/0002invflags_0
+++ b/iptables/tests/shell/testcases/nft-only/0002invflags_0
@@ -2,7 +2,7 @@
set -e
-[[ $XT_MULTI == */xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
+[[ $XT_MULTI == *xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
$XT_MULTI iptables -A INPUT -p tcp --dport 53 ! -s 192.168.0.1 -j ACCEPT
$XT_MULTI ip6tables -A INPUT -p tcp --dport 53 ! -s feed:babe::1 -j ACCEPT
diff --git a/iptables/tests/shell/testcases/nft-only/0003delete-with-comment_0 b/iptables/tests/shell/testcases/nft-only/0003delete-with-comment_0
index 67af9fd8..ccb009e4 100755
--- a/iptables/tests/shell/testcases/nft-only/0003delete-with-comment_0
+++ b/iptables/tests/shell/testcases/nft-only/0003delete-with-comment_0
@@ -2,7 +2,7 @@
set -e
-[[ $XT_MULTI == */xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
+[[ $XT_MULTI == *xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
comment1="foo bar"
comment2="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
diff --git a/iptables/tests/shell/testcases/nft-only/0006-policy-override_0 b/iptables/tests/shell/testcases/nft-only/0006-policy-override_0
new file mode 100755
index 00000000..68e2019b
--- /dev/null
+++ b/iptables/tests/shell/testcases/nft-only/0006-policy-override_0
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+[[ $XT_MULTI == *xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
+
+# make sure none of the commands invoking nft_xt_builtin_init() override
+# non-default chain policies via needless chain add.
+
+RC=0
+
+do_test() {
+ $XT_MULTI $@
+ $XT_MULTI iptables -S | grep -q -- '-P FORWARD DROP' && return
+
+ echo "command '$@' kills chain policies"
+ $XT_MULTI iptables -P FORWARD DROP
+ RC=1
+}
+
+$XT_MULTI iptables -P FORWARD DROP
+
+do_test iptables -A OUTPUT -j ACCEPT
+do_test iptables -F
+do_test iptables -N foo
+do_test iptables -E foo foo2
+do_test iptables -I OUTPUT -j ACCEPT
+do_test iptables -nL
+do_test iptables -S
+
+exit $RC
diff --git a/iptables/tests/shell/testcases/nft-only/0007-mid-restore-flush_0 b/iptables/tests/shell/testcases/nft-only/0007-mid-restore-flush_0
new file mode 100755
index 00000000..43880ffb
--- /dev/null
+++ b/iptables/tests/shell/testcases/nft-only/0007-mid-restore-flush_0
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+[[ $XT_MULTI == *xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
+nft -v >/dev/null || { echo "skip $XT_MULTI (no nft)"; exit 0; }
+
+coproc $XT_MULTI iptables-restore --noflush
+
+cat >&"${COPROC[1]}" <<EOF
+*filter
+:foo [0:0]
+COMMIT
+*filter
+:foo [0:0]
+EOF
+
+$XT_MULTI iptables-save | grep -q ':foo'
+nft flush ruleset
+
+echo "COMMIT" >&"${COPROC[1]}"
+sleep 1
+
+[[ -n $COPROC_PID ]] && kill $COPROC_PID
+wait
diff --git a/iptables/tests/shell/testcases/nft-only/0008-basechain-policy_0 b/iptables/tests/shell/testcases/nft-only/0008-basechain-policy_0
new file mode 100755
index 00000000..a81e9bad
--- /dev/null
+++ b/iptables/tests/shell/testcases/nft-only/0008-basechain-policy_0
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+[[ $XT_MULTI == *xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
+set -e
+
+$XT_MULTI iptables -t raw -P OUTPUT DROP
+
+# make sure iptables-nft-restore can correctly handle basechain policies when
+# they aren't set with --noflush
+#
+$XT_MULTI iptables-restore --noflush <<EOF
+*raw
+:OUTPUT - [0:0]
+:PREROUTING - [0:0]
+:neutron-linuxbri-OUTPUT - [0:0]
+:neutron-linuxbri-PREROUTING - [0:0]
+-I OUTPUT 1 -j neutron-linuxbri-OUTPUT
+-I PREROUTING 1 -j neutron-linuxbri-PREROUTING
+-I neutron-linuxbri-PREROUTING 1 -m physdev --physdev-in brq7425e328-56 -j CT --zone 4097
+-I neutron-linuxbri-PREROUTING 2 -i brq7425e328-56 -j CT --zone 4097
+-I neutron-linuxbri-PREROUTING 3 -m physdev --physdev-in tap7f101a28-1d -j CT --zone 4097
+
+COMMIT
+EOF
+
+$XT_MULTI iptables-save | grep -C2 raw | grep OUTPUT | grep DROP
+if [ $? -ne 0 ]; then
+ exit 1
+fi
diff --git a/iptables/tests/shell/testcases/nft-only/0009-needless-bitwise_0 b/iptables/tests/shell/testcases/nft-only/0009-needless-bitwise_0
new file mode 100755
index 00000000..41588a10
--- /dev/null
+++ b/iptables/tests/shell/testcases/nft-only/0009-needless-bitwise_0
@@ -0,0 +1,346 @@
+#!/bin/bash -x
+
+[[ $XT_MULTI == *xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
+set -e
+
+nft flush ruleset
+
+(
+ echo "*filter"
+ for plen in "" 32 30 24 16 8 0; do
+ addr="10.1.2.3${plen:+/}$plen"
+ echo "-A OUTPUT -d $addr"
+ done
+ echo "COMMIT"
+) | $XT_MULTI iptables-restore
+
+(
+ echo "*filter"
+ for plen in "" 128 124 120 112 88 80 64 48 16 8 0; do
+ addr="feed:c0ff:ee00:0102:0304:0506:0708:090A${plen:+/}$plen"
+ echo "-A OUTPUT -d $addr"
+ done
+ echo "COMMIT"
+) | $XT_MULTI ip6tables-restore
+
+masks="
+ff:ff:ff:ff:ff:ff
+ff:ff:ff:ff:ff:f0
+ff:ff:ff:ff:ff:00
+ff:ff:ff:ff:00:00
+ff:ff:ff:00:00:00
+ff:ff:00:00:00:00
+ff:00:00:00:00:00
+"
+(
+ echo "*filter"
+ for plen in "" 32 30 24 16 8 0; do
+ addr="10.1.2.3${plen:+/}$plen"
+ echo "-A OUTPUT -d $addr"
+ done
+ for mask in $masks; do
+ echo "-A OUTPUT --destination-mac fe:ed:00:c0:ff:ee/$mask"
+ done
+ echo "COMMIT"
+) | $XT_MULTI arptables-restore
+
+(
+ echo "*filter"
+ for mask in $masks; do
+ echo "-A OUTPUT -d fe:ed:00:c0:ff:ee/$mask"
+ done
+ echo "COMMIT"
+) | $XT_MULTI ebtables-restore
+
+EXPECT="ip filter OUTPUT 4
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x0302010a ]
+ [ counter pkts 0 bytes 0 ]
+
+ip filter OUTPUT 5 4
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x0302010a ]
+ [ counter pkts 0 bytes 0 ]
+
+ip filter OUTPUT 6 5
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0xfcffffff ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x0002010a ]
+ [ counter pkts 0 bytes 0 ]
+
+ip filter OUTPUT 7 6
+ [ payload load 3b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x0002010a ]
+ [ counter pkts 0 bytes 0 ]
+
+ip filter OUTPUT 8 7
+ [ payload load 2b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x0000010a ]
+ [ counter pkts 0 bytes 0 ]
+
+ip filter OUTPUT 9 8
+ [ payload load 1b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ counter pkts 0 bytes 0 ]
+
+ip filter OUTPUT 10 9
+ [ counter pkts 0 bytes 0 ]
+
+ip6 filter OUTPUT 4
+ [ payload load 16b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0xffc0edfe 0x020100ee 0x06050403 0x0a090807 ]
+ [ counter pkts 0 bytes 0 ]
+
+ip6 filter OUTPUT 5 4
+ [ payload load 16b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0xffc0edfe 0x020100ee 0x06050403 0x0a090807 ]
+ [ counter pkts 0 bytes 0 ]
+
+ip6 filter OUTPUT 6 5
+ [ payload load 16b @ network header + 24 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0xffffffff 0xffffffff 0xffffffff 0xf0ffffff ) ^ 0x00000000 0x00000000 0x00000000 0x00000000 ]
+ [ cmp eq reg 1 0xffc0edfe 0x020100ee 0x06050403 0x00090807 ]
+ [ counter pkts 0 bytes 0 ]
+
+ip6 filter OUTPUT 7 6
+ [ payload load 15b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0xffc0edfe 0x020100ee 0x06050403 0x00090807 ]
+ [ counter pkts 0 bytes 0 ]
+
+ip6 filter OUTPUT 8 7
+ [ payload load 14b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0xffc0edfe 0x020100ee 0x06050403 0x00000807 ]
+ [ counter pkts 0 bytes 0 ]
+
+ip6 filter OUTPUT 9 8
+ [ payload load 11b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0xffc0edfe 0x020100ee 0x00050403 ]
+ [ counter pkts 0 bytes 0 ]
+
+ip6 filter OUTPUT 10 9
+ [ payload load 10b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0xffc0edfe 0x020100ee 0x00000403 ]
+ [ counter pkts 0 bytes 0 ]
+
+ip6 filter OUTPUT 11 10
+ [ payload load 8b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0xffc0edfe 0x020100ee ]
+ [ counter pkts 0 bytes 0 ]
+
+ip6 filter OUTPUT 12 11
+ [ payload load 6b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0xffc0edfe 0x000000ee ]
+ [ counter pkts 0 bytes 0 ]
+
+ip6 filter OUTPUT 13 12
+ [ payload load 2b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0x0000edfe ]
+ [ counter pkts 0 bytes 0 ]
+
+ip6 filter OUTPUT 14 13
+ [ payload load 1b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0x000000fe ]
+ [ counter pkts 0 bytes 0 ]
+
+ip6 filter OUTPUT 15 14
+ [ counter pkts 0 bytes 0 ]
+
+arp filter OUTPUT 3
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ cmp eq reg 1 0x00000004 ]
+ [ payload load 4b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0x0302010a ]
+ [ counter pkts 0 bytes 0 ]
+
+arp filter OUTPUT 4 3
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ cmp eq reg 1 0x00000004 ]
+ [ payload load 4b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0x0302010a ]
+ [ counter pkts 0 bytes 0 ]
+
+arp filter OUTPUT 5 4
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ cmp eq reg 1 0x00000004 ]
+ [ payload load 4b @ network header + 24 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0xfcffffff ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x0002010a ]
+ [ counter pkts 0 bytes 0 ]
+
+arp filter OUTPUT 6 5
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ cmp eq reg 1 0x00000004 ]
+ [ payload load 3b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0x0002010a ]
+ [ counter pkts 0 bytes 0 ]
+
+arp filter OUTPUT 7 6
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ cmp eq reg 1 0x00000004 ]
+ [ payload load 2b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0x0000010a ]
+ [ counter pkts 0 bytes 0 ]
+
+arp filter OUTPUT 8 7
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ cmp eq reg 1 0x00000004 ]
+ [ payload load 1b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ counter pkts 0 bytes 0 ]
+
+arp filter OUTPUT 9 8
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ cmp eq reg 1 0x00000004 ]
+ [ counter pkts 0 bytes 0 ]
+
+arp filter OUTPUT 10 9
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ cmp eq reg 1 0x00000004 ]
+ [ payload load 6b @ network header + 18 => reg 1 ]
+ [ cmp eq reg 1 0xc000edfe 0x0000eeff ]
+ [ counter pkts 0 bytes 0 ]
+
+arp filter OUTPUT 11 10
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ cmp eq reg 1 0x00000004 ]
+ [ payload load 6b @ network header + 18 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0xffffffff 0x0000f0ff ) ^ 0x00000000 0x00000000 ]
+ [ cmp eq reg 1 0xc000edfe 0x0000e0ff ]
+ [ counter pkts 0 bytes 0 ]
+
+arp filter OUTPUT 12 11
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ cmp eq reg 1 0x00000004 ]
+ [ payload load 5b @ network header + 18 => reg 1 ]
+ [ cmp eq reg 1 0xc000edfe 0x000000ff ]
+ [ counter pkts 0 bytes 0 ]
+
+arp filter OUTPUT 13 12
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ cmp eq reg 1 0x00000004 ]
+ [ payload load 4b @ network header + 18 => reg 1 ]
+ [ cmp eq reg 1 0xc000edfe ]
+ [ counter pkts 0 bytes 0 ]
+
+arp filter OUTPUT 14 13
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ cmp eq reg 1 0x00000004 ]
+ [ payload load 3b @ network header + 18 => reg 1 ]
+ [ cmp eq reg 1 0x0000edfe ]
+ [ counter pkts 0 bytes 0 ]
+
+arp filter OUTPUT 15 14
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ cmp eq reg 1 0x00000004 ]
+ [ payload load 2b @ network header + 18 => reg 1 ]
+ [ cmp eq reg 1 0x0000edfe ]
+ [ counter pkts 0 bytes 0 ]
+
+arp filter OUTPUT 16 15
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ cmp eq reg 1 0x00000004 ]
+ [ payload load 1b @ network header + 18 => reg 1 ]
+ [ cmp eq reg 1 0x000000fe ]
+ [ counter pkts 0 bytes 0 ]
+
+bridge filter OUTPUT 4
+ [ payload load 6b @ link header + 0 => reg 1 ]
+ [ cmp eq reg 1 0xc000edfe 0x0000eeff ]
+ [ counter pkts 0 bytes 0 ]
+
+bridge filter OUTPUT 5 4
+ [ payload load 6b @ link header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0xffffffff 0x0000f0ff ) ^ 0x00000000 0x00000000 ]
+ [ cmp eq reg 1 0xc000edfe 0x0000e0ff ]
+ [ counter pkts 0 bytes 0 ]
+
+bridge filter OUTPUT 6 5
+ [ payload load 5b @ link header + 0 => reg 1 ]
+ [ cmp eq reg 1 0xc000edfe 0x000000ff ]
+ [ counter pkts 0 bytes 0 ]
+
+bridge filter OUTPUT 7 6
+ [ payload load 4b @ link header + 0 => reg 1 ]
+ [ cmp eq reg 1 0xc000edfe ]
+ [ counter pkts 0 bytes 0 ]
+
+bridge filter OUTPUT 8 7
+ [ payload load 3b @ link header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x0000edfe ]
+ [ counter pkts 0 bytes 0 ]
+
+bridge filter OUTPUT 9 8
+ [ payload load 2b @ link header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x0000edfe ]
+ [ counter pkts 0 bytes 0 ]
+
+bridge filter OUTPUT 10 9
+ [ payload load 1b @ link header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x000000fe ]
+ [ counter pkts 0 bytes 0 ]
+"
+
+# print nothing but:
+# - lines with bytecode (starting with ' [')
+# - empty lines (so printed diff is not a complete mess)
+filter() {
+ awk '/^( \[|$)/{print}'
+}
+
+diff -u -Z <(filter <<< "$EXPECT") <(nft --debug=netlink list ruleset | filter)
diff --git a/iptables/xshared.c b/iptables/xshared.c
index 16c58914..71f68990 100644
--- a/iptables/xshared.c
+++ b/iptables/xshared.c
@@ -249,15 +249,20 @@ void xs_init_match(struct xtables_match *match)
static int xtables_lock(int wait, struct timeval *wait_interval)
{
struct timeval time_left, wait_time;
+ const char *lock_file;
int fd, i = 0;
time_left.tv_sec = wait;
time_left.tv_usec = 0;
- fd = open(XT_LOCK_NAME, O_CREAT, 0600);
+ lock_file = getenv("XTABLES_LOCKFILE");
+ if (lock_file == NULL || lock_file[0] == '\0')
+ lock_file = XT_LOCK_NAME;
+
+ fd = open(lock_file, O_CREAT, 0600);
if (fd < 0) {
fprintf(stderr, "Fatal: can't open lock file %s: %s\n",
- XT_LOCK_NAME, strerror(errno));
+ lock_file, strerror(errno));
return XT_LOCK_FAILED;
}
@@ -265,7 +270,7 @@ static int xtables_lock(int wait, struct timeval *wait_interval)
if (flock(fd, LOCK_EX) == 0)
return fd;
- fprintf(stderr, "Can't lock %s: %s\n", XT_LOCK_NAME,
+ fprintf(stderr, "Can't lock %s: %s\n", lock_file,
strerror(errno));
return XT_LOCK_BUSY;
}
@@ -495,7 +500,6 @@ void add_param_to_argv(struct argv_store *store, char *parsestart, int line)
continue;
} else if (*curchar == '"') {
quote_open = 0;
- *curchar = '"';
} else {
add_param(&param, curchar);
continue;
@@ -775,3 +779,77 @@ int parse_rulenumber(const char *rule)
return rulenum;
}
+
+/* Table of legal combinations of commands and options. If any of the
+ * given commands make an option legal, that option is legal (applies to
+ * CMD_LIST and CMD_ZERO only).
+ * Key:
+ * + compulsory
+ * x illegal
+ * optional
+ */
+static const char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] =
+/* Well, it's better than "Re: Linux vs FreeBSD" */
+{
+ /* -n -s -d -p -j -v -x -i -o --line -c -f 2 3 l 4 5 6 */
+/*INSERT*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' ',' ',' ',' ',' ',' ',' ',' '},
+/*DELETE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x','x',' ',' ',' ',' ',' ',' ',' '},
+/*DELETE_NUM*/{'x','x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x','x'},
+/*REPLACE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' ',' ',' ',' ',' ',' ',' ',' '},
+/*APPEND*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' ',' ',' ',' ',' ',' ',' ',' '},
+/*LIST*/ {' ','x','x','x','x',' ',' ','x','x',' ','x','x','x','x','x','x','x','x'},
+/*FLUSH*/ {'x','x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x','x'},
+/*ZERO*/ {'x','x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x','x'},
+/*NEW_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x','x'},
+/*DEL_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x','x'},
+/*SET_POLICY*/{'x','x','x','x','x',' ','x','x','x','x',' ','x','x','x','x','x','x','x'},
+/*RENAME*/ {'x','x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x','x'},
+/*LIST_RULES*/{'x','x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x','x'},
+/*ZERO_NUM*/ {'x','x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x','x'},
+/*CHECK*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x','x',' ',' ',' ',' ',' ',' ',' '},
+};
+
+void generic_opt_check(int command, int options)
+{
+ int i, j, legal = 0;
+
+ /* Check that commands are valid with options. Complicated by the
+ * fact that if an option is legal with *any* command given, it is
+ * legal overall (ie. -z and -l).
+ */
+ for (i = 0; i < NUMBER_OF_OPT; i++) {
+ legal = 0; /* -1 => illegal, 1 => legal, 0 => undecided. */
+
+ for (j = 0; j < NUMBER_OF_CMD; j++) {
+ if (!(command & (1<<j)))
+ continue;
+
+ if (!(options & (1<<i))) {
+ if (commands_v_options[j][i] == '+')
+ xtables_error(PARAMETER_PROBLEM,
+ "You need to supply the `-%c' "
+ "option for this command\n",
+ optflags[i]);
+ } else {
+ if (commands_v_options[j][i] != 'x')
+ legal = 1;
+ else if (legal == 0)
+ legal = -1;
+ }
+ }
+ if (legal == -1)
+ xtables_error(PARAMETER_PROBLEM,
+ "Illegal option `-%c' with this command\n",
+ optflags[i]);
+ }
+}
+
+char opt2char(int option)
+{
+ const char *ptr;
+
+ for (ptr = optflags; option > 1; option >>= 1, ptr++)
+ ;
+
+ return *ptr;
+}
diff --git a/iptables/xshared.h b/iptables/xshared.h
index c41bd054..9159b2b1 100644
--- a/iptables/xshared.h
+++ b/iptables/xshared.h
@@ -30,15 +30,20 @@ enum {
OPT_VIANAMEOUT = 1 << 8,
OPT_LINENUMBERS = 1 << 9,
OPT_COUNTERS = 1 << 10,
+ OPT_FRAGMENT = 1 << 11,
/* below are for arptables only */
- OPT_S_MAC = 1 << 11,
- OPT_D_MAC = 1 << 12,
- OPT_H_LENGTH = 1 << 13,
- OPT_OPCODE = 1 << 14,
- OPT_H_TYPE = 1 << 15,
- OPT_P_TYPE = 1 << 16,
+ OPT_S_MAC = 1 << 12,
+ OPT_D_MAC = 1 << 13,
+ OPT_H_LENGTH = 1 << 14,
+ OPT_OPCODE = 1 << 15,
+ OPT_H_TYPE = 1 << 16,
+ OPT_P_TYPE = 1 << 17,
};
+#define NUMBER_OF_OPT ARRAY_SIZE(optflags)
+static const char optflags[]
+= { 'n', 's', 'd', 'p', 'j', 'v', 'x', 'i', 'o', '0', 'c', 'f', 2, 3, 'l', 4, 5, 6 };
+
enum {
CMD_NONE = 0,
CMD_INSERT = 1 << 0,
@@ -216,4 +221,7 @@ void add_command(unsigned int *cmd, const int newcmd,
const int othercmds, int invert);
int parse_rulenumber(const char *rule);
+void generic_opt_check(int command, int options);
+char opt2char(int option);
+
#endif /* IPTABLES_XSHARED_H */
diff --git a/iptables/xtables-arp-standalone.c b/iptables/xtables-arp-standalone.c
index eca7bb97..04cf7dcc 100644
--- a/iptables/xtables-arp-standalone.c
+++ b/iptables/xtables-arp-standalone.c
@@ -56,6 +56,7 @@ int xtables_arp_main(int argc, char *argv[])
ret = nft_commit(&h);
nft_fini(&h);
+ xtables_fini();
if (!ret)
fprintf(stderr, "arptables: %s\n", nft_strerror(errno));
diff --git a/iptables/xtables-arp.c b/iptables/xtables-arp.c
index 9cfad762..4a89ae95 100644
--- a/iptables/xtables-arp.c
+++ b/iptables/xtables-arp.c
@@ -53,10 +53,6 @@
#include "nft-arp.h"
#include <linux/netfilter_arp/arp_tables.h>
-#define NUMBER_OF_OPT 16
-static const char optflags[NUMBER_OF_OPT]
-= { 'n', 's', 'd', 2, 3, 7, 8, 4, 5, 6, 'j', 'v', 'i', 'o', '0', 'c'};
-
static struct option original_opts[] = {
{ "append", 1, 0, 'A' },
{ "delete", 1, 0, 'D' },
@@ -113,74 +109,29 @@ struct xtables_globals arptables_globals = {
static int inverse_for_options[] =
{
/* -n */ 0,
-/* -s */ ARPT_INV_SRCIP,
-/* -d */ ARPT_INV_TGTIP,
+/* -s */ IPT_INV_SRCIP,
+/* -d */ IPT_INV_DSTIP,
/* -p */ 0,
/* -j */ 0,
/* -v */ 0,
/* -x */ 0,
-/* -i */ ARPT_INV_VIA_IN,
-/* -o */ ARPT_INV_VIA_OUT,
+/* -i */ IPT_INV_VIA_IN,
+/* -o */ IPT_INV_VIA_OUT,
/*--line*/ 0,
/* -c */ 0,
-/* 2 */ ARPT_INV_SRCDEVADDR,
-/* 3 */ ARPT_INV_TGTDEVADDR,
-/* -l */ ARPT_INV_ARPHLN,
-/* 4 */ ARPT_INV_ARPOP,
-/* 5 */ ARPT_INV_ARPHRD,
-/* 6 */ ARPT_INV_ARPPRO,
+/* -f */ 0,
+/* 2 */ IPT_INV_SRCDEVADDR,
+/* 3 */ IPT_INV_TGTDEVADDR,
+/* -l */ IPT_INV_ARPHLN,
+/* 4 */ IPT_INV_ARPOP,
+/* 5 */ IPT_INV_ARPHRD,
+/* 6 */ IPT_INV_PROTO,
};
/***********************************************/
/* ARPTABLES SPECIFIC NEW FUNCTIONS ADDED HERE */
/***********************************************/
-static unsigned char mac_type_unicast[ETH_ALEN] = {0,0,0,0,0,0};
-static unsigned char msk_type_unicast[ETH_ALEN] = {1,0,0,0,0,0};
-static unsigned char mac_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
-static unsigned char msk_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
-static unsigned char mac_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
-static unsigned char msk_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
-
-/*
- * put the mac address into 6 (ETH_ALEN) bytes
- */
-static int getmac_and_mask(char *from, char *to, char *mask)
-{
- char *p;
- int i;
- struct ether_addr *addr;
-
- if (strcasecmp(from, "Unicast") == 0) {
- memcpy(to, mac_type_unicast, ETH_ALEN);
- memcpy(mask, msk_type_unicast, ETH_ALEN);
- return 0;
- }
- if (strcasecmp(from, "Multicast") == 0) {
- memcpy(to, mac_type_multicast, ETH_ALEN);
- memcpy(mask, msk_type_multicast, ETH_ALEN);
- return 0;
- }
- if (strcasecmp(from, "Broadcast") == 0) {
- memcpy(to, mac_type_broadcast, ETH_ALEN);
- memcpy(mask, msk_type_broadcast, ETH_ALEN);
- return 0;
- }
- if ( (p = strrchr(from, '/')) != NULL) {
- *p = '\0';
- if (!(addr = ether_aton(p + 1)))
- return -1;
- memcpy(mask, addr, ETH_ALEN);
- } else
- memset(mask, 0xff, ETH_ALEN);
- if (!(addr = ether_aton(from)))
- return -1;
- memcpy(to, addr, ETH_ALEN);
- for (i = 0; i < ETH_ALEN; i++)
- to[i] &= mask[i];
- return 0;
-}
-
static int getlength_and_mask(char *from, uint8_t *to, uint8_t *mask)
{
char *p, *buffer;
@@ -235,7 +186,7 @@ exit_tryhelp(int status)
}
static void
-exit_printhelp(void)
+printhelp(void)
{
struct xtables_target *t = NULL;
int i;
@@ -325,16 +276,6 @@ exit_printhelp(void)
printf("\n");
t->help();
}
- exit(0);
-}
-
-static char
-opt2char(int option)
-{
- const char *ptr;
- for (ptr = optflags; option > 1; option >>= 1, ptr++);
-
- return *ptr;
}
static int
@@ -400,7 +341,7 @@ list_entries(struct nft_handle *h, const char *chain, const char *table,
if (linenumbers)
format |= FMT_LINENUMBERS;
- return nft_rule_list(h, chain, table, rulenum, format);
+ return nft_cmd_rule_list(h, chain, table, rulenum, format);
}
static int
@@ -427,10 +368,10 @@ append_entry(struct nft_handle *h,
cs->arp.arp.tgt.s_addr = daddrs[j].s_addr;
cs->arp.arp.tmsk.s_addr = dmasks[j].s_addr;
if (append) {
- ret = nft_rule_append(h, chain, table, cs, NULL,
+ ret = nft_cmd_rule_append(h, chain, table, cs, NULL,
verbose);
} else {
- ret = nft_rule_insert(h, chain, table, cs,
+ ret = nft_cmd_rule_insert(h, chain, table, cs,
rulenum, verbose);
}
}
@@ -455,7 +396,7 @@ replace_entry(const char *chain,
cs->arp.arp.smsk.s_addr = smask->s_addr;
cs->arp.arp.tmsk.s_addr = dmask->s_addr;
- return nft_rule_replace(h, chain, table, cs, rulenum, verbose);
+ return nft_cmd_rule_replace(h, chain, table, cs, rulenum, verbose);
}
static int
@@ -479,7 +420,7 @@ delete_entry(const char *chain,
for (j = 0; j < ndaddrs; j++) {
cs->arp.arp.tgt.s_addr = daddrs[j].s_addr;
cs->arp.arp.tmsk.s_addr = dmasks[j].s_addr;
- ret = nft_rule_delete(h, chain, table, cs, verbose);
+ ret = nft_cmd_rule_delete(h, chain, table, cs, verbose);
}
}
@@ -500,17 +441,10 @@ int nft_init_arp(struct nft_handle *h, const char *pname)
init_extensionsa();
#endif
- memset(h, 0, sizeof(*h));
- h->family = NFPROTO_ARP;
-
- if (nft_init(h, xtables_arp) < 0)
+ if (nft_init(h, NFPROTO_ARP, xtables_arp) < 0)
xtables_error(OTHER_PROBLEM,
"Could not initialize nftables layer.");
- h->ops = nft_family_ops_lookup(h->family);
- if (h->ops == NULL)
- xtables_error(PARAMETER_PROBLEM, "Unknown family");
-
return 0;
}
@@ -673,7 +607,8 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
if (!optarg)
optarg = argv[optind];
- exit_printhelp();
+ printhelp();
+ command = CMD_NONE;
break;
case 's':
check_inverse(optarg, &invert, &optind, argc);
@@ -693,7 +628,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
check_inverse(optarg, &invert, &optind, argc);
set_option(&options, OPT_S_MAC, &cs.arp.arp.invflags,
invert);
- if (getmac_and_mask(argv[optind - 1],
+ if (xtables_parse_mac_and_mask(argv[optind - 1],
cs.arp.arp.src_devaddr.addr, cs.arp.arp.src_devaddr.mask))
xtables_error(PARAMETER_PROBLEM, "Problem with specified "
"source mac");
@@ -704,7 +639,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
set_option(&options, OPT_D_MAC, &cs.arp.arp.invflags,
invert);
- if (getmac_and_mask(argv[optind - 1],
+ if (xtables_parse_mac_and_mask(argv[optind - 1],
cs.arp.arp.tgt_devaddr.addr, cs.arp.arp.tgt_devaddr.mask))
xtables_error(PARAMETER_PROBLEM, "Problem with specified "
"destination mac");
@@ -888,8 +823,6 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
if (optind < argc)
xtables_error(PARAMETER_PROBLEM,
"unknown arguments found on commandline");
- if (!command)
- xtables_error(PARAMETER_PROBLEM, "no command specified");
if (invert)
xtables_error(PARAMETER_PROBLEM,
"nothing appropriate following !");
@@ -910,7 +843,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
&dmasks, &ndaddrs);
if ((nsaddrs > 1 || ndaddrs > 1) &&
- (cs.arp.arp.invflags & (ARPT_INV_SRCIP | ARPT_INV_TGTIP)))
+ (cs.arp.arp.invflags & (IPT_INV_SRCIP | IPT_INV_DSTIP)))
xtables_error(PARAMETER_PROBLEM, "! not allowed with multiple"
" source or destination IP addresses");
@@ -962,7 +895,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
options&OPT_VERBOSE, h);
break;
case CMD_DELETE_NUM:
- ret = nft_rule_delete_num(h, chain, *table, rulenum - 1, verbose);
+ ret = nft_cmd_rule_delete_num(h, chain, *table, rulenum - 1, verbose);
break;
case CMD_REPLACE:
ret = replace_entry(chain, *table, &cs, rulenum - 1,
@@ -984,10 +917,10 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
options&OPT_LINENUMBERS);
break;
case CMD_FLUSH:
- ret = nft_rule_flush(h, chain, *table, options & OPT_VERBOSE);
+ ret = nft_cmd_rule_flush(h, chain, *table, options & OPT_VERBOSE);
break;
case CMD_ZERO:
- ret = nft_chain_zero_counters(h, chain, *table,
+ ret = nft_cmd_chain_zero_counters(h, chain, *table,
options & OPT_VERBOSE);
break;
case CMD_LIST|CMD_ZERO:
@@ -997,25 +930,27 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
/*options&OPT_EXPANDED*/0,
options&OPT_LINENUMBERS);
if (ret)
- ret = nft_chain_zero_counters(h, chain, *table,
+ ret = nft_cmd_chain_zero_counters(h, chain, *table,
options & OPT_VERBOSE);
break;
case CMD_NEW_CHAIN:
- ret = nft_chain_user_add(h, chain, *table);
+ ret = nft_cmd_chain_user_add(h, chain, *table);
break;
case CMD_DELETE_CHAIN:
- ret = nft_chain_user_del(h, chain, *table,
+ ret = nft_cmd_chain_user_del(h, chain, *table,
options & OPT_VERBOSE);
break;
case CMD_RENAME_CHAIN:
- ret = nft_chain_user_rename(h, chain, *table, newname);
+ ret = nft_cmd_chain_user_rename(h, chain, *table, newname);
break;
case CMD_SET_POLICY:
- ret = nft_chain_set(h, *table, chain, policy, NULL);
+ ret = nft_cmd_chain_set(h, *table, chain, policy, NULL);
if (ret < 0)
xtables_error(PARAMETER_PROBLEM, "Wrong policy `%s'\n",
policy);
break;
+ case CMD_NONE:
+ break;
default:
/* We should never reach this... */
exit_tryhelp(2);
@@ -1026,9 +961,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
free(daddrs);
free(dmasks);
- if (cs.target)
- free(cs.target->t);
-
+ nft_clear_iptables_command_state(&cs);
xtables_free_opts(1);
/* if (verbose > 1)
diff --git a/iptables/xtables-eb-standalone.c b/iptables/xtables-eb-standalone.c
index a9081c78..181cf2d0 100644
--- a/iptables/xtables-eb-standalone.c
+++ b/iptables/xtables-eb-standalone.c
@@ -53,6 +53,8 @@ int xtables_eb_main(int argc, char *argv[])
if (ret)
ret = nft_bridge_commit(&h);
+ nft_fini_eb(&h);
+
if (!ret)
fprintf(stderr, "ebtables: %s\n", nft_strerror(errno));
diff --git a/iptables/xtables-eb-translate.c b/iptables/xtables-eb-translate.c
index 96b2730f..83ae77cb 100644
--- a/iptables/xtables-eb-translate.c
+++ b/iptables/xtables-eb-translate.c
@@ -397,7 +397,9 @@ print_zero:
if (ebt_check_inverse2(optarg, argc, argv))
cs.eb.invflags |= EBT_ISOURCE;
- if (ebt_get_mac_and_mask(optarg, cs.eb.sourcemac, cs.eb.sourcemsk))
+ if (xtables_parse_mac_and_mask(optarg,
+ cs.eb.sourcemac,
+ cs.eb.sourcemsk))
xtables_error(PARAMETER_PROBLEM, "Problem with specified source mac '%s'", optarg);
cs.eb.bitmask |= EBT_SOURCEMAC;
break;
@@ -406,7 +408,9 @@ print_zero:
if (ebt_check_inverse2(optarg, argc, argv))
cs.eb.invflags |= EBT_IDEST;
- if (ebt_get_mac_and_mask(optarg, cs.eb.destmac, cs.eb.destmsk))
+ if (xtables_parse_mac_and_mask(optarg,
+ cs.eb.destmac,
+ cs.eb.destmsk))
xtables_error(PARAMETER_PROBLEM, "Problem with specified destination mac '%s'", optarg);
cs.eb.bitmask |= EBT_DESTMAC;
break;
diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c
index 15b971da..cfa9317c 100644
--- a/iptables/xtables-eb.c
+++ b/iptables/xtables-eb.c
@@ -55,57 +55,6 @@
* 1: the inverse '!' of the option has already been specified */
int ebt_invert = 0;
-unsigned char eb_mac_type_unicast[ETH_ALEN] = {0,0,0,0,0,0};
-unsigned char eb_msk_type_unicast[ETH_ALEN] = {1,0,0,0,0,0};
-unsigned char eb_mac_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
-unsigned char eb_msk_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
-unsigned char eb_mac_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
-unsigned char eb_msk_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
-unsigned char eb_mac_type_bridge_group[ETH_ALEN] = {0x01,0x80,0xc2,0,0,0};
-unsigned char eb_msk_type_bridge_group[ETH_ALEN] = {255,255,255,255,255,255};
-
-int ebt_get_mac_and_mask(const char *from, unsigned char *to,
- unsigned char *mask)
-{
- char *p;
- int i;
- struct ether_addr *addr = NULL;
-
- if (strcasecmp(from, "Unicast") == 0) {
- memcpy(to, eb_mac_type_unicast, ETH_ALEN);
- memcpy(mask, eb_msk_type_unicast, ETH_ALEN);
- return 0;
- }
- if (strcasecmp(from, "Multicast") == 0) {
- memcpy(to, eb_mac_type_multicast, ETH_ALEN);
- memcpy(mask, eb_msk_type_multicast, ETH_ALEN);
- return 0;
- }
- if (strcasecmp(from, "Broadcast") == 0) {
- memcpy(to, eb_mac_type_broadcast, ETH_ALEN);
- memcpy(mask, eb_msk_type_broadcast, ETH_ALEN);
- return 0;
- }
- if (strcasecmp(from, "BGA") == 0) {
- memcpy(to, eb_mac_type_bridge_group, ETH_ALEN);
- memcpy(mask, eb_msk_type_bridge_group, ETH_ALEN);
- return 0;
- }
- if ( (p = strrchr(from, '/')) != NULL) {
- *p = '\0';
- if (!(addr = ether_aton(p + 1)))
- return -1;
- memcpy(mask, addr, ETH_ALEN);
- } else
- memset(mask, 0xff, ETH_ALEN);
- if (!(addr = ether_aton(from)))
- return -1;
- memcpy(to, addr, ETH_ALEN);
- for (i = 0; i < ETH_ALEN; i++)
- to[i] &= mask[i];
- return 0;
-}
-
static int ebt_check_inverse2(const char option[], int argc, char **argv)
{
if (!option)
@@ -150,9 +99,9 @@ append_entry(struct nft_handle *h,
int ret = 1;
if (append)
- ret = nft_rule_append(h, chain, table, cs, NULL, verbose);
+ ret = nft_cmd_rule_append(h, chain, table, cs, NULL, verbose);
else
- ret = nft_rule_insert(h, chain, table, cs, rule_nr, verbose);
+ ret = nft_cmd_rule_insert(h, chain, table, cs, rule_nr, verbose);
return ret;
}
@@ -169,10 +118,10 @@ delete_entry(struct nft_handle *h,
int ret = 1;
if (rule_nr == -1)
- ret = nft_rule_delete(h, chain, table, cs, verbose);
+ ret = nft_cmd_rule_delete(h, chain, table, cs, verbose);
else {
do {
- ret = nft_rule_delete_num(h, chain, table,
+ ret = nft_cmd_rule_delete_num(h, chain, table,
rule_nr, verbose);
rule_nr++;
} while (rule_nr < rule_nr_end);
@@ -427,7 +376,7 @@ static int list_rules(struct nft_handle *h, const char *chain, const char *table
if (!counters)
format |= FMT_NOCOUNTS;
- return nft_rule_list(h, chain, table, rule_nr, format);
+ return nft_cmd_rule_list(h, chain, table, rule_nr, format);
}
static int parse_rule_range(const char *argv, int *rule_nr, int *rule_nr_end)
@@ -739,16 +688,9 @@ int nft_init_eb(struct nft_handle *h, const char *pname)
init_extensionsb();
#endif
- memset(h, 0, sizeof(*h));
-
- h->family = NFPROTO_BRIDGE;
-
- if (nft_init(h, xtables_bridge) < 0)
+ if (nft_init(h, NFPROTO_BRIDGE, xtables_bridge) < 0)
xtables_error(OTHER_PROBLEM,
"Could not initialize nftables layer.");
- h->ops = nft_family_ops_lookup(h->family);
- if (!h->ops)
- xtables_error(PARAMETER_PROBLEM, "Unknown family");
/* manually registering ebt matches, given the original ebtables parser
* don't use '-m matchname' and the match can't be loaded dynamically when
@@ -759,6 +701,24 @@ int nft_init_eb(struct nft_handle *h, const char *pname)
return 0;
}
+void nft_fini_eb(struct nft_handle *h)
+{
+ struct xtables_match *match;
+ struct xtables_target *target;
+
+ for (match = xtables_matches; match; match = match->next) {
+ free(match->m);
+ }
+ for (target = xtables_targets; target; target = target->next) {
+ free(target->t);
+ }
+
+ free(opts);
+
+ nft_fini(h);
+ xtables_fini();
+}
+
int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table,
bool restore)
{
@@ -820,7 +780,7 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table,
flags |= OPT_COMMAND;
if (c == 'N') {
- ret = nft_chain_user_add(h, chain, *table);
+ ret = nft_cmd_chain_user_add(h, chain, *table);
break;
} else if (c == 'X') {
/* X arg is optional, optarg is NULL */
@@ -828,7 +788,7 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table,
chain = argv[optind];
optind++;
}
- ret = nft_chain_user_del(h, chain, *table, 0);
+ ret = nft_cmd_chain_user_del(h, chain, *table, 0);
break;
}
@@ -842,7 +802,8 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table,
else if (strchr(argv[optind], ' ') != NULL)
xtables_error(PARAMETER_PROBLEM, "Use of ' ' not allowed in chain names");
- ret = nft_chain_user_rename(h, chain, *table,
+ errno = 0;
+ ret = nft_cmd_chain_user_rename(h, chain, *table,
argv[optind]);
if (ret != 0 && errno == ENOENT)
xtables_error(PARAMETER_PROBLEM, "Chain '%s' doesn't exists", chain);
@@ -1026,7 +987,9 @@ print_zero:
if (ebt_check_inverse2(optarg, argc, argv))
cs.eb.invflags |= EBT_ISOURCE;
- if (ebt_get_mac_and_mask(optarg, cs.eb.sourcemac, cs.eb.sourcemsk))
+ if (xtables_parse_mac_and_mask(optarg,
+ cs.eb.sourcemac,
+ cs.eb.sourcemsk))
xtables_error(PARAMETER_PROBLEM, "Problem with specified source mac '%s'", optarg);
cs.eb.bitmask |= EBT_SOURCEMAC;
break;
@@ -1035,7 +998,9 @@ print_zero:
if (ebt_check_inverse2(optarg, argc, argv))
cs.eb.invflags |= EBT_IDEST;
- if (ebt_get_mac_and_mask(optarg, cs.eb.destmac, cs.eb.destmsk))
+ if (xtables_parse_mac_and_mask(optarg,
+ cs.eb.destmac,
+ cs.eb.destmsk))
xtables_error(PARAMETER_PROBLEM, "Problem with specified destination mac '%s'", optarg);
cs.eb.bitmask |= EBT_DESTMAC;
break;
@@ -1144,7 +1109,7 @@ print_zero:
/*case 7 :*/ /* atomic-init */
/*case 10:*/ /* atomic-save */
case 11: /* init-table */
- nft_table_flush(h, *table);
+ nft_cmd_table_flush(h, *table, false);
return 1;
/*
replace->command = c;
@@ -1207,7 +1172,7 @@ print_zero:
if (command == 'h' && !(flags & OPT_ZERO)) {
print_help(cs.target, cs.matches, *table);
- exit(0);
+ ret = 1;
}
/* Do the final checks */
@@ -1232,13 +1197,13 @@ print_zero:
if (command == 'P') {
if (selected_chain >= NF_BR_NUMHOOKS) {
- ret = ebt_set_user_chain_policy(h, *table, chain, policy);
+ ret = ebt_cmd_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);
+ ret = nft_cmd_chain_set(h, *table, chain, policy, NULL);
if (ret < 0)
xtables_error(PARAMETER_PROBLEM, "Wrong policy");
}
@@ -1251,9 +1216,9 @@ print_zero:
flags&LIST_C);
}
if (flags & OPT_ZERO) {
- ret = nft_chain_zero_counters(h, chain, *table, 0);
+ ret = nft_cmd_chain_zero_counters(h, chain, *table, 0);
} else if (command == 'F') {
- ret = nft_rule_flush(h, chain, *table, 0);
+ ret = nft_cmd_rule_flush(h, chain, *table, 0);
} else if (command == 'A') {
ret = append_entry(h, chain, *table, &cs, 0, 0, true);
} else if (command == 'I') {
diff --git a/iptables/xtables-monitor.c b/iptables/xtables-monitor.c
index a5245d14..4b980980 100644
--- a/iptables/xtables-monitor.c
+++ b/iptables/xtables-monitor.c
@@ -93,6 +93,8 @@ static int rule_cb(const struct nlmsghdr *nlh, void *data)
if (arg->nfproto && arg->nfproto != family)
goto err_free;
+ arg->h->ops = nft_family_ops_lookup(family);
+
if (arg->is_event)
printf(" EVENT: ");
switch (family) {
@@ -104,6 +106,7 @@ static int rule_cb(const struct nlmsghdr *nlh, void *data)
printf("-0 ");
break;
default:
+ puts("");
goto err_free;
}
@@ -225,12 +228,12 @@ static void trace_print_rule(const struct nftnl_trace *nlt, struct cb_arg *args)
exit(EXIT_FAILURE);
}
- nlh = nftnl_chain_nlmsg_build_hdr(buf, NFT_MSG_GETRULE, family, NLM_F_DUMP, 0);
+ nlh = nftnl_chain_nlmsg_build_hdr(buf, NFT_MSG_GETRULE, family, 0, 0);
nftnl_rule_set_u32(r, NFTNL_RULE_FAMILY, family);
nftnl_rule_set_str(r, NFTNL_RULE_CHAIN, chain);
nftnl_rule_set_str(r, NFTNL_RULE_TABLE, table);
- nftnl_rule_set_u64(r, NFTNL_RULE_POSITION, handle);
+ nftnl_rule_set_u64(r, NFTNL_RULE_HANDLE, handle);
nftnl_rule_nlmsg_build_payload(nlh, r);
nftnl_rule_free(r);
@@ -246,24 +249,21 @@ static void trace_print_rule(const struct nftnl_trace *nlt, struct cb_arg *args)
}
portid = mnl_socket_get_portid(nl);
- if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
- perror("mnl_socket_send");
- exit(EXIT_FAILURE);
- }
+ if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
+ perror("mnl_socket_send");
+ exit(EXIT_FAILURE);
+ }
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
- while (ret > 0) {
+ if (ret > 0) {
args->is_event = false;
- ret = mnl_cb_run(buf, ret, 0, portid, rule_cb, args);
- if (ret <= 0)
- break;
- ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
- }
- if (ret == -1) {
- perror("error");
- exit(EXIT_FAILURE);
- }
- mnl_socket_close(nl);
+ ret = mnl_cb_run(buf, ret, 0, portid, rule_cb, args);
+ }
+ if (ret == -1) {
+ perror("error");
+ exit(EXIT_FAILURE);
+ }
+ mnl_socket_close(nl);
}
static void trace_print_packet(const struct nftnl_trace *nlt, struct cb_arg *args)
@@ -274,14 +274,14 @@ static void trace_print_packet(const struct nftnl_trace *nlt, struct cb_arg *arg
uint32_t mark;
char name[IFNAMSIZ];
- printf("PACKET: %d %08x ", args->nfproto, nftnl_trace_get_u32(nlt, NFTNL_TRACE_ID));
+ family = nftnl_trace_get_u32(nlt, NFTNL_TRACE_FAMILY);
+ printf("PACKET: %d %08x ", family, nftnl_trace_get_u32(nlt, NFTNL_TRACE_ID));
if (nftnl_trace_is_set(nlt, NFTNL_TRACE_IIF))
printf("IN=%s ", if_indextoname(nftnl_trace_get_u32(nlt, NFTNL_TRACE_IIF), name));
if (nftnl_trace_is_set(nlt, NFTNL_TRACE_OIF))
printf("OUT=%s ", if_indextoname(nftnl_trace_get_u32(nlt, NFTNL_TRACE_OIF), name));
- family = nftnl_trace_get_u32(nlt, NFTNL_TRACE_FAMILY);
nfproto = family;
if (nftnl_trace_is_set(nlt, NFTNL_TRACE_NFPROTO)) {
nfproto = nftnl_trace_get_u32(nlt, NFTNL_TRACE_NFPROTO);
@@ -306,6 +306,9 @@ static void trace_print_packet(const struct nftnl_trace *nlt, struct cb_arg *arg
printf("MACDST=%s ", ether_ntoa((const void *)eh->h_dest));
printf("MACPROTO=%04x ", ntohs(eh->h_proto));
break;
+ case ARPHRD_LOOPBACK:
+ printf("LOOPBACK ");
+ break;
default:
printf("LL=0x%x ", type);
for (i = 0 ; i < len; i++)
@@ -434,9 +437,18 @@ static void trace_print_packet(const struct nftnl_trace *nlt, struct cb_arg *arg
mark = nftnl_trace_get_u32(nlt, NFTNL_TRACE_MARK);
if (mark)
printf("MARK=0x%x ", mark);
+ puts("");
+}
+
+static void trace_print_hdr(const struct nftnl_trace *nlt)
+{
+ printf(" TRACE: %d %08x %s:%s", nftnl_trace_get_u32(nlt, NFTNL_TABLE_FAMILY),
+ nftnl_trace_get_u32(nlt, NFTNL_TRACE_ID),
+ nftnl_trace_get_str(nlt, NFTNL_TRACE_TABLE),
+ nftnl_trace_get_str(nlt, NFTNL_TRACE_CHAIN));
}
-static void print_verdict(struct nftnl_trace *nlt, uint32_t verdict)
+static void print_verdict(const struct nftnl_trace *nlt, uint32_t verdict)
{
const char *chain;
@@ -497,38 +509,41 @@ static int trace_cb(const struct nlmsghdr *nlh, struct cb_arg *arg)
arg->nfproto != nftnl_trace_get_u32(nlt, NFTNL_TABLE_FAMILY))
goto err_free;
- printf(" TRACE: %d %08x %s:%s", nftnl_trace_get_u32(nlt, NFTNL_TABLE_FAMILY),
- nftnl_trace_get_u32(nlt, NFTNL_TRACE_ID),
- nftnl_trace_get_str(nlt, NFTNL_TRACE_TABLE),
- nftnl_trace_get_str(nlt, NFTNL_TRACE_CHAIN));
-
switch (nftnl_trace_get_u32(nlt, NFTNL_TRACE_TYPE)) {
case NFT_TRACETYPE_RULE:
verdict = nftnl_trace_get_u32(nlt, NFTNL_TRACE_VERDICT);
- printf(":rule:0x%llx:", (unsigned long long)nftnl_trace_get_u64(nlt, NFTNL_TRACE_RULE_HANDLE));
- print_verdict(nlt, verdict);
- if (nftnl_trace_is_set(nlt, NFTNL_TRACE_RULE_HANDLE))
- trace_print_rule(nlt, arg);
if (nftnl_trace_is_set(nlt, NFTNL_TRACE_LL_HEADER) ||
nftnl_trace_is_set(nlt, NFTNL_TRACE_NETWORK_HEADER))
trace_print_packet(nlt, arg);
+
+ if (nftnl_trace_is_set(nlt, NFTNL_TRACE_RULE_HANDLE)) {
+ trace_print_hdr(nlt);
+ printf(":rule:0x%" PRIx64":", nftnl_trace_get_u64(nlt, NFTNL_TRACE_RULE_HANDLE));
+ print_verdict(nlt, verdict);
+ printf(" ");
+ trace_print_rule(nlt, arg);
+ }
break;
case NFT_TRACETYPE_POLICY:
+ trace_print_hdr(nlt);
printf(":policy:");
verdict = nftnl_trace_get_u32(nlt, NFTNL_TRACE_POLICY);
print_verdict(nlt, verdict);
+ puts("");
break;
case NFT_TRACETYPE_RETURN:
+ trace_print_hdr(nlt);
printf(":return:");
trace_print_return(nlt);
+ puts("");
break;
}
- puts("");
err_free:
nftnl_trace_free(nlt);
err:
+ fflush(stdout);
return MNL_CB_OK;
}
@@ -615,7 +630,7 @@ int xtables_monitor_main(int argc, char *argv[])
init_extensions4();
#endif
- if (nft_init(&h, xtables_ipv4)) {
+ if (nft_init(&h, AF_INET, xtables_ipv4)) {
fprintf(stderr, "%s/%s Failed to initialize nft: %s\n",
xtables_globals.program_name,
xtables_globals.program_version,
@@ -688,6 +703,8 @@ int xtables_monitor_main(int argc, char *argv[])
}
mnl_socket_close(nl);
+ xtables_fini();
+
return EXIT_SUCCESS;
}
diff --git a/iptables/xtables-restore.c b/iptables/xtables-restore.c
index acee2e27..d2739497 100644
--- a/iptables/xtables-restore.c
+++ b/iptables/xtables-restore.c
@@ -61,11 +61,10 @@ static void print_usage(const char *name, const char *version)
static const struct nft_xt_restore_cb restore_cb = {
.commit = nft_commit,
.abort = nft_abort,
- .table_new = nft_table_new,
- .table_flush = nft_table_flush,
+ .table_flush = nft_cmd_table_flush,
.do_command = do_commandx,
- .chain_set = nft_chain_set,
- .chain_restore = nft_chain_restore,
+ .chain_set = nft_cmd_chain_set,
+ .chain_restore = nft_cmd_chain_restore,
};
struct nft_xt_restore_state {
@@ -128,10 +127,14 @@ static void xtables_restore_parse_line(struct nft_handle *h,
if (p->tablename && (strcmp(p->tablename, table) != 0))
return;
+ /* implicit commit if no explicit COMMIT supported */
+ if (!p->commit)
+ cb->commit(h);
+
if (h->noflush == 0) {
DEBUGP("Cleaning all chains of table '%s'\n", table);
if (cb->table_flush)
- cb->table_flush(h, table);
+ cb->table_flush(h, table, verbose);
}
ret = 1;
@@ -191,7 +194,7 @@ static void xtables_restore_parse_line(struct nft_handle *h,
"cannot create chain '%s' (%s)\n",
chain, strerror(errno));
} else if (h->family == NFPROTO_BRIDGE &&
- !ebt_set_user_chain_policy(h, state->curtable->name,
+ !ebt_cmd_user_chain_policy(h, state->curtable->name,
chain, policy)) {
xtables_error(OTHER_PROBLEM,
"Can't set policy `%s' on `%s' line %u: %s\n",
@@ -250,95 +253,16 @@ static void xtables_restore_parse_line(struct nft_handle *h,
}
}
-/* Return true if given iptables-restore line will require a full cache.
- * Typically these are commands referring to an existing rule
- * (either by number or content) or commands listing the ruleset. */
-static bool cmd_needs_full_cache(char *cmd)
-{
- char c, chain[32];
- int rulenum, mcount;
-
- mcount = sscanf(cmd, "-%c %31s %d", &c, chain, &rulenum);
-
- if (mcount == 3)
- return true;
- if (mcount < 1)
- return false;
-
- switch (c) {
- case 'D':
- case 'C':
- case 'S':
- case 'L':
- case 'Z':
- return true;
- }
-
- return false;
-}
-
-#define PREBUFSIZ 65536
-
void xtables_restore_parse(struct nft_handle *h,
const struct nft_xt_restore_parse *p)
{
struct nft_xt_restore_state state = {};
- char preload_buffer[PREBUFSIZ] = {}, buffer[10240], *ptr;
-
- if (!h->noflush) {
- nft_fake_cache(h);
- } else {
- ssize_t pblen = sizeof(preload_buffer);
- bool do_cache = false;
-
- ptr = preload_buffer;
- while (fgets(buffer, sizeof(buffer), p->in)) {
- size_t blen = strlen(buffer);
-
- /* drop trailing newline; xtables_restore_parse_line()
- * uses strtok() which replaces them by nul-characters,
- * causing unpredictable string delimiting in
- * preload_buffer */
- if (buffer[blen - 1] == '\n')
- buffer[blen - 1] = '\0';
- else
- blen++;
-
- pblen -= blen;
- if (pblen <= 0) {
- /* buffer exhausted */
- do_cache = true;
- break;
- }
-
- if (cmd_needs_full_cache(buffer)) {
- do_cache = true;
- break;
- }
-
- /* copy string including terminating nul-char */
- memcpy(ptr, buffer, blen);
- ptr += blen;
- buffer[0] = '\0';
- }
+ char buffer[10240] = {};
- if (do_cache)
- nft_build_cache(h, NULL);
- }
+ if (!verbose && !h->noflush)
+ nft_cache_level_set(h, NFT_CL_FAKE, NULL);
line = 0;
- ptr = preload_buffer;
- while (*ptr) {
- h->error.lineno = ++line;
- DEBUGP("%s: buffered line %d: '%s'\n", __func__, line, ptr);
- xtables_restore_parse_line(h, p, &state, ptr);
- ptr += strlen(ptr) + 1;
- }
- if (*buffer) {
- h->error.lineno = ++line;
- DEBUGP("%s: overrun line %d: '%s'\n", __func__, line, buffer);
- xtables_restore_parse_line(h, p, &state, buffer);
- }
while (fgets(buffer, sizeof(buffer), p->in)) {
h->error.lineno = ++line;
DEBUGP("%s: input line %d: '%s'\n", __func__, line, buffer);
@@ -358,15 +282,13 @@ static int
xtables_restore_main(int family, const char *progname, int argc, char *argv[])
{
const struct builtin_table *tables;
- struct nft_handle h = {
- .family = family,
- .restore = true,
- };
- int c;
struct nft_xt_restore_parse p = {
.commit = true,
.cb = &restore_cb,
};
+ bool noflush = false;
+ struct nft_handle h;
+ int c;
line = 0;
@@ -379,7 +301,7 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[])
exit(1);
}
- while ((c = getopt_long(argc, argv, "bcvVthnM:T:46wW", options, NULL)) != -1) {
+ while ((c = getopt_long(argc, argv, "bcvVthnM:T:wW", options, NULL)) != -1) {
switch (c) {
case 'b':
fprintf(stderr, "-b/--binary option is not implemented\n");
@@ -400,7 +322,7 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[])
print_usage(prog_name, PACKAGE_VERSION);
exit(0);
case 'n':
- h.noflush = 1;
+ noflush = true;
break;
case 'M':
xtables_modprobe_program = optarg;
@@ -408,13 +330,6 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[])
case 'T':
p.tablename = optarg;
break;
- case '4':
- h.family = AF_INET;
- break;
- case '6':
- h.family = AF_INET6;
- xtables_set_nfproto(AF_INET6);
- break;
case 'w': /* fallthrough. Ignored by xt-restore */
case 'W':
if (!optarg && xs_has_arg(argc, argv))
@@ -462,17 +377,20 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[])
return 1;
}
- if (nft_init(&h, tables) < 0) {
+ if (nft_init(&h, family, tables) < 0) {
fprintf(stderr, "%s/%s Failed to initialize nft: %s\n",
xtables_globals.program_name,
xtables_globals.program_version,
strerror(errno));
exit(EXIT_FAILURE);
}
+ h.noflush = noflush;
+ h.restore = true;
xtables_restore_parse(&h, &p);
nft_fini(&h);
+ xtables_fini();
fclose(p.in);
return 0;
}
@@ -489,20 +407,12 @@ 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);
-}
-
static const struct nft_xt_restore_cb ebt_restore_cb = {
.commit = nft_bridge_commit,
- .table_new = nft_table_new,
- .table_flush = ebt_table_flush,
+ .table_flush = nft_cmd_table_flush,
.do_command = do_commandeb,
- .chain_set = nft_chain_set,
- .chain_restore = nft_chain_restore,
+ .chain_set = nft_cmd_chain_set,
+ .chain_restore = nft_cmd_chain_restore,
};
static const struct option ebt_restore_options[] = {
@@ -537,18 +447,17 @@ int xtables_eb_restore_main(int argc, char *argv[])
nft_init_eb(&h, "ebtables-restore");
h.noflush = noflush;
xtables_restore_parse(&h, &p);
- nft_fini(&h);
+ nft_fini_eb(&h);
return 0;
}
static const struct nft_xt_restore_cb arp_restore_cb = {
.commit = nft_commit,
- .table_new = nft_table_new,
- .table_flush = nft_table_flush,
+ .table_flush = nft_cmd_table_flush,
.do_command = do_commandarp,
- .chain_set = nft_chain_set,
- .chain_restore = nft_chain_restore,
+ .chain_set = nft_cmd_chain_set,
+ .chain_restore = nft_cmd_chain_restore,
};
int xtables_arp_restore_main(int argc, char *argv[])
@@ -562,6 +471,7 @@ int xtables_arp_restore_main(int argc, char *argv[])
nft_init_arp(&h, "arptables-restore");
xtables_restore_parse(&h, &p);
nft_fini(&h);
+ xtables_fini();
return 0;
}
diff --git a/iptables/xtables-save.c b/iptables/xtables-save.c
index 3a52f8c3..d7901c65 100644
--- a/iptables/xtables-save.c
+++ b/iptables/xtables-save.c
@@ -32,7 +32,7 @@
#define prog_name xtables_globals.program_name
#define prog_vers xtables_globals.program_version
-static const char *ipt_save_optstring = "bcdt:M:f:46V";
+static const char *ipt_save_optstring = "bcdt:M:f:V";
static const struct option ipt_save_options[] = {
{.name = "counters", .has_arg = false, .val = 'c'},
{.name = "version", .has_arg = false, .val = 'V'},
@@ -40,8 +40,6 @@ static const struct option ipt_save_options[] = {
{.name = "table", .has_arg = true, .val = 't'},
{.name = "modprobe", .has_arg = true, .val = 'M'},
{.name = "file", .has_arg = true, .val = 'f'},
- {.name = "ipv4", .has_arg = false, .val = '4'},
- {.name = "ipv6", .has_arg = false, .val = '6'},
{NULL},
};
@@ -70,7 +68,6 @@ struct do_output_data {
static int
__do_output(struct nft_handle *h, const char *tablename, void *data)
{
- struct nftnl_chain_list *chain_list;
struct do_output_data *d = data;
time_t now;
@@ -83,10 +80,6 @@ __do_output(struct nft_handle *h, const char *tablename, void *data)
return 0;
}
- chain_list = nft_chain_list_get(h, tablename, NULL);
- if (!chain_list)
- return 0;
-
now = time(NULL);
printf("# Generated by %s v%s on %s", prog_name,
prog_vers, ctime(&now));
@@ -94,7 +87,7 @@ __do_output(struct nft_handle *h, const char *tablename, void *data)
printf("*%s\n", tablename);
/* Dump out chain names first,
* thereby preventing dependency conflicts */
- nft_chain_save(h, chain_list);
+ nft_chain_foreach(h, tablename, nft_chain_save, h);
nft_rule_save(h, tablename, d->format);
if (d->commit)
printf("COMMIT\n");
@@ -139,10 +132,8 @@ xtables_save_main(int family, int argc, char *argv[],
struct do_output_data d = {
.format = FMT_NOCOUNTS,
};
+ struct nft_handle h;
bool dump = false;
- struct nft_handle h = {
- .family = family,
- };
FILE *file = NULL;
int ret, c;
@@ -189,13 +180,6 @@ xtables_save_main(int family, int argc, char *argv[],
case 'd':
dump = true;
break;
- case '4':
- h.family = AF_INET;
- break;
- case '6':
- h.family = AF_INET6;
- xtables_set_nfproto(AF_INET6);
- break;
case 'V':
printf("%s v%s (nf_tables)\n", prog_name, prog_vers);
exit(0);
@@ -242,19 +226,21 @@ xtables_save_main(int family, int argc, char *argv[],
return 1;
}
- if (nft_init(&h, tables) < 0) {
+ if (nft_init(&h, family, tables) < 0) {
fprintf(stderr, "%s/%s Failed to initialize nft: %s\n",
xtables_globals.program_name,
xtables_globals.program_version,
strerror(errno));
exit(EXIT_FAILURE);
}
- h.ops = nft_family_ops_lookup(h.family);
- if (!h.ops)
- xtables_error(PARAMETER_PROBLEM, "Unknown family");
+
+ nft_cache_level_set(&h, NFT_CL_RULES, NULL);
+ nft_cache_build(&h);
+ nft_xt_fake_builtin_chains(&h, tablename, NULL);
ret = do_output(&h, tablename, &d);
nft_fini(&h);
+ xtables_fini();
if (dump)
exit(0);
diff --git a/iptables/xtables-standalone.c b/iptables/xtables-standalone.c
index 1a28c548..7b71db62 100644
--- a/iptables/xtables-standalone.c
+++ b/iptables/xtables-standalone.c
@@ -44,9 +44,7 @@ xtables_main(int family, const char *progname, int argc, char *argv[])
{
int ret;
char *table = "filter";
- struct nft_handle h = {
- .family = family,
- };
+ struct nft_handle h;
xtables_globals.program_name = progname;
ret = xtables_init_all(&xtables_globals, family);
@@ -61,7 +59,7 @@ xtables_main(int family, const char *progname, int argc, char *argv[])
init_extensions4();
#endif
- if (nft_init(&h, xtables_ipv4) < 0) {
+ if (nft_init(&h, family, xtables_ipv4) < 0) {
fprintf(stderr, "%s/%s Failed to initialize nft: %s\n",
xtables_globals.program_name,
xtables_globals.program_version,
@@ -74,16 +72,13 @@ xtables_main(int family, const char *progname, int argc, char *argv[])
ret = nft_commit(&h);
nft_fini(&h);
+ xtables_fini();
if (!ret) {
- if (errno == EINVAL) {
- fprintf(stderr, "iptables: %s. "
- "Run `dmesg' for more information.\n",
- nft_strerror(errno));
- } else {
- fprintf(stderr, "iptables: %s.\n",
- nft_strerror(errno));
- }
+ fprintf(stderr, "%s: %s.%s\n", progname, nft_strerror(errno),
+ (errno == EINVAL ?
+ " Run `dmesg' for more information." : ""));
+
if (errno == EAGAIN)
exit(RESOURCE_PROBLEM);
}
diff --git a/iptables/xtables-translate.c b/iptables/xtables-translate.c
index a42c60a3..575fb320 100644
--- a/iptables/xtables-translate.c
+++ b/iptables/xtables-translate.c
@@ -32,16 +32,38 @@
void xlate_ifname(struct xt_xlate *xl, const char *nftmeta, const char *ifname,
bool invert)
{
- char iface[IFNAMSIZ];
- int ifaclen;
+ int ifaclen = strlen(ifname), i, j;
+ char iface[IFNAMSIZ * 2];
- if (ifname[0] == '\0')
+ if (ifaclen < 1 || ifaclen >= IFNAMSIZ)
return;
- strcpy(iface, ifname);
- ifaclen = strlen(iface);
- if (iface[ifaclen - 1] == '+')
- iface[ifaclen - 1] = '*';
+ for (i = 0, j = 0; i < ifaclen + 1; i++, j++) {
+ switch (ifname[i]) {
+ case '*':
+ iface[j++] = '\\';
+ /* fall through */
+ default:
+ iface[j] = ifname[i];
+ break;
+ }
+ }
+
+ if (ifaclen == 1 && ifname[0] == '+') {
+ /* Nftables does not support wildcard only string. Workaround
+ * is easy, given that this will match always or never
+ * depending on 'invert' value. To match always, simply don't
+ * generate an expression. To match never, use an invalid
+ * interface name (kernel doesn't accept '/' in names) to match
+ * against. */
+ if (!invert)
+ return;
+ strcpy(iface, "INVAL/D");
+ invert = false;
+ }
+
+ if (iface[j - 2] == '+')
+ iface[j - 2] = '*';
xt_xlate_add(xl, "%s %s\"%s\" ", nftmeta, invert ? "!= " : "", iface);
}
@@ -227,7 +249,7 @@ static int do_command_xlate(struct nft_handle *h, int argc, char *argv[],
cs.restore = restore;
- if (!restore)
+ if (!restore && p.command != CMD_NONE)
printf("nft ");
switch (p.command) {
@@ -288,13 +310,16 @@ static int do_command_xlate(struct nft_handle *h, int argc, char *argv[],
break;
case CMD_SET_POLICY:
break;
+ case CMD_NONE:
+ ret = 1;
+ break;
default:
/* We should never reach this... */
printf("Unsupported command?\n");
exit(1);
}
- xtables_rule_matches_free(&cs.matches);
+ nft_clear_iptables_command_state(&cs);
if (h->family == AF_INET) {
free(args.s.addr.v4);
@@ -458,7 +483,7 @@ static int xtables_xlate_main_common(struct nft_handle *h,
return 1;
}
- if (nft_init(h, tables) < 0) {
+ if (nft_init(h, family, tables) < 0) {
fprintf(stderr, "%s/%s Failed to initialize nft: %s\n",
xtables_globals.program_name,
xtables_globals.program_version,
@@ -487,6 +512,7 @@ static int xtables_xlate_main(int family, const char *progname, int argc,
fprintf(stderr, "Translation not implemented\n");
nft_fini(&h);
+ xtables_fini();
exit(!ret);
}
@@ -541,6 +567,7 @@ static int xtables_restore_xlate_main(int family, const char *progname,
printf("# Completed on %s", ctime(&now));
nft_fini(&h);
+ xtables_fini();
fclose(p.in);
exit(0);
}
diff --git a/iptables/xtables.c b/iptables/xtables.c
index 8f9dc628..9779bd83 100644
--- a/iptables/xtables.c
+++ b/iptables/xtables.c
@@ -43,11 +43,6 @@
#include "nft-shared.h"
#include "nft.h"
-#define OPT_FRAGMENT 0x00800U
-#define NUMBER_OF_OPT ARRAY_SIZE(optflags)
-static const char optflags[]
-= { 'n', 's', 'd', 'p', 'j', 'v', 'x', 'i', 'o', '0', 'c', 'f'};
-
static struct option original_opts[] = {
{.name = "append", .has_arg = 1, .val = 'A'},
{.name = "delete", .has_arg = 1, .val = 'D'},
@@ -99,36 +94,6 @@ struct xtables_globals xtables_globals = {
.compat_rev = nft_compatible_revision,
};
-/* Table of legal combinations of commands and options. If any of the
- * given commands make an option legal, that option is legal (applies to
- * CMD_LIST and CMD_ZERO only).
- * Key:
- * + compulsory
- * x illegal
- * optional
- */
-
-static const char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] =
-/* Well, it's better than "Re: Linux vs FreeBSD" */
-{
- /* -n -s -d -p -j -v -x -i -o --line -c -f */
-/*INSERT*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' ',' '},
-/*DELETE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x','x',' '},
-/*DELETE_NUM*/{'x','x','x','x','x',' ','x','x','x','x','x','x'},
-/*REPLACE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' ',' '},
-/*APPEND*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' ',' '},
-/*LIST*/ {' ','x','x','x','x',' ',' ','x','x',' ','x','x'},
-/*FLUSH*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
-/*ZERO*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
-/*ZERO_NUM*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
-/*NEW_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
-/*DEL_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
-/*SET_POLICY*/{'x','x','x','x','x',' ','x','x','x','x',' ','x'},
-/*RENAME*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
-/*LIST_RULES*/{'x','x','x','x','x',' ','x','x','x','x','x','x'},
-/*CHECK*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x','x',' '},
-};
-
static const int inverse_for_options[NUMBER_OF_OPT] =
{
/* -n */ 0,
@@ -161,7 +126,7 @@ exit_tryhelp(int status)
}
static void
-exit_printhelp(const struct xtables_rule_match *matches)
+printhelp(const struct xtables_rule_match *matches)
{
printf("%s v%s\n\n"
"Usage: %s -[ACD] chain rule-specification [options]\n"
@@ -240,7 +205,6 @@ exit_printhelp(const struct xtables_rule_match *matches)
"[!] --version -V print package version.\n");
print_extension_helps(xtables_targets, matches);
- exit(0);
}
void
@@ -263,51 +227,6 @@ xtables_exit_error(enum xtables_exittype status, const char *msg, ...)
exit(status);
}
-static void
-generic_opt_check(int command, int options)
-{
- int i, j, legal = 0;
-
- /* Check that commands are valid with options. Complicated by the
- * fact that if an option is legal with *any* command given, it is
- * legal overall (ie. -z and -l).
- */
- for (i = 0; i < NUMBER_OF_OPT; i++) {
- legal = 0; /* -1 => illegal, 1 => legal, 0 => undecided. */
-
- for (j = 0; j < NUMBER_OF_CMD; j++) {
- if (!(command & (1<<j)))
- continue;
-
- if (!(options & (1<<i))) {
- if (commands_v_options[j][i] == '+')
- xtables_error(PARAMETER_PROBLEM,
- "You need to supply the `-%c' "
- "option for this command\n",
- optflags[i]);
- } else {
- if (commands_v_options[j][i] != 'x')
- legal = 1;
- else if (legal == 0)
- legal = -1;
- }
- }
- if (legal == -1)
- xtables_error(PARAMETER_PROBLEM,
- "Illegal option `-%c' with this command\n",
- optflags[i]);
- }
-}
-
-static char
-opt2char(int option)
-{
- const char *ptr;
- for (ptr = optflags; option > 1; option >>= 1, ptr++);
-
- return *ptr;
-}
-
/*
* All functions starting with "parse" should succeed, otherwise
* the program fails.
@@ -361,11 +280,11 @@ add_entry(const char *chain,
cs->fw.ip.dmsk.s_addr = d.mask.v4[j].s_addr;
if (append) {
- ret = nft_rule_append(h, chain, table,
+ ret = nft_cmd_rule_append(h, chain, table,
cs, NULL,
verbose);
} else {
- ret = nft_rule_insert(h, chain, table,
+ ret = nft_cmd_rule_insert(h, chain, table,
cs, rulenum,
verbose);
}
@@ -381,11 +300,11 @@ add_entry(const char *chain,
memcpy(&cs->fw6.ipv6.dmsk,
&d.mask.v6[j], sizeof(struct in6_addr));
if (append) {
- ret = nft_rule_append(h, chain, table,
+ ret = nft_cmd_rule_append(h, chain, table,
cs, NULL,
verbose);
} else {
- ret = nft_rule_insert(h, chain, table,
+ ret = nft_cmd_rule_insert(h, chain, table,
cs, rulenum,
verbose);
}
@@ -418,7 +337,7 @@ replace_entry(const char *chain, const char *table,
} else
return 1;
- return nft_rule_replace(h, chain, table, cs, rulenum, verbose);
+ return nft_cmd_rule_replace(h, chain, table, cs, rulenum, verbose);
}
static int
@@ -440,7 +359,7 @@ delete_entry(const char *chain, const char *table,
for (j = 0; j < d.naddrs; j++) {
cs->fw.ip.dst.s_addr = d.addr.v4[j].s_addr;
cs->fw.ip.dmsk.s_addr = d.mask.v4[j].s_addr;
- ret = nft_rule_delete(h, chain,
+ ret = nft_cmd_rule_delete(h, chain,
table, cs, verbose);
}
} else if (family == AF_INET6) {
@@ -453,7 +372,7 @@ delete_entry(const char *chain, const char *table,
&d.addr.v6[j], sizeof(struct in6_addr));
memcpy(&cs->fw6.ipv6.dmsk,
&d.mask.v6[j], sizeof(struct in6_addr));
- ret = nft_rule_delete(h, chain,
+ ret = nft_cmd_rule_delete(h, chain,
table, cs, verbose);
}
}
@@ -480,7 +399,7 @@ check_entry(const char *chain, const char *table,
for (j = 0; j < d.naddrs; j++) {
cs->fw.ip.dst.s_addr = d.addr.v4[j].s_addr;
cs->fw.ip.dmsk.s_addr = d.mask.v4[j].s_addr;
- ret = nft_rule_check(h, chain,
+ ret = nft_cmd_rule_check(h, chain,
table, cs, verbose);
}
} else if (family == AF_INET6) {
@@ -493,7 +412,7 @@ check_entry(const char *chain, const char *table,
&d.addr.v6[j], sizeof(struct in6_addr));
memcpy(&cs->fw6.ipv6.dmsk,
&d.mask.v6[j], sizeof(struct in6_addr));
- ret = nft_rule_check(h, chain,
+ ret = nft_cmd_rule_check(h, chain,
table, cs, verbose);
}
}
@@ -524,7 +443,7 @@ list_entries(struct nft_handle *h, const char *chain, const char *table,
if (linenumbers)
format |= FMT_LINENUMBERS;
- return nft_rule_list(h, chain, table, rulenum, format);
+ return nft_cmd_rule_list(h, chain, table, rulenum, format);
}
static int
@@ -534,7 +453,7 @@ list_rules(struct nft_handle *h, const char *chain, const char *table,
if (counters)
counters = -1; /* iptables -c format */
- return nft_rule_list_save(h, chain, table, rulenum, counters);
+ return nft_cmd_rule_list_save(h, chain, table, rulenum, counters);
}
void do_parse(struct nft_handle *h, int argc, char *argv[],
@@ -571,10 +490,6 @@ void do_parse(struct nft_handle *h, int argc, char *argv[],
demand-load a protocol. */
opterr = 0;
- h->ops = nft_family_ops_lookup(h->family);
- if (h->ops == NULL)
- xtables_error(PARAMETER_PROBLEM, "Unknown family");
-
opts = xt_params->orig_opts;
while ((cs->c = getopt_long(argc, argv,
"-:A:C:D:R:I:L::S::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:fbvw::W::nt:m:xc:g:46",
@@ -728,7 +643,9 @@ void do_parse(struct nft_handle *h, int argc, char *argv[],
xtables_find_match(cs->protocol,
XTF_TRY_LOAD, &cs->matches);
- exit_printhelp(cs->matches);
+ printhelp(cs->matches);
+ p->command = CMD_NONE;
+ return;
/*
* Option selection
@@ -917,27 +834,22 @@ void do_parse(struct nft_handle *h, int argc, char *argv[],
break;
case '4':
+ if (args->family == AF_INET)
+ break;
+
if (p->restore && args->family == AF_INET6)
return;
- if (args->family != AF_INET)
- exit_tryhelp(2);
-
- h->ops = nft_family_ops_lookup(args->family);
- break;
+ exit_tryhelp(2);
case '6':
+ if (args->family == AF_INET6)
+ break;
+
if (p->restore && args->family == AF_INET)
return;
- args->family = AF_INET6;
- xtables_set_nfproto(AF_INET6);
-
- h->ops = nft_family_ops_lookup(args->family);
- if (h->ops == NULL)
- xtables_error(PARAMETER_PROBLEM,
- "Unknown family");
- break;
+ exit_tryhelp(2);
case 1: /* non option */
if (optarg[0] == '!' && optarg[1] == '\0') {
@@ -1031,11 +943,6 @@ void do_parse(struct nft_handle *h, int argc, char *argv[],
opt2char(OPT_VIANAMEIN),
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);
}
}
@@ -1066,8 +973,8 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
cs.options & OPT_VERBOSE, h);
break;
case CMD_DELETE_NUM:
- ret = nft_rule_delete_num(h, p.chain, p.table,
- p.rulenum - 1, p.verbose);
+ ret = nft_cmd_rule_delete_num(h, p.chain, p.table,
+ p.rulenum - 1, p.verbose);
break;
case CMD_CHECK:
ret = check_entry(p.chain, p.table, &cs, h->family,
@@ -1085,15 +992,15 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
cs.options&OPT_VERBOSE, h, false);
break;
case CMD_FLUSH:
- ret = nft_rule_flush(h, p.chain, p.table,
- cs.options & OPT_VERBOSE);
+ ret = nft_cmd_rule_flush(h, p.chain, p.table,
+ cs.options & OPT_VERBOSE);
break;
case CMD_ZERO:
- ret = nft_chain_zero_counters(h, p.chain, p.table,
- cs.options & OPT_VERBOSE);
+ ret = nft_cmd_chain_zero_counters(h, p.chain, p.table,
+ cs.options & OPT_VERBOSE);
break;
case CMD_ZERO_NUM:
- ret = nft_rule_zero_counters(h, p.chain, p.table,
+ ret = nft_cmd_rule_zero_counters(h, p.chain, p.table,
p.rulenum - 1);
break;
case CMD_LIST:
@@ -1105,11 +1012,11 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
cs.options & OPT_EXPANDED,
cs.options & OPT_LINENUMBERS);
if (ret && (p.command & CMD_ZERO)) {
- ret = nft_chain_zero_counters(h, p.chain, p.table,
+ ret = nft_cmd_chain_zero_counters(h, p.chain, p.table,
cs.options & OPT_VERBOSE);
}
if (ret && (p.command & CMD_ZERO_NUM)) {
- ret = nft_rule_zero_counters(h, p.chain, p.table,
+ ret = nft_cmd_rule_zero_counters(h, p.chain, p.table,
p.rulenum - 1);
}
nft_check_xt_legacy(h->family, false);
@@ -1120,27 +1027,27 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
ret = list_rules(h, p.chain, p.table, p.rulenum,
cs.options & OPT_VERBOSE);
if (ret && (p.command & CMD_ZERO)) {
- ret = nft_chain_zero_counters(h, p.chain, p.table,
+ ret = nft_cmd_chain_zero_counters(h, p.chain, p.table,
cs.options & OPT_VERBOSE);
}
if (ret && (p.command & CMD_ZERO_NUM)) {
- ret = nft_rule_zero_counters(h, p.chain, p.table,
+ ret = nft_cmd_rule_zero_counters(h, p.chain, p.table,
p.rulenum - 1);
}
nft_check_xt_legacy(h->family, false);
break;
case CMD_NEW_CHAIN:
- ret = nft_chain_user_add(h, p.chain, p.table);
+ ret = nft_cmd_chain_user_add(h, p.chain, p.table);
break;
case CMD_DELETE_CHAIN:
- ret = nft_chain_user_del(h, p.chain, p.table,
+ ret = nft_cmd_chain_user_del(h, p.chain, p.table,
cs.options & OPT_VERBOSE);
break;
case CMD_RENAME_CHAIN:
- ret = nft_chain_user_rename(h, p.chain, p.table, p.newname);
+ ret = nft_cmd_chain_user_rename(h, p.chain, p.table, p.newname);
break;
case CMD_SET_POLICY:
- ret = nft_chain_set(h, p.table, p.chain, p.policy, NULL);
+ ret = nft_cmd_chain_set(h, p.table, p.chain, p.policy, NULL);
break;
case CMD_NONE:
/* do_parse ignored the line (eg: -4 with ip6tables-restore) */
@@ -1152,11 +1059,7 @@ 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) {
- free(cs.target->t);
- cs.target->t = NULL;
- }
+ nft_clear_iptables_command_state(&cs);
if (h->family == AF_INET) {
free(args.s.addr.v4);
diff --git a/libipq/ipq_set_verdict.3 b/libipq/ipq_set_verdict.3
index 7771ed6a..a6172b30 100644
--- a/libipq/ipq_set_verdict.3
+++ b/libipq/ipq_set_verdict.3
@@ -30,7 +30,7 @@ The
.B ipq_set_verdict
function issues a verdict on a packet previously obtained with
.BR ipq_read ,
-specifing the intended disposition of the packet, and optionally
+specifying the intended disposition of the packet, and optionally
supplying a modified version of the payload data.
.PP
The
diff --git a/libiptc/Android.bp b/libiptc/Android.bp
index 9f95909b..d7297a92 100644
--- a/libiptc/Android.bp
+++ b/libiptc/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "external_iptables_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-GPL
+ default_applicable_licenses: ["external_iptables_license"],
+}
+
cc_defaults {
name: "libiptc_defaults",
defaults: ["iptables_defaults"],
diff --git a/libiptc/libiptc.c b/libiptc/libiptc.c
index 58882015..ceeb017b 100644
--- a/libiptc/libiptc.c
+++ b/libiptc/libiptc.c
@@ -1169,7 +1169,7 @@ static int iptcc_compile_chain(struct xtc_handle *h, STRUCT_REPLACE *repl, struc
else
foot->target.verdict = RETURN;
/* set policy-counters */
- memcpy(&foot->e.counters, &c->counters, sizeof(STRUCT_COUNTERS));
+ foot->e.counters = c->counters;
return 0;
}
diff --git a/libxtables/Android.bp b/libxtables/Android.bp
index 41d61466..ed0cc44e 100644
--- a/libxtables/Android.bp
+++ b/libxtables/Android.bp
@@ -1,6 +1,16 @@
//----------------------------------------------------------------
// libxtables
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "external_iptables_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-GPL-2.0
+ // SPDX-license-identifier-LGPL
+ default_applicable_licenses: ["external_iptables_license"],
+}
+
cc_library_static {
name: "libxtables",
defaults: ["iptables_defaults"],
diff --git a/libxtables/xtables.c b/libxtables/xtables.c
index 895f6988..35fa6258 100644
--- a/libxtables/xtables.c
+++ b/libxtables/xtables.c
@@ -45,6 +45,9 @@
#include <xtables.h>
#include <limits.h> /* INT_MAX in ip_tables.h/ip6_tables.h */
+#ifdef __BIONIC__
+#include <linux/if_ether.h> /* ETH_ALEN */
+#endif
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
#include <libiptc/libxtc.h>
@@ -203,8 +206,44 @@ struct xtables_match *xtables_matches;
struct xtables_target *xtables_targets;
/* Fully register a match/target which was previously partially registered. */
-static bool xtables_fully_register_pending_match(struct xtables_match *me);
-static bool xtables_fully_register_pending_target(struct xtables_target *me);
+static bool xtables_fully_register_pending_match(struct xtables_match *me,
+ struct xtables_match *prev);
+static bool xtables_fully_register_pending_target(struct xtables_target *me,
+ struct xtables_target *prev);
+
+#ifndef NO_SHARED_LIBS
+/* registry for loaded shared objects to close later */
+struct dlreg {
+ struct dlreg *next;
+ void *handle;
+};
+static struct dlreg *dlreg = NULL;
+
+static int dlreg_add(void *handle)
+{
+ struct dlreg *new = malloc(sizeof(*new));
+
+ if (!new)
+ return -1;
+
+ new->handle = handle;
+ new->next = dlreg;
+ dlreg = new;
+ return 0;
+}
+
+static void dlreg_free(void)
+{
+ struct dlreg *next;
+
+ while (dlreg) {
+ next = dlreg->next;
+ dlclose(dlreg->handle);
+ free(dlreg);
+ dlreg = next;
+ }
+}
+#endif
void xtables_init(void)
{
@@ -233,6 +272,13 @@ void xtables_init(void)
xtables_libdir = XTABLES_LIBDIR;
}
+void xtables_fini(void)
+{
+#ifndef NO_SHARED_LIBS
+ dlreg_free();
+#endif
+}
+
void xtables_set_nfproto(uint8_t nfproto)
{
switch (nfproto) {
@@ -567,6 +613,8 @@ static void *load_extension(const char *search_path, const char *af_prefix,
next = dir + strlen(dir);
for (prefix = all_prefixes; *prefix != NULL; ++prefix) {
+ void *handle;
+
snprintf(path, sizeof(path), "%.*s/%s%s.so",
(unsigned int)(next - dir), dir,
*prefix, name);
@@ -578,11 +626,14 @@ static void *load_extension(const char *search_path, const char *af_prefix,
strerror(errno));
return NULL;
}
- if (dlopen(path, RTLD_NOW) == NULL) {
+ handle = dlopen(path, RTLD_NOW);
+ if (handle == NULL) {
fprintf(stderr, "%s: %s\n", path, dlerror());
break;
}
+ dlreg_add(handle);
+
if (is_target)
ptr = xtables_find_target(name, XTF_DONT_LOAD);
else
@@ -616,6 +667,7 @@ struct xtables_match *
xtables_find_match(const char *name, enum xtables_tryload tryload,
struct xtables_rule_match **matches)
{
+ struct xtables_match *prev = NULL;
struct xtables_match **dptr;
struct xtables_match *ptr;
const char *icmp6 = "icmp6";
@@ -637,8 +689,12 @@ xtables_find_match(const char *name, enum xtables_tryload tryload,
if (extension_cmp(name, (*dptr)->name, (*dptr)->family)) {
ptr = *dptr;
*dptr = (*dptr)->next;
- if (xtables_fully_register_pending_match(ptr))
+ if (xtables_fully_register_pending_match(ptr, prev)) {
+ prev = ptr;
+ continue;
+ } else if (prev) {
continue;
+ }
*dptr = ptr;
}
dptr = &((*dptr)->next);
@@ -732,6 +788,7 @@ xtables_find_match_revision(const char *name, enum xtables_tryload tryload,
struct xtables_target *
xtables_find_target(const char *name, enum xtables_tryload tryload)
{
+ struct xtables_target *prev = NULL;
struct xtables_target **dptr;
struct xtables_target *ptr;
@@ -748,8 +805,12 @@ xtables_find_target(const char *name, enum xtables_tryload tryload)
if (extension_cmp(name, (*dptr)->name, (*dptr)->family)) {
ptr = *dptr;
*dptr = (*dptr)->next;
- if (xtables_fully_register_pending_target(ptr))
+ if (xtables_fully_register_pending_target(ptr, prev)) {
+ prev = ptr;
+ continue;
+ } else if (prev) {
continue;
+ }
*dptr = ptr;
}
dptr = &((*dptr)->next);
@@ -757,6 +818,7 @@ 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 0 /* Code block below causes memory leak. (Bugs 162925719 and 168688680) */
struct xtables_target *clone;
/* First target of this type: */
@@ -772,6 +834,7 @@ xtables_find_target(const char *name, enum xtables_tryload tryload)
clone->next = clone;
ptr = clone;
+#endif
break;
}
}
@@ -856,7 +919,8 @@ int xtables_compatible_revision(const char *name, uint8_t revision, int opt)
xtables_load_ko(xtables_modprobe_program, true);
- strcpy(rev.name, name);
+ strncpy(rev.name, name, XT_EXTENSION_MAXNAMELEN - 1);
+ rev.name[XT_EXTENSION_MAXNAMELEN - 1] = '\0';
rev.revision = revision;
max_rev = getsockopt(sockfd, afinfo->ipproto, opt, &rev, &s);
@@ -901,8 +965,14 @@ static void xtables_check_options(const char *name, const struct option *opt)
}
}
+static int xtables_match_prefer(const struct xtables_match *a,
+ const struct xtables_match *b);
+
void xtables_register_match(struct xtables_match *me)
{
+ struct xtables_match **pos;
+ bool seen_myself = false;
+
if (me->next) {
fprintf(stderr, "%s: match \"%s\" already registered\n",
xt_params->program_name, me->name);
@@ -954,10 +1024,34 @@ void xtables_register_match(struct xtables_match *me)
if (me->extra_opts != NULL)
xtables_check_options(me->name, me->extra_opts);
-
- /* place on linked list of matches pending full registration */
- me->next = xtables_pending_matches;
- xtables_pending_matches = me;
+ /* order into linked list of matches pending full registration */
+ for (pos = &xtables_pending_matches; *pos; pos = &(*pos)->next) {
+ /* group by name and family */
+ if (strcmp(me->name, (*pos)->name) ||
+ me->family != (*pos)->family) {
+ if (seen_myself)
+ break; /* end of own group, append to it */
+ continue;
+ }
+ /* found own group */
+ seen_myself = true;
+ if (xtables_match_prefer(me, *pos) >= 0)
+ break; /* put preferred items first in group */
+ }
+ /* if own group was not found, prepend item */
+ if (!*pos && !seen_myself)
+ pos = &xtables_pending_matches;
+
+ me->next = *pos;
+ *pos = me;
+#ifdef DEBUG
+ printf("%s: inserted match %s (family %d, revision %d):\n",
+ __func__, me->name, me->family, me->revision);
+ for (pos = &xtables_pending_matches; *pos; pos = &(*pos)->next) {
+ printf("%s:\tmatch %s (family %d, revision %d)\n", __func__,
+ (*pos)->name, (*pos)->family, (*pos)->revision);
+ }
+#endif
}
/**
@@ -1021,64 +1115,27 @@ static int xtables_target_prefer(const struct xtables_target *a,
b->revision, b->family);
}
-static bool xtables_fully_register_pending_match(struct xtables_match *me)
+static bool xtables_fully_register_pending_match(struct xtables_match *me,
+ struct xtables_match *prev)
{
- struct xtables_match **i, *old, *pos = NULL;
+ struct xtables_match **i;
const char *rn;
- int compare;
/* See if new match can be used. */
rn = (me->real_name != NULL) ? me->real_name : me->name;
if (!compatible_match_revision(rn, me->revision))
return false;
- old = xtables_find_match(me->name, XTF_DURING_LOAD, NULL);
- while (old) {
- compare = xtables_match_prefer(old, me);
- if (compare == 0) {
- fprintf(stderr,
- "%s: match `%s' already registered.\n",
- xt_params->program_name, me->name);
- exit(1);
- }
-
- /* Now we have two (or more) options, check compatibility. */
- rn = (old->real_name != NULL) ? old->real_name : old->name;
- if (compare > 0) {
- /* Kernel tells old isn't compatible anymore??? */
- if (!compatible_match_revision(rn, old->revision)) {
- /* Delete old one. */
- for (i = &xtables_matches; *i != old;)
- i = &(*i)->next;
- *i = old->next;
- }
- pos = old;
- old = old->next;
- if (!old)
- break;
- if (!extension_cmp(me->name, old->name, old->family))
- break;
- continue;
- }
-
- /* Found right old */
- pos = old;
- break;
- }
-
- if (!pos) {
+ if (!prev) {
/* Append to list. */
for (i = &xtables_matches; *i; i = &(*i)->next);
- } else if (compare < 0) {
- /* Prepend it */
- for (i = &xtables_matches; *i != pos; i = &(*i)->next);
- } else if (compare > 0) {
+ } else {
/* Append it */
- i = &pos->next;
- pos = pos->next;
+ i = &prev->next;
+ prev = prev->next;
}
- me->next = pos;
+ me->next = prev;
*i = me;
me->m = NULL;
@@ -1089,13 +1146,17 @@ static bool xtables_fully_register_pending_match(struct xtables_match *me)
void xtables_register_matches(struct xtables_match *match, unsigned int n)
{
- do {
- xtables_register_match(&match[--n]);
- } while (n > 0);
+ int i;
+
+ for (i = 0; i < n; i++)
+ xtables_register_match(&match[i]);
}
void xtables_register_target(struct xtables_target *me)
{
+ struct xtables_target **pos;
+ bool seen_myself = false;
+
if (me->next) {
fprintf(stderr, "%s: target \"%s\" already registered\n",
xt_params->program_name, me->name);
@@ -1151,16 +1212,40 @@ void xtables_register_target(struct xtables_target *me)
if (me->family != afinfo->family && me->family != AF_UNSPEC)
return;
- /* place on linked list of targets pending full registration */
- me->next = xtables_pending_targets;
- xtables_pending_targets = me;
+ /* order into linked list of targets pending full registration */
+ for (pos = &xtables_pending_targets; *pos; pos = &(*pos)->next) {
+ /* group by name */
+ if (!extension_cmp(me->name, (*pos)->name, (*pos)->family)) {
+ if (seen_myself)
+ break; /* end of own group, append to it */
+ continue;
+ }
+ /* found own group */
+ seen_myself = true;
+ if (xtables_target_prefer(me, *pos) >= 0)
+ break; /* put preferred items first in group */
+ }
+ /* if own group was not found, prepend item */
+ if (!*pos && !seen_myself)
+ pos = &xtables_pending_targets;
+
+ me->next = *pos;
+ *pos = me;
+#ifdef DEBUG
+ printf("%s: inserted target %s (family %d, revision %d):\n",
+ __func__, me->name, me->family, me->revision);
+ for (pos = &xtables_pending_targets; *pos; pos = &(*pos)->next) {
+ printf("%s:\ttarget %s (family %d, revision %d)\n", __func__,
+ (*pos)->name, (*pos)->family, (*pos)->revision);
+ }
+#endif
}
-static bool xtables_fully_register_pending_target(struct xtables_target *me)
+static bool xtables_fully_register_pending_target(struct xtables_target *me,
+ struct xtables_target *prev)
{
- struct xtables_target **i, *old, *pos = NULL;
+ struct xtables_target **i;
const char *rn;
- int compare;
if (strcmp(me->name, "standard") != 0) {
/* See if new target can be used. */
@@ -1169,54 +1254,17 @@ static bool xtables_fully_register_pending_target(struct xtables_target *me)
return false;
}
- old = xtables_find_target(me->name, XTF_DURING_LOAD);
- while (old) {
- compare = xtables_target_prefer(old, me);
- if (compare == 0) {
- fprintf(stderr,
- "%s: target `%s' already registered.\n",
- xt_params->program_name, me->name);
- exit(1);
- }
-
- /* Now we have two (or more) options, check compatibility. */
- rn = (old->real_name != NULL) ? old->real_name : old->name;
- if (compare > 0) {
- /* Kernel tells old isn't compatible anymore??? */
- if (!compatible_target_revision(rn, old->revision)) {
- /* Delete old one. */
- for (i = &xtables_targets; *i != old;)
- i = &(*i)->next;
- *i = old->next;
- }
- pos = old;
- old = old->next;
- if (!old)
- break;
- if (!extension_cmp(me->name, old->name, old->family))
- break;
- continue;
- }
-
- /* Found right old */
- pos = old;
- break;
- }
-
- if (!pos) {
+ if (!prev) {
/* Prepend to list. */
i = &xtables_targets;
- pos = xtables_targets;
- } else if (compare < 0) {
- /* Prepend it */
- for (i = &xtables_targets; *i != pos; i = &(*i)->next);
- } else if (compare > 0) {
+ prev = xtables_targets;
+ } else {
/* Append it */
- i = &pos->next;
- pos = pos->next;
+ i = &prev->next;
+ prev = prev->next;
}
- me->next = pos;
+ me->next = prev;
*i = me;
me->t = NULL;
@@ -1227,9 +1275,10 @@ static bool xtables_fully_register_pending_target(struct xtables_target *me)
void xtables_register_targets(struct xtables_target *target, unsigned int n)
{
- do {
- xtables_register_target(&target[--n]);
- } while (n > 0);
+ int i;
+
+ for (i = 0; i < n; i++)
+ xtables_register_target(&target[i]);
}
/* receives a list of xtables_rule_match, release them */
@@ -2093,6 +2142,79 @@ void xtables_print_num(uint64_t number, unsigned int format)
printf(FMT("%4lluT ","%lluT "), (unsigned long long)number);
}
+#include <netinet/ether.h>
+
+static const unsigned char mac_type_unicast[ETH_ALEN] = {};
+static const unsigned char msk_type_unicast[ETH_ALEN] = {1};
+static const unsigned char mac_type_multicast[ETH_ALEN] = {1};
+static const unsigned char msk_type_multicast[ETH_ALEN] = {1};
+#define ALL_ONE_MAC {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
+static const unsigned char mac_type_broadcast[ETH_ALEN] = ALL_ONE_MAC;
+static const unsigned char msk_type_broadcast[ETH_ALEN] = ALL_ONE_MAC;
+static const unsigned char mac_type_bridge_group[ETH_ALEN] = {0x01, 0x80, 0xc2};
+static const unsigned char msk_type_bridge_group[ETH_ALEN] = ALL_ONE_MAC;
+#undef ALL_ONE_MAC
+
+int xtables_parse_mac_and_mask(const char *from, void *to, void *mask)
+{
+ char *p;
+ int i;
+ struct ether_addr *addr = NULL;
+
+ if (strcasecmp(from, "Unicast") == 0) {
+ memcpy(to, mac_type_unicast, ETH_ALEN);
+ memcpy(mask, msk_type_unicast, ETH_ALEN);
+ return 0;
+ }
+ if (strcasecmp(from, "Multicast") == 0) {
+ memcpy(to, mac_type_multicast, ETH_ALEN);
+ memcpy(mask, msk_type_multicast, ETH_ALEN);
+ return 0;
+ }
+ if (strcasecmp(from, "Broadcast") == 0) {
+ memcpy(to, mac_type_broadcast, ETH_ALEN);
+ memcpy(mask, msk_type_broadcast, ETH_ALEN);
+ return 0;
+ }
+ if (strcasecmp(from, "BGA") == 0) {
+ memcpy(to, mac_type_bridge_group, ETH_ALEN);
+ memcpy(mask, msk_type_bridge_group, ETH_ALEN);
+ return 0;
+ }
+ if ( (p = strrchr(from, '/')) != NULL) {
+ *p = '\0';
+ if (!(addr = ether_aton(p + 1)))
+ return -1;
+ memcpy(mask, addr, ETH_ALEN);
+ } else
+ memset(mask, 0xff, ETH_ALEN);
+ if (!(addr = ether_aton(from)))
+ return -1;
+ memcpy(to, addr, ETH_ALEN);
+ for (i = 0; i < ETH_ALEN; i++)
+ ((char *)to)[i] &= ((char *)mask)[i];
+ return 0;
+}
+
+int xtables_print_well_known_mac_and_mask(const void *mac, const void *mask)
+{
+ if (!memcmp(mac, mac_type_unicast, ETH_ALEN) &&
+ !memcmp(mask, msk_type_unicast, ETH_ALEN))
+ printf("Unicast");
+ else if (!memcmp(mac, mac_type_multicast, ETH_ALEN) &&
+ !memcmp(mask, msk_type_multicast, ETH_ALEN))
+ printf("Multicast");
+ else if (!memcmp(mac, mac_type_broadcast, ETH_ALEN) &&
+ !memcmp(mask, msk_type_broadcast, ETH_ALEN))
+ printf("Broadcast");
+ else if (!memcmp(mac, mac_type_bridge_group, ETH_ALEN) &&
+ !memcmp(mask, msk_type_bridge_group, ETH_ALEN))
+ printf("BGA");
+ else
+ return -1;
+ return 0;
+}
+
void xtables_print_mac(const unsigned char *macaddress)
{
unsigned int i;
diff --git a/utils/Makefile.am b/utils/Makefile.am
index d09a6974..42bd9737 100644
--- a/utils/Makefile.am
+++ b/utils/Makefile.am
@@ -14,6 +14,11 @@ sbin_PROGRAMS += nfnl_osf
pkgdata_DATA += pf.os
nfnl_osf_LDADD = ${libnfnetlink_LIBS}
+
+uninstall-hook:
+ dir=${DESTDIR}${pkgdatadir}; { \
+ test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; \
+ } || rmdir -p --ignore-fail-on-non-empty "$$dir"
endif
if ENABLE_BPFC
diff --git a/utils/nfnl_osf.c b/utils/nfnl_osf.c
index 15d53197..8008e83d 100644
--- a/utils/nfnl_osf.c
+++ b/utils/nfnl_osf.c
@@ -378,9 +378,11 @@ static int osf_load_line(char *buffer, int len, int del)
memset(buf, 0, sizeof(buf));
if (del)
- nfnl_fill_hdr(nfnlssh, nmh, 0, AF_UNSPEC, 0, OSF_MSG_REMOVE, NLM_F_REQUEST);
+ nfnl_fill_hdr(nfnlssh, nmh, 0, AF_UNSPEC, 0, OSF_MSG_REMOVE,
+ NLM_F_ACK | NLM_F_REQUEST);
else
- nfnl_fill_hdr(nfnlssh, nmh, 0, AF_UNSPEC, 0, OSF_MSG_ADD, NLM_F_REQUEST | NLM_F_CREATE);
+ nfnl_fill_hdr(nfnlssh, nmh, 0, AF_UNSPEC, 0, OSF_MSG_ADD,
+ NLM_F_ACK | NLM_F_REQUEST | NLM_F_CREATE);
nfnl_addattr_l(nmh, sizeof(buf), OSF_ATTR_FINGER, &f, sizeof(struct xt_osf_user_finger));
@@ -390,7 +392,7 @@ static int osf_load_line(char *buffer, int len, int del)
static int osf_load_entries(char *path, int del)
{
FILE *inf;
- int err = 0;
+ int err = 0, lineno = 0;
char buf[1024];
inf = fopen(path, "r");
@@ -400,7 +402,9 @@ static int osf_load_entries(char *path, int del)
}
while(fgets(buf, sizeof(buf), inf)) {
- int len;
+ int len, rc;
+
+ lineno++;
if (buf[0] == '#' || buf[0] == '\n' || buf[0] == '\r')
continue;
@@ -412,9 +416,11 @@ static int osf_load_entries(char *path, int del)
buf[len] = '\0';
- err = osf_load_line(buf, len, del);
- if (err)
- break;
+ rc = osf_load_line(buf, len, del);
+ if (rc && (!del || errno != ENOENT)) {
+ ulog_err("Failed to load line %d", lineno);
+ err = rc;
+ }
memset(buf, 0, sizeof(buf));
}
@@ -446,6 +452,7 @@ int main(int argc, char *argv[])
if (!fingerprints) {
err = -ENOENT;
+ ulog("Missing fingerprints file argument.\n");
goto err_out_exit;
}