summaryrefslogtreecommitdiffstats
path: root/iptables/nft.c
diff options
context:
space:
mode:
authorFlorian Westphal <fw@strlen.de>2021-08-14 19:46:43 +0200
committerFlorian Westphal <fw@strlen.de>2021-09-07 14:16:07 +0200
commit61e85e3192deaff3b9dd1eb9270863acc7a26311 (patch)
tree2f5d28c03235d25b2cef5f1e0f64b928ed551c5f /iptables/nft.c
parent544e7dc1541e4db3abc9896ff757e7642c97738e (diff)
iptables-nft: allow removal of empty builtin chains
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>
Diffstat (limited to 'iptables/nft.c')
-rw-r--r--iptables/nft.c78
1 files changed, 51 insertions, 27 deletions
diff --git a/iptables/nft.c b/iptables/nft.c
index c9ed38bd..89dde9ec 100644
--- a/iptables/nft.c
+++ b/iptables/nft.c
@@ -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" },