]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
src: 'nft list chain' prints anonymous chains correctly
authorPablo Neira Ayuso <pablo@netfilter.org>
Wed, 12 Jan 2022 00:34:01 +0000 (01:34 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Sat, 15 Jan 2022 17:15:23 +0000 (18:15 +0100)
If the user is requesting a chain listing, e.g. nft list chain x y
and a rule refers to an anonymous chain that cannot be found in the cache,
then fetch such anonymous chain and its ruleset.

Closes: https://bugzilla.netfilter.org/show_bug.cgi?id=1577
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
include/cache.h
include/netlink.h
src/cache.c
src/netlink_delinearize.c
tests/shell/testcases/cache/0010_implicit_chain_0 [new file with mode: 0755]

index d185f3cfeda06eda7c79088c8e1a40e8ab7fb6ee..b6c7d48bfba6cdef6d4e5b04f15d0c5fa6c6bfee 100644 (file)
@@ -134,4 +134,7 @@ struct nft_cache {
        uint32_t                flags;
 };
 
+void nft_chain_cache_update(struct netlink_ctx *ctx, struct table *table,
+                           const char *chain);
+
 #endif /* _NFT_CACHE_H_ */
index 0e439061e3800799aeb19749067c23ee6f001ea0..e8e0f68ae1a49a139cb3539b7c76190b92bcf6a9 100644 (file)
@@ -39,6 +39,7 @@ struct netlink_parse_ctx {
        struct stmt             *stmt;
        struct expr             *registers[MAX_REGS + 1];
        unsigned int            debug_mask;
+       struct netlink_ctx      *nlctx;
 };
 
 struct rule_pp_ctx {
index 14957f2de3a99a252b49f635a09369ef595f3dac..630d6ae1307c2f8761fa65819873ff293594ec5d 100644 (file)
@@ -423,6 +423,21 @@ chain_cache_dump(struct netlink_ctx *ctx,
        return chain_list;
 }
 
+void nft_chain_cache_update(struct netlink_ctx *ctx, struct table *table,
+                           const char *chain)
+{
+       struct nftnl_chain_list *chain_list;
+
+       chain_list = mnl_nft_chain_dump(ctx, table->handle.family,
+                                       table->handle.table.name, chain);
+       if (!chain_list)
+               return;
+
+       chain_cache_init(ctx, table, chain_list);
+
+       nftnl_chain_list_free(chain_list);
+}
+
 void chain_cache_add(struct chain *chain, struct table *table)
 {
        uint32_t hash;
@@ -834,6 +849,22 @@ static int rule_init_cache(struct netlink_ctx *ctx, struct table *table,
        return ret;
 }
 
+static int implicit_chain_cache(struct netlink_ctx *ctx, struct table *table,
+                               const char *chain_name)
+{
+       struct nft_cache_filter filter;
+       struct chain *chain;
+       int ret = 0;
+
+       list_for_each_entry(chain, &table->chain_bindings, cache.list) {
+               filter.list.table = table->handle.table.name;
+               filter.list.chain = chain->handle.chain.name;
+               ret = rule_init_cache(ctx, table, &filter);
+       }
+
+       return ret;
+}
+
 static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags,
                              const struct nft_cache_filter *filter)
 {
@@ -926,6 +957,12 @@ static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags,
                        ret = rule_init_cache(ctx, table, filter);
                        if (ret < 0)
                                goto cache_fails;
+
+                       if (filter && filter->list.table && filter->list.chain) {
+                               ret = implicit_chain_cache(ctx, table, filter->list.chain);
+                               if (ret < 0)
+                                       goto cache_fails;
+                       }
                }
        }
 
index fd81e07151c2b70a2f1eae97c6a1e697fc4d0be4..873164299c6d456d8426b5d2a80f77859420bb2b 100644 (file)
@@ -218,6 +218,13 @@ static void netlink_parse_chain_verdict(struct netlink_parse_ctx *ctx,
 
        expr_chain_export(expr->chain, chain_name);
        chain = chain_binding_lookup(ctx->table, chain_name);
+
+       /* Special case: 'nft list chain x y' needs to pull in implicit chains */
+       if (!chain && !strncmp(chain_name, "__chain", strlen("__chain"))) {
+               nft_chain_cache_update(ctx->nlctx, ctx->table, chain_name);
+               chain = chain_binding_lookup(ctx->table, chain_name);
+       }
+
        if (chain) {
                ctx->stmt = chain_stmt_alloc(loc, chain, verdict);
                expr_free(expr);
@@ -3128,6 +3135,7 @@ struct rule *netlink_delinearize_rule(struct netlink_ctx *ctx,
        memset(&_ctx, 0, sizeof(_ctx));
        _ctx.msgs = ctx->msgs;
        _ctx.debug_mask = ctx->nft->debug_mask;
+       _ctx.nlctx = ctx;
 
        memset(&h, 0, sizeof(h));
        h.family = nftnl_rule_get_u32(nlr, NFTNL_RULE_FAMILY);
diff --git a/tests/shell/testcases/cache/0010_implicit_chain_0 b/tests/shell/testcases/cache/0010_implicit_chain_0
new file mode 100755 (executable)
index 0000000..0ab0db9
--- /dev/null
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+set -e
+
+EXPECTED="table ip f {
+       chain c {
+               jump {
+                       accept
+               }
+       }
+}"
+
+$NFT 'table ip f { chain c { jump { accept; }; }; }'
+GET="$($NFT list chain ip f c)"
+
+if [ "$EXPECTED" != "$GET" ] ; then
+       $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+       exit 1
+fi