newnat patch
From kadlec@blackhole.kfki.hu Mon Sep 17 11:09:30 2001
Date: Fri, 22 Jun 2001 23:28:09 +0200 (CEST)
From: Jozsef Kadlecsik
To: Harald Welte
Cc: Netfilter Development Mailinglist
Subject: Re: Status of the newnat code
On Fri, 22 Jun 2001, Jozsef Kadlecsik wrote:
> So I wrote a version, in which the (naive) checking for resent packets is
> done in the core. It required to integrate ip_conntrack_alloc_expect into
> ip_conntrack_expect_related. Also, because all checks are done at holding
> the ip_conntrack_lock, I converted the expectations counter into a simple
> integer.
>
> It passed all (ftp) tests from the testsuite, so at least backward
> compatible :-). The incremental patch against the original newnat code is
> below.
Arrrgh, very sorry! Stupid, stupid me: incomplete patch, two lines were
missing.
However, there is a bigger problem, and I don't see a solution without
adding more data to the ip_conntrack_expect structure: iff we limit
the maximal number of simultaneous expectations and there is NAT and we
want to support resent packets, then as far as I see, it cannot be done
properly:
- first packet carrying the data of the expectation arrives
- conntrack detects it, registers the expectation
- NAT deregister the expectation and registers the NATed one
- resent packet arrives with the data of the same expectation
- conntrack can't check that it's resent data, because
the registered expectation it could compare to is NATed
It seems to me, something like
#ifdef CONFIG_IP_NF_NAT_NEEDED
/* Saved tuple, mask for conntrack */
struct ip_conntrack_tuple ct_tuple, ct_mask;
#endif
should be added to the ip_conntrack_expect structure.
Wish I were wrong...
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 Wed Jun 20 17:15:12 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 */
+ unsigned int 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 Wed Jun 20 17:31:22 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,
@@ -24,10 +27,7 @@
extern int ip_conntrack_helper_register(struct ip_conntrack_helper *);
extern void ip_conntrack_helper_unregister(struct ip_conntrack_helper *);
-struct ip_conntrack_expect *
-ip_conntrack_alloc_expect(struct ip_conntrack *related_to);
-
-/* Add an expected connection: can only have one per connection */
+/* Add an expected connection: can have more than one per connection */
extern int ip_conntrack_expect_related(struct ip_conntrack *related_to,
struct ip_conntrack_expect *exp);
extern void ip_conntrack_unexpect_related(struct ip_conntrack_expect *exp);
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 Fri Jun 22 19:10:00 2001
@@ -163,6 +163,8 @@
/* delete from global and local lists */
list_del(&expect->list);
list_del(&expect->expected_list);
+ if (!expect->sibling)
+ expect->expectant->expecting--;
kfree(expect);
}
@@ -182,8 +184,10 @@
/* we skip established expectations, as we want to delete
* the un-established ones only */
- if (exp->sibling)
+ if (exp->sibling) {
+ DEBUGP("destroy_expectations: skipping established %p of %p\n", exp->sibling, ct);
continue;
+ }
IP_NF_ASSERT(list_inlist(&expect_list, exp));
IP_NF_ASSERT(exp->expectant == ct);
@@ -616,6 +620,7 @@
expected->sibling = conntrack;
IP_NF_ASSERT(master_ct(conntrack));
LIST_DELETE(&expect_list, expected);
+ expected->expectant->expecting--;
nf_conntrack_get(&master_ct(conntrack)->infos[0]);
}
atomic_inc(&ip_conntrack_count);
@@ -786,53 +791,60 @@
return ip_ct_tuple_mask_cmp(&i->tuple, &new->tuple, &intersect_mask);
}
-/* 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 */
-
- expect = (struct ip_conntrack_expect *)
- kmalloc(sizeof(*expect), GFP_ATOMIC);
-
- if (!expect) {
- if (net_ratelimit())
- printk("ip_conntrack: OOM allocating expect\n");
- return NULL;
- }
-
- /* 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;
-}
-
/* Add a related connection. */
int ip_conntrack_expect_related(struct ip_conntrack *related_to,
- struct ip_conntrack_expect *exp)
+ struct ip_conntrack_expect *expect)
{
+ struct ip_conntrack_expect *new;
+
WRITE_LOCK(&ip_conntrack_lock);
- DEBUGP("ip_conntrack_expect_related(%p, %p)\n", related_to, exp);
+ DEBUGP("ip_conntrack_expect_related %p\n", related_to);
+ DUMP_TUPLE(&expect->tuple);
+ DUMP_TUPLE(&expect->mask);
+
+ if (LIST_FIND(&related_to->sibling_list, expect_clash,
+ struct ip_conntrack_expect *, expect)) {
+ WRITE_UNLOCK(&ip_conntrack_lock);
+ DEBUGP("expect_related: resent packet\n");
+ return -EEXIST;
+ }
+ if (related_to->helper->max_expected
+ && related_to->expecting >= related_to->helper->max_expected) {
+ DEBUGP("expect_related: max number of expected connections (%i) reached\n",
+ related_to->helper->max_expected);
+ WRITE_UNLOCK(&ip_conntrack_lock);
+ return -EPERM;
+ }
+
if (LIST_FIND(&expect_list, expect_clash,
- struct ip_conntrack_expect *, exp)) {
+ struct ip_conntrack_expect *, expect)) {
WRITE_UNLOCK(&ip_conntrack_lock);
DEBUGP("expect_related: busy!\n");
return -EBUSY;
}
- exp->expectant = related_to;
+ new = (struct ip_conntrack_expect *)
+ kmalloc(sizeof(*expect), GFP_ATOMIC);
+
+ if (!new) {
+ WRITE_UNLOCK(&ip_conntrack_lock);
+ DEBUGP("expect_relaed: OOM allocating expect\n");
+ return -ENOMEM;
+ }
+
+ /* Fill the structure with the data */
+ memcpy(new, expect, sizeof(*expect));
+ INIT_LIST_HEAD(&new->list);
+ INIT_LIST_HEAD(&new->expected_list);
+ new->expectant = related_to;
+ new->sibling = NULL;
+
/* add to expected list for this connection */
- list_add(&exp->expected_list, &related_to->sibling_list);
+ list_prepend(&related_to->sibling_list, &new->expected_list);
/* add to global list of expectations */
- list_prepend(&expect_list, &exp->list);
+ list_prepend(&expect_list, &new->list);
+ related_to->expecting++;
WRITE_UNLOCK(&ip_conntrack_lock);
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 Fri Jun 22 22:59:25 2001
@@ -243,8 +243,8 @@
int dir = CTINFO2DIR(ctinfo);
unsigned int matchlen, matchoff;
struct ip_ct_ftp_master *ct_ftp_info = &ct->help.ct_ftp_info;
- struct ip_ct_ftp_expect *exp_ftp_info;
- struct ip_conntrack_expect *exp;
+ struct ip_conntrack_expect expect, *exp = &expect;
+ struct ip_ct_ftp_expect *exp_ftp_info = &exp->help.exp_ftp_info;
unsigned int i;
int found = 0;
@@ -334,17 +334,6 @@
(int)matchlen, data + matchoff,
matchlen, ntohl(tcph->seq) + matchoff);
- /* allocate a new expectation */
- exp = ip_conntrack_alloc_expect(ct);
- if (!exp) {
- if (net_ratelimit())
- printk("conntrack_ftp: unable to allocate new "
- "expectation\n");
- return NF_ACCEPT;
- }
-
- exp_ftp_info = &exp->help.exp_ftp_info;
-
/* Update the ftp info */
LOCK_BH(&ip_ftp_lock);
if (htonl((array[0] << 24) | (array[1] << 16) | (array[2] << 8) | array[3])
@@ -416,6 +405,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_conntrack_standalone.c linux-2.4.5/net/ipv4/netfilter.newnat2/ip_conntrack_standalone.c
--- linux-2.4.5/net/ipv4/netfilter.newnat1/ip_conntrack_standalone.c Tue Jun 12 09:10:50 2001
+++ linux-2.4.5/net/ipv4/netfilter.newnat2/ip_conntrack_standalone.c Wed Jun 20 17:32:12 2001
@@ -327,7 +327,6 @@
EXPORT_SYMBOL(ip_conntrack_helper_unregister);
EXPORT_SYMBOL(ip_ct_selective_cleanup);
EXPORT_SYMBOL(ip_ct_refresh);
-EXPORT_SYMBOL(ip_conntrack_alloc_expect);
EXPORT_SYMBOL(ip_conntrack_expect_related);
EXPORT_SYMBOL(ip_conntrack_unexpect_related);
EXPORT_SYMBOL(ip_conntrack_tuple_taken);
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 Fri Jun 22 22:59:11 2001
@@ -177,11 +177,7 @@
struct iphdr *iph = (*pskb)->nh.iph;
struct tcphdr *tcph = (void *)iph + iph->ihl*4;
u_int16_t port;
- struct ip_conntrack_expect *exp;
-
- exp = ip_conntrack_alloc_expect(ct);
- if (!exp)
- return 0;
+ struct ip_conntrack_expect expect, *exp = &expect;
/* copy whole old expectation */
memcpy(exp, oldexp, sizeof(*oldexp));
@@ -298,7 +294,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