summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2022-01-12 01:34:01 +0100
committerPablo Neira Ayuso <pablo@netfilter.org>2022-01-15 18:15:23 +0100
commit57291e35fcf6dbbc2fb0bd6b0465a9a82b66eb93 (patch)
tree37728cad2d541382f69e9d292321ec3fb106985f
parente3d00ed1f657d5ce989a780990c6fb0097368d1e (diff)
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 <pablo@netfilter.org>
-rw-r--r--include/cache.h3
-rw-r--r--include/netlink.h1
-rw-r--r--src/cache.c37
-rw-r--r--src/netlink_delinearize.c8
-rwxr-xr-xtests/shell/testcases/cache/0010_implicit_chain_019
5 files changed, 68 insertions, 0 deletions
diff --git a/include/cache.h b/include/cache.h
index d185f3cf..b6c7d48b 100644
--- a/include/cache.h
+++ b/include/cache.h
@@ -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_ */
diff --git a/include/netlink.h b/include/netlink.h
index 0e439061..e8e0f68a 100644
--- a/include/netlink.h
+++ b/include/netlink.h
@@ -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 {
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);
diff --git a/tests/shell/testcases/cache/0010_implicit_chain_0 b/tests/shell/testcases/cache/0010_implicit_chain_0
new file mode 100755
index 00000000..0ab0db95
--- /dev/null
+++ b/tests/shell/testcases/cache/0010_implicit_chain_0
@@ -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