]> git.ipfire.org Git - thirdparty/iptables.git/commitdiff
iptables-nft: allow removal of empty builtin chains
authorFlorian Westphal <fw@strlen.de>
Sat, 14 Aug 2021 17:46:43 +0000 (19:46 +0200)
committerFlorian Westphal <fw@strlen.de>
Tue, 7 Sep 2021 12:16:07 +0000 (14:16 +0200)
The only reason why this is prohibited is that you cannot do it
in iptables-legacy.

This removes the artifical limitation.

"iptables-nft -X" will leave the builtin chains alone;
Also, deletion is only permitted if the chain is empty.

Signed-off-by: Florian Westphal <fw@strlen.de>
iptables/iptables.8.in
iptables/nft-cmd.c
iptables/nft-cmd.h
iptables/nft.c
iptables/nft.h
iptables/xtables-arp.c
iptables/xtables-eb.c
iptables/xtables.c

index 999cf339845f9a2cf9cc7e1517dc492fe0378d79..759ec54fdeb72bf7c3312b18e2a9018228603b97 100644 (file)
 .SH NAME
 iptables/ip6tables \(em administration tool for IPv4/IPv6 packet filtering and NAT
 .SH SYNOPSIS
-\fBiptables\fP [\fB\-t\fP \fItable\fP] {\fB\-A\fP|\fB\-C\fP|\fB\-D\fP}
+\fBiptables\fP [\fB\-t\fP \fItable\fP] {\fB\-A\fP|\fB\-C\fP|\fB\-D\fP|\fB-V\fP}
 \fIchain\fP \fIrule-specification\fP
 .P
-\fBip6tables\fP [\fB\-t\fP \fItable\fP] {\fB\-A\fP|\fB\-C\fP|\fB\-D\fP}
+\fBip6tables\fP [\fB\-t\fP \fItable\fP] {\fB\-A\fP|\fB\-C\fP|\fB\-D\fP|\fB-V\fP}
 \fIchain rule-specification\fP
 .PP
 \fBiptables\fP [\fB\-t\fP \fItable\fP] \fB\-I\fP \fIchain\fP [\fIrulenum\fP] \fIrule-specification\fP
@@ -220,11 +220,11 @@ Create a new user-defined chain by the given name.  There must be no
 target of that name already.
 .TP
 \fB\-X\fP, \fB\-\-delete\-chain\fP [\fIchain\fP]
-Delete the optional user-defined chain specified.  There must be no references
+Delete the chain specified.  There must be no references
 to the chain.  If there are, you must delete or replace the referring rules
 before the chain can be deleted.  The chain must be empty, i.e. not contain
-any rules.  If no argument is given, it will attempt to delete every
-non-builtin chain in the table.
+any rules.  If no argument is given, it will delete all empty chains in the
+table. Empty builtin chains can only be deleted with \fBiptables-nft\fP.
 .TP
 \fB\-P\fP, \fB\-\-policy\fP \fIchain target\fP
 Set the policy for the built-in (non-user-defined) chain to the given target.
@@ -362,6 +362,9 @@ For appending, insertion, deletion and replacement, this causes
 detailed information on the rule or rules to be printed. \fB\-v\fP may be
 specified multiple times to possibly emit more detailed debug statements.
 .TP
+\fB\-V\fP, \fB\-\-version\fP
+Show program version and the kernel API used.
+.TP
 \fB\-w\fP, \fB\-\-wait\fP [\fIseconds\fP]
 Wait for the xtables lock.
 To prevent multiple instances of the program from running concurrently,
index 87e66905655d622c86ddb229003d6b6883e9f087..35b392689c2f191867253218d68be1d52f72a0d0 100644 (file)
@@ -205,12 +205,12 @@ int nft_cmd_chain_user_add(struct nft_handle *h, const char *chain,
        return 1;
 }
 
-int nft_cmd_chain_user_del(struct nft_handle *h, const char *chain,
-                          const char *table, bool verbose)
+int nft_cmd_chain_del(struct nft_handle *h, const char *chain,
+                     const char *table, bool verbose)
 {
        struct nft_cmd *cmd;
 
-       cmd = nft_cmd_new(h, NFT_COMPAT_CHAIN_USER_DEL, table, chain, NULL, -1,
+       cmd = nft_cmd_new(h, NFT_COMPAT_CHAIN_DEL, table, chain, NULL, -1,
                          verbose);
        if (!cmd)
                return 0;
@@ -317,7 +317,7 @@ int nft_cmd_table_flush(struct nft_handle *h, const char *table, bool verbose)
 
        if (verbose) {
                return nft_cmd_rule_flush(h, NULL, table, verbose) &&
-                      nft_cmd_chain_user_del(h, NULL, table, verbose);
+                      nft_cmd_chain_del(h, NULL, table, verbose);
        }
 
        cmd = nft_cmd_new(h, NFT_COMPAT_TABLE_FLUSH, table, NULL, NULL, -1,
index ecf7655a4a6133808de457546e3b0950dd17e810..b5a99ef74ad9ccdd460e9d46d1f579ca92ff62e7 100644 (file)
@@ -49,8 +49,8 @@ int nft_cmd_zero_counters(struct nft_handle *h, const char *chain,
                          const char *table, bool verbose);
 int nft_cmd_chain_user_add(struct nft_handle *h, const char *chain,
                           const char *table);
-int nft_cmd_chain_user_del(struct nft_handle *h, const char *chain,
-                          const char *table, bool verbose);
+int nft_cmd_chain_del(struct nft_handle *h, const char *chain,
+                     const char *table, bool verbose);
 int nft_cmd_chain_zero_counters(struct nft_handle *h, const char *chain,
                                const char *table, bool verbose);
 int nft_cmd_rule_list(struct nft_handle *h, const char *chain,
index c9ed38bd29a535177047acc25ff9bbcfa0d6ec57..89dde9ecca779aeba0525776ca5eee208ede4f9f 100644 (file)
@@ -290,7 +290,7 @@ static int mnl_append_error(const struct nft_handle *h,
                [NFT_COMPAT_TABLE_FLUSH] = "TABLE_FLUSH",
                [NFT_COMPAT_CHAIN_ADD] = "CHAIN_ADD",
                [NFT_COMPAT_CHAIN_USER_ADD] = "CHAIN_USER_ADD",
-               [NFT_COMPAT_CHAIN_USER_DEL] = "CHAIN_USER_DEL",
+               [NFT_COMPAT_CHAIN_DEL] = "CHAIN_DEL",
                [NFT_COMPAT_CHAIN_USER_FLUSH] = "CHAIN_USER_FLUSH",
                [NFT_COMPAT_CHAIN_UPDATE] = "CHAIN_UPDATE",
                [NFT_COMPAT_CHAIN_RENAME] = "CHAIN_RENAME",
@@ -321,7 +321,7 @@ static int mnl_append_error(const struct nft_handle *h,
        case NFT_COMPAT_CHAIN_ADD:
        case NFT_COMPAT_CHAIN_ZERO:
        case NFT_COMPAT_CHAIN_USER_ADD:
-       case NFT_COMPAT_CHAIN_USER_DEL:
+       case NFT_COMPAT_CHAIN_DEL:
        case NFT_COMPAT_CHAIN_USER_FLUSH:
        case NFT_COMPAT_CHAIN_UPDATE:
        case NFT_COMPAT_CHAIN_RENAME:
@@ -1836,22 +1836,19 @@ int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table
 #define NLM_F_NONREC   0x100   /* Do not delete recursively    */
 #endif
 
-struct chain_user_del_data {
+struct chain_del_data {
        struct nft_handle       *handle;
+       struct nft_cache        *cache;
+       enum nft_table_type     type;
        bool                    verbose;
-       int                     builtin_err;
 };
 
-static int __nft_chain_user_del(struct nft_chain *nc, void *data)
+static int __nft_chain_del(struct nft_chain *nc, void *data)
 {
-       struct chain_user_del_data *d = data;
+       struct chain_del_data *d = data;
        struct nftnl_chain *c = nc->nftnl;
        struct nft_handle *h = d->handle;
 
-       /* don't delete built-in chain */
-       if (nft_chain_builtin(c))
-               return d->builtin_err;
-
        if (d->verbose)
                fprintf(stdout, "Deleting chain `%s'\n",
                        nftnl_chain_get_str(c, NFTNL_CHAIN_NAME));
@@ -1859,9 +1856,16 @@ static int __nft_chain_user_del(struct nft_chain *nc, void *data)
 
        /* XXX This triggers a fast lookup from the kernel. */
        nftnl_chain_unset(c, NFTNL_CHAIN_HANDLE);
-       if (!batch_chain_add(h, NFT_COMPAT_CHAIN_USER_DEL, c))
+       if (!batch_chain_add(h, NFT_COMPAT_CHAIN_DEL, c))
                return -1;
 
+       if (nft_chain_builtin(c)) {
+               uint32_t num = nftnl_chain_get_u32(c, NFTNL_CHAIN_HOOKNUM);
+
+               if (nc == d->cache->table[d->type].base_chains[num])
+                       d->cache->table[d->type].base_chains[num] = NULL;
+       }
+
        /* nftnl_chain is freed when deleting the batch object */
        nc->nftnl = NULL;
 
@@ -1870,17 +1874,18 @@ static int __nft_chain_user_del(struct nft_chain *nc, void *data)
        return 0;
 }
 
-int nft_chain_user_del(struct nft_handle *h, const char *chain,
+int nft_chain_del(struct nft_handle *h, const char *chain,
                       const char *table, bool verbose)
 {
-       struct chain_user_del_data d = {
+       const struct builtin_table *t;
+       struct chain_del_data d = {
                .handle = h,
                .verbose = verbose,
        };
        struct nft_chain *c;
        int ret = 0;
 
-       nft_fn = nft_chain_user_del;
+       nft_fn = nft_chain_del;
 
        if (chain) {
                c = nft_chain_find(h, table, chain);
@@ -1888,17 +1893,37 @@ int nft_chain_user_del(struct nft_handle *h, const char *chain,
                        errno = ENOENT;
                        return 0;
                }
-               d.builtin_err = -2;
-               ret = __nft_chain_user_del(c, &d);
+
+               if (nft_chain_builtin(c->nftnl)) {
+                       t = nft_table_builtin_find(h, table);
+                       if (!t) {
+                               errno = EINVAL;
+                               return 0;
+                       }
+
+                       d.type = t->type;
+                       d.cache = h->cache;
+               }
+
+               ret = __nft_chain_del(c, &d);
                if (ret == -2)
                        errno = EINVAL;
                goto out;
        }
 
+       t = nft_table_builtin_find(h, table);
+       if (!t) {
+               errno = EINVAL;
+               return 0;
+       }
+
+       d.type = t->type;
+       d.cache = h->cache;
+
        if (verbose)
                nft_cache_sort_chains(h, table);
 
-       ret = nft_chain_foreach(h, table, __nft_chain_user_del, &d);
+       ret = nft_chain_foreach(h, table, __nft_chain_del, &d);
 out:
        /* the core expects 1 for success and 0 for error */
        return ret == 0 ? 1 : 0;
@@ -2663,7 +2688,7 @@ static void batch_obj_del(struct nft_handle *h, struct obj_update *o)
        case NFT_COMPAT_CHAIN_USER_ADD:
        case NFT_COMPAT_CHAIN_ADD:
                break;
-       case NFT_COMPAT_CHAIN_USER_DEL:
+       case NFT_COMPAT_CHAIN_DEL:
        case NFT_COMPAT_CHAIN_USER_FLUSH:
        case NFT_COMPAT_CHAIN_UPDATE:
        case NFT_COMPAT_CHAIN_RENAME:
@@ -2748,7 +2773,7 @@ static void nft_refresh_transaction(struct nft_handle *h)
                case NFT_COMPAT_TABLE_ADD:
                case NFT_COMPAT_CHAIN_ADD:
                case NFT_COMPAT_CHAIN_ZERO:
-               case NFT_COMPAT_CHAIN_USER_DEL:
+               case NFT_COMPAT_CHAIN_DEL:
                case NFT_COMPAT_CHAIN_USER_FLUSH:
                case NFT_COMPAT_CHAIN_UPDATE:
                case NFT_COMPAT_CHAIN_RENAME:
@@ -2814,7 +2839,7 @@ retry:
                                                   NLM_F_EXCL, n->seq,
                                                   n->chain);
                        break;
-               case NFT_COMPAT_CHAIN_USER_DEL:
+               case NFT_COMPAT_CHAIN_DEL:
                        nft_compat_chain_batch_add(h, NFT_MSG_DELCHAIN,
                                                   NLM_F_NONREC, n->seq,
                                                   n->chain);
@@ -3059,9 +3084,9 @@ static int nft_prepare(struct nft_handle *h)
                case NFT_COMPAT_CHAIN_USER_ADD:
                        ret = nft_chain_user_add(h, cmd->chain, cmd->table);
                        break;
-               case NFT_COMPAT_CHAIN_USER_DEL:
-                       ret = nft_chain_user_del(h, cmd->chain, cmd->table,
-                                                cmd->verbose);
+               case NFT_COMPAT_CHAIN_DEL:
+                       ret = nft_chain_del(h, cmd->chain, cmd->table,
+                                           cmd->verbose);
                        break;
                case NFT_COMPAT_CHAIN_RESTORE:
                        ret = nft_chain_restore(h, cmd->chain, cmd->table);
@@ -3260,10 +3285,9 @@ const char *nft_strerror(int err)
                const char *message;
        } table[] =
          {
-           { nft_chain_user_del, ENOTEMPTY, "Chain is not empty" },
-           { nft_chain_user_del, EINVAL, "Can't delete built-in chain" },
-           { nft_chain_user_del, EBUSY, "Directory not empty" },
-           { nft_chain_user_del, EMLINK,
+           { nft_chain_del, ENOTEMPTY, "Chain is not empty" },
+           { nft_chain_del, EBUSY, "Directory not empty" },
+           { nft_chain_del, EMLINK,
              "Can't delete chain with references left" },
            { nft_chain_user_add, EEXIST, "Chain already exists" },
            { nft_chain_user_rename, EEXIST, "File exists" },
index 4ac7e0099d5670a3ff33db5d1136dc8fbdb94706..a7b652ff62a45b7721718ece171f55b70b9b78fe 100644 (file)
@@ -53,7 +53,7 @@ enum obj_update_type {
        NFT_COMPAT_TABLE_FLUSH,
        NFT_COMPAT_CHAIN_ADD,
        NFT_COMPAT_CHAIN_USER_ADD,
-       NFT_COMPAT_CHAIN_USER_DEL,
+       NFT_COMPAT_CHAIN_DEL,
        NFT_COMPAT_CHAIN_USER_FLUSH,
        NFT_COMPAT_CHAIN_UPDATE,
        NFT_COMPAT_CHAIN_RENAME,
@@ -147,7 +147,7 @@ struct nftnl_chain;
 int nft_chain_set(struct nft_handle *h, const char *table, const char *chain, const char *policy, const struct xt_counters *counters);
 int nft_chain_save(struct nft_chain *c, void *data);
 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, bool verbose);
+int nft_chain_del(struct nft_handle *h, const char *chain, const char *table, bool verbose);
 int nft_chain_restore(struct nft_handle *h, 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, bool verbose);
index 4a351f0cab4a7ff8be94fe0216a52ede9f2e9c1d..9a079f06b948a9fd36c03270d975fbee12fd3814 100644 (file)
@@ -893,8 +893,8 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
                ret = nft_cmd_chain_user_add(h, chain, *table);
                break;
        case CMD_DELETE_CHAIN:
-               ret = nft_cmd_chain_user_del(h, chain, *table,
-                                        options & OPT_VERBOSE);
+               ret = nft_cmd_chain_del(h, chain, *table,
+                                       options & OPT_VERBOSE);
                break;
        case CMD_RENAME_CHAIN:
                ret = nft_cmd_chain_user_rename(h, chain, *table, newname);
index 6e5ecd4864fa55c046bffa8aa37e946e4b11859e..23023ce13e4b8950558f326b8806db590af5e608 100644 (file)
@@ -771,7 +771,7 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table,
                                        chain = argv[optind];
                                        optind++;
                                }
-                               ret = nft_cmd_chain_user_del(h, chain, *table, 0);
+                               ret = nft_cmd_chain_del(h, chain, *table, 0);
                                break;
                        }
 
index daa9b137b5fa4846a90f91591bbdbcd8a8f2ba91..0a700e08474009f6d84d15d53846d7579d802d98 100644 (file)
@@ -998,8 +998,8 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
                ret = nft_cmd_chain_user_add(h, p.chain, p.table);
                break;
        case CMD_DELETE_CHAIN:
-               ret = nft_cmd_chain_user_del(h, p.chain, p.table,
-                                        cs.options & OPT_VERBOSE);
+               ret = nft_cmd_chain_del(h, p.chain, p.table,
+                                       cs.options & OPT_VERBOSE);
                break;
        case CMD_RENAME_CHAIN:
                ret = nft_cmd_chain_user_rename(h, p.chain, p.table, p.newname);