[PATCH 5/8] Netfilter: Use ct_extend for helper pointer

Rusty Russell rusty at rustcorp.com.au
Wed Jan 12 21:59:00 CET 2005


Name: Use ct_extend for helper pointer
Status: Tested lightly under nfsim
Signed-off-by: Rusty Russell <rusty at rustcorp.com.au>

Most connections don't have a connection tracking helper.  So that
pointer is a good candidate to put in ct_extend.

Index: linux-2.6.10-bk14-Netfilter/net/ipv4/netfilter/ip_nat_core.c
===================================================================
--- linux-2.6.10-bk14-Netfilter.orig/net/ipv4/netfilter/ip_nat_core.c	2005-01-12 23:29:00.605426112 +1100
+++ linux-2.6.10-bk14-Netfilter/net/ipv4/netfilter/ip_nat_core.c	2005-01-12 23:43:00.822693672 +1100
@@ -283,7 +283,8 @@
 
 		/* Alter conntrack table so will recognize replies. */
 		invert_tuplepr(&reply, &new_tuple);
-		ip_conntrack_alter_reply(conntrack, &reply);
+		if (ip_conntrack_alter_reply(conntrack, &reply) != 0)
+			return NF_DROP;
 
 		/* Non-atomic: we own this at the moment. */
 		if (maniptype == IP_NAT_MANIP_SRC)
Index: linux-2.6.10-bk14-Netfilter/net/ipv4/netfilter/ip_conntrack_standalone.c
===================================================================
--- linux-2.6.10-bk14-Netfilter.orig/net/ipv4/netfilter/ip_conntrack_standalone.c	2005-01-12 23:41:09.571606408 +1100
+++ linux-2.6.10-bk14-Netfilter/net/ipv4/netfilter/ip_conntrack_standalone.c	2005-01-12 23:42:01.974639936 +1100
@@ -385,11 +385,17 @@
 
 	/* This is where we call the helper: as the packet goes out. */
 	ct = ip_conntrack_get(*pskb, &ctinfo);
-	if (ct && ct->helper) {
-		unsigned int ret;
-		ret = ct->helper->help(pskb, ct, ctinfo);
-		if (ret != NF_ACCEPT)
-			return ret;
+	if (ct) {
+		struct ip_conntrack_helper **helpp;
+
+		/* Don't need lock: ct not in hash yet. */
+		helpp = ct_extend_find(ct->ext, CTE_CT_HELPER);
+		if (helpp) {
+			unsigned int ret;
+			ret = (*helpp)->help(pskb, ct, ctinfo);
+			if (ret != NF_ACCEPT)
+				return ret;
+		}
 	}
 
 	/* We've seen it coming out the other side: confirm it */
Index: linux-2.6.10-bk14-Netfilter/include/linux/netfilter_ipv4/ip_nat.h
===================================================================
--- linux-2.6.10-bk14-Netfilter.orig/include/linux/netfilter_ipv4/ip_nat.h	2005-01-12 23:29:00.641420640 +1100
+++ linux-2.6.10-bk14-Netfilter/include/linux/netfilter_ipv4/ip_nat.h	2005-01-12 23:43:00.823693520 +1100
@@ -57,9 +57,6 @@
 {
 	struct list_head bysource;
 
-	/* Helper (NULL if none). */
-	struct ip_nat_helper *helper;
-
 	struct ip_nat_seq seq[IP_CT_DIR_MAX];
 };
 
Index: linux-2.6.10-bk14-Netfilter/include/linux/netfilter_ipv4/ip_conntrack.h
===================================================================
--- linux-2.6.10-bk14-Netfilter.orig/include/linux/netfilter_ipv4/ip_conntrack.h	2005-01-12 23:41:09.573606104 +1100
+++ linux-2.6.10-bk14-Netfilter/include/linux/netfilter_ipv4/ip_conntrack.h	2005-01-12 23:42:02.014633856 +1100
@@ -172,9 +172,6 @@
 	/* Current number of expected connections */
 	unsigned int expecting;
 
-	/* Helper, if any. */
-	struct ip_conntrack_helper *helper;
-
 	/* Storage reserved for other modules: */
 	union ip_conntrack_proto proto;
 
@@ -202,8 +199,8 @@
 /* get master conntrack via master expectation */
 #define master_ct(conntr) (conntr->master)
 
-/* Alter reply tuple (maybe alter helper). */
-extern void
+/* Alter reply tuple (maybe alter helper).  Returns 0 or -errno. */
+extern int
 ip_conntrack_alter_reply(struct ip_conntrack *conntrack,
 			 const struct ip_conntrack_tuple *newreply);
 
Index: linux-2.6.10-bk14-Netfilter/net/ipv4/netfilter/ipt_helper.c
===================================================================
--- linux-2.6.10-bk14-Netfilter.orig/net/ipv4/netfilter/ipt_helper.c	2005-01-12 23:29:00.605426112 +1100
+++ linux-2.6.10-bk14-Netfilter/net/ipv4/netfilter/ipt_helper.c	2005-01-12 23:42:02.015633704 +1100
@@ -18,6 +18,7 @@
 #include <linux/netfilter_ipv4/ip_conntrack_helper.h>
 #include <linux/netfilter_ipv4/ip_tables.h>
 #include <linux/netfilter_ipv4/ipt_helper.h>
+#include <linux/netfilter_ipv4/ct_extend.h>
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Martin Josefsson <gandalf at netfilter.org>");
@@ -40,6 +41,7 @@
 	const struct ipt_helper_info *info = matchinfo;
 	struct ip_conntrack *ct;
 	enum ip_conntrack_info ctinfo;
+	struct ip_conntrack_helper **helpp;
 	int ret = info->invert;
 	
 	ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
@@ -54,20 +56,21 @@
 	}
 
 	READ_LOCK(&ip_conntrack_lock);
-	if (!ct->master->helper) {
+	helpp = ct_extend_find(ct->master->ext, CTE_CT_HELPER);
+	if (!helpp) {
 		DEBUGP("ipt_helper: master ct %p has no helper\n", 
 			exp->expectant);
 		goto out_unlock;
 	}
 
 	DEBUGP("master's name = %s , info->name = %s\n", 
-		ct->master->helper->name, info->name);
+		(*helpp)->name, info->name);
 
 	if (info->name[0] == '\0')
 		ret ^= 1;
 	else
-		ret ^= !strncmp(ct->master->helper->name, info->name, 
-		                strlen(ct->master->helper->name));
+		ret ^= !strncmp((*helpp)->name, info->name, 
+		                strlen((*helpp)->name));
 out_unlock:
 	READ_UNLOCK(&ip_conntrack_lock);
 	return ret;
Index: linux-2.6.10-bk14-Netfilter/include/linux/netfilter_ipv4/ct_extend.h
===================================================================
--- linux-2.6.10-bk14-Netfilter.orig/include/linux/netfilter_ipv4/ct_extend.h	2005-01-12 23:41:58.520165096 +1100
+++ linux-2.6.10-bk14-Netfilter/include/linux/netfilter_ipv4/ct_extend.h	2005-01-12 23:43:16.845257872 +1100
@@ -7,12 +7,14 @@
 	CTE_MASQ,
 	CTE_FTP_CONN,
 	CTE_MARK,
+	CTE_CT_HELPER,
 	CTE_MAX,
 } __attribute__((packed));
 
 #define CTE_MASQ_TYPE char 	/* Actually char[IFNAMSIZ] */
 #define CTE_FTP_CONN_TYPE struct ip_ct_ftp_master
 #define CTE_MARK_TYPE unsigned long
+#define CTE_CT_HELPER_TYPE struct ip_conntrack_helper *
 
 /* Extensions: optional stuff which isn't permanently in struct. */
 struct ct_extend {
Index: linux-2.6.10-bk14-Netfilter/net/ipv4/netfilter/ip_conntrack_core.c
===================================================================
--- linux-2.6.10-bk14-Netfilter.orig/net/ipv4/netfilter/ip_conntrack_core.c	2005-01-12 23:41:09.578605344 +1100
+++ linux-2.6.10-bk14-Netfilter/net/ipv4/netfilter/ip_conntrack_core.c	2005-01-12 23:42:02.018633248 +1100
@@ -574,8 +574,19 @@
 		nf_conntrack_get(&conntrack->master->ct_general);
 		CONNTRACK_STAT_INC(expect_new);
 	} else {
-		conntrack->helper = ip_ct_find_helper(&repl_tuple);
+		struct ip_conntrack_helper *helper, **helpp;
 
+		helper = ip_ct_find_helper(&repl_tuple);
+		if (helper) {
+			helpp = ct_extend_add(&conntrack->ext, CTE_CT_HELPER,
+					      GFP_ATOMIC);
+			if (!helpp) {
+				kmem_cache_free(ip_conntrack_cachep,conntrack);
+				WRITE_UNLOCK(&ip_conntrack_lock);
+				return NULL;
+			}
+			*helpp = helper;
+		}
 		CONNTRACK_STAT_INC(new);
 	}
 
@@ -805,18 +816,19 @@
 	kmem_cache_free(ip_conntrack_expect_cachep, expect);
 }
 
-static void ip_conntrack_expect_insert(struct ip_conntrack_expect *exp)
+static void ip_conntrack_expect_insert(struct ip_conntrack_expect *exp,
+				       struct ip_conntrack_helper *helper)
 {
 	atomic_inc(&exp->master->ct_general.use);
 	exp->master->expecting++;
 	list_add(&exp->list, &ip_conntrack_expect_list);
 
-	if (exp->master->helper->timeout) {
+	if (helper->timeout) {
 		init_timer(&exp->timeout);
 		exp->timeout.data = (unsigned long)exp;
 		exp->timeout.function = expectation_timed_out;
 		exp->timeout.expires
-			= jiffies + exp->master->helper->timeout * HZ;
+			= jiffies + helper->timeout * HZ;
 		add_timer(&exp->timeout);
 	} else
 		exp->timeout.function = NULL;
@@ -840,12 +852,13 @@
 	}
 }
 
-static inline int refresh_timer(struct ip_conntrack_expect *i)
+static inline int refresh_timer(struct ip_conntrack_expect *i,
+				struct ip_conntrack_helper *helper)
 {
 	if (!del_timer(&i->timeout))
 		return 0;
 
-	i->timeout.expires = jiffies + i->master->helper->timeout*HZ;
+	i->timeout.expires = jiffies + helper->timeout*HZ;
 	add_timer(&i->timeout);
 	return 1;
 }
@@ -854,16 +867,20 @@
 {
 	struct ip_conntrack_expect *i;
 	int ret;
+	struct ip_conntrack_helper **helpp;
 
 	DEBUGP("ip_conntrack_expect_related %p\n", related_to);
 	DEBUGP("tuple: "); DUMP_TUPLE(&expect->tuple);
 	DEBUGP("mask:  "); DUMP_TUPLE(&expect->mask);
 
 	WRITE_LOCK(&ip_conntrack_lock);
+	helpp = ct_extend_find(expect->master->ext, CTE_CT_HELPER);
+	BUG_ON(!helpp || !*helpp);
+
 	list_for_each_entry(i, &ip_conntrack_expect_list, list) {
 		if (expect_matches(i, expect)) {
 			/* Refresh timer: if it's dying, ignore.. */
-			if (refresh_timer(i)) {
+			if (refresh_timer(i, *helpp)) {
 				ret = 0;
 				/* We don't need the one they've given us. */
 				ip_conntrack_expect_free(expect);
@@ -876,11 +893,11 @@
 	}
 
 	/* Will be over limit? */
-	if (expect->master->helper->max_expected && 
-	    expect->master->expecting >= expect->master->helper->max_expected)
+	if ((*helpp)->max_expected && 
+	    expect->master->expecting >= (*helpp)->max_expected)
 		evict_oldest_expect(expect->master);
 
-	ip_conntrack_expect_insert(expect);
+	ip_conntrack_expect_insert(expect, *helpp);
 	ret = 0;
 out:
 	WRITE_UNLOCK(&ip_conntrack_lock);
@@ -889,10 +906,11 @@
 
 /* Alter reply tuple (maybe alter helper).  This is for NAT, and is
    implicitly racy: see __ip_conntrack_confirm */
-void ip_conntrack_alter_reply(struct ip_conntrack *conntrack,
-			      const struct ip_conntrack_tuple *newreply)
+int ip_conntrack_alter_reply(struct ip_conntrack *conntrack,
+			     const struct ip_conntrack_tuple *newreply)
 {
-	WRITE_LOCK(&ip_conntrack_lock);
+	struct ip_conntrack_helper *helper, **helpp;
+
 	/* Should be unconfirmed, so not in hash table yet */
 	IP_NF_ASSERT(!is_confirmed(conntrack));
 
@@ -900,9 +918,25 @@
 	DUMP_TUPLE(newreply);
 
 	conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply;
-	if (!conntrack->master && conntrack->expecting == 0)
-		conntrack->helper = ip_ct_find_helper(newreply);
+	if (conntrack->master || conntrack->expecting)
+		return 0;
+
+	WRITE_LOCK(&ip_conntrack_lock);
+	helper = ip_ct_find_helper(newreply);
+	if (helper) {
+		helpp = ct_extend_find(conntrack->ext, CTE_CT_HELPER);
+		if (!helpp) {
+			helpp = ct_extend_add(&conntrack->ext, CTE_CT_HELPER,
+					      GFP_ATOMIC);
+			if (!helpp) {
+				READ_UNLOCK(&ip_conntrack_lock);
+				return -ENOMEM;
+			}
+		}
+		*helpp = helper;
+	}
 	WRITE_UNLOCK(&ip_conntrack_lock);
+	return 0;
 }
 
 int ip_conntrack_helper_register(struct ip_conntrack_helper *me)
@@ -918,8 +952,13 @@
 static inline int unhelp(struct ip_conntrack_tuple_hash *i,
 			 const struct ip_conntrack_helper *me)
 {
-	if (tuplehash_to_ctrack(i)->helper == me)
-		tuplehash_to_ctrack(i)->helper = NULL;
+	struct ip_conntrack_helper **helpp;
+	helpp = ct_extend_find(tuplehash_to_ctrack(i)->ext, CTE_CT_HELPER);
+
+	if (helpp && *helpp == me)
+		tuplehash_to_ctrack(i)->ext
+			= ct_extend_del(tuplehash_to_ctrack(i)->ext,
+					CTE_CT_HELPER);
 	return 0;
 }
 
@@ -934,7 +973,10 @@
 
 	/* Get rid of expectations */
 	list_for_each_entry_safe(exp, tmp, &ip_conntrack_expect_list, list) {
-		if (exp->master->helper == me && del_timer(&exp->timeout)) {
+		struct ip_conntrack_helper **helpp;
+		helpp = ct_extend_find(exp->master->ext, CTE_CT_HELPER);
+
+		if (*helpp == me && del_timer(&exp->timeout)) {
 			unlink_expect(exp);
 			destroy_expect(exp);
 		}
@@ -1178,6 +1220,13 @@
 				     * ip_conntrack_htable_size));
 }
 
+static struct ct_extend_type helper_extend =
+{
+	.len = sizeof(struct ip_conntrack_helper *),
+	.align = __alignof__(struct ip_conntrack_helper *),
+	.type = CTE_CT_HELPER,
+};
+
 /* Mishearing the voices in his head, our hero wonders how he's
    supposed to kill the mall. */
 void ip_conntrack_cleanup(void)
@@ -1196,6 +1245,7 @@
 	}
 
 	unregister_cte_mark();
+	unregister_ct_extend_type(&helper_extend);
 	kmem_cache_destroy(ip_conntrack_cachep);
 	kmem_cache_destroy(ip_conntrack_expect_cachep);
 	free_conntrack_hash();
@@ -1293,6 +1343,7 @@
 	/*  - and look it like as a confirmed connection */
 	set_bit(IPS_CONFIRMED_BIT, &ip_conntrack_untracked.status);
 
+	register_ct_extend_type(&helper_extend);
 	register_cte_mark();
 
 	return ret;




More information about the netfilter-devel mailing list