From 57291e35fcf6dbbc2fb0bd6b0465a9a82b66eb93 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 12 Jan 2022 01:34:01 +0100 Subject: src: 'nft list chain' prints anonymous chains correctly 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 --- src/cache.c | 37 +++++++++++++++++++++++++++++++++++++ src/netlink_delinearize.c | 8 ++++++++ 2 files changed, 45 insertions(+) (limited to 'src') diff --git a/src/cache.c b/src/cache.c index 14957f2d..630d6ae1 100644 --- a/src/cache.c +++ b/src/cache.c @@ -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; + } } } diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c index fd81e071..87316429 100644 --- a/src/netlink_delinearize.c +++ b/src/netlink_delinearize.c @@ -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); -- cgit v1.2.3