Currently, when running `iptables-restore --table=X`, where `X` is not the first table in the rules dump, the restore will fail when parsing the second table: - a lock is acquird when parsing the first table name - the table name does not match the parameter to `--table` so processing continues until the next table - when processing the next table a lock is acquired, which fails because a lock is already held This will release the lock as soon as it's decided the current table won't be used. With existing code: # iptables -L Chain INPUT (policy ACCEPT) target prot opt source destination Chain FORWARD (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination # iptables-restore <iptables.dump Another app is currently holding the xtables lock. Perhaps you want to use the -w option? # iptables -L Chain INPUT (policy ACCEPT) target prot opt source destination Chain FORWARD (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination With this change: # iptables -L Chain INPUT (policy ACCEPT) target prot opt source destination Chain FORWARD (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination # iptables-restore <iptables.dump # iptables -L Chain INPUT (policy DROP) target prot opt source destination ACCEPT all -- anywhere anywhere ACCEPT all -- anywhere anywhere state RELATED,ESTABLISHED ACCEPT icmp -- anywhere anywhere Chain FORWARD (policy DROP) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination REJECT tcp -- anywhere anywhere tcp dpt:netbios-ns reject-with icmp-port-unreachable REJECT udp -- anywhere anywhere udp dpt:netbios-ns reject-with icmp-port-unreachable And the test suite: # ./iptables/tests/shell/run-tests.sh I: [OK] ././iptables/tests/shell/testcases/chain/0001duplicate_1 I: [OK] ././iptables/tests/shell/testcases/chain/0002newchain_0 I: [OK] ././iptables/tests/shell/testcases/chain/0003rename_1 I: [OK] ././iptables/tests/shell/testcases/ebtables/0001-ebtables- basic_0 I: [OK] ././iptables/tests/shell/testcases/firewalld-restore/0001- firewalld_0 I: [OK] ././iptables/tests/shell/testcases/firewalld-restore/0002- firewalld-restart_0 I: [OK] ././iptables/tests/shell/testcases/ipt-restore/0001load- specific-table_0 I: [OK] ././iptables/tests/shell/testcases/ipt-save/0001load- dumps_0 I: [OK] ././iptables/tests/shell/testcases/ipt-save/0002load- fedora27-firewalld_0 I: legacy results: [OK] 9 [FAILED] 0 [TOTAL] 9 I: [OK] ././iptables/tests/shell/testcases/chain/0001duplicate_1 I: [OK] ././iptables/tests/shell/testcases/chain/0002newchain_0 I: [OK] ././iptables/tests/shell/testcases/chain/0003rename_1 I: [OK] ././iptables/tests/shell/testcases/ebtables/0001-ebtables- basic_0 I: [OK] ././iptables/tests/shell/testcases/firewalld-restore/0001- firewalld_0 I: [OK] ././iptables/tests/shell/testcases/firewalld-restore/0002- firewalld-restart_0 I: [OK] ././iptables/tests/shell/testcases/ipt-restore/0001load- specific-table_0 I: [OK] ././iptables/tests/shell/testcases/ipt-save/0001load- dumps_0 I: [OK] ././iptables/tests/shell/testcases/ipt-save/0002load- fedora27-firewalld_0 I: nft results: [OK] 9 [FAILED] 0 [TOTAL] 9 I: combined results: [OK] 18 [FAILED] 0 [TOTAL] 18 Signed-off-by: Joel Goguen <contact+netfilter@xxxxxxxxxx> --- iptables/ip6tables-restore.c | 7 +++- iptables/iptables-restore.c | 9 +++-- .../ipt-restore/0001load-specific-table_0 | 42 ++++++++++++++++++++++ .../testcases/ipt-restore/dumps/ip6tables.dump | 30 ++++++++++++++++ .../testcases/ipt-restore/dumps/iptables.dump | 30 ++++++++++++++++ 5 files changed, 115 insertions(+), 3 deletions(-) diff --git iptables/ip6tables-restore.c iptables/ip6tables-restore.c index ceffa616..a880fae5 100644 --- iptables/ip6tables-restore.c +++ iptables/ip6tables-restore.c @@ -325,8 +325,13 @@ int ip6tables_restore_main(int argc, char *argv[]) strncpy(curtable, table, XT_TABLE_MAXNAMELEN); curtable[XT_TABLE_MAXNAMELEN] = '\0'; - if (tablename != NULL && strcmp(tablename, table) != 0) + if (tablename != NULL && strcmp(tablename, table) != 0) { + if (lock >= 0) { + xtables_unlock(lock); + lock = XT_LOCK_NOT_ACQUIRED; + } continue; + } if (handle) ops->free(handle); diff --git iptables/iptables-restore.c iptables/iptables-restore.c index 39198752..190a990f 100644 --- iptables/iptables-restore.c +++ iptables/iptables-restore.c @@ -97,7 +97,7 @@ static int parse_counters(char *string, struct xt_counters *ctr) static char *newargv[255]; static int newargc; -/* function adding one argument to newargv, updating newargc +/* function adding one argument to newargv, updating newargc * returns true if argument added, false otherwise */ static int add_argv(char *what) { DEBUGP("add_argv: %s\n", what); @@ -323,8 +323,13 @@ iptables_restore_main(int argc, char *argv[]) strncpy(curtable, table, XT_TABLE_MAXNAMELEN); curtable[XT_TABLE_MAXNAMELEN] = '\0'; - if (tablename && (strcmp(tablename, table) != 0)) + if (tablename && (strcmp(tablename, table) != 0)) { + if (lock >= 0) { + xtables_unlock(lock); + lock = XT_LOCK_NOT_ACQUIRED; + } continue; + } if (handle) ops->free(handle); diff --git iptables/tests/shell/testcases/ipt-restore/0001load-specific-table_0 iptables/tests/shell/testcases/ipt-restore/0001load-specific-table_0 new file mode 100755 index 00000000..56d2d966 --- /dev/null +++ iptables/tests/shell/testcases/ipt-restore/0001load-specific-table_0 @@ -0,0 +1,42 @@ +#!/bin/bash +# vim: syntax=sh:noexpandtab:sw=4:ts=4:sts=4 + +RET=0 +tmpfile="" + +set -x + +clean_tempfile() +{ + if [ -n "${tmpfile}" ]; then + rm -f "${tmpfile}" + fi +} + +trap clean_tempfile EXIT + +tmpfile=$(mktemp) || exit 1 + +do_simple() +{ + iptables="${1}" + table="${2}" + dumpfile="$(dirname "${0}")/dumps/${iptables}.dump" + + "$XT_MULTI" "${iptables}-restore" --table="${table}" <"${dumpfile}"; rv=$? + + if [ "${rv}" -ne 0 ]; then + RET=1 + fi +} + +do_simple "iptables" "filter" +do_simple "iptables" "mangle" +do_simple "iptables" "raw" +do_simple "iptables" "nat" +do_simple "ip6tables" "filter" +do_simple "ip6tables" "mangle" +do_simple "ip6tables" "raw" +do_simple "ip6tables" "nat" + +exit "${RET}" diff --git iptables/tests/shell/testcases/ipt-restore/dumps/ip6tables.dump iptables/tests/shell/testcases/ipt-restore/dumps/ip6tables.dump new file mode 100644 index 00000000..4ac4f882 --- /dev/null +++ iptables/tests/shell/testcases/ipt-restore/dumps/ip6tables.dump @@ -0,0 +1,30 @@ +*nat +:PREROUTING ACCEPT [0:0] +:INPUT ACCEPT [0:0] +:OUTPUT ACCEPT [8:656] +:POSTROUTING ACCEPT [8:656] +COMMIT + +*mangle +:PREROUTING ACCEPT [794:190738] +:INPUT ACCEPT [794:190738] +:FORWARD ACCEPT [0:0] +:OUTPUT ACCEPT [991:170303] +:POSTROUTING ACCEPT [991:170303] +COMMIT + +*raw +:PREROUTING ACCEPT [794:190738] +:OUTPUT ACCEPT [991:170303] +COMMIT + +*filter +:INPUT DROP [0:0] +:FORWARD DROP [0:0] +:OUTPUT ACCEPT [991:170303] +-A INPUT -i lo -j ACCEPT +-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT +-A INPUT -p ipv6-icmp -j ACCEPT +-A OUTPUT -p tcp -m tcp --dport 137 -j REJECT --reject-with icmp6-port- unreachable +-A OUTPUT -p udp -m udp --dport 137 -j REJECT --reject-with icmp6-port- unreachable +COMMIT diff --git iptables/tests/shell/testcases/ipt-restore/dumps/iptables.dump iptables/tests/shell/testcases/ipt-restore/dumps/iptables.dump new file mode 100644 index 00000000..6e4e42d3 --- /dev/null +++ iptables/tests/shell/testcases/ipt-restore/dumps/iptables.dump @@ -0,0 +1,30 @@ +*nat +:PREROUTING ACCEPT [1:89] +:INPUT ACCEPT [0:0] +:OUTPUT ACCEPT [351:24945] +:POSTROUTING ACCEPT [351:24945] +COMMIT + +*mangle +:PREROUTING ACCEPT [3270:1513114] +:INPUT ACCEPT [3270:1513114] +:FORWARD ACCEPT [0:0] +:OUTPUT ACCEPT [3528:1087907] +:POSTROUTING ACCEPT [3546:1090751] +COMMIT + +*raw +:PREROUTING ACCEPT [3270:1513114] +:OUTPUT ACCEPT [3528:1087907] +COMMIT + +*filter +:INPUT DROP [37:4057] +:FORWARD DROP [0:0] +:OUTPUT ACCEPT [3528:1087907] +-A INPUT -i lo -j ACCEPT +-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT +-A INPUT -p icmp -j ACCEPT +-A OUTPUT -p tcp -m tcp --dport 137 -j REJECT --reject-with icmp-port- unreachable +-A OUTPUT -p udp -m udp --dport 137 -j REJECT --reject-with icmp-port- unreachable +COMMIT -- To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html