From df3d92bec600720b2fb50470212ed7cd1ef00c36 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 7 May 2018 15:32:33 +0200 Subject: xtables-compat-restore: flush user-defined chains with -n -n still flushes user-defined chains and its content, the following snippet: iptables-compat -N FOO iptables-compat -I INPUT iptables-compat -I FOO iptables-compat -I FOO iptables-compat-save > A iptables-compat-restore < A iptables-compat -N BAR iptables-compat -A BAR iptables-compat-restore -n < A results in: iptables-compat-save # Generated by xtables-save v1.6.2 on Mon May 7 17:18:44 2018 *filter :INPUT ACCEPT [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] :BAR - [0:0] :FOO - [0:0] -A INPUT -A INPUT -A BAR -A FOO -A FOO COMMIT # Completed on Mon May 7 17:18:44 2018 Still, user-defined chains that are not re-defined, such as BAR, are left in place. Reported-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- iptables/nft-shared.h | 3 +++ iptables/nft.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++ iptables/nft.h | 2 ++ iptables/xtables-restore.c | 16 ++++++++++++-- 4 files changed, 74 insertions(+), 2 deletions(-) (limited to 'iptables') diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index 56b270e5..34027af9 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -248,6 +248,9 @@ struct nft_xt_restore_cb { struct nftnl_chain_list *(*chain_list)(struct nft_handle *h); void (*chain_del)(struct nftnl_chain_list *clist, const char *curtable, const char *chain); + int (*chain_user_flush)(struct nft_handle *h, + struct nftnl_chain_list *clist, + const char *table, const char *chain); int (*chain_set)(struct nft_handle *h, const char *table, const char *chain, const char *policy, const struct xt_counters *counters); diff --git a/iptables/nft.c b/iptables/nft.c index 543e44d7..7f9eb7f0 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -255,6 +255,7 @@ enum obj_update_type { 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_RULE_APPEND, @@ -1361,6 +1362,55 @@ err: return ret == 0 ? 1 : 0; } +struct chain_user_flush_data { + struct nft_handle *handle; + const char *table; + const char *chain; +}; + +static int __nft_chain_user_flush(struct nftnl_chain *c, void *data) +{ + const char *table_name = nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE); + const char *chain_name = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME); + struct chain_user_flush_data *d = data; + struct nft_handle *h = d->handle; + const char *table = d->table; + const char *chain = d->chain; + int ret; + + if (strcmp(table, table_name) != 0) + return 0; + + 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); + } + + return 0; +} + +int nft_chain_user_flush(struct nft_handle *h, struct nftnl_chain_list *list, + const char *table, const char *chain) +{ + struct chain_user_flush_data d = { + .handle = h, + .table = table, + .chain = chain, + }; + + nft_fn = nft_chain_user_flush; + + nftnl_chain_list_foreach(list, __nft_chain_user_flush, &d); + + return 1; +} + int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table) { int ret; @@ -2275,6 +2325,11 @@ static int nft_action(struct nft_handle *h, int action) NLM_F_NONREC, seq++, n->chain); break; + case NFT_COMPAT_CHAIN_USER_FLUSH: + nft_compat_chain_batch_add(h, NFT_MSG_DELCHAIN, + 0, seq++, + n->chain); + break; case NFT_COMPAT_CHAIN_UPDATE: nft_compat_chain_batch_add(h, NFT_MSG_NEWCHAIN, h->restore ? diff --git a/iptables/nft.h b/iptables/nft.h index 2d5c37e5..0c4beb99 100644 --- a/iptables/nft.h +++ b/iptables/nft.h @@ -71,6 +71,8 @@ struct nftnl_chain *nft_chain_list_find(struct nftnl_chain_list *list, const cha int nft_chain_save(struct nft_handle *h, struct nftnl_chain_list *list, const char *table); 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); +int nft_chain_user_flush(struct nft_handle *h, struct nftnl_chain_list *list, + const char *chain, const char *table); int nft_chain_user_rename(struct nft_handle *h, const char *chain, const char *table, const char *newname); int nft_chain_zero_counters(struct nft_handle *h, const char *chain, const char *table); diff --git a/iptables/xtables-restore.c b/iptables/xtables-restore.c index 6e7652ff..ac753c43 100644 --- a/iptables/xtables-restore.c +++ b/iptables/xtables-restore.c @@ -196,6 +196,7 @@ struct nft_xt_restore_cb restore_cb = { .commit = nft_commit, .abort = nft_abort, .table_flush = nft_table_flush, + .chain_user_flush = nft_chain_user_flush, .chain_del = chain_delete, .do_command = do_commandx, .chain_set = nft_chain_set, @@ -294,8 +295,19 @@ void xtables_restore_parse(struct nft_handle *h, exit(1); } - if (cb->chain_del) - cb->chain_del(chain_list, curtable, chain); + if (noflush == 0) { + if (cb->chain_del) + cb->chain_del(chain_list, curtable, + chain); + } else { + /* Apparently -n still flushes existing user + * defined chains that are redefined. Otherwise, + * leave them as is. + */ + if (cb->chain_user_flush) + cb->chain_user_flush(h, chain_list, + curtable, chain); + } if (strlen(chain) >= XT_EXTENSION_MAXNAMELEN) xtables_error(PARAMETER_PROBLEM, -- cgit v1.2.3