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