newnat patch

From kadlec@blackhole.kfki.hu Mon Sep 17 11:06:42 2001
Date: Mon, 18 Jun 2001 12:11:00 +0200 (CEST)
From: Jozsef Kadlecsik 
To: Harald Welte 
Cc: Netfilter Development Mailinglist 
Subject: Re: Status of the newnat code

Hi Harald!

On Fri, 15 Jun 2001, Harald Welte wrote:

> > > As for the DoS: the multirel stuff (or the client) is going to have to
> > > restrict numbers.  For FTP it's easy.  For others it might be more of
> > > a judgement call...
> >
> > I have written a restricted version of the newnat code: at registering a
> > new conntrack helper, one must define the max number of parallel expected
> > connections (zero means no limit). I haven't tested it yet.
>
> Yes, as already indicated, this feature is needed (and planned from the
> beginning on, as you can read in the comments of the code).
>
> > Do I waste my time? Are you or Harald working on such a new version of
> > the code?
>
> Well, I don't recommend anybody making changes to the code currently, as
> it is very 'dynamic'. That's why it isn't in patch-o-matic yet. Suggestions,
> Comments and feature-requests are welcome.
>
> Could you send me an incremental patch? I'll try to apply.

The patch below adds the following new (untested) features:

- max number of simultaneous expected connections per helper introduced
- if the max number of simultaneous expected connection is reached, then
  the most recent expected entry is reused (resent packet is assumed)
- if there are unused entries in the sibling_list (i.e. the expected
  connection is in the conntrack table and not expected any more), then
  those entries are reused as well (otherwise for example a simple FTP
  session could create a long-long sibling_list with a single relevant
  entry on it).

Regards,
Jozsef
-
E-mail  : kadlec@blackhole.kfki.hu, kadlec@sunserv.kfki.hu
WWW-Home: http://www.kfki.hu/~kadlec
Address : KFKI Research Institute for Particle and Nuclear Physics
          H-1525 Budapest 114, POB. 49, Hungary


diff -urN --exclude-from=diff.exclude linux-2.4.5/include/linux/netfilter_ipv4.newnat1/ip_conntrack.h linux-2.4.5/include/linux/netfilter_ipv4.newnat2/ip_conntrack.h
--- linux-2.4.5/include/linux/netfilter_ipv4.newnat1/ip_conntrack.h	Tue Jun 12 09:10:50 2001
+++ linux-2.4.5/include/linux/netfilter_ipv4.newnat2/ip_conntrack.h	Mon Jun 18 11:09:44 2001
@@ -126,6 +126,9 @@
 	/* If we're expecting another related connection, this will be
            in expected linked list */
 	struct list_head sibling_list;
+
+	/* Current number of expected connections */
+	atomic_t expecting;

 	/* If we were expected by an expectation, this will be it */
 	struct ip_conntrack_expect *master;
diff -urN --exclude-from=diff.exclude linux-2.4.5/include/linux/netfilter_ipv4.newnat1/ip_conntrack_helper.h linux-2.4.5/include/linux/netfilter_ipv4.newnat2/ip_conntrack_helper.h
--- linux-2.4.5/include/linux/netfilter_ipv4.newnat1/ip_conntrack_helper.h	Tue Jun 12 09:10:50 2001
+++ linux-2.4.5/include/linux/netfilter_ipv4.newnat2/ip_conntrack_helper.h	Mon Jun 18 11:11:19 2001
@@ -14,6 +14,9 @@
 	struct ip_conntrack_tuple tuple;
 	struct ip_conntrack_tuple mask;

+	/* Maximum number of concurrent expected connections */
+	unsigned int max_expected;
+
 	/* Function to call when data passes; return verdict, or -1 to
            invalidate. */
 	int (*help)(const struct iphdr *, size_t len,
diff -urN --exclude-from=diff.exclude linux-2.4.5/net/ipv4/netfilter.newnat1/ip_conntrack_core.c linux-2.4.5/net/ipv4/netfilter.newnat2/ip_conntrack_core.c
--- linux-2.4.5/net/ipv4/netfilter.newnat1/ip_conntrack_core.c	Tue Jun 12 09:10:50 2001
+++ linux-2.4.5/net/ipv4/netfilter.newnat2/ip_conntrack_core.c	Mon Jun 18 12:04:45 2001
@@ -163,6 +163,8 @@
 	/* delete from global and local lists */
 	list_del(&expect->list);
 	list_del(&expect->expected_list);
+	if (!expect->sibling)
+		atomic_dec(&expect->expectant->expecting);
 	kfree(expect);
 }

@@ -616,6 +618,7 @@
 		expected->sibling = conntrack;
 		IP_NF_ASSERT(master_ct(conntrack));
 		LIST_DELETE(&expect_list, expected);
+		atomic_dec(&expected->expectant->expecting);
 		nf_conntrack_get(&master_ct(conntrack)->infos[0]);
 	}
 	atomic_inc(&ip_conntrack_count);
@@ -786,31 +789,58 @@
 	return ip_ct_tuple_mask_cmp(&i->tuple, &new->tuple, &intersect_mask);
 }

+static inline int reusable(const struct ip_conntrack_expect *expect)
+{
+	return (expect->sibling != NULL);
+}
+
 /* Allocate a new expectation */
 struct ip_conntrack_expect *
 ip_conntrack_alloc_expect(struct ip_conntrack *related_to)
 {
 	struct ip_conntrack_expect *expect;

-	/* FIXME: Ideally we want to have a helper-defined limit
-	 * for the maximum number of expectations for one master conn -HW */
+	if (related_to->helper->max_expected
+	    && atomic_read(&related_to->expecting) >= related_to->helper->max_expected) {
+	    	/* Reuse the most recent expected connection entry:
+	    	   assume as a resent packet */
+	    	DEBUGP("ip_conntrack: max number of expected connections (%i) reached\n",
+	    	       related_to->helper->max_expected);
+		WRITE_LOCK(&ip_conntrack_lock);
+	    	expect = (struct ip_conntrack_expect *)&related_to->sibling_list;
+		list_del(&expect->expected_list);
+		list_del(&expect->list);
+		WRITE_UNLOCK(&ip_conntrack_lock);
+	    	goto init;
+	}
+	atomic_inc(&related_to->expecting);
+
+	/* Reuse free entry */
+	WRITE_LOCK(&ip_conntrack_lock);
+	expect = LIST_FIND(&related_to->sibling_list, reusable,
+			   struct ip_conntrack_expect *);
+	if (expect) {
+		list_del(&expect->expected_list);
+		WRITE_UNLOCK(&ip_conntrack_lock);
+		goto init;
+	}
+	WRITE_UNLOCK(&ip_conntrack_lock);

 	expect = (struct ip_conntrack_expect *)
 		 kmalloc(sizeof(*expect), GFP_ATOMIC);

 	if (!expect) {
+		atomic_dec(&related_to->expecting);
 		if (net_ratelimit())
 			printk("ip_conntrack: OOM allocating expect\n");
 		return NULL;
 	}
-
+init:
 	/* initialize */
 	memset(expect, 0, sizeof(*expect));
 	INIT_LIST_HEAD(&expect->list);
 	INIT_LIST_HEAD(&expect->expected_list);

-	/* FIXME: bump the above mentioned expectation count -HW */
-
 	return expect;
 }

@@ -825,12 +855,14 @@
 		      struct ip_conntrack_expect *, exp)) {
 		WRITE_UNLOCK(&ip_conntrack_lock);
 		DEBUGP("expect_related: busy!\n");
+		atomic_dec(&related_to->expecting);
+		kfree(exp);
 		return -EBUSY;
 	}

 	exp->expectant = related_to;
 	/* add to expected list for this connection */
-	list_add(&exp->expected_list, &related_to->sibling_list);
+	list_prepend(&related_to->sibling_list, &exp->expected_list);
 	/* add to global list of expectations */
 	list_prepend(&expect_list, &exp->list);

diff -urN --exclude-from=diff.exclude linux-2.4.5/net/ipv4/netfilter.newnat1/ip_conntrack_ftp.c linux-2.4.5/net/ipv4/netfilter.newnat2/ip_conntrack_ftp.c
--- linux-2.4.5/net/ipv4/netfilter.newnat1/ip_conntrack_ftp.c	Tue Jun 12 09:10:50 2001
+++ linux-2.4.5/net/ipv4/netfilter.newnat2/ip_conntrack_ftp.c	Thu Jun 14 11:28:56 2001
@@ -416,6 +416,7 @@
 		ftp[i].tuple.dst.protonum = IPPROTO_TCP;
 		ftp[i].mask.src.u.tcp.port = 0xFFFF;
 		ftp[i].mask.dst.protonum = 0xFFFF;
+		ftp[i].max_expected = 1;
 		ftp[i].help = help;
 		DEBUGP("ip_ct_ftp: registering helper for port %d\n",
 				ports[i]);
diff -urN --exclude-from=diff.exclude linux-2.4.5/net/ipv4/netfilter.newnat1/ip_nat_core.c linux-2.4.5/net/ipv4/netfilter.newnat2/ip_nat_core.c
--- linux-2.4.5/net/ipv4/netfilter.newnat1/ip_nat_core.c	Tue Jun 12 09:10:50 2001
+++ linux-2.4.5/net/ipv4/netfilter.newnat2/ip_nat_core.c	Thu Jun 14 11:54:03 2001
@@ -21,6 +21,7 @@
 #define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_nat_lock)
 #define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_nat_lock)

+#include 
 #include 
 #include 
 #include 
diff -urN --exclude-from=diff.exclude linux-2.4.5/net/ipv4/netfilter.newnat1/ip_nat_ftp.c linux-2.4.5/net/ipv4/netfilter.newnat2/ip_nat_ftp.c
--- linux-2.4.5/net/ipv4/netfilter.newnat1/ip_nat_ftp.c	Tue Jun 12 09:10:50 2001
+++ linux-2.4.5/net/ipv4/netfilter.newnat2/ip_nat_ftp.c	Thu Jun 14 11:50:31 2001
@@ -298,7 +298,7 @@

 static int __init init(void)
 {
-	int i, ret;
+	int i, ret = 0;
 	char *tmpname;

 	if (ports[0] == 0)
diff -urN --exclude-from=diff.exclude linux-2.4.5/net/ipv4/netfilter.newnat1/ip_nat_helper.c linux-2.4.5/net/ipv4/netfilter.newnat2/ip_nat_helper.c
--- linux-2.4.5/net/ipv4/netfilter.newnat1/ip_nat_helper.c	Fri Apr 27 23:15:01 2001
+++ linux-2.4.5/net/ipv4/netfilter.newnat2/ip_nat_helper.c	Thu Jun 14 11:54:40 2001
@@ -19,6 +19,7 @@
 #define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_nat_lock)
 #define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_nat_lock)

+#include 
 #include 
 #include 
 #include