]> git.ipfire.org Git - thirdparty/iptables.git/commitdiff
iptables-compat: do not fail on restore if user chain exists
authorPablo Neira Ayuso <pablo@netfilter.org>
Fri, 4 May 2018 09:25:00 +0000 (11:25 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Sat, 5 May 2018 08:05:44 +0000 (10:05 +0200)
The following snippet fails if user chain FOO exists, but it should not fail:

iptables-compat -F
iptables-compat -N FOO
iptables-compat-save > foo
iptables-compat-restore < foo

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 525f3f0ee5db5b738ed251d7e8a683988df5dd65..089828a333cd0207263c346d37a9951b87655785 100644 (file)
@@ -256,7 +256,7 @@ struct nft_xt_restore_cb {
        int (*chain_user_add)(struct nft_handle *h, const char *chain,
                              const char *table);
 
-       int (*rule_flush)(struct nft_handle *h, const char *chain, const char *table);
+       int (*table_flush)(struct nft_handle *h, const char *table);
 
        int (*do_command)(struct nft_handle *h, int argc, char *argv[],
                          char **table, bool restore);
index bff73e765f8b267978dc4b6b3bb70194ee973cae..271269f984a3465731017ec8b635849da7f9bbf0 100644 (file)
@@ -262,6 +262,7 @@ enum obj_update_type {
        NFT_COMPAT_RULE_REPLACE,
        NFT_COMPAT_RULE_DELETE,
        NFT_COMPAT_RULE_FLUSH,
+       NFT_COMPAT_TABLE_FLUSH,
 };
 
 enum obj_action {
@@ -1289,6 +1290,27 @@ next:
        return 1;
 }
 
+int nft_table_flush(struct nft_handle *h, const char *table)
+{
+       struct nftnl_table *r;
+       int ret = 0;
+
+       nft_fn = nft_table_flush;
+
+       r = nftnl_table_alloc();
+       if (r == NULL) {
+               ret = -1;
+               goto err;
+       }
+
+       nftnl_table_set_str(r, NFTNL_TABLE_NAME, table);
+
+       batch_table_add(h, NFT_COMPAT_TABLE_FLUSH, r);
+err:
+       /* the core expects 1 for success and 0 for error */
+       return ret == 0 ? 1 : 0;
+}
+
 static void
 __nft_rule_flush(struct nft_handle *h, const char *table, const char *chain)
 {
@@ -2300,6 +2322,11 @@ static int nft_action(struct nft_handle *h, int action)
                        nft_compat_rule_batch_add(h, NFT_MSG_DELRULE, 0,
                                                  seq++, n->rule);
                        break;
+               case NFT_COMPAT_TABLE_FLUSH:
+                       nft_compat_table_batch_add(h, NFT_MSG_DELTABLE,
+                                                  0,
+                                                  seq++, n->table);
+                       break;
                }
 
                h->obj_list_num--;
index aaf3cbe0c0e367d6935b897c9a73a2d8da43644f..2d5c37e5b5023ec348d61fe0d941fe22e40d9957 100644 (file)
@@ -58,6 +58,7 @@ struct nftnl_chain_list;
 int nft_for_each_table(struct nft_handle *h, int (*func)(struct nft_handle *h, const char *tablename, bool counters), bool counters);
 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);
 
 /*
  * Operations with chains.
index fc39ad9c4fa5f67e062a6bb239a092c3aeea724d..3de496f853878e922b92f610bdaf9af7c9d4b41d 100644 (file)
@@ -191,7 +191,7 @@ struct nft_xt_restore_cb restore_cb = {
        .commit         = nft_commit,
        .abort          = nft_abort,
        .chains_purge   = nft_table_purge_chains,
-       .rule_flush     = nft_rule_flush,
+       .table_flush    = nft_table_flush,
        .chain_del      = chain_delete,
        .do_command     = do_commandx,
        .chain_set      = nft_chain_set,
@@ -270,8 +270,8 @@ void xtables_restore_parse(struct nft_handle *h,
                        if (noflush == 0) {
                                DEBUGP("Cleaning all chains of table '%s'\n",
                                        table);
-                               if (cb->rule_flush)
-                                       cb->rule_flush(h, NULL, table);
+                               if (cb->table_flush)
+                                       cb->table_flush(h, table);
                        }
 
                        ret = 1;