]> git.ipfire.org Git - thirdparty/iptables.git/commitdiff
xtables-compat-restore: flush user-defined chains with -n
authorPablo Neira Ayuso <pablo@netfilter.org>
Mon, 7 May 2018 13:32:33 +0000 (15:32 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Mon, 7 May 2018 15:40:12 +0000 (17:40 +0200)
-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 <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
iptables/nft-shared.h
iptables/nft.c
iptables/nft.h
iptables/xtables-restore.c

index 56b270e5a4b74c65c2b983bff2e3727b5d2b3f43..34027af931ec622e3c20f6746050aecfb9400f95 100644 (file)
@@ -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);
index 543e44d792b102da5e621d6694fa6afe512b1812..7f9eb7f0e21af2ade9707bb5b8af756054021e9e 100644 (file)
@@ -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 ?
index 2d5c37e5b5023ec348d61fe0d941fe22e40d9957..0c4beb998de853d10b66c4d6aa58789fb9d00c29 100644 (file)
@@ -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);
 
index 6e7652ff7668b50f7a6167ca28368bd7cb11d5e2..ac753c43bc91f554ec23d9743bae2ff501a0bb45 100644 (file)
@@ -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,