[PATCH 055/103] netfilter: xtables2: per-rule match skeletal functions

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

 



Notes: In xt2 rules, the layer-2/3 match structure (e.g. struct
ip6t_ip6) is now a standalone entry_match, together with the
recently-transformed layer-2/3 matches.

Signed-off-by: Jan Engelhardt <jengelh@xxxxxxxxxx>
---
 include/linux/netfilter/x_tables.h |   34 +++++++++++
 net/netfilter/x_tables.c           |  116 ++++++++++++++++++++++++++++++++++++
 2 files changed, 150 insertions(+), 0 deletions(-)

diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
index 8addd6f..fbea89c 100644
--- a/include/linux/netfilter/x_tables.h
+++ b/include/linux/netfilter/x_tables.h
@@ -409,12 +409,34 @@ struct xt_table_info
 
 struct xt2_table;
 
+enum {
+	XT2_INV_L4PROTO = 1 << 0,
+};
+
 /**
  * @anchor:		list anchor for parent (xt2_chain.rule_list)
+ * @match_list:		list of called match extensions (xt2_entry_match)
+ * @l4proto:		layer-4 protocol used (needed for xt_check_*)
+ * @flags:		extra flags (see above)
  */
 struct xt2_rule {
 	struct list_head anchor;
+	struct list_head match_list;
 	struct xt2_chain *chain;
+	uint8_t l4proto, flags;
+};
+
+/**
+ * @anchor:	list anchor for parent (xt2_rule.match_list)
+ * @ext:	pointer to extension
+ * @data:	parameter block for extension (aka. "matchinfo")
+ * @dsize:	size of @data (since @ext->matchsize may be -1)
+ */
+struct xt2_entry_match {
+	struct list_head anchor;
+	const struct xt_match *ext;
+	void *data;
+	unsigned int dsize;
 };
 
 /**
@@ -422,12 +444,15 @@ struct xt2_rule {
  * @rule_list:	list of struct xt2_rule
  * @name:	name of chain
  * @table:	back link to table chain is contained in
+ * @comefrom:	bitmask from which hooks the chain is entered
+ * 		(currently needed for xt_check_*)
  */
 struct xt2_chain {
 	struct list_head anchor;
 	struct list_head rule_list;
 	char name[31];
 	struct xt2_table *table;
+	unsigned int comefrom;
 };
 
 /**
@@ -613,6 +638,8 @@ extern void xt_hook_unlink(const struct xt_table *, struct nf_hook_ops *);
 extern void *xt_repldata_create(const struct xt_table *);
 
 extern struct xt2_rule *xt2_rule_new(struct xt2_chain *);
+extern int xt2_rule_add_match(struct xt2_rule *, const char *, uint8_t,
+	const void *, unsigned int, bool);
 
 extern struct xt2_chain *xt2_chain_new(struct xt2_table *, const char *);
 extern void xt2_chain_append(struct xt2_rule *);
@@ -624,6 +651,13 @@ extern int xt2_table_register(struct net *, struct xt2_table *);
 extern struct xt2_table *xt2_table_replace(struct net *, struct xt2_table *);
 extern void xt2_table_destroy(struct net *, struct xt2_table *);
 
+static inline int
+xt2_rule_add_oldmatch(struct xt2_rule *rule, const struct xt_entry_match *m)
+{
+	return xt2_rule_add_match(rule, m->u.user.name, m->u.user.revision,
+	       m->data, m->u.match_size - sizeof(*m), true);
+}
+
 static inline struct xt2_table *
 xt2_table_lookup(struct net *net, const char *name, uint8_t nfproto,
                  unsigned int lock_mask)
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index 3906dfb..0d50942 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -1308,15 +1308,131 @@ struct xt2_rule *xt2_rule_new(struct xt2_chain *chain)
 	if (rule == NULL)
 		return NULL;
 
+	rule->l4proto = 0;
+	rule->flags = 0;
 	rule->chain = chain;
 	INIT_LIST_HEAD(&rule->anchor);
+	INIT_LIST_HEAD(&rule->match_list);
 	return rule;
 }
 EXPORT_SYMBOL_GPL(xt2_rule_new);
 
+/**
+ * Find the struct ip6t_ip6 from an xt2 rule. Compat needs this, for now.
+ * Returns %NULL if not found.
+ */
+static void *xt2_entryinfo_mt_get(const struct xt2_rule *rule)
+{
+	const struct xt2_entry_match *ematch;
+
+	if (list_empty(&rule->match_list))
+		return NULL;
+	ematch = list_first_entry(&rule->match_list, typeof(*ematch), anchor);
+
+	/* The entryinfo is always in first place in xt1-compat mode. */
+	switch (rule->chain->table->nfproto) {
+	case NFPROTO_IPV4:
+		if (strcmp(ematch->ext->name, "ipv4") != 0)
+			return NULL;
+		break;
+	case NFPROTO_IPV6:
+		if (strcmp(ematch->ext->name, "ipv6") != 0)
+			return NULL;
+		break;
+	case NFPROTO_ARP:
+		if (strcmp(ematch->ext->name, "arp") != 0)
+			return NULL;
+		break;
+	case NFPROTO_BRIDGE:
+		if (strcmp(ematch->ext->name, "eth") != 0)
+			return NULL;
+		break;
+	default:
+		return NULL;
+	}
+
+	return ematch->data;
+}
+
+/**
+ * @ext_name:	name of extension
+ * @ext_rev:	requested revision
+ * @data:	private extension data block (parameters, etc.)
+ * @dsize:	size of supplied data
+ */
+int xt2_rule_add_match(struct xt2_rule *rule, const char *ext_name,
+                       uint8_t ext_rev, const void *data, unsigned int dsize,
+                       bool check_pad)
+{
+	const uint8_t nfproto = rule->chain->table->nfproto;
+	struct xt2_entry_match *ematch;
+	struct xt_mtchk_param mtpar;
+	const struct xt_match *ext;
+	int ret;
+
+	ext = try_then_request_module(xt_find_match(nfproto,
+	      ext_name, ext_rev), "%st_%s", xt_prefix[nfproto], ext_name);
+	if (ext == NULL)
+		return -ENOENT;
+	if (IS_ERR(ext))
+		return PTR_ERR(ext);
+
+	ret = -ENOMEM;
+	ematch = kmalloc(sizeof(*ematch), GFP_KERNEL);
+	if (ematch == NULL)
+		goto put_module;
+	ematch->ext   = ext;
+	ematch->data  = kmemdup(data, dsize, GFP_KERNEL);
+	ematch->dsize = dsize;
+	if (ematch->data == NULL)
+		goto free_ematch;
+
+	mtpar.table     = rule->chain->table->name;
+	mtpar.match     = ext;
+	mtpar.matchinfo = ematch->data;
+	mtpar.hook_mask = rule->chain->comefrom;
+	mtpar.family    = rule->chain->table->nfproto;
+	mtpar.entryinfo = xt2_entryinfo_mt_get(rule);
+	ret = xt_check_match(&mtpar, dsize, rule->l4proto,
+	      rule->flags & XT2_INV_L4PROTO, check_pad);
+	if (ret < 0)
+		goto free_edata;
+
+	INIT_LIST_HEAD(&ematch->anchor);
+	list_add_tail(&ematch->anchor, &rule->match_list);
+	return 0;
+
+ free_edata:
+	kfree(ematch->data);
+ free_ematch:
+	kfree(ematch);
+ put_module:
+	module_put(ext->me);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(xt2_rule_add_match);
+
 static void xt2_rule_free(struct xt2_rule *rule)
 {
+	struct xt2_entry_match *ematch, *next_ematch;
+	struct xt_mtdtor_param mtpar;
+
+	mtpar.family = rule->chain->table->nfproto;
 	list_del(&rule->anchor);
+
+	list_for_each_entry_safe(ematch, next_ematch,
+	    &rule->match_list, anchor) {
+		list_del(&ematch->anchor);
+		/* Note: ematch->ext is never NULL. */
+		if (ematch->ext->destroy != NULL) {
+			mtpar.match     = ematch->ext;
+			mtpar.matchinfo = ematch->data;
+			ematch->ext->destroy(&mtpar);
+		}
+		module_put(ematch->ext->me);
+		kfree(ematch->data);
+		kfree(ematch);
+	}
 	kfree(rule);
 }
 
-- 
1.6.3.3

--
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