diff -urN --exclude-from=diff.exclude linux-2.4.5/include/linux/netfilter_ipv4.orig/ip_conntrack.h linux-2.4.5/include/linux/netfilter_ipv4/ip_conntrack.h --- linux-2.4.5/include/linux/netfilter_ipv4.orig/ip_conntrack.h Fri Apr 27 23:15:01 2001 +++ linux-2.4.5/include/linux/netfilter_ipv4/ip_conntrack.h Sun Jul 8 15:14:27 2001 @@ -6,6 +6,7 @@ #include #include +#include enum ip_conntrack_info { @@ -62,26 +63,64 @@ IPS_ASSURED = (1 << IPS_ASSURED_BIT), }; +#ifdef CONFIG_IP_NF_NAT_NEEDED +#include +#endif + +#if defined(CONFIG_IP_NF_FTP) || defined(CONFIG_IP_NF_FTP_MODULE) +#include +#endif + struct ip_conntrack_expect { - /* Internal linked list */ + /* Internal linked list (global expectation list) */ struct list_head list; + /* expectation list for this master */ + struct list_head expected_list; + + /* The conntrack of the master connection */ + struct ip_conntrack *expectant; + + /* The conntrack of the sibling connection, set after + * expectation arrived */ + struct ip_conntrack *sibling; + + /* Tuple saved for conntrack */ + struct ip_conntrack_tuple ct_tuple; + + /* Data filled out by the conntrack helpers follow: */ + /* We expect this tuple, with the following mask */ struct ip_conntrack_tuple tuple, mask; /* Function to call after setup and insertion */ int (*expectfn)(struct ip_conntrack *new); - /* The conntrack we are part of (set iff we're live) */ - struct ip_conntrack *expectant; -}; + /* At which sequence number did this expectation occur */ + u_int32_t seq; + + union { + /* insert conntrack helper private dat here */ +#if defined(CONFIG_IP_NF_FTP) || defined(CONFIG_IP_NF_FTP_MODULE) + struct ip_ct_ftp_expect exp_ftp_info; +#endif #ifdef CONFIG_IP_NF_NAT_NEEDED -#include + union { + /* insert nat helper private data here */ + } nat; #endif + } help; +}; -#include +#define IP_CONNTRACK_EXPECT_SIZEOF_HEAD \ + (2*sizeof(struct list_head) \ + + 2*sizeof(struct ip_conntrack *) \ + + 3*sizeof(struct ip_conntrack_tuple)) +#define IP_CONNTRACK_EXPECT_SIZEOF_DATA \ + (sizeof(struct ip_conntrack_expect) \ + - IP_CONNTRACK_EXPECT_SIZEOF_HEAD) struct ip_conntrack { @@ -100,10 +139,13 @@ /* If we're expecting another related connection, this will be in expected linked list */ - struct ip_conntrack_expect expected; + struct list_head sibling_list; + + /* Current number of expected connections */ + unsigned int expecting; - /* If we were expected by another connection, this will be it */ - struct nf_ct_info master; + /* If we were expected by an expectation, this will be it */ + struct ip_conntrack_expect *master; /* Helper, if any. */ struct ip_conntrack_helper *helper; @@ -120,7 +162,9 @@ } proto; union { - struct ip_ct_ftp ct_ftp_info; +#if defined(CONFIG_IP_NF_FTP) || defined(CONFIG_IP_NF_FTP_MODULE) + struct ip_ct_ftp_master ct_ftp_info; +#endif } help; #ifdef CONFIG_IP_NF_NAT_NEEDED @@ -137,6 +181,9 @@ #endif /* CONFIG_IP_NF_NAT_NEEDED */ }; + +/* get master conntrack via master expectation */ +#define master_ct(conntr) (conntr->master ? conntr->master->expectant : NULL) /* Alter reply tuple (maybe alter helper). If it's already taken, return 0 and don't do alteration. */ diff -urN --exclude-from=diff.exclude linux-2.4.5/include/linux/netfilter_ipv4.orig/ip_conntrack_ftp.h linux-2.4.5/include/linux/netfilter_ipv4/ip_conntrack_ftp.h --- linux-2.4.5/include/linux/netfilter_ipv4.orig/ip_conntrack_ftp.h Thu Apr 26 00:00:28 2001 +++ linux-2.4.5/include/linux/netfilter_ipv4/ip_conntrack_ftp.h Thu Jun 14 11:00:44 2001 @@ -23,18 +23,20 @@ IP_CT_FTP_EPSV, }; -/* We record seq number and length of ftp ip/port text here: all in - host order. */ -struct ip_ct_ftp +/* This structure is per expected connection */ +struct ip_ct_ftp_expect { - /* This tells NAT that this is an ftp connection */ - int is_ftp; - u_int32_t seq; - /* 0 means not found yet */ - u_int32_t len; - enum ip_ct_ftp_type ftptype; - /* Port that was to be used */ - u_int16_t port; + /* We record seq number and length of ftp ip/port text here: all in + * host order. */ + + /* sequence number of IP address in packet is in ip_conntrack_expect */ + u_int32_t len; /* length of IP address */ + enum ip_ct_ftp_type ftptype; /* PORT or PASV ? */ + u_int16_t port; /* TCP port that was to be used */ +}; + +/* This structure exists only once per master */ +struct ip_ct_ftp_master { /* Next valid seq position for cmd matching after newline */ u_int32_t seq_aft_nl[IP_CT_DIR_MAX]; /* 0 means seq_match_aft_nl not set */ diff -urN --exclude-from=diff.exclude linux-2.4.5/include/linux/netfilter_ipv4.orig/ip_conntrack_helper.h linux-2.4.5/include/linux/netfilter_ipv4/ip_conntrack_helper.h --- linux-2.4.5/include/linux/netfilter_ipv4.orig/ip_conntrack_helper.h Mon Dec 11 22:31:23 2000 +++ linux-2.4.5/include/linux/netfilter_ipv4/ip_conntrack_helper.h Sun Jul 8 15:15:59 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,11 +27,12 @@ extern int ip_conntrack_helper_register(struct ip_conntrack_helper *); extern void ip_conntrack_helper_unregister(struct ip_conntrack_helper *); -/* 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, - const struct ip_conntrack_tuple *tuple, - const struct ip_conntrack_tuple *mask, - int (*expectfn)(struct ip_conntrack *)); -extern void ip_conntrack_unexpect_related(struct ip_conntrack *related_to); + struct ip_conntrack_expect *exp); +extern int ip_conntrack_change_expect(struct ip_conntrack_expect *expect, + struct ip_conntrack_tuple *origtuple, + struct ip_conntrack_tuple *newtuple); +extern void ip_conntrack_unexpect_related(struct ip_conntrack_expect *exp); #endif /*_IP_CONNTRACK_HELPER_H*/ diff -urN --exclude-from=diff.exclude linux-2.4.5/include/linux/netfilter_ipv4.orig/ip_nat_helper.h linux-2.4.5/include/linux/netfilter_ipv4/ip_nat_helper.h --- linux-2.4.5/include/linux/netfilter_ipv4.orig/ip_nat_helper.h Thu Apr 26 00:00:28 2001 +++ linux-2.4.5/include/linux/netfilter_ipv4/ip_nat_helper.h Sun Jul 8 15:16:05 2001 @@ -17,11 +17,18 @@ /* Helper function: returns verdict */ unsigned int (*help)(struct ip_conntrack *ct, + struct ip_conntrack_expect *exp, struct ip_nat_info *info, enum ip_conntrack_info ctinfo, unsigned int hooknum, struct sk_buff **pskb); + /* Returns verdict and sets up NAT for this connection */ + unsigned int (*expect)(struct sk_buff **pskb, + unsigned int hooknum, + struct ip_conntrack *ct, + struct ip_nat_info *info); + const char *name; }; @@ -39,5 +46,5 @@ extern int ip_nat_seq_adjust(struct sk_buff *skb, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo); -extern void ip_nat_delete_sack(struct sk_buff *skb, struct tcphdr *tcph); +extern void ip_nat_delete_sack(struct sk_buff *skb); #endif diff -urN --exclude-from=diff.exclude linux-2.4.5/include/linux/netfilter_ipv4.orig/ip_nat_protocol.h linux-2.4.5/include/linux/netfilter_ipv4/ip_nat_protocol.h --- linux-2.4.5/include/linux/netfilter_ipv4.orig/ip_nat_protocol.h Mon Dec 11 22:31:32 2000 +++ linux-2.4.5/include/linux/netfilter_ipv4/ip_nat_protocol.h Thu Jun 14 11:26:38 2001 @@ -44,6 +44,10 @@ unsigned int (*print_range)(char *buffer, const struct ip_nat_range *range); + + /* Has to decide if a expectation matches one packet or not */ + int (*exp_matches_pkt)(struct ip_conntrack_expect *exp, + struct sk_buff **pskb); }; /* Protocol registration. */ diff -urN --exclude-from=diff.exclude linux-2.4.5/include/linux/netfilter_ipv4.orig/ip_nat_rule.h linux-2.4.5/include/linux/netfilter_ipv4/ip_nat_rule.h --- linux-2.4.5/include/linux/netfilter_ipv4.orig/ip_nat_rule.h Mon Dec 11 22:31:32 2000 +++ linux-2.4.5/include/linux/netfilter_ipv4/ip_nat_rule.h Sun Jul 8 15:16:05 2001 @@ -5,24 +5,7 @@ #include #ifdef __KERNEL__ -/* Want to be told when we first NAT an expected packet for a conntrack? */ -struct ip_nat_expect -{ - struct list_head list; - /* Returns 1 (and sets verdict) if it has setup NAT for this - connection */ - int (*expect)(struct sk_buff **pskb, - unsigned int hooknum, - struct ip_conntrack *ct, - struct ip_nat_info *info, - struct ip_conntrack *master, - struct ip_nat_info *masterinfo, - unsigned int *verdict); -}; - -extern int ip_nat_expect_register(struct ip_nat_expect *expect); -extern void ip_nat_expect_unregister(struct ip_nat_expect *expect); extern int ip_nat_rule_init(void) __init; extern void ip_nat_rule_cleanup(void); extern int ip_nat_rule_find(struct sk_buff **pskb, diff -urN --exclude-from=diff.exclude linux-2.4.5/net/ipv4/netfilter.orig/ip_conntrack_core.c linux-2.4.5/net/ipv4/netfilter/ip_conntrack_core.c --- linux-2.4.5/net/ipv4/netfilter.orig/ip_conntrack_core.c Fri Apr 27 23:15:01 2001 +++ linux-2.4.5/net/ipv4/netfilter/ip_conntrack_core.c Sun Jul 8 15:15:44 2001 @@ -3,7 +3,12 @@ extension. */ /* (c) 1999 Paul `Rusty' Russell. Licenced under the GNU General - Public Licence. */ + * Public Licence. + * + * 23 Apr 2001: Harald Welte + * - new API and handling of conntrack/nat helpers + * - now capable of multiple expectations for one master + * */ #ifdef MODULE #define __NO_VERSION__ @@ -37,13 +42,14 @@ #include #include -#if 0 +#if 1 #define DEBUGP printk #else #define DEBUGP(format, args...) #endif DECLARE_RWLOCK(ip_conntrack_lock); +DECLARE_RWLOCK(ip_conntrack_expect_tuple_lock); void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack) = NULL; LIST_HEAD(expect_list); @@ -150,9 +156,52 @@ return protocol->invert_tuple(inverse, orig); } +/* remove one specific expectation from all lists and free it */ +static void unexpect_related(struct ip_conntrack_expect *expect) +{ + MUST_BE_WRITE_LOCKED(&ip_conntrack_lock); + DEBUGP("unexpect_related(%p)\n", expect); + /* delete from global and local lists */ + list_del(&expect->list); + list_del(&expect->expected_list); + if (!expect->sibling) + expect->expectant->expecting--; + kfree(expect); +} + +/* delete all expectations for this conntrack */ +static void destroy_expectations(struct ip_conntrack *ct) +{ + struct list_head *exp_entry, *next; + struct ip_conntrack_expect *exp; + + DEBUGP("destroy_expectations(%p)\n", ct); + + for (exp_entry = ct->sibling_list.next; + exp_entry != &ct->sibling_list; exp_entry = next) { + next = exp_entry->next; + exp = list_entry(exp_entry, struct ip_conntrack_expect, + expected_list); + + /* we skip established expectations, as we want to delete + * the un-established ones only */ + 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); + + /* delete expectation from global and private lists */ + unexpect_related(exp); + } +} + static void clean_from_lists(struct ip_conntrack *ct) { + DEBUGP("clean_from_lists(%p)\n", ct); MUST_BE_WRITE_LOCKED(&ip_conntrack_lock); /* Remove from both hash lists: must not NULL out next ptrs, otherwise we'll look unconfirmed. Fortunately, LIST_DELETE @@ -163,12 +212,9 @@ LIST_DELETE(&ip_conntrack_hash [hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple)], &ct->tuplehash[IP_CT_DIR_REPLY]); - /* If our expected is in the list, take it out. */ - if (ct->expected.expectant) { - IP_NF_ASSERT(list_inlist(&expect_list, &ct->expected)); - IP_NF_ASSERT(ct->expected.expectant == ct); - LIST_DELETE(&expect_list, &ct->expected); - } + + /* Destroy all un-established, pending expectations */ + destroy_expectations(ct); } static void @@ -176,14 +222,33 @@ { struct ip_conntrack *ct = (struct ip_conntrack *)nfct; + DEBUGP("destroy_conntrack(%p)\n", ct); IP_NF_ASSERT(atomic_read(&nfct->use) == 0); IP_NF_ASSERT(!timer_pending(&ct->timeout)); - if (ct->master.master) - nf_conntrack_put(&ct->master); + if (ct->master && master_ct(ct)) + ip_conntrack_put(master_ct(ct)); - if (ip_conntrack_destroyed) + if (ip_conntrack_destroyed) { + DEBUGP("destr_conntr: calling ip_conntrack_destroyed\n"); ip_conntrack_destroyed(ct); + } + + WRITE_LOCK(&ip_conntrack_lock); + /* remove it from the expectation list, as there may + * expectations survive and we want to leave their list + * in a consistent state -HW */ + DEBUGP("destroy_conntrack: lemme see...\n"); + /* list_del(&ct->sibling_list); */ + /* Delete our master expectation from the local list + and destroy it, if we've been expected */ + if (ct->master) { + list_del(&ct->master->expected_list); + kfree(ct->master); + } + WRITE_UNLOCK(&ip_conntrack_lock); + + DEBUGP("destr_conntr: returning ct to slab\n"); kmem_cache_free(ip_conntrack_cachep, ct); atomic_dec(&ip_conntrack_count); } @@ -465,6 +530,7 @@ static inline int expect_cmp(const struct ip_conntrack_expect *i, const struct ip_conntrack_tuple *tuple) { + MUST_BE_READ_LOCKED(&ip_conntrack_expect_tuple_lock); return ip_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask); } @@ -513,7 +579,7 @@ return ERR_PTR(-ENOMEM); } - memset(conntrack, 0, sizeof(struct ip_conntrack)); + memset(conntrack, 0, sizeof(*conntrack)); atomic_set(&conntrack->ct_general.use, 1); conntrack->ct_general.destroy = destroy_conntrack; conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *tuple; @@ -532,31 +598,37 @@ conntrack->timeout.data = (unsigned long)conntrack; conntrack->timeout.function = death_by_timeout; + INIT_LIST_HEAD(&conntrack->sibling_list); + /* Mark clearly that it's not in the hash table. */ conntrack->tuplehash[IP_CT_DIR_ORIGINAL].list.next = NULL; - /* Write lock required for deletion of expected. Without - this, a read-lock would do. */ WRITE_LOCK(&ip_conntrack_lock); conntrack->helper = LIST_FIND(&helpers, helper_cmp, struct ip_conntrack_helper *, &repl_tuple); + /* Need finding and deleting of expected ONLY if we win race */ + READ_LOCK(&ip_conntrack_expect_tuple_lock); expected = LIST_FIND(&expect_list, expect_cmp, struct ip_conntrack_expect *, tuple); + READ_UNLOCK(&ip_conntrack_expect_tuple_lock); /* If master is not in hash table yet (ie. packet hasn't left this machine yet), how can other end know about expected? Hence these are not the droids you are looking for (if master ct never got confirmed, we'd hold a reference to it and weird things would happen to future packets). */ if (expected && is_confirmed(expected->expectant)) { + DEBUGP("conntrack: expectation arrives ct=%p exp=%p\n", + conntrack, expected); /* Welcome, Mr. Bond. We've been expecting you... */ + IP_NF_ASSERT(master_ct(conntrack)); conntrack->status = IPS_EXPECTED; - conntrack->master.master = &expected->expectant->ct_general; - IP_NF_ASSERT(conntrack->master.master); + conntrack->master = expected; + expected->sibling = conntrack; LIST_DELETE(&expect_list, expected); - expected->expectant = NULL; - nf_conntrack_get(&conntrack->master); + expected->expectant->expecting--; + nf_conntrack_get(&master_ct(conntrack)->infos[0]); } atomic_inc(&ip_conntrack_count); WRITE_UNLOCK(&ip_conntrack_lock); @@ -708,60 +780,148 @@ return invert_tuple(inverse, orig, find_proto(orig->dst.protonum)); } -static void unexpect_related(struct ip_conntrack *related_to) -{ - MUST_BE_WRITE_LOCKED(&ip_conntrack_lock); - list_del(&related_to->expected.list); - related_to->expected.expectant = NULL; +static inline int resent_expect(const struct ip_conntrack_expect *i, + const struct ip_conntrack_tuple *tuple, + const struct ip_conntrack_tuple *mask) +{ + DEBUGP("resent_expect\n"); + DEBUGP(" tuple: "); DUMP_TUPLE(&i->tuple); + DEBUGP("ct_tuple: "); DUMP_TUPLE(&i->ct_tuple); + DEBUGP("test tuple: "); DUMP_TUPLE(tuple); + return (((i->ct_tuple.dst.protonum == 0 && ip_ct_tuple_equal(&i->tuple, tuple)) + || (i->ct_tuple.dst.protonum && ip_ct_tuple_equal(&i->ct_tuple, tuple))) + && ip_ct_tuple_equal(&i->mask, mask)); } /* Would two expected things clash? */ static inline int expect_clash(const struct ip_conntrack_expect *i, - const struct ip_conntrack_expect *new) + const struct ip_conntrack_tuple *tuple, + const struct ip_conntrack_tuple *mask) { /* Part covered by intersection of masks must be unequal, otherwise they clash */ struct ip_conntrack_tuple intersect_mask - = { { i->mask.src.ip & new->mask.src.ip, - { i->mask.src.u.all & new->mask.src.u.all } }, - { i->mask.dst.ip & new->mask.dst.ip, - { i->mask.dst.u.all & new->mask.dst.u.all }, - i->mask.dst.protonum & new->mask.dst.protonum } }; + = { { i->mask.src.ip & mask->src.ip, + { i->mask.src.u.all & mask->src.u.all } }, + { i->mask.dst.ip & mask->dst.ip, + { i->mask.dst.u.all & mask->dst.u.all }, + i->mask.dst.protonum & mask->dst.protonum } }; - return ip_ct_tuple_mask_cmp(&i->tuple, &new->tuple, &intersect_mask); + return ip_ct_tuple_mask_cmp(&i->tuple, tuple, &intersect_mask); } /* Add a related connection. */ int ip_conntrack_expect_related(struct ip_conntrack *related_to, - const struct ip_conntrack_tuple *tuple, - const struct ip_conntrack_tuple *mask, - int (*expectfn)(struct ip_conntrack *)) + struct ip_conntrack_expect *expect) { + struct ip_conntrack_expect *new; + WRITE_LOCK(&ip_conntrack_lock); - if (related_to->expected.expectant) - unexpect_related(related_to); + /* Because of the write lock, no reader can walk the lists, + * so there is no need to use the tuple lock too */ - related_to->expected.tuple = *tuple; - related_to->expected.mask = *mask; - related_to->expected.expectfn = expectfn; + DEBUGP("ip_conntrack_expect_related %p\n", related_to); + DEBUGP("tuple: "); DUMP_TUPLE(&expect->tuple); + DEBUGP("mask: "); DUMP_TUPLE(&expect->mask); + + new = LIST_FIND(&expect_list, resent_expect, + struct ip_conntrack_expect *, &expect->tuple, &expect->mask); + if (new) { + /* Copy data filled out by the helper, except the tuple and mask + * (NAT may altered it) */ + memcpy((void *)new + IP_CONNTRACK_EXPECT_SIZEOF_HEAD, + (void *)expect + IP_CONNTRACK_EXPECT_SIZEOF_HEAD, + IP_CONNTRACK_EXPECT_SIZEOF_DATA); + 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) { + WRITE_UNLOCK(&ip_conntrack_lock); + DEBUGP("expect_related: max number of expected connections (%i) reached\n", + related_to->helper->max_expected); + return -EPERM; + } + if (LIST_FIND(&expect_list, expect_clash, - struct ip_conntrack_expect *, &related_to->expected)) { + struct ip_conntrack_expect *, &expect->tuple, &expect->mask)) { WRITE_UNLOCK(&ip_conntrack_lock); + DEBUGP("expect_related: busy!\n"); return -EBUSY; } - list_prepend(&expect_list, &related_to->expected); - related_to->expected.expectant = related_to; - WRITE_UNLOCK(&ip_conntrack_lock); + 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; + memset(&new->ct_tuple, 0, sizeof(new->ct_tuple)); + + /* add to expected list for this connection */ + list_add(&new->expected_list, &related_to->sibling_list); + /* add to global list of expectations */ + list_prepend(&expect_list, &new->list); + related_to->expecting++; + + WRITE_UNLOCK(&ip_conntrac_lock); return 0; } -void ip_conntrack_unexpect_related(struct ip_conntrack *related_to) +/* Change tuple in an existing expectation */ +int ip_conntrack_change_expect(struct ip_conntrack_expect *expect, + struct ip_conntrack_tuple *origtuple, + struct ip_conntrack_tuple *newtuple) +{ + MUST_BE_READ_LOCKED(&ip_conntrack_lock); + + DEBUGP("change_expect:\n"); + DEBUGP("origtuple: "); DUMP_TUPLE(origtuple); + DEBUGP("newtuple: "); DUMP_TUPLE(newtuple); + if (expect->ct_tuple.dst.protonum == 0 && ip_ct_tuple_equal(&expect->tuple, origtuple)) { + /* Never seen before */ + DEBUGP("change expect: never seen before\n"); + if (LIST_FIND(&expect_list, expect_clash, + struct ip_conntrack_expect *, newtuple, &expect->mask)) { + /* Force NAT to find an unused tuple */ + return -1; + } else { + WRITE_LOCK(ip_conntrack_expect_tuple_lock); + memcpy(&expect->ct_tuple, origtuple, sizeof(expect->tuple)); + memcpy(&expect->tuple, newtuple, sizeof(expect->tuple)); + WRITE_UNLOCK(ip_conntrack_expect_tuple_lock); + return 0; + } + } else if (expect->ct_tuple.dst.protonum && ip_ct_tuple_equal(&expect->ct_tuple, origtuple)) { + /* Resent packet */ + DEBUGP("change expect: resent packet\n"); + if (ip_ct_tuple_equal(&expect->tuple, newtuple)) { + return 0; + } else { + /* Force NAT to choose again the same port */ + return -1; + } + } + + return -1; +} + +void ip_conntrack_unexpect_related(struct ip_conntrack_expect *expect) { WRITE_LOCK(&ip_conntrack_lock); - unexpect_related(related_to); + unexpect_related(expect); WRITE_UNLOCK(&ip_conntrack_lock); } @@ -806,12 +966,7 @@ if (i->ctrack->helper == me) { i->ctrack->helper = NULL; /* Get rid of any expected. */ - if (i->ctrack->expected.expectant) { - IP_NF_ASSERT(i->ctrack->expected.expectant - == i->ctrack); - LIST_DELETE(&expect_list, &i->ctrack->expected); - i->ctrack->expected.expectant = NULL; - } + destroy_expectations(i->ctrack); } return 0; } diff -urN --exclude-from=diff.exclude linux-2.4.5/net/ipv4/netfilter.orig/ip_conntrack_ftp.c linux-2.4.5/net/ipv4/netfilter/ip_conntrack_ftp.c --- linux-2.4.5/net/ipv4/netfilter.orig/ip_conntrack_ftp.c Thu Apr 26 00:02:09 2001 +++ linux-2.4.5/net/ipv4/netfilter/ip_conntrack_ftp.c Mon Jul 2 17:12:56 2001 @@ -23,7 +23,7 @@ static int loose = 0; MODULE_PARM(loose, "i"); -#if 0 +#if 1 #define DEBUGP printk #else #define DEBUGP(format, args...) @@ -242,8 +242,10 @@ u_int32_t array[6] = { 0 }; int dir = CTINFO2DIR(ctinfo); unsigned int matchlen, matchoff; - struct ip_conntrack_tuple t, mask; - struct ip_ct_ftp *info = &ct->help.ct_ftp_info; + struct ip_ct_ftp_master *ct_ftp_info = &ct->help.ct_ftp_info; + 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; @@ -271,8 +273,8 @@ } LOCK_BH(&ip_ftp_lock); - old_seq_aft_nl_set = info->seq_aft_nl_set[dir]; - old_seq_aft_nl = info->seq_aft_nl[dir]; + old_seq_aft_nl_set = ct_ftp_info->seq_aft_nl_set[dir]; + old_seq_aft_nl = ct_ftp_info->seq_aft_nl[dir]; DEBUGP("conntrack_ftp: datalen %u\n", datalen); if ((datalen > 0) && (data[datalen-1] == '\n')) { @@ -281,8 +283,9 @@ || after(ntohl(tcph->seq) + datalen, old_seq_aft_nl)) { DEBUGP("conntrack_ftp: updating nl to %u\n", ntohl(tcph->seq) + datalen); - info->seq_aft_nl[dir] = ntohl(tcph->seq) + datalen; - info->seq_aft_nl_set[dir] = 1; + ct_ftp_info->seq_aft_nl[dir] = + ntohl(tcph->seq) + datalen; + ct_ftp_info->seq_aft_nl_set[dir] = 1; } } UNLOCK_BH(&ip_ftp_lock); @@ -335,11 +338,10 @@ LOCK_BH(&ip_ftp_lock); if (htonl((array[0] << 24) | (array[1] << 16) | (array[2] << 8) | array[3]) == ct->tuplehash[dir].tuple.src.ip) { - info->is_ftp = 1; - info->seq = ntohl(tcph->seq) + matchoff; - info->len = matchlen; - info->ftptype = search[i].ftptype; - info->port = array[4] << 8 | array[5]; + exp->seq = ntohl(tcph->seq) + matchoff; + exp_ftp_info->len = matchlen; + exp_ftp_info->ftptype = search[i].ftptype; + exp_ftp_info->port = array[4] << 8 | array[5]; } else { /* Enrico Scholz's passive FTP to partially RNAT'd ftp server: it really wants us to connect to a @@ -356,18 +358,21 @@ if (!loose) goto out; } - t = ((struct ip_conntrack_tuple) + exp->tuple = ((struct ip_conntrack_tuple) { { ct->tuplehash[!dir].tuple.src.ip, { 0 } }, { htonl((array[0] << 24) | (array[1] << 16) | (array[2] << 8) | array[3]), { htons(array[4] << 8 | array[5]) }, IPPROTO_TCP }}); - mask = ((struct ip_conntrack_tuple) + exp->mask = ((struct ip_conntrack_tuple) { { 0xFFFFFFFF, { 0 } }, { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }}); + + exp->expectfn = NULL; + /* Ignore failure; should only happen with NAT */ - ip_conntrack_expect_related(ct, &t, &mask, NULL); + ip_conntrack_expect_related(ct, &expect); out: UNLOCK_BH(&ip_ftp_lock); @@ -400,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.orig/ip_conntrack_proto_generic.c linux-2.4.5/net/ipv4/netfilter/ip_conntrack_proto_generic.c --- linux-2.4.5/net/ipv4/netfilter.orig/ip_conntrack_proto_generic.c Fri Apr 27 23:15:01 2001 +++ linux-2.4.5/net/ipv4/netfilter/ip_conntrack_proto_generic.c Wed Jun 27 07:00:21 2001 @@ -58,4 +58,3 @@ = { { NULL, NULL }, 0, "unknown", generic_pkt_to_tuple, generic_invert_tuple, generic_print_tuple, generic_print_conntrack, established, new, NULL }; - diff -urN --exclude-from=diff.exclude linux-2.4.5/net/ipv4/netfilter.orig/ip_conntrack_standalone.c linux-2.4.5/net/ipv4/netfilter/ip_conntrack_standalone.c --- linux-2.4.5/net/ipv4/netfilter.orig/ip_conntrack_standalone.c Fri Apr 27 23:15:01 2001 +++ linux-2.4.5/net/ipv4/netfilter/ip_conntrack_standalone.c Sat Jul 7 22:05:33 2001 @@ -328,6 +328,9 @@ EXPORT_SYMBOL(ip_ct_selective_cleanup); EXPORT_SYMBOL(ip_ct_refresh); EXPORT_SYMBOL(ip_conntrack_expect_related); +EXPORT_SYMBOL(ip_conntrack_change_expect); +EXPORT_SYMBOL(ip_conntrack_unexpect_related); EXPORT_SYMBOL(ip_conntrack_tuple_taken); EXPORT_SYMBOL(ip_ct_gather_frags); EXPORT_SYMBOL(ip_conntrack_htable_size); +EXPORT_SYMBOL(ip_conntrack_lock); diff -urN --exclude-from=diff.exclude linux-2.4.5/net/ipv4/netfilter.orig/ip_nat_core.c linux-2.4.5/net/ipv4/netfilter/ip_nat_core.c --- linux-2.4.5/net/ipv4/netfilter.orig/ip_nat_core.c Wed May 16 19:31:27 2001 +++ linux-2.4.5/net/ipv4/netfilter/ip_nat_core.c Sun Jul 8 08:56:54 2001 @@ -21,19 +21,22 @@ #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 #include +#include #include -#if 0 +#if 1 #define DEBUGP printk #else #define DEBUGP(format, args...) #endif DECLARE_RWLOCK(ip_nat_lock); +DECLARE_RWLOCK_EXTERN(ip_conntrack_lock); /* Calculated at init based on memory size */ static unsigned int ip_nat_htable_size; @@ -717,6 +720,19 @@ #endif } +static inline int exp_for_packet(struct ip_conntrack_expect *exp, + struct sk_buff **pskb) +{ + int proto = (*pskb)->nh.iph->protocol; + int ret; + + READ_LOCK(&ip_nat_lock); + ret = find_nat_proto(proto)->exp_matches_pkt(exp, pskb); + READ_UNLOCK(&ip_nat_lock); + + return ret; +} + /* Do packet manipulations according to binding. */ unsigned int do_bindings(struct ip_conntrack *ct, @@ -728,6 +744,7 @@ unsigned int i; struct ip_nat_helper *helper; enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); + int is_tcp = (*pskb)->nh.iph->protocol == IPPROTO_TCP; /* Need nat lock to protect against modification, but neither conntrack (referenced) and helper (deleted with @@ -754,11 +771,60 @@ READ_UNLOCK(&ip_nat_lock); if (helper) { + struct ip_conntrack_expect *exp; + struct list_head *cur_item; + int ret = NF_ACCEPT; + + DEBUGP("do_bindings: helper existing for (%p)\n", ct); + /* Always defragged for helpers */ IP_NF_ASSERT(!((*pskb)->nh.iph->frag_off & __constant_htons(IP_MF|IP_OFFSET))); - return helper->help(ct, info, ctinfo, hooknum, pskb); - } else return NF_ACCEPT; + + /* FIXME: put this in a l4-proto specific function, + * and call this function here. */ + /* Delete SACK_OK on initial TCP SYNs. */ + if (is_tcp) + ip_nat_delete_sack(*pskb); + + /* Have to grab read lock before sibling_list traversal */ + READ_LOCK(&ip_conntrack_lock); + list_for_each(cur_item, &ct->sibling_list) { + exp = list_entry(cur_item, struct ip_conntrack_expect, + expected_list); + + /* if this expectation is already established, skip */ + if (exp->sibling) + continue; + + if (exp_for_packet(exp, pskb)) { + /* FIXME: May be true multiple times in the case of UDP!! */ + DEBUGP("calling nat helper (exp=%p) for packet\n", + exp); + ret = helper->help(ct, exp, info, ctinfo, + hooknum, pskb); + if (ret != NF_ACCEPT) { + READ_UNLOCK(&ip_conntrack_lock); + return ret; + } + } + } + READ_UNLOCK(&ip_conntrack_lock); + + /* FIXME: put this in a l4-proto specific function, + * and call this function here. */ + DEBUGP("ip_nat_core: adjusting sequence number\n"); + /* Adjust sequence number only once per packet + * (helper is called at all hooks) */ + if (is_tcp && hooknum == NF_IP_POST_ROUTING) + ip_nat_seq_adjust(*pskb, ct, ctinfo); + + return ret; + + } else + return NF_ACCEPT; + + /* not reached */ } unsigned int diff -urN --exclude-from=diff.exclude linux-2.4.5/net/ipv4/netfilter.orig/ip_nat_ftp.c linux-2.4.5/net/ipv4/netfilter/ip_nat_ftp.c --- linux-2.4.5/net/ipv4/netfilter.orig/ip_nat_ftp.c Thu Apr 26 00:02:35 2001 +++ linux-2.4.5/net/ipv4/netfilter/ip_nat_ftp.c Sun Jul 8 15:14:43 2001 @@ -10,7 +10,7 @@ #include #include -#if 0 +#if 1 #define DEBUGP printk #else #define DEBUGP(format, args...) @@ -26,40 +26,33 @@ DECLARE_LOCK_EXTERN(ip_ftp_lock); + /* FIXME: Time out? --RR */ -static int +static unsigned int ftp_nat_expected(struct sk_buff **pskb, unsigned int hooknum, struct ip_conntrack *ct, - struct ip_nat_info *info, - struct ip_conntrack *master, - struct ip_nat_info *masterinfo, - unsigned int *verdict) + struct ip_nat_info *info) { struct ip_nat_multi_range mr; u_int32_t newdstip, newsrcip, newip; - struct ip_ct_ftp *ftpinfo; + struct ip_ct_ftp_expect *exp_ftp_info; + + struct ip_conntrack *master = master_ct(ct); IP_NF_ASSERT(info); IP_NF_ASSERT(master); - IP_NF_ASSERT(masterinfo); IP_NF_ASSERT(!(info->initialized & (1<help.ct_ftp_info; + exp_ftp_info = &ct->master->help.exp_ftp_info; LOCK_BH(&ip_ftp_lock); - if (!ftpinfo->is_ftp) { - UNLOCK_BH(&ip_ftp_lock); - DEBUGP("nat_expected: master not ftp\n"); - return 0; - } - if (ftpinfo->ftptype == IP_CT_FTP_PORT - || ftpinfo->ftptype == IP_CT_FTP_EPRT) { + if (exp_ftp_info->ftptype == IP_CT_FTP_PORT + || exp_ftp_info->ftptype == IP_CT_FTP_EPRT) { /* PORT command: make connection go to the client. */ newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; newsrcip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; @@ -92,11 +85,9 @@ mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED; mr.range[0].min = mr.range[0].max = ((union ip_conntrack_manip_proto) - { htons(ftpinfo->port) }); + { htons(exp_ftp_info->port) }); } - *verdict = ip_nat_setup_info(ct, &mr, hooknum); - - return 1; + return ip_nat_setup_info(ct, &mr, hooknum); } static int @@ -176,27 +167,22 @@ [IP_CT_FTP_EPSV] mangle_epsv_packet }; -static int ftp_data_fixup(const struct ip_ct_ftp *ct_ftp_info, +static int ftp_data_fixup(const struct ip_ct_ftp_expect *ct_ftp_info, struct ip_conntrack *ct, - unsigned int datalen, struct sk_buff **pskb, - enum ip_conntrack_info ctinfo) + enum ip_conntrack_info ctinfo, + struct ip_conntrack_expect *expect) { u_int32_t newip; struct iphdr *iph = (*pskb)->nh.iph; struct tcphdr *tcph = (void *)iph + iph->ihl*4; u_int16_t port; - struct ip_conntrack_tuple tuple; - /* Don't care about source port */ - const struct ip_conntrack_tuple mask - = { { 0xFFFFFFFF, { 0 } }, - { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF } }; + struct ip_conntrack_tuple origtuple, newtuple; - memset(&tuple, 0, sizeof(tuple)); MUST_BE_LOCKED(&ip_ftp_lock); - DEBUGP("FTP_NAT: seq %u + %u in %u + %u\n", - ct_ftp_info->seq, ct_ftp_info->len, - ntohl(tcph->seq), datalen); + DEBUGP("FTP_NAT: seq %u + %u in %u\n", + expect->seq, ct_ftp_info->len, + ntohl(tcph->seq)); /* Change address inside packet to match way we're mapping this connection. */ @@ -206,29 +192,48 @@ is */ newip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; /* Expect something from client->server */ - tuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; - tuple.dst.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; + newtuple.src.ip = + ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; + newtuple.dst.ip = + ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; + /* The original tuple */ + origtuple.src.ip = + ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; + origtuple.dst.ip = + ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; } else { /* PORT command: must be where server thinks client is */ newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; /* Expect something from server->client */ - tuple.src.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; - tuple.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; + newtuple.src.ip = + ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; + newtuple.dst.ip = + ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; + /* The original tuple */ + origtuple.src.ip = + ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; + origtuple.dst.ip = + ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; } - tuple.dst.protonum = IPPROTO_TCP; + origtuple.dst.protonum = + newtuple.dst.protonum = IPPROTO_TCP; + + origtuple.src.u.tcp.port = + newtuple.src.u.tcp.port = expect->tuple.src.u.tcp.port; /* Try to get same port: if not, try to change it. */ + origtuple.dst.u.tcp.port = htons(ct_ftp_info->port); for (port = ct_ftp_info->port; port != 0; port++) { - tuple.dst.u.tcp.port = htons(port); + newtuple.dst.u.tcp.port = htons(port); - if (ip_conntrack_expect_related(ct, &tuple, &mask, NULL) == 0) + if (ip_conntrack_change_expect(expect, &origtuple, &newtuple) == 0) break; } if (port == 0) return 0; if (!mangle[ct_ftp_info->ftptype](pskb, newip, port, - ct_ftp_info->seq - ntohl(tcph->seq), + expect->seq - ntohl(tcph->seq), ct_ftp_info->len, ct, ctinfo)) return 0; @@ -236,22 +241,19 @@ } static unsigned int help(struct ip_conntrack *ct, + struct ip_conntrack_expect *exp, struct ip_nat_info *info, enum ip_conntrack_info ctinfo, unsigned int hooknum, struct sk_buff **pskb) { - struct iphdr *iph = (*pskb)->nh.iph; - struct tcphdr *tcph = (void *)iph + iph->ihl*4; - unsigned int datalen; int dir; - int score; - struct ip_ct_ftp *ct_ftp_info - = &ct->help.ct_ftp_info; - - /* Delete SACK_OK on initial TCP SYNs. */ - if (tcph->syn && !tcph->ack) - ip_nat_delete_sack(*pskb, tcph); + struct ip_ct_ftp_expect *ct_ftp_info; + + if (!exp) + DEBUGP("ip_nat_ftp: no exp!!"); + + ct_ftp_info = &exp->help.exp_ftp_info; /* Only mangle things once: original direction in POST_ROUTING and reply direction on PRE_ROUTING. */ @@ -266,52 +268,19 @@ return NF_ACCEPT; } - datalen = (*pskb)->len - iph->ihl * 4 - tcph->doff * 4; - score = 0; LOCK_BH(&ip_ftp_lock); - if (ct_ftp_info->len) { - /* If it's in the right range... */ - score += between(ct_ftp_info->seq, ntohl(tcph->seq), - ntohl(tcph->seq) + datalen); - score += between(ct_ftp_info->seq + ct_ftp_info->len, - ntohl(tcph->seq), - ntohl(tcph->seq) + datalen); - if (score == 1) { - /* Half a match? This means a partial retransmisison. - It's a cracker being funky. */ - if (net_ratelimit()) { - printk("FTP_NAT: partial packet %u/%u in %u/%u\n", - ct_ftp_info->seq, ct_ftp_info->len, - ntohl(tcph->seq), - ntohl(tcph->seq) + datalen); - } - UNLOCK_BH(&ip_ftp_lock); - return NF_DROP; - } else if (score == 2) { - if (!ftp_data_fixup(ct_ftp_info, ct, datalen, - pskb, ctinfo)) { - UNLOCK_BH(&ip_ftp_lock); - return NF_DROP; - } - /* skb may have been reallocated */ - iph = (*pskb)->nh.iph; - tcph = (void *)iph + iph->ihl*4; - } + if (!ftp_data_fixup(ct_ftp_info, ct, pskb, ctinfo, exp)) { + UNLOCK_BH(&ip_ftp_lock); + return NF_DROP; } - UNLOCK_BH(&ip_ftp_lock); - ip_nat_seq_adjust(*pskb, ct, ctinfo); - return NF_ACCEPT; } static struct ip_nat_helper ftp[MAX_PORTS]; static char ftp_names[MAX_PORTS][6]; -static struct ip_nat_expect ftp_expect -= { { NULL, NULL }, ftp_nat_expected }; - /* Not __exit: called from init() */ static void fini(void) { @@ -321,49 +290,44 @@ DEBUGP("ip_nat_ftp: unregistering port %d\n", ports[i]); ip_nat_helper_unregister(&ftp[i]); } - - ip_nat_expect_unregister(&ftp_expect); } static int __init init(void) { - int i, ret; + int i, ret = 0; char *tmpname; - ret = ip_nat_expect_register(&ftp_expect); - if (ret == 0) { - if (ports[0] == 0) - ports[0] = 21; - - for (i = 0; (i < MAX_PORTS) && ports[i]; i++) { - - memset(&ftp[i], 0, sizeof(struct ip_nat_helper)); - - ftp[i].tuple.dst.protonum = IPPROTO_TCP; - ftp[i].tuple.src.u.tcp.port = htons(ports[i]); - ftp[i].mask.dst.protonum = 0xFFFF; - ftp[i].mask.src.u.tcp.port = 0xFFFF; - ftp[i].help = help; - - tmpname = &ftp_names[i][0]; - sprintf(tmpname, "ftp%2.2d", i); - ftp[i].name = tmpname; - - DEBUGP("ip_nat_ftp: Trying to register for port %d\n", - ports[i]); - ret = ip_nat_helper_register(&ftp[i]); - - if (ret) { - printk("ip_nat_ftp: error registering helper for port %d\n", ports[i]); - fini(); - return ret; - } - ports_c++; - } + if (ports[0] == 0) + ports[0] = 21; - } else { - ip_nat_expect_unregister(&ftp_expect); + for (i = 0; (i < MAX_PORTS) && ports[i]; i++) { + + memset(&ftp[i], 0, sizeof(struct ip_nat_helper)); + + ftp[i].tuple.dst.protonum = IPPROTO_TCP; + ftp[i].tuple.src.u.tcp.port = htons(ports[i]); + ftp[i].mask.dst.protonum = 0xFFFF; + ftp[i].mask.src.u.tcp.port = 0xFFFF; + ftp[i].help = help; + ftp[i].expect = ftp_nat_expected; + + tmpname = &ftp_names[i][0]; + sprintf(tmpname, "ftp%2.2d", i); + ftp[i].name = tmpname; + + DEBUGP("ip_nat_ftp: Trying to register for port %d\n", + ports[i]); + ret = ip_nat_helper_register(&ftp[i]); + + if (ret) { + printk("ip_nat_ftp: error registering " + "helper for port %d\n", ports[i]); + fini(); + return ret; + } + ports_c++; } + return ret; } diff -urN --exclude-from=diff.exclude linux-2.4.5/net/ipv4/netfilter.orig/ip_nat_helper.c linux-2.4.5/net/ipv4/netfilter/ip_nat_helper.c --- linux-2.4.5/net/ipv4/netfilter.orig/ip_nat_helper.c Fri Apr 27 23:15:01 2001 +++ linux-2.4.5/net/ipv4/netfilter/ip_nat_helper.c Wed Jul 4 18:05:30 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 @@ -232,10 +233,16 @@ /* Grrr... SACK. Fuck me even harder. Don't want to fix it on the fly, so blow it away. */ void -ip_nat_delete_sack(struct sk_buff *skb, struct tcphdr *tcph) +ip_nat_delete_sack(struct sk_buff *skb) { + struct iphdr *iph = skb->nh.iph; + struct tcphdr *tcph = (void *)iph + iph->ihl*4; unsigned int i; u_int8_t *opt = (u_int8_t *)tcph; + + /* Delete SACK_OK on initial TCP SYNs. */ + if (!(tcph->syn && !tcph->ack)) + return; DEBUGP("Seeking SACKPERM in SYN packet (doff = %u).\n", tcph->doff * 4); diff -urN --exclude-from=diff.exclude linux-2.4.5/net/ipv4/netfilter.orig/ip_nat_proto_icmp.c linux-2.4.5/net/ipv4/netfilter/ip_nat_proto_icmp.c --- linux-2.4.5/net/ipv4/netfilter.orig/ip_nat_proto_icmp.c Fri Mar 17 19:56:20 2000 +++ linux-2.4.5/net/ipv4/netfilter/ip_nat_proto_icmp.c Wed Jun 27 07:00:21 2001 @@ -87,11 +87,18 @@ else return 0; } +static int icmp_exp_matches_pkt(struct ip_conntrack_expect *exp, + struct sk_buff **pskb) +{ + return 1; +} + struct ip_nat_protocol ip_nat_protocol_icmp = { { NULL, NULL }, "ICMP", IPPROTO_ICMP, icmp_manip_pkt, icmp_in_range, icmp_unique_tuple, icmp_print, - icmp_print_range + icmp_print_range, + icmp_exp_matches_pkt }; diff -urN --exclude-from=diff.exclude linux-2.4.5/net/ipv4/netfilter.orig/ip_nat_proto_tcp.c linux-2.4.5/net/ipv4/netfilter/ip_nat_proto_tcp.c --- linux-2.4.5/net/ipv4/netfilter.orig/ip_nat_proto_tcp.c Fri Mar 17 19:56:20 2000 +++ linux-2.4.5/net/ipv4/netfilter/ip_nat_proto_tcp.c Mon Jul 2 17:16:52 2001 @@ -5,6 +5,8 @@ #include #include +#include + #include #include #include @@ -133,11 +135,24 @@ else return 0; } +static int tcp_exp_matches_pkt(struct ip_conntrack_expect *exp, + struct sk_buff **pskb) +{ + struct iphdr *iph = (*pskb)->nh.iph; + struct tcphdr *tcph = (struct tcphdr *)((u_int32_t *)iph + iph->ihl); + unsigned int datalen; + + datalen = (*pskb)->len - iph->ihl*4 - tcph->doff*4; + + return between(exp->seq, ntohl(tcph->seq), ntohl(tcph->seq) + datalen); +} + struct ip_nat_protocol ip_nat_protocol_tcp = { { NULL, NULL }, "TCP", IPPROTO_TCP, tcp_manip_pkt, tcp_in_range, tcp_unique_tuple, tcp_print, - tcp_print_range + tcp_print_range, + tcp_exp_matches_pkt }; diff -urN --exclude-from=diff.exclude linux-2.4.5/net/ipv4/netfilter.orig/ip_nat_proto_udp.c linux-2.4.5/net/ipv4/netfilter/ip_nat_proto_udp.c --- linux-2.4.5/net/ipv4/netfilter.orig/ip_nat_proto_udp.c Fri Aug 4 22:07:24 2000 +++ linux-2.4.5/net/ipv4/netfilter/ip_nat_proto_udp.c Wed Jun 27 07:00:21 2001 @@ -132,11 +132,18 @@ else return 0; } +static int udp_exp_matches_pkt(struct ip_conntrack_expect *exp, + struct sk_buff **pskb) +{ + return 1; +} + struct ip_nat_protocol ip_nat_protocol_udp = { { NULL, NULL }, "UDP", IPPROTO_UDP, udp_manip_pkt, udp_in_range, udp_unique_tuple, udp_print, - udp_print_range + udp_print_range, + udp_exp_matches_pkt }; diff -urN --exclude-from=diff.exclude linux-2.4.5/net/ipv4/netfilter.orig/ip_nat_rule.c linux-2.4.5/net/ipv4/netfilter/ip_nat_rule.c --- linux-2.4.5/net/ipv4/netfilter.orig/ip_nat_rule.c Fri Apr 27 23:15:01 2001 +++ linux-2.4.5/net/ipv4/netfilter/ip_nat_rule.c Wed Jun 27 07:00:21 2001 @@ -106,8 +106,6 @@ = { { NULL, NULL }, "nat", &nat_initial_table.repl, NAT_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL }; -LIST_HEAD(nat_expect_list); - /* Source NAT */ static unsigned int ipt_snat_target(struct sk_buff **pskb, unsigned int hooknum, @@ -242,19 +240,6 @@ return ip_nat_setup_info(conntrack, &mr, hooknum); } -static inline int call_expect(const struct ip_nat_expect *i, - struct sk_buff **pskb, - unsigned int hooknum, - struct ip_conntrack *ct, - struct ip_nat_info *info, - struct ip_conntrack *master, - struct ip_nat_info *masterinfo, - unsigned int *verdict) -{ - return i->expect(pskb, hooknum, ct, info, master, masterinfo, - verdict); -} - int ip_nat_rule_find(struct sk_buff **pskb, unsigned int hooknum, const struct net_device *in, @@ -264,41 +249,14 @@ { int ret; - /* Master won't vanish while this ctrack still alive */ - if (ct->master.master) { - struct ip_conntrack *master; - - master = (struct ip_conntrack *)ct->master.master; - if (LIST_FIND(&nat_expect_list, - call_expect, - struct ip_nat_expect *, - pskb, hooknum, ct, info, - master, &master->nat.info, &ret)) - return ret; - } ret = ipt_do_table(pskb, hooknum, in, out, &nat_table, NULL); + if (ret == NF_ACCEPT) { if (!(info->initialized & (1 << HOOK2MANIP(hooknum)))) /* NUL mapping */ ret = alloc_null_binding(ct, info, hooknum); } return ret; -} - -int ip_nat_expect_register(struct ip_nat_expect *expect) -{ - WRITE_LOCK(&ip_nat_lock); - list_prepend(&nat_expect_list, expect); - WRITE_UNLOCK(&ip_nat_lock); - - return 0; -} - -void ip_nat_expect_unregister(struct ip_nat_expect *expect) -{ - WRITE_LOCK(&ip_nat_lock); - LIST_DELETE(&nat_expect_list, expect); - WRITE_UNLOCK(&ip_nat_lock); } static struct ipt_target ipt_snat_reg diff -urN --exclude-from=diff.exclude linux-2.4.5/net/ipv4/netfilter.orig/ip_nat_standalone.c linux-2.4.5/net/ipv4/netfilter/ip_nat_standalone.c --- linux-2.4.5/net/ipv4/netfilter.orig/ip_nat_standalone.c Fri Apr 27 23:15:01 2001 +++ linux-2.4.5/net/ipv4/netfilter/ip_nat_standalone.c Wed Jun 27 07:00:21 2001 @@ -5,7 +5,12 @@ */ /* (c) 1999 Paul `Rusty' Russell. Licenced under the GNU General - Public Licence. */ + * Public Licence. + * + * 23 Apr 2001: Harald Welte + * - new API and handling of conntrack/nat helpers + * - now capable of multiple expectations for one master + * */ #include #include @@ -43,6 +48,15 @@ : ((hooknum) == NF_IP_LOCAL_OUT ? "LOCAL_OUT" \ : "*ERROR*"))) +static inline int call_expect(struct ip_conntrack *master, + struct sk_buff **pskb, + unsigned int hooknum, + struct ip_conntrack *ct, + struct ip_nat_info *info) +{ + return master->nat.info.helper->expect(pskb, hooknum, ct, info); +} + static unsigned int ip_nat_fn(unsigned int hooknum, struct sk_buff **pskb, @@ -103,8 +117,16 @@ int in_hashes = info->initialized; unsigned int ret; - ret = ip_nat_rule_find(pskb, hooknum, in, out, - ct, info); + if (ct->master + && master_ct(ct)->nat.info.helper + && master_ct(ct)->nat.info.helper->expect) { + ret = call_expect(master_ct(ct), pskb, + hooknum, ct, info); + } else { + ret = ip_nat_rule_find(pskb, hooknum, in, out, + ct, info); + } + if (ret != NF_ACCEPT) { WRITE_UNLOCK(&ip_nat_lock); return ret; @@ -337,8 +359,6 @@ EXPORT_SYMBOL(ip_nat_setup_info); EXPORT_SYMBOL(ip_nat_helper_register); EXPORT_SYMBOL(ip_nat_helper_unregister); -EXPORT_SYMBOL(ip_nat_expect_register); -EXPORT_SYMBOL(ip_nat_expect_unregister); EXPORT_SYMBOL(ip_nat_cheat_check); EXPORT_SYMBOL(ip_nat_mangle_tcp_packet); EXPORT_SYMBOL(ip_nat_seq_adjust);