netfilter-devel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH nft 0/4] fix list chain x y with anonymous chains
@ 2022-01-12  0:33 Pablo Neira Ayuso
  2022-01-12  0:33 ` [PATCH nft 1/4] src: do not use the nft_cache_filter object from mnl.c Pablo Neira Ayuso
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Pablo Neira Ayuso @ 2022-01-12  0:33 UTC (permalink / raw)
  To: netfilter-devel

Hi,

Patches 1 to 3 are cache preparation work.

Then, patch 4 fixes listing

 # nft list chain x y
 table ip x {
        chain y {
                jump {
                        accept
                }
        }
 }

This is broken in the nftables 1.0.1 release.

See https://bugzilla.netfilter.org/show_bug.cgi?id=1577

Pablo Neira Ayuso (4):
  src: do not use the nft_cache_filter object from mnl.c
  cache: do not set error code twice
  cache: add helper function to fill up the rule cache
  src: 'nft list chain' prints anonymous chains correctly

 include/cache.h                               |   3 +
 include/mnl.h                                 |   2 +-
 include/netlink.h                             |   1 +
 src/cache.c                                   | 113 ++++++++++++------
 src/mnl.c                                     |  12 +-
 src/netlink_delinearize.c                     |   8 ++
 .../testcases/cache/0010_implicit_chain_0     |  19 +++
 7 files changed, 113 insertions(+), 45 deletions(-)
 create mode 100755 tests/shell/testcases/cache/0010_implicit_chain_0

-- 
2.30.2


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH nft 1/4] src: do not use the nft_cache_filter object from mnl.c
  2022-01-12  0:33 [PATCH nft 0/4] fix list chain x y with anonymous chains Pablo Neira Ayuso
@ 2022-01-12  0:33 ` Pablo Neira Ayuso
  2022-01-12  0:33 ` [PATCH nft 2/4] cache: do not set error code twice Pablo Neira Ayuso
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Pablo Neira Ayuso @ 2022-01-12  0:33 UTC (permalink / raw)
  To: netfilter-devel

Pass the table and chain strings to mnl_nft_rule_dump() instead.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 include/mnl.h |  2 +-
 src/cache.c   |  9 ++++++++-
 src/mnl.c     | 12 +++++-------
 3 files changed, 14 insertions(+), 9 deletions(-)

diff --git a/include/mnl.h b/include/mnl.h
index b006192cf7b2..a4abe1ae3242 100644
--- a/include/mnl.h
+++ b/include/mnl.h
@@ -34,7 +34,7 @@ int mnl_nft_rule_del(struct netlink_ctx *ctx, struct cmd *cmd);
 int mnl_nft_rule_replace(struct netlink_ctx *ctx, struct cmd *cmd);
 
 struct nftnl_rule_list *mnl_nft_rule_dump(struct netlink_ctx *ctx, int family,
-					  const struct nft_cache_filter *filter);
+					  const char *table, const char *chain);
 
 int mnl_nft_chain_add(struct netlink_ctx *ctx, struct cmd *cmd,
 		      unsigned int flags);
diff --git a/src/cache.c b/src/cache.c
index 6494e4743f8d..6ca6bbc6645b 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -478,8 +478,15 @@ static int rule_cache_init(struct netlink_ctx *ctx, const struct handle *h,
 			   const struct nft_cache_filter *filter)
 {
 	struct nftnl_rule_list *rule_cache;
+	const char *table;
+	const char *chain;
 
-	rule_cache = mnl_nft_rule_dump(ctx, h->family, filter);
+	if (filter) {
+		table = filter->list.table;
+		chain = filter->list.chain;
+	}
+
+	rule_cache = mnl_nft_rule_dump(ctx, h->family, table, chain);
 	if (rule_cache == NULL) {
 		if (errno == EINTR)
 			return -1;
diff --git a/src/mnl.c b/src/mnl.c
index 5413f8658f9b..6be991a4827c 100644
--- a/src/mnl.c
+++ b/src/mnl.c
@@ -654,7 +654,7 @@ err_free:
 }
 
 struct nftnl_rule_list *mnl_nft_rule_dump(struct netlink_ctx *ctx, int family,
-					  const struct nft_cache_filter *filter)
+					  const char *table, const char *chain)
 {
 	char buf[MNL_SOCKET_BUFFER_SIZE];
 	struct nftnl_rule_list *nlr_list;
@@ -662,16 +662,14 @@ struct nftnl_rule_list *mnl_nft_rule_dump(struct netlink_ctx *ctx, int family,
 	struct nlmsghdr *nlh;
 	int ret;
 
-	if (filter && filter->list.table) {
+	if (table) {
 		nlr = nftnl_rule_alloc();
 		if (!nlr)
 			memory_allocation_error();
 
-		nftnl_rule_set_str(nlr, NFTNL_RULE_TABLE,
-				   filter->list.table);
-		if (filter->list.chain)
-			nftnl_rule_set_str(nlr, NFTNL_RULE_CHAIN,
-					   filter->list.chain);
+		nftnl_rule_set_str(nlr, NFTNL_RULE_TABLE, table);
+		if (chain)
+			nftnl_rule_set_str(nlr, NFTNL_RULE_CHAIN, chain);
 	}
 
 	nlr_list = nftnl_rule_list_alloc();
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH nft 2/4] cache: do not set error code twice
  2022-01-12  0:33 [PATCH nft 0/4] fix list chain x y with anonymous chains Pablo Neira Ayuso
  2022-01-12  0:33 ` [PATCH nft 1/4] src: do not use the nft_cache_filter object from mnl.c Pablo Neira Ayuso
@ 2022-01-12  0:33 ` Pablo Neira Ayuso
  2022-01-12  0:34 ` [PATCH nft 3/4] cache: add helper function to fill up the rule cache Pablo Neira Ayuso
  2022-01-12  0:34 ` [PATCH nft 4/4] src: 'nft list chain' prints anonymous chains correctly Pablo Neira Ayuso
  3 siblings, 0 replies; 5+ messages in thread
From: Pablo Neira Ayuso @ 2022-01-12  0:33 UTC (permalink / raw)
  To: netfilter-devel

The 'ret' variable is already set to a negative value to report an
error, do not set it again to a negative value.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 src/cache.c | 28 +++++++---------------------
 1 file changed, 7 insertions(+), 21 deletions(-)

diff --git a/src/cache.c b/src/cache.c
index 6ca6bbc6645b..0e9e7fe5381d 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -847,10 +847,8 @@ static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags,
 	list_for_each_entry(table, &ctx->nft->cache.table_cache.list, cache.list) {
 		if (flags & NFT_CACHE_SET_BIT) {
 			ret = set_cache_init(ctx, table, set_list);
-			if (ret < 0) {
-				ret = -1;
+			if (ret < 0)
 				goto cache_fails;
-			}
 		}
 		if (flags & NFT_CACHE_SETELEM_BIT) {
 			list_for_each_entry(set, &table->set_cache.list, cache.list) {
@@ -862,10 +860,8 @@ static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags,
 
 				ret = netlink_list_setelems(ctx, &set->handle,
 							    set);
-				if (ret < 0) {
-					ret = -1;
+				if (ret < 0)
 					goto cache_fails;
-				}
 			}
 		} else if (flags & NFT_CACHE_SETELEM_MAYBE) {
 			list_for_each_entry(set, &table->set_cache.list, cache.list) {
@@ -877,25 +873,19 @@ static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags,
 
 				ret = netlink_list_setelems(ctx, &set->handle,
 							    set);
-				if (ret < 0) {
-					ret = -1;
+				if (ret < 0)
 					goto cache_fails;
-				}
 			}
 		}
 		if (flags & NFT_CACHE_CHAIN_BIT) {
 			ret = chain_cache_init(ctx, table, chain_list);
-			if (ret < 0) {
-				ret = -1;
+			if (ret < 0)
 				goto cache_fails;
-			}
 		}
 		if (flags & NFT_CACHE_FLOWTABLE_BIT) {
 			ret = ft_cache_init(ctx, table, ft_list);
-			if (ret < 0) {
-				ret = -1;
+			if (ret < 0)
 				goto cache_fails;
-			}
 		}
 		if (flags & NFT_CACHE_OBJECT_BIT) {
 			obj_list = obj_cache_dump(ctx, table);
@@ -907,10 +897,8 @@ static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags,
 
 			nftnl_obj_list_free(obj_list);
 
-			if (ret < 0) {
-				ret = -1;
+			if (ret < 0)
 				goto cache_fails;
-			}
 		}
 
 		if (flags & NFT_CACHE_RULE_BIT) {
@@ -927,10 +915,8 @@ static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags,
 
 				list_move_tail(&rule->list, &chain->rules);
 			}
-			if (ret < 0) {
-				ret = -1;
+			if (ret < 0)
 				goto cache_fails;
-			}
 		}
 	}
 
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH nft 3/4] cache: add helper function to fill up the rule cache
  2022-01-12  0:33 [PATCH nft 0/4] fix list chain x y with anonymous chains Pablo Neira Ayuso
  2022-01-12  0:33 ` [PATCH nft 1/4] src: do not use the nft_cache_filter object from mnl.c Pablo Neira Ayuso
  2022-01-12  0:33 ` [PATCH nft 2/4] cache: do not set error code twice Pablo Neira Ayuso
@ 2022-01-12  0:34 ` Pablo Neira Ayuso
  2022-01-12  0:34 ` [PATCH nft 4/4] src: 'nft list chain' prints anonymous chains correctly Pablo Neira Ayuso
  3 siblings, 0 replies; 5+ messages in thread
From: Pablo Neira Ayuso @ 2022-01-12  0:34 UTC (permalink / raw)
  To: netfilter-devel

Add a helper function to dump the rules and add them to the
corresponding chain.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 src/cache.c | 41 +++++++++++++++++++++++++----------------
 1 file changed, 25 insertions(+), 16 deletions(-)

diff --git a/src/cache.c b/src/cache.c
index 0e9e7fe5381d..14957f2de3a9 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -474,7 +474,7 @@ static int list_rule_cb(struct nftnl_rule *nlr, void *data)
 	return 0;
 }
 
-static int rule_cache_init(struct netlink_ctx *ctx, const struct handle *h,
+static int rule_cache_dump(struct netlink_ctx *ctx, const struct handle *h,
 			   const struct nft_cache_filter *filter)
 {
 	struct nftnl_rule_list *rule_cache;
@@ -811,6 +811,29 @@ static int cache_init_tables(struct netlink_ctx *ctx, struct handle *h,
 	return 0;
 }
 
+static int rule_init_cache(struct netlink_ctx *ctx, struct table *table,
+			   const struct nft_cache_filter *filter)
+{
+	struct rule *rule, *nrule;
+	struct chain *chain;
+	int ret;
+
+	ret = rule_cache_dump(ctx, &table->handle, filter);
+
+	list_for_each_entry_safe(rule, nrule, &ctx->list, list) {
+		chain = chain_cache_find(table, rule->handle.chain.name);
+		if (!chain)
+			chain = chain_binding_lookup(table,
+						     rule->handle.chain.name);
+		if (!chain)
+			return -1;
+
+		list_move_tail(&rule->list, &chain->rules);
+	}
+
+	return ret;
+}
+
 static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags,
 			      const struct nft_cache_filter *filter)
 {
@@ -818,9 +841,7 @@ static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags,
 	struct nftnl_chain_list *chain_list = NULL;
 	struct nftnl_set_list *set_list = NULL;
 	struct nftnl_obj_list *obj_list;
-	struct rule *rule, *nrule;
 	struct table *table;
-	struct chain *chain;
 	struct set *set;
 	int ret = 0;
 
@@ -902,19 +923,7 @@ static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags,
 		}
 
 		if (flags & NFT_CACHE_RULE_BIT) {
-			ret = rule_cache_init(ctx, &table->handle, filter);
-			list_for_each_entry_safe(rule, nrule, &ctx->list, list) {
-				chain = chain_cache_find(table, rule->handle.chain.name);
-				if (!chain)
-					chain = chain_binding_lookup(table,
-							rule->handle.chain.name);
-				if (!chain) {
-					ret = -1;
-					goto cache_fails;
-				}
-
-				list_move_tail(&rule->list, &chain->rules);
-			}
+			ret = rule_init_cache(ctx, table, filter);
 			if (ret < 0)
 				goto cache_fails;
 		}
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH nft 4/4] src: 'nft list chain' prints anonymous chains correctly
  2022-01-12  0:33 [PATCH nft 0/4] fix list chain x y with anonymous chains Pablo Neira Ayuso
                   ` (2 preceding siblings ...)
  2022-01-12  0:34 ` [PATCH nft 3/4] cache: add helper function to fill up the rule cache Pablo Neira Ayuso
@ 2022-01-12  0:34 ` Pablo Neira Ayuso
  3 siblings, 0 replies; 5+ messages in thread
From: Pablo Neira Ayuso @ 2022-01-12  0:34 UTC (permalink / raw)
  To: netfilter-devel

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                               |  3 ++
 include/netlink.h                             |  1 +
 src/cache.c                                   | 37 +++++++++++++++++++
 src/netlink_delinearize.c                     |  8 ++++
 .../testcases/cache/0010_implicit_chain_0     | 19 ++++++++++
 5 files changed, 68 insertions(+)
 create mode 100755 tests/shell/testcases/cache/0010_implicit_chain_0

diff --git a/include/cache.h b/include/cache.h
index d185f3cfeda0..b6c7d48bfba6 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 0e439061e380..e8e0f68ae1a4 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 14957f2de3a9..630d6ae1307c 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 323e9150cdf6..0ea89135cc9a 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);
@@ -3141,6 +3148,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 000000000000..0ab0db957cf2
--- /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
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2022-01-12  0:34 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-01-12  0:33 [PATCH nft 0/4] fix list chain x y with anonymous chains Pablo Neira Ayuso
2022-01-12  0:33 ` [PATCH nft 1/4] src: do not use the nft_cache_filter object from mnl.c Pablo Neira Ayuso
2022-01-12  0:33 ` [PATCH nft 2/4] cache: do not set error code twice Pablo Neira Ayuso
2022-01-12  0:34 ` [PATCH nft 3/4] cache: add helper function to fill up the rule cache Pablo Neira Ayuso
2022-01-12  0:34 ` [PATCH nft 4/4] src: 'nft list chain' prints anonymous chains correctly Pablo Neira Ayuso

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).