diff options
author | Phil Sutter <phil@nwl.cc> | 2018-09-06 19:33:20 +0200 |
---|---|---|
committer | Florian Westphal <fw@strlen.de> | 2018-09-10 15:20:13 +0200 |
commit | 7345037e08a385e078350de1006f5ee2299cd2ef (patch) | |
tree | da8d4db8777caf9d610aa10190c32478e0407e9e | |
parent | 7df11d1699ceaf4a841a46a42f446aec5593efd3 (diff) |
xtables-restore: Fix flushing referenced custom chains
The logic to replicate 'iptables-restore --noflush' behaviour of
flushing custom chains if listed in the dump was broken for chains being
referenced. A minimal dump reproducing the issue is:
| *filter
| :foobar - [0:0]
| -I INPUT -j foobar
| -A foobar -j ACCEPT
| COMMIT
With --noflush, this can be restored just once in iptables-nft-restore.
Consecutive attempts return an error since xtables tries to delete the
referenced chain and recreate it instead of performing a real flush.
Fix this by really flushing the custom chain in 'chain_user_flush'
callback and running 'chain_user_add' callback only if the chain doesn't
exist already.
Fixes: df3d92bec6007 ("xtables-compat-restore: flush user-defined chains with -n")
Signed-off-by: Phil Sutter <phil@nwl.cc>
Signed-off-by: Florian Westphal <fw@strlen.de>
-rw-r--r-- | iptables/nft.c | 10 | ||||
-rw-r--r-- | iptables/xtables-restore.c | 8 |
2 files changed, 8 insertions, 10 deletions
diff --git a/iptables/nft.c b/iptables/nft.c index 7123060b..77ad38be 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -1491,7 +1491,6 @@ static int __nft_chain_user_flush(struct nftnl_chain *c, void *data) struct nft_handle *h = d->handle; const char *table = d->table; const char *chain = d->chain; - int ret; if (strcmp(table, table_name) != 0) return 0; @@ -1499,13 +1498,8 @@ static int __nft_chain_user_flush(struct nftnl_chain *c, void *data) if (strcmp(chain, chain_name) != 0) return 0; - if (!nftnl_chain_is_set(c, NFTNL_CHAIN_HOOKNUM)) { - ret = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_FLUSH, c); - if (ret < 0) - return ret; - - nftnl_chain_list_del(c); - } + if (!nftnl_chain_is_set(c, NFTNL_CHAIN_HOOKNUM)) + __nft_rule_flush(h, table, chain); return 0; } diff --git a/iptables/xtables-restore.c b/iptables/xtables-restore.c index d2b79208..d187b129 100644 --- a/iptables/xtables-restore.c +++ b/iptables/xtables-restore.c @@ -182,6 +182,7 @@ void xtables_restore_parse(struct nft_handle *h, /* New chain. */ char *policy, *chain = NULL; struct xt_counters count = {}; + bool chain_exists = false; chain = strtok(buffer+1, " \t\n"); DEBUGP("line %u, chain '%s'\n", line, chain); @@ -196,7 +197,9 @@ void xtables_restore_parse(struct nft_handle *h, if (cb->chain_del) cb->chain_del(chain_list, curtable->name, chain); - } else { + } else if (nft_chain_list_find(chain_list, + curtable->name, chain)) { + chain_exists = true; /* Apparently -n still flushes existing user * defined chains that are redefined. Otherwise, * leave them as is. @@ -246,7 +249,8 @@ void xtables_restore_parse(struct nft_handle *h, ret = 1; } else { - if (cb->chain_user_add && + if (!chain_exists && + cb->chain_user_add && cb->chain_user_add(h, chain, curtable->name) < 0) { if (errno == EEXIST) |