[PATCH 4/7] netfilter: xtables2: chain renaming support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



To keep in mind for later patches: for a ruleset to use
pointer-following chain jumps that work with the create-delete cycle
of renames of the target chain, it needs to point to something that
remains during that. What I thought up:

struct xt2_chain { char name[48]; struct xt2_p_chain *persistent; };
struct xt2_p_chain { struct xt2_chain *back; void *packed_data; };

and the ruleset pointing to a struct xt2_p_chain.

Signed-off-by: Jan Engelhardt <jengelh@xxxxxxxxxx>
---
 include/linux/netfilter/nfnetlink_xtables.h |    3 ++
 include/net/netfilter/x_tables2.h           |    2 +
 net/netfilter/xt2_core.c                    |   31 +++++++++++++++++
 net/netfilter/xt2_nfnetlink.c               |   47 +++++++++++++++++++++++++++
 4 files changed, 83 insertions(+), 0 deletions(-)

diff --git a/include/linux/netfilter/nfnetlink_xtables.h b/include/linux/netfilter/nfnetlink_xtables.h
index fe1b6ce..296012a 100644
--- a/include/linux/netfilter/nfnetlink_xtables.h
+++ b/include/linux/netfilter/nfnetlink_xtables.h
@@ -5,18 +5,21 @@ enum nfxt_msg_type {
 	NFXTM_IDENTIFY = 1,
 	NFXTM_CHAIN_NEW,
 	NFXTM_CHAIN_DEL,
+	NFXTM_CHAIN_MOVE,
 };
 
 /**
  * %NFXTA_NAME:			name of the object being operated on
  * %NFXTA_ERRNO:		system error code (%Exxx)
  * %NFXTA_XTERRNO:		NFXT-specific error code (cf. enum nfxt_errno)
+ * %NFXTA_NEW_NAME:		new name of object
  */
 enum nfxt_attr_type {
 	NFXTA_UNSPEC = 0,
 	NFXTA_NAME,
 	NFXTA_ERRNO,
 	NFXTA_XTERRNO,
+	NFXTA_NEW_NAME,
 };
 
 /**
diff --git a/include/net/netfilter/x_tables2.h b/include/net/netfilter/x_tables2.h
index b13eab7..198ec31 100644
--- a/include/net/netfilter/x_tables2.h
+++ b/include/net/netfilter/x_tables2.h
@@ -42,5 +42,7 @@ extern struct xt2_pernet_data *xtables2_pernet(struct net *);
 extern struct xt2_chain *xt2_chain_new(struct xt2_table *, const char *);
 extern struct xt2_chain *xt2_chain_lookup(struct xt2_table *, const char *);
 extern void xt2_chain_free(struct xt2_chain *);
+extern struct xt2_chain *xt2_chain_move(struct xt2_table *, const char *,
+					const char *);
 
 #endif /* _NET_NETFILTER_XTABLES2_H */
diff --git a/net/netfilter/xt2_core.c b/net/netfilter/xt2_core.c
index 5e7426d..5d8f155 100644
--- a/net/netfilter/xt2_core.c
+++ b/net/netfilter/xt2_core.c
@@ -100,6 +100,37 @@ void xt2_chain_free(struct xt2_chain *chain)
 EXPORT_SYMBOL_GPL(xt2_chain_free);
 
 /**
+ * @table:	table to add the new chain to
+ * @name:	current name for the chain; not %NULL
+ * @new_name:	new name for the chain; not %NULL
+ *
+ * Rename chain by means of a create-delete cycle. This is to avoid
+ * temporary invisiblity of the chain and/or duplicate chain names for readers.
+ *
+ * Caller should hold table lock.
+ */
+struct xt2_chain *xt2_chain_move(struct xt2_table *table, const char *old_name,
+				 const char *new_name)
+{
+	struct xt2_chain *old_chain, *new_chain;
+
+	if (strlen(new_name) >= ARRAY_SIZE(new_chain->name))
+		return ERR_PTR(-ENAMETOOLONG);
+	if (xt2_chain_lookup(table, new_name) != NULL)
+		return ERR_PTR(-EEXIST);
+	old_chain = xt2_chain_lookup(table, old_name);
+	if (old_chain == NULL)
+		return ERR_PTR(-ENOENT);
+	new_chain = xt2_chain_new(table, new_name);
+	if (IS_ERR(new_chain))
+		return new_chain;
+	/* - rule move magic here once that code appears */
+	xt2_chain_free(old_chain);
+	return new_chain;
+}
+EXPORT_SYMBOL_GPL(xt2_chain_move);
+
+/**
  * Create a new table with no chains and no rules.
  */
 static struct xt2_table *xt2_table_new(void)
diff --git a/net/netfilter/xt2_nfnetlink.c b/net/netfilter/xt2_nfnetlink.c
index b50e468d..9f29b34 100644
--- a/net/netfilter/xt2_nfnetlink.c
+++ b/net/netfilter/xt2_nfnetlink.c
@@ -253,10 +253,56 @@ xtnetlink_chain_del(struct sock *xtnl, struct sk_buff *iskb,
 	return ret;
 }
 
+static int
+xtnetlink_chain_move(struct sock *xtnl, struct sk_buff *iskb,
+		     const struct nlmsghdr *imsg,
+		     const struct nlattr *const *ad)
+{
+	struct xt2_pernet_data *pnet = xtables2_pernet(sock_net(xtnl));
+	struct xtnetlink_pktref ref = {.c_skb = iskb, .c_msg = imsg};
+	const char *old_name, *new_name;
+	const struct xt2_chain *chain;
+	const struct nlattr *attr;
+	struct xt2_table *table;
+	int ret;
+
+	attr = nlmsg_find_attr(imsg, sizeof(struct nfgenmsg), NFXTA_NAME);
+	if (attr == NULL)
+		return xtnetlink_error(xtnl, &ref, NFXTE_ATTRSET_INCOMPLETE);
+	old_name = nla_data(attr);
+	if (*old_name == '\0')
+		return xtnetlink_error(xtnl, &ref, NFXTE_CHAIN_NOENT);
+	attr = nlmsg_find_attr(imsg, sizeof(struct nfgenmsg), NFXTA_NEW_NAME);
+	if (attr == NULL)
+		return xtnetlink_error(xtnl, &ref, NFXTE_ATTRSET_INCOMPLETE);
+	new_name = nla_data(attr);
+	if (*new_name == '\0')
+		return xtnetlink_error(xtnl, &ref, NFXTE_CHAIN_INVALID_NAME);
+
+	mutex_lock(&pnet->master_lock);
+	table = pnet->master;
+	mutex_lock(&table->lock);
+	chain = xt2_chain_move(table, old_name, new_name);
+	ret   = IS_ERR(chain) ? PTR_ERR(chain) : 0;
+	mutex_unlock(&table->lock);
+	mutex_unlock(&pnet->master_lock);
+	switch (ret) {
+	case -ENAMETOOLONG:
+		return xtnetlink_error(xtnl, &ref, NFXTE_CHAIN_NAMETOOLONG);
+	case -EEXIST:
+		return xtnetlink_error(xtnl, &ref, NFXTE_CHAIN_EXISTS);
+	case -ENOENT:
+		return xtnetlink_error(xtnl, &ref, NFXTE_CHAIN_NOENT);
+	default:
+		return xtnetlink_error(xtnl, &ref, ret);
+	}
+}
+
 static const struct nla_policy xtnetlink_policy[] = {
 	[NFXTA_NAME] = {.type = NLA_NUL_STRING},
 	[NFXTA_ERRNO] = {.type = NLA_U32},
 	[NFXTA_XTERRNO] = {.type = NLA_U32},
+	[NFXTA_NEW_NAME] = {.type = NLA_NUL_STRING},
 };
 
 /*
@@ -272,6 +318,7 @@ static const struct nfnl_callback xtnetlink_callback[] = {
 	[NFXTM_IDENTIFY] = {.call = xtnetlink_identify, pol},
 	[NFXTM_CHAIN_NEW] = {.call = xtnetlink_chain_new, pol},
 	[NFXTM_CHAIN_DEL] = {.call = xtnetlink_chain_del, pol},
+	[NFXTM_CHAIN_MOVE] = {.call = xtnetlink_chain_move, pol},
 };
 #undef pol
 
-- 
1.7.7

--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Netfitler Users]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux