From: Mark Huang Date: Thu, 11 Aug 2005 20:53:44 +0000 (+0000) Subject: patch-o-matic-ng-20050810 pptp-conntrack-nat X-Git-Tag: before-fedora-2_6_18-1_2239_FC5-vs2_0_2_2-rc6-merge~169 X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=fda5a37345b600db5e569d327717a76e49461730;p=linux-2.6.git patch-o-matic-ng-20050810 pptp-conntrack-nat --- diff --git a/include/linux/netfilter_ipv4/ip_conntrack.h b/include/linux/netfilter_ipv4/ip_conntrack.h index f32a88939..0ea861a1b 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack.h +++ b/include/linux/netfilter_ipv4/ip_conntrack.h @@ -90,7 +90,6 @@ union ip_conntrack_proto { union ip_conntrack_expect_proto { /* insert expect proto private data here */ - struct ip_ct_gre_expect gre; }; /* Add protocol helper include file here */ @@ -109,6 +108,13 @@ union ip_conntrack_help { #ifdef CONFIG_IP_NF_NAT_NEEDED #include +#include + +/* per conntrack: nat application helper private data */ +union ip_conntrack_nat_help { + /* insert nat helper private data here */ + struct ip_nat_pptp nat_pptp_info; +}; #endif #include @@ -168,6 +174,7 @@ struct ip_conntrack #ifdef CONFIG_IP_NF_NAT_NEEDED struct { struct ip_nat_info info; + union ip_conntrack_nat_help help; #if defined(CONFIG_IP_NF_TARGET_MASQUERADE) || \ defined(CONFIG_IP_NF_TARGET_MASQUERADE_MODULE) int masq_index; diff --git a/include/linux/netfilter_ipv4/ip_conntrack_core.h b/include/linux/netfilter_ipv4/ip_conntrack_core.h index d84be02cb..16d0f0d9c 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack_core.h +++ b/include/linux/netfilter_ipv4/ip_conntrack_core.h @@ -34,6 +34,13 @@ struct ip_conntrack_tuple_hash * ip_conntrack_find_get(const struct ip_conntrack_tuple *tuple, const struct ip_conntrack *ignored_conntrack); +struct ip_conntrack_tuple_hash * +__ip_conntrack_find(const struct ip_conntrack_tuple *tuple, + const struct ip_conntrack *ignored_conntrack); + +struct ip_conntrack_expect * +__ip_conntrack_exp_find(const struct ip_conntrack_tuple *tuple); + extern int __ip_conntrack_confirm(struct sk_buff **pskb); /* Confirm a connection: returns NF_DROP if packet must be dropped. */ diff --git a/include/linux/netfilter_ipv4/ip_conntrack_pptp.h b/include/linux/netfilter_ipv4/ip_conntrack_pptp.h index 0fbec884a..0c3e102be 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack_pptp.h +++ b/include/linux/netfilter_ipv4/ip_conntrack_pptp.h @@ -33,6 +33,10 @@ struct ip_ct_pptp_master { enum pptp_ctrlcall_state cstate; /* call state */ u_int16_t pac_call_id; /* call id of PAC, host byte order */ u_int16_t pns_call_id; /* call id of PNS, host byte order */ + + /* in pre-2.6.11 this used to be per-expect. Now it is per-conntrack + * and therefore imposes a fixed limit on the number of maps */ + struct ip_ct_gre_keymap *keymap_orig, *keymap_reply; }; /* conntrack_expect private member */ @@ -45,6 +49,7 @@ struct ip_ct_pptp_expect { #ifdef __KERNEL__ + #include DECLARE_LOCK_EXTERN(ip_pptp_lock); @@ -306,5 +311,28 @@ union pptp_ctrl_union { struct PptpSetLinkInfo setlink; }; +struct ip_conntrack; + +extern int +(*ip_nat_pptp_hook_outbound)(struct sk_buff **pskb, + struct ip_conntrack *ct, + enum ip_conntrack_info ctinfo, + struct PptpControlHeader *ctlh, + union pptp_ctrl_union *pptpReq); + +extern int +(*ip_nat_pptp_hook_inbound)(struct sk_buff **pskb, + struct ip_conntrack *ct, + enum ip_conntrack_info ctinfo, + struct PptpControlHeader *ctlh, + union pptp_ctrl_union *pptpReq); + +extern int +(*ip_nat_pptp_hook_exp_gre)(struct ip_conntrack_expect *exp_orig, + struct ip_conntrack_expect *exp_reply); + +extern void +(*ip_nat_pptp_hook_expectfn)(struct ip_conntrack *ct, + struct ip_conntrack_expect *exp); #endif /* __KERNEL__ */ #endif /* _CONNTRACK_PPTP_H */ diff --git a/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h b/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h index 07646857c..8d090ef82 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h +++ b/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h @@ -71,13 +71,9 @@ struct ip_ct_gre { unsigned int timeout; }; -/* this is part of ip_conntrack_expect */ -struct ip_ct_gre_expect { - struct ip_ct_gre_keymap *keymap_orig, *keymap_reply; -}; - #ifdef __KERNEL__ struct ip_conntrack_expect; +struct ip_conntrack; /* structure for original <-> reply keymap */ struct ip_ct_gre_keymap { @@ -86,18 +82,13 @@ struct ip_ct_gre_keymap { struct ip_conntrack_tuple tuple; }; - /* add new tuple->key_reply pair to keymap */ -int ip_ct_gre_keymap_add(struct ip_conntrack_expect *exp, +int ip_ct_gre_keymap_add(struct ip_conntrack *ct, struct ip_conntrack_tuple *t, int reply); -/* change an existing keymap entry */ -void ip_ct_gre_keymap_change(struct ip_ct_gre_keymap *km, - struct ip_conntrack_tuple *t); - /* delete keymap entries */ -void ip_ct_gre_keymap_destroy(struct ip_conntrack_expect *exp); +void ip_ct_gre_keymap_destroy(struct ip_conntrack *ct); /* get pointer to gre key, if present */ diff --git a/include/linux/netfilter_ipv4/ip_conntrack_tuple.h b/include/linux/netfilter_ipv4/ip_conntrack_tuple.h index a37866339..ca2021ee0 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack_tuple.h +++ b/include/linux/netfilter_ipv4/ip_conntrack_tuple.h @@ -14,7 +14,7 @@ union ip_conntrack_manip_proto { /* Add other protocols here. */ - u_int32_t all; + u_int16_t all; struct { u_int16_t port; @@ -25,12 +25,12 @@ union ip_conntrack_manip_proto struct { u_int16_t id; } icmp; - struct { - u_int32_t key; - } gre; struct { u_int16_t port; } sctp; + struct { + u_int16_t key; /* key is 32bit, pptp onky uses 16 */ + } gre; }; /* The manipulable part of the tuple. */ @@ -50,7 +50,7 @@ struct ip_conntrack_tuple u_int32_t ip; union { /* Add other protocols here. */ - u_int32_t all; + u_int16_t all; struct { u_int16_t port; @@ -61,12 +61,12 @@ struct ip_conntrack_tuple struct { u_int8_t type, code; } icmp; - struct { - u_int32_t key; - } gre; struct { u_int16_t port; } sctp; + struct { + u_int16_t key; + } gre; } u; /* The protocol. */ @@ -95,16 +95,10 @@ enum ip_conntrack_dir #ifdef __KERNEL__ #define DUMP_TUPLE(tp) \ -DEBUGP("tuple %p: %u %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u\n", \ +DEBUGP("tuple %p: %u %u.%u.%u.%u:%hu -> %u.%u.%u.%u:%hu\n", \ (tp), (tp)->dst.protonum, \ - NIPQUAD((tp)->src.ip), ntohl((tp)->src.u.all), \ - NIPQUAD((tp)->dst.ip), ntohl((tp)->dst.u.all)) - -#define DUMP_TUPLE_RAW(x) \ - DEBUGP("tuple %p: %u %u.%u.%u.%u:0x%08x -> %u.%u.%u.%u:0x%08x\n",\ - (x), (x)->dst.protonum, \ - NIPQUAD((x)->src.ip), ntohl((x)->src.u.all), \ - NIPQUAD((x)->dst.ip), ntohl((x)->dst.u.all)) + NIPQUAD((tp)->src.ip), ntohs((tp)->src.u.all), \ + NIPQUAD((tp)->dst.ip), ntohs((tp)->dst.u.all)) #define CTINFO2DIR(ctinfo) ((ctinfo) >= IP_CT_IS_REPLY ? IP_CT_DIR_REPLY : IP_CT_DIR_ORIGINAL) diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 5ef8dae9a..e9c730d72 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -692,91 +692,14 @@ config IP_NF_ARP_MANGLE Allows altering the ARP packet payload: source and destination hardware and network addresses. -# Backwards compatibility modules: only if you don't build in the others. -config IP_NF_COMPAT_IPCHAINS - tristate "ipchains (2.2-style) support" - depends on IP_NF_CONNTRACK!=y && IP_NF_IPTABLES!=y - help - This option places ipchains (with masquerading and redirection - support) back into the kernel, using the new netfilter - infrastructure. It is not recommended for new installations (see - `Packet filtering'). With this enabled, you should be able to use - the ipchains tool exactly as in 2.2 kernels. - - To compile it as a module, choose M here. If unsure, say N. - -config IP_NF_COMPAT_IPFWADM - tristate "ipfwadm (2.0-style) support" - depends on IP_NF_CONNTRACK!=y && IP_NF_IPTABLES!=y && IP_NF_COMPAT_IPCHAINS!=y - help - This option places ipfwadm (with masquerading and redirection - support) back into the kernel, using the new netfilter - infrastructure. It is not recommended for new installations (see - `Packet filtering'). With this enabled, you should be able to use - the ipfwadm tool exactly as in 2.0 kernels. - - To compile it as a module, choose M here. If unsure, say N. - -config IP_NF_TARGET_NOTRACK - tristate 'NOTRACK target support' - depends on IP_NF_RAW - depends on IP_NF_CONNTRACK - help - The NOTRACK target allows a select rule to specify - which packets *not* to enter the conntrack/NAT - subsystem with all the consequences (no ICMP error tracking, - no protocol helpers for the selected packets). - - If you want to compile it as a module, say M here and read - . If unsure, say `N'. - -config IP_NF_RAW - tristate 'raw table support (required for NOTRACK/TRACE)' - depends on IP_NF_IPTABLES - help - This option adds a `raw' table to iptables. This table is the very - first in the netfilter framework and hooks in at the PREROUTING - and OUTPUT chains. - - If you want to compile it as a module, say M here and read - . If unsure, say `N'. - help - -config IP_NF_MATCH_ADDRTYPE - tristate 'address type match support' - depends on IP_NF_IPTABLES - help - This option allows you to match what routing thinks of an address, - eg. UNICAST, LOCAL, BROADCAST, ... - - If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. - -config IP_NF_MATCH_REALM - tristate 'realm match support' - depends on IP_NF_IPTABLES - select NET_CLS_ROUTE - help - This option adds a `realm' match, which allows you to use the realm - key from the routing subsytem inside iptables. - - This match pretty much resembles the CONFIG_NET_CLS_ROUTE4 option - in tc world. - - If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. - -config IP_NF_CT_ACCT - bool "Connection tracking flow accounting" - depends on IP_NF_CONNTRACK - config IP_NF_CT_PROTO_GRE tristate ' GRE protocol support' depends on IP_NF_CONNTRACK help - This module adds generic support for connection tracking and NAT of the - GRE protocol (RFC1701, RFC2784). Please note that this will only work - with GRE connections using the key field of the GRE header. + This module adds generic support for connection tracking and NAT of + the GRE protocol (RFC1701, RFC2784). Please note that this will + only work with GRE connections using the key field of the GRE + header. You will need GRE support to enable PPTP support. @@ -787,14 +710,15 @@ config IP_NF_PPTP tristate 'PPTP protocol support' depends on IP_NF_CT_PROTO_GRE help - This module adds support for PPTP (Point to Point Tunnelling Protocol, - RFC2637) conncection tracking and NAT. + This module adds support for PPTP (Point to Point Tunnelling + Protocol, RFC2637) conncection tracking and NAT. - If you are running PPTP sessions over a stateful firewall or NAT box, - you may want to enable this feature. + If you are running PPTP sessions over a stateful firewall or NAT + box, you may want to enable this feature. Please note that not all PPTP modes of operation are supported yet. - For more info, read top of the file net/ipv4/netfilter/ip_conntrack_pptp.c + For more info, read top of the file + net/ipv4/netfilter/ip_conntrack_pptp.c If you want to compile it as a module, say M here and read Documentation/modules.txt. If unsure, say `N'. diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index c2f450309..512a630e7 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -9,28 +9,27 @@ iptable_nat-objs := ip_nat_standalone.o ip_nat_rule.o ip_nat_core.o ip_nat_helpe # connection tracking obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o -# connection tracking protocol helpers +# SCTP protocol connection tracking obj-$(CONFIG_IP_NF_CT_PROTO_GRE) += ip_conntrack_proto_gre.o # NAT protocol helpers obj-$(CONFIG_IP_NF_NAT_PROTO_GRE) += ip_nat_proto_gre.o -# SCTP protocol connection tracking obj-$(CONFIG_IP_NF_CT_PROTO_SCTP) += ip_conntrack_proto_sctp.o # connection tracking helpers +obj-$(CONFIG_IP_NF_PPTP) += ip_conntrack_pptp.o obj-$(CONFIG_IP_NF_AMANDA) += ip_conntrack_amanda.o obj-$(CONFIG_IP_NF_TFTP) += ip_conntrack_tftp.o obj-$(CONFIG_IP_NF_FTP) += ip_conntrack_ftp.o obj-$(CONFIG_IP_NF_IRC) += ip_conntrack_irc.o -obj-$(CONFIG_IP_NF_PPTP) += ip_conntrack_pptp.o # NAT helpers +obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.o obj-$(CONFIG_IP_NF_NAT_AMANDA) += ip_nat_amanda.o obj-$(CONFIG_IP_NF_NAT_TFTP) += ip_nat_tftp.o obj-$(CONFIG_IP_NF_NAT_FTP) += ip_nat_ftp.o obj-$(CONFIG_IP_NF_NAT_IRC) += ip_nat_irc.o -obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.o # generic IP tables obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c index 1956c79c3..d11386a82 100644 --- a/net/ipv4/netfilter/ip_conntrack_core.c +++ b/net/ipv4/netfilter/ip_conntrack_core.c @@ -117,7 +117,6 @@ ip_ct_get_tuple(const struct iphdr *iph, tuple->src.ip = iph->saddr; tuple->dst.ip = iph->daddr; tuple->dst.protonum = iph->protocol; - tuple->src.u.all = tuple->dst.u.all = 0; tuple->dst.dir = IP_CT_DIR_ORIGINAL; return protocol->pkt_to_tuple(skb, dataoff, tuple); @@ -133,8 +132,6 @@ ip_ct_invert_tuple(struct ip_conntrack_tuple *inverse, inverse->dst.protonum = orig->dst.protonum; inverse->dst.dir = !orig->dst.dir; - inverse->src.u.all = inverse->dst.u.all = 0; - return protocol->invert_tuple(inverse, orig); } @@ -168,8 +165,8 @@ static void expectation_timed_out(unsigned long ul_expect) /* If an expectation for this connection is found, it gets delete from * global list then returned. */ -static struct ip_conntrack_expect * -find_expectation(const struct ip_conntrack_tuple *tuple) +struct ip_conntrack_expect * +__ip_conntrack_exp_find(const struct ip_conntrack_tuple *tuple) { struct ip_conntrack_expect *i; @@ -290,7 +287,7 @@ conntrack_tuple_cmp(const struct ip_conntrack_tuple_hash *i, && ip_ct_tuple_equal(tuple, &i->tuple); } -static struct ip_conntrack_tuple_hash * +struct ip_conntrack_tuple_hash * __ip_conntrack_find(const struct ip_conntrack_tuple *tuple, const struct ip_conntrack *ignored_conntrack) { @@ -516,7 +513,7 @@ init_conntrack(const struct ip_conntrack_tuple *tuple, conntrack->timeout.function = death_by_timeout; WRITE_LOCK(&ip_conntrack_lock); - exp = find_expectation(tuple); + exp = __ip_conntrack_exp_find(tuple); if (exp) { DEBUGP("conntrack: expectation arrives ct=%p exp=%p\n", diff --git a/net/ipv4/netfilter/ip_conntrack_pptp.c b/net/ipv4/netfilter/ip_conntrack_pptp.c index 29ab1a495..574a17124 100644 --- a/net/ipv4/netfilter/ip_conntrack_pptp.c +++ b/net/ipv4/netfilter/ip_conntrack_pptp.c @@ -1,5 +1,5 @@ /* - * ip_conntrack_pptp.c - Version 2.0 + * ip_conntrack_pptp.c - Version 3.0 * * Connection tracking support for PPTP (Point to Point Tunneling Protocol). * PPTP is a a protocol for creating virtual private networks. @@ -9,7 +9,7 @@ * GRE is defined in RFC 1701 and RFC 1702. Documentation of * PPTP can be found in RFC 2637 * - * (C) 2000-2003 by Harald Welte + * (C) 2000-2005 by Harald Welte * * Development of this code funded by Astaro AG (http://www.astaro.com/) * @@ -17,9 +17,9 @@ * - We blindly assume that control connections are always * established in PNS->PAC direction. This is a violation * of RFFC2673 + * - We can only support one single call within each session * - * TODO: - finish support for multiple calls within one session - * (needs expect reservations in newnat) + * TODO: * - testing of incoming PPTP calls * * Changes: @@ -35,6 +35,12 @@ * 2004-10-22 - Version 2.0 * - merge Mandrake's 2.6.x port with recent 2.6.x API changes * - fix lots of linear skb assumptions from Mandrake's port + * 2005-06-10 - Version 2.1 + * - use ip_conntrack_expect_free() instead of kfree() on the + * expect's (which are from the slab for quite some time) + * 2005-06-10 - Version 3.0 + * - port helper to post-2.6.11 API changes, + * funded by Oxcoda NetBox Blue (http://www.netboxblue.com/) * */ @@ -46,11 +52,13 @@ #include #include +#include +#include #include #include #include -#define IP_CT_PPTP_VERSION "2.0" +#define IP_CT_PPTP_VERSION "3.0" MODULE_LICENSE("GPL"); MODULE_AUTHOR("Harald Welte "); @@ -58,6 +66,28 @@ MODULE_DESCRIPTION("Netfilter connection tracking helper module for PPTP"); DECLARE_LOCK(ip_pptp_lock); +int +(*ip_nat_pptp_hook_outbound)(struct sk_buff **pskb, + struct ip_conntrack *ct, + enum ip_conntrack_info ctinfo, + struct PptpControlHeader *ctlh, + union pptp_ctrl_union *pptpReq); + +int +(*ip_nat_pptp_hook_inbound)(struct sk_buff **pskb, + struct ip_conntrack *ct, + enum ip_conntrack_info ctinfo, + struct PptpControlHeader *ctlh, + union pptp_ctrl_union *pptpReq); + +int +(*ip_nat_pptp_hook_exp_gre)(struct ip_conntrack_expect *expect_orig, + struct ip_conntrack_expect *expect_reply); + +void +(*ip_nat_pptp_hook_expectfn)(struct ip_conntrack *ct, + struct ip_conntrack_expect *exp); + #if 0 #include "ip_conntrack_pptp_priv.h" #define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s: " format, __FILE__, __FUNCTION__, ## args) @@ -73,96 +103,98 @@ DECLARE_LOCK(ip_pptp_lock); #define PPTP_GRE_TIMEOUT (10 MINS) #define PPTP_GRE_STREAM_TIMEOUT (5 DAYS) -static int pptp_expectfn(struct ip_conntrack *ct) +static void pptp_expectfn(struct ip_conntrack *ct, + struct ip_conntrack_expect *exp) { - struct ip_conntrack *master; - struct ip_conntrack_expect *exp; - DEBUGP("increasing timeouts\n"); + /* increase timeout of GRE data channel conntrack entry */ ct->proto.gre.timeout = PPTP_GRE_TIMEOUT; ct->proto.gre.stream_timeout = PPTP_GRE_STREAM_TIMEOUT; - master = master_ct(ct); - if (!master) { - DEBUGP(" no master!!!\n"); - return 0; - } + /* Can you see how rusty this code is, compared with the pre-2.6.11 + * one? That's what happened to my shiny newnat of 2002 ;( -HW */ - exp = ct->master; - if (!exp) { - DEBUGP("no expectation!!\n"); - return 0; - } + if (!ip_nat_pptp_hook_expectfn) { + struct ip_conntrack_tuple inv_t; + struct ip_conntrack_expect *exp_other; - DEBUGP("completing tuples with ct info\n"); - /* we can do this, since we're unconfirmed */ - if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key == - htonl(master->help.ct_pptp_info.pac_call_id)) { - /* assume PNS->PAC */ - ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key = - htonl(master->help.ct_pptp_info.pns_call_id); - ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key = - htonl(master->help.ct_pptp_info.pns_call_id); + /* obviously this tuple inversion only works until you do NAT */ + invert_tuplepr(&inv_t, &exp->tuple); + DEBUGP("trying to unexpect other dir: "); + DUMP_TUPLE(&inv_t); + + exp_other = __ip_conntrack_exp_find(&inv_t); + if (exp_other) { + /* delete other expectation. */ + DEBUGP("found\n"); + ip_conntrack_unexpect_related(exp_other); + } else { + DEBUGP("not found\n"); + } } else { - /* assume PAC->PNS */ - ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key = - htonl(master->help.ct_pptp_info.pac_call_id); - ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key = - htonl(master->help.ct_pptp_info.pac_call_id); + /* we need more than simple inversion */ + ip_nat_pptp_hook_expectfn(ct, exp); } - - /* delete other expectation */ - if (exp->expected_list.next != &exp->expected_list) { - struct ip_conntrack_expect *other_exp; - struct list_head *cur_item, *next; - - for (cur_item = master->sibling_list.next; - cur_item != &master->sibling_list; cur_item = next) { - next = cur_item->next; - other_exp = list_entry(cur_item, - struct ip_conntrack_expect, - expected_list); - /* remove only if occurred at same sequence number */ - if (other_exp != exp && other_exp->seq == exp->seq) { - DEBUGP("unexpecting other direction\n"); - ip_ct_gre_keymap_destroy(other_exp); - ip_conntrack_unexpect_related(other_exp); - } +} + +static int timeout_ct_or_exp(const struct ip_conntrack_tuple *t) +{ + struct ip_conntrack_tuple_hash *h; + struct ip_conntrack_expect *exp; + + DEBUGP("trying to timeout ct or exp for tuple "); + DUMP_TUPLE(t); + + h = __ip_conntrack_find(t, NULL); + if (h) { + struct ip_conntrack *sibling = tuplehash_to_ctrack(h); + DEBUGP("setting timeout of conntrack %p to 0\n", sibling); + sibling->proto.gre.timeout = 0; + sibling->proto.gre.stream_timeout = 0; + /* refresh_acct will not modify counters if skb == NULL */ + ip_ct_refresh_acct(sibling, 0, NULL, 0); + return 1; + } else { + exp = __ip_conntrack_exp_find(t); + if (exp) { + DEBUGP("unexpect_related of expect %p\n", exp); + ip_conntrack_unexpect_related(exp); + return 1; } } return 0; } + /* timeout GRE data connections */ static int pptp_timeout_related(struct ip_conntrack *ct) { - struct list_head *cur_item, *next; - struct ip_conntrack_expect *exp; + struct ip_conntrack_tuple t; + int ret; - /* FIXME: do we have to lock something ? */ - for (cur_item = ct->sibling_list.next; - cur_item != &ct->sibling_list; cur_item = next) { - next = cur_item->next; - exp = list_entry(cur_item, struct ip_conntrack_expect, - expected_list); + /* Since ct->sibling_list has literally rusted away in 2.6.11, + * we now need another way to find out about our sibling + * contrack and expects... -HW */ - ip_ct_gre_keymap_destroy(exp); - if (!exp->sibling) { - ip_conntrack_unexpect_related(exp); - continue; - } + /* try original (pns->pac) tuple */ + memcpy(&t, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, sizeof(t)); + t.dst.protonum = IPPROTO_GRE; + t.src.u.gre.key = htons(ct->help.ct_pptp_info.pns_call_id); + t.dst.u.gre.key = htons(ct->help.ct_pptp_info.pac_call_id); - DEBUGP("setting timeout of conntrack %p to 0\n", - exp->sibling); - exp->sibling->proto.gre.timeout = 0; - exp->sibling->proto.gre.stream_timeout = 0; - /* refresh_acct will not modify counters if skb == NULL */ - ip_ct_refresh_acct(exp->sibling, 0, NULL, 0); - } + ret = timeout_ct_or_exp(&t); - return 0; + /* try reply (pac->pns) tuple */ + memcpy(&t, &ct->tuplehash[IP_CT_DIR_REPLY].tuple, sizeof(t)); + t.dst.protonum = IPPROTO_GRE; + t.src.u.gre.key = htons(ct->help.ct_pptp_info.pac_call_id); + t.dst.u.gre.key = htons(ct->help.ct_pptp_info.pns_call_id); + + ret += timeout_ct_or_exp(&t); + + return ret; } /* expect GRE connections (PNS->PAC and PAC->PNS direction) */ @@ -176,79 +208,109 @@ exp_gre(struct ip_conntrack *master, struct ip_conntrack_tuple exp_tuples[] = { /* tuple in original direction, PNS->PAC */ { .src = { .ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip, - .u = { .gre = { .key = htonl(ntohs(peer_callid)) } } + .u = { .gre = { .key = peer_callid } } }, .dst = { .ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip, - .u = { .gre = { .key = htonl(ntohs(callid)) } }, + .u = { .gre = { .key = callid } }, .protonum = IPPROTO_GRE }, }, /* tuple in reply direction, PAC->PNS */ { .src = { .ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip, - .u = { .gre = { .key = htonl(ntohs(callid)) } } + .u = { .gre = { .key = callid } } }, .dst = { .ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip, - .u = { .gre = { .key = htonl(ntohs(peer_callid)) } }, + .u = { .gre = { .key = peer_callid } }, .protonum = IPPROTO_GRE }, } - }, *exp_tuple; + }; - for (exp_tuple = exp_tuples; exp_tuple < &exp_tuples[2]; exp_tuple++) { - struct ip_conntrack_expect *exp; + struct ip_conntrack_expect *exp_orig, *exp_reply; - exp = ip_conntrack_expect_alloc(); - if (exp == NULL) - return 1; + exp_orig = ip_conntrack_expect_alloc(); + if (exp_orig == NULL) + return 1; - memcpy(&exp->tuple, exp_tuple, sizeof(exp->tuple)); + exp_reply = ip_conntrack_expect_alloc(); + if (exp_reply == NULL) { + ip_conntrack_expect_free(exp_orig); + return 1; + } - exp->mask.src.ip = 0xffffffff; - exp->mask.src.u.all = 0; - exp->mask.dst.u.all = 0; - exp->mask.dst.u.gre.key = 0xffffffff; - exp->mask.dst.ip = 0xffffffff; - exp->mask.dst.protonum = 0xffff; - - exp->seq = seq; - exp->expectfn = pptp_expectfn; + memcpy(&exp_orig->tuple, &exp_tuples[0], sizeof(exp_orig->tuple)); - exp->help.exp_pptp_info.pac_call_id = ntohs(callid); - exp->help.exp_pptp_info.pns_call_id = ntohs(peer_callid); + exp_orig->mask.src.ip = 0xffffffff; + exp_orig->mask.src.u.all = 0; + exp_orig->mask.dst.u.all = 0; + exp_orig->mask.dst.u.gre.key = 0xffff; + exp_orig->mask.dst.ip = 0xffffffff; + exp_orig->mask.dst.protonum = 0xff; + + exp_orig->master = master; + exp_orig->expectfn = pptp_expectfn; - DEBUGP("calling expect_related "); - DUMP_TUPLE_RAW(&exp->tuple); - - /* Add GRE keymap entries */ - if (ip_ct_gre_keymap_add(exp, &exp->tuple, 0) != 0) { - kfree(exp); + exp_orig->dir = IP_CT_DIR_ORIGINAL; + + /* both expectations are identical apart from tuple */ + memcpy(exp_reply, exp_orig, sizeof(*exp_reply)); + memcpy(&exp_reply->tuple, &exp_tuples[1], sizeof(exp_reply->tuple)); + + exp_reply->dir = !exp_orig->dir; + + if (ip_nat_pptp_hook_exp_gre) + return ip_nat_pptp_hook_exp_gre(exp_orig, exp_reply); + else { + + DEBUGP("calling expect_related PNS->PAC"); + DUMP_TUPLE(&exp_orig->tuple); + + if (ip_conntrack_expect_related(exp_orig) != 0) { + ip_conntrack_expect_free(exp_orig); + ip_conntrack_expect_free(exp_reply); + DEBUGP("cannot expect_related()\n"); return 1; } - invert_tuplepr(&inv_tuple, &exp->tuple); - if (ip_ct_gre_keymap_add(exp, &inv_tuple, 1) != 0) { - ip_ct_gre_keymap_destroy(exp); - kfree(exp); + DEBUGP("calling expect_related PAC->PNS"); + DUMP_TUPLE(&exp_reply->tuple); + + if (ip_conntrack_expect_related(exp_reply) != 0) { + ip_conntrack_unexpect_related(exp_orig); + ip_conntrack_expect_free(exp_reply); + DEBUGP("cannot expect_related()\n"); return 1; } - - if (ip_conntrack_expect_related(exp, master) != 0) { - ip_ct_gre_keymap_destroy(exp); - kfree(exp); - DEBUGP("cannot expect_related()\n"); + + /* Add GRE keymap entries */ + if (ip_ct_gre_keymap_add(master, &exp_reply->tuple, 0) != 0) { + ip_conntrack_unexpect_related(exp_orig); + ip_conntrack_unexpect_related(exp_reply); + DEBUGP("cannot keymap_add() exp\n"); + return 1; + } + + invert_tuplepr(&inv_tuple, &exp_reply->tuple); + if (ip_ct_gre_keymap_add(master, &inv_tuple, 1) != 0) { + ip_conntrack_unexpect_related(exp_orig); + ip_conntrack_unexpect_related(exp_reply); + ip_ct_gre_keymap_destroy(master); + DEBUGP("cannot keymap_add() exp_inv\n"); return 1; } + } return 0; } static inline int -pptp_inbound_pkt(struct sk_buff *skb, +pptp_inbound_pkt(struct sk_buff **pskb, struct tcphdr *tcph, unsigned int ctlhoff, size_t datalen, - struct ip_conntrack *ct) + struct ip_conntrack *ct, + enum ip_conntrack_info ctinfo) { struct PptpControlHeader _ctlh, *ctlh; unsigned int reqlen; @@ -257,14 +319,14 @@ pptp_inbound_pkt(struct sk_buff *skb, u_int16_t msg, *cid, *pcid; u_int32_t seq; - ctlh = skb_header_pointer(skb, ctlhoff, sizeof(_ctlh), &_ctlh); + ctlh = skb_header_pointer(*pskb, ctlhoff, sizeof(_ctlh), &_ctlh); if (unlikely(!ctlh)) { DEBUGP("error during skb_header_pointer\n"); return NF_ACCEPT; } reqlen = datalen - sizeof(struct pptp_pkt_hdr) - sizeof(_ctlh); - pptpReq = skb_header_pointer(skb, ctlhoff+sizeof(struct pptp_pkt_hdr), + pptpReq = skb_header_pointer(*pskb, ctlhoff+sizeof(_ctlh), reqlen, &_pptpReq); if (unlikely(!pptpReq)) { DEBUGP("error during skb_header_pointer\n"); @@ -441,16 +503,22 @@ pptp_inbound_pkt(struct sk_buff *skb, break; } + + if (ip_nat_pptp_hook_inbound) + return ip_nat_pptp_hook_inbound(pskb, ct, ctinfo, ctlh, + pptpReq); + return NF_ACCEPT; } static inline int -pptp_outbound_pkt(struct sk_buff *skb, +pptp_outbound_pkt(struct sk_buff **pskb, struct tcphdr *tcph, unsigned int ctlhoff, size_t datalen, - struct ip_conntrack *ct) + struct ip_conntrack *ct, + enum ip_conntrack_info ctinfo) { struct PptpControlHeader _ctlh, *ctlh; unsigned int reqlen; @@ -458,12 +526,12 @@ pptp_outbound_pkt(struct sk_buff *skb, struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info; u_int16_t msg, *cid, *pcid; - ctlh = skb_header_pointer(skb, ctlhoff, sizeof(_ctlh), &_ctlh); + ctlh = skb_header_pointer(*pskb, ctlhoff, sizeof(_ctlh), &_ctlh); if (!ctlh) return NF_ACCEPT; reqlen = datalen - sizeof(struct pptp_pkt_hdr) - sizeof(_ctlh); - pptpReq = skb_header_pointer(skb, ctlhoff+sizeof(_ctlh), reqlen, + pptpReq = skb_header_pointer(*pskb, ctlhoff+sizeof(_ctlh), reqlen, &_pptpReq); if (!pptpReq) return NF_ACCEPT; @@ -488,7 +556,7 @@ pptp_outbound_pkt(struct sk_buff *skb, case PPTP_OUT_CALL_REQUEST: if (reqlen < sizeof(_pptpReq.ocreq)) { DEBUGP("%s: short packet\n", strMName[msg]); - break; + /* FIXME: break; */ } /* client initiating connection to server */ @@ -555,6 +623,10 @@ pptp_outbound_pkt(struct sk_buff *skb, /* unknown: no need to create GRE masq table entry */ break; } + + if (ip_nat_pptp_hook_outbound) + return ip_nat_pptp_hook_outbound(pskb, ct, ctinfo, ctlh, + pptpReq); return NF_ACCEPT; } @@ -562,14 +634,14 @@ pptp_outbound_pkt(struct sk_buff *skb, /* track caller id inside control connection, call expect_related */ static int -conntrack_pptp_help(struct sk_buff *skb, +conntrack_pptp_help(struct sk_buff **pskb, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) { struct pptp_pkt_hdr _pptph, *pptph; struct tcphdr _tcph, *tcph; - u_int32_t tcplen = skb->len - skb->nh.iph->ihl * 4; + u_int32_t tcplen = (*pskb)->len - (*pskb)->nh.iph->ihl * 4; u_int32_t datalen; void *datalimit; int dir = CTINFO2DIR(ctinfo); @@ -586,8 +658,8 @@ conntrack_pptp_help(struct sk_buff *skb, return NF_ACCEPT; } - nexthdr_off = skb->nh.iph->ihl*4; - tcph = skb_header_pointer(skb, skb->nh.iph->ihl*4, sizeof(_tcph), + nexthdr_off = (*pskb)->nh.iph->ihl*4; + tcph = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl*4, sizeof(_tcph), &_tcph); if (!tcph) return NF_ACCEPT; @@ -602,9 +674,10 @@ conntrack_pptp_help(struct sk_buff *skb, datalen = tcplen - tcph->doff * 4; /* checksum invalid? */ - if (tcp_v4_check(tcph, tcplen, skb->nh.iph->saddr, skb->nh.iph->daddr, - csum_partial((char *) tcph, tcplen, 0))) { - printk(KERN_NOTICE __FILE__ ": bad csum\n"); + if (tcp_v4_check(tcph, tcplen, (*pskb)->nh.iph->saddr, + (*pskb)->nh.iph->daddr, + csum_partial((char *) tcph, tcplen, 0))) { + DEBUGP(" bad csum\n"); /* W2K PPTP server sends TCP packets with wrong checksum :(( */ //return NF_ACCEPT; } @@ -619,7 +692,7 @@ conntrack_pptp_help(struct sk_buff *skb, } nexthdr_off += tcph->doff*4; - pptph = skb_header_pointer(skb, skb->nh.iph->ihl*4 + tcph->doff*4, + pptph = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl*4 + tcph->doff*4, sizeof(_pptph), &_pptph); if (!pptph) { DEBUGP("no full PPTP header, can't track\n"); @@ -645,10 +718,12 @@ conntrack_pptp_help(struct sk_buff *skb, * established from PNS->PAC. However, RFC makes no guarantee */ if (dir == IP_CT_DIR_ORIGINAL) /* client -> server (PNS -> PAC) */ - ret = pptp_outbound_pkt(skb, tcph, nexthdr_off, datalen, ct); + ret = pptp_outbound_pkt(pskb, tcph, nexthdr_off, datalen, ct, + ctinfo); else /* server -> client (PAC -> PNS) */ - ret = pptp_inbound_pkt(skb, tcph, nexthdr_off, datalen, ct); + ret = pptp_inbound_pkt(pskb, tcph, nexthdr_off, datalen, ct, + ctinfo); DEBUGP("sstate: %d->%d, cstate: %d->%d\n", oldsstate, info->sstate, oldcstate, info->cstate); UNLOCK_BH(&ip_pptp_lock); @@ -660,10 +735,9 @@ conntrack_pptp_help(struct sk_buff *skb, static struct ip_conntrack_helper pptp = { .list = { NULL, NULL }, .name = "pptp", - .flags = IP_CT_HELPER_F_REUSE_EXPECT, .me = THIS_MODULE, .max_expected = 2, - .timeout = 0, + .timeout = 5 * 60, .tuple = { .src = { .ip = 0, .u = { .tcp = { .port = __constant_htons(PPTP_CONTROL_PORT) } } @@ -678,7 +752,7 @@ static struct ip_conntrack_helper pptp = { }, .dst = { .ip = 0, .u = { .all = 0 }, - .protonum = 0xffff + .protonum = 0xff } }, .help = conntrack_pptp_help @@ -689,7 +763,7 @@ static int __init init(void) { int retcode; - DEBUGP(__FILE__ ": registering helper\n"); + DEBUGP(" registering helper\n"); if ((retcode = ip_conntrack_helper_register(&pptp))) { printk(KERN_ERR "Unable to register conntrack application " "helper for pptp: %d\n", retcode); @@ -710,3 +784,7 @@ module_init(init); module_exit(fini); EXPORT_SYMBOL(ip_pptp_lock); +EXPORT_SYMBOL(ip_nat_pptp_hook_outbound); +EXPORT_SYMBOL(ip_nat_pptp_hook_inbound); +EXPORT_SYMBOL(ip_nat_pptp_hook_exp_gre); +EXPORT_SYMBOL(ip_nat_pptp_hook_expectfn); diff --git a/net/ipv4/netfilter/ip_conntrack_proto_gre.c b/net/ipv4/netfilter/ip_conntrack_proto_gre.c index 013f759cc..c386e578e 100644 --- a/net/ipv4/netfilter/ip_conntrack_proto_gre.c +++ b/net/ipv4/netfilter/ip_conntrack_proto_gre.c @@ -1,5 +1,5 @@ /* - * ip_conntrack_proto_gre.c - Version 2.0 + * ip_conntrack_proto_gre.c - Version 3.0 * * Connection tracking protocol helper module for GRE. * @@ -17,7 +17,7 @@ * * Documentation about PPTP can be found in RFC 2637 * - * (C) 2000-2004 by Harald Welte + * (C) 2000-2005 by Harald Welte * * Development of this code funded by Astaro AG (http://www.astaro.com/) * @@ -57,8 +57,8 @@ MODULE_DESCRIPTION("netfilter connection tracking protocol helper for GRE"); #if 0 #define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s: " format, __FILE__, __FUNCTION__, ## args) #define DUMP_TUPLE_GRE(x) printk("%u.%u.%u.%u:0x%x -> %u.%u.%u.%u:0x%x\n", \ - NIPQUAD((x)->src.ip), ntohl((x)->src.u.gre.key), \ - NIPQUAD((x)->dst.ip), ntohl((x)->dst.u.gre.key)) + NIPQUAD((x)->src.ip), ntohs((x)->src.u.gre.key), \ + NIPQUAD((x)->dst.ip), ntohs((x)->dst.u.gre.key)) #else #define DEBUGP(x, args...) #define DUMP_TUPLE_GRE(x) @@ -80,27 +80,32 @@ static inline int gre_key_cmpfn(const struct ip_ct_gre_keymap *km, static u_int32_t gre_keymap_lookup(struct ip_conntrack_tuple *t) { struct ip_ct_gre_keymap *km; - u_int32_t key; + u_int32_t key = 0; READ_LOCK(&ip_ct_gre_lock); km = LIST_FIND(&gre_keymap_list, gre_key_cmpfn, struct ip_ct_gre_keymap *, t); - if (!km) { - READ_UNLOCK(&ip_ct_gre_lock); - return 0; - } - - key = km->tuple.src.u.gre.key; + if (km) + key = km->tuple.src.u.gre.key; READ_UNLOCK(&ip_ct_gre_lock); + + DEBUGP("lookup src key 0x%x up key for ", key); + DUMP_TUPLE_GRE(t); return key; } -/* add a single keymap entry, associate with specified expect */ -int ip_ct_gre_keymap_add(struct ip_conntrack_expect *exp, - struct ip_conntrack_tuple *t, int reply) +/* add a single keymap entry, associate with specified master ct */ +int +ip_ct_gre_keymap_add(struct ip_conntrack *ct, + struct ip_conntrack_tuple *t, int reply) { - struct ip_ct_gre_keymap *km; + struct ip_ct_gre_keymap *km, *old; + + if (!ct->helper || strcmp(ct->helper->name, "pptp")) { + DEBUGP("refusing to add GRE keymap to non-pptp session\n"); + return -1; + } km = kmalloc(sizeof(*km), GFP_ATOMIC); if (!km) @@ -111,10 +116,41 @@ int ip_ct_gre_keymap_add(struct ip_conntrack_expect *exp, memcpy(&km->tuple, t, sizeof(*t)); - if (!reply) - exp->proto.gre.keymap_orig = km; - else - exp->proto.gre.keymap_reply = km; + if (!reply) { + if (ct->help.ct_pptp_info.keymap_orig) { + kfree(km); + + /* check whether it's a retransmission */ + old = LIST_FIND(&gre_keymap_list, gre_key_cmpfn, + struct ip_ct_gre_keymap *, t); + if (old == ct->help.ct_pptp_info.keymap_orig) { + DEBUGP("retransmission\n"); + return 0; + } + + DEBUGP("trying to override keymap_orig for ct %p\n", + ct); + return -2; + } + ct->help.ct_pptp_info.keymap_orig = km; + } else { + if (ct->help.ct_pptp_info.keymap_reply) { + kfree(km); + + /* check whether it's a retransmission */ + old = LIST_FIND(&gre_keymap_list, gre_key_cmpfn, + struct ip_ct_gre_keymap *, t); + if (old == ct->help.ct_pptp_info.keymap_reply) { + DEBUGP("retransmission\n"); + return 0; + } + + DEBUGP("trying to override keymap_reply for ct %p\n", + ct); + return -2; + } + ct->help.ct_pptp_info.keymap_reply = km; + } DEBUGP("adding new entry %p: ", km); DUMP_TUPLE_GRE(&km->tuple); @@ -126,41 +162,30 @@ int ip_ct_gre_keymap_add(struct ip_conntrack_expect *exp, return 0; } -/* change the tuple of a keymap entry (used by nat helper) */ -void ip_ct_gre_keymap_change(struct ip_ct_gre_keymap *km, - struct ip_conntrack_tuple *t) +/* destroy the keymap entries associated with specified master ct */ +void ip_ct_gre_keymap_destroy(struct ip_conntrack *ct) { - if (!km) - { - printk(KERN_WARNING - "NULL GRE conntrack keymap change requested\n"); - return; - } - - DEBUGP("changing entry %p to: ", km); - DUMP_TUPLE_GRE(t); + DEBUGP("entering for ct %p\n", ct); - WRITE_LOCK(&ip_ct_gre_lock); - memcpy(&km->tuple, t, sizeof(km->tuple)); - WRITE_UNLOCK(&ip_ct_gre_lock); -} + if (!ct->helper || strcmp(ct->helper->name, "pptp")) { + DEBUGP("refusing to destroy GRE keymap to non-pptp session\n"); + return; + } -/* destroy the keymap entries associated with specified expect */ -void ip_ct_gre_keymap_destroy(struct ip_conntrack_expect *exp) -{ - DEBUGP("entering for exp %p\n", exp); WRITE_LOCK(&ip_ct_gre_lock); - if (exp->proto.gre.keymap_orig) { - DEBUGP("removing %p from list\n", exp->proto.gre.keymap_orig); - list_del(&exp->proto.gre.keymap_orig->list); - kfree(exp->proto.gre.keymap_orig); - exp->proto.gre.keymap_orig = NULL; + if (ct->help.ct_pptp_info.keymap_orig) { + DEBUGP("removing %p from list\n", + ct->help.ct_pptp_info.keymap_orig); + list_del(&ct->help.ct_pptp_info.keymap_orig->list); + kfree(ct->help.ct_pptp_info.keymap_orig); + ct->help.ct_pptp_info.keymap_orig = NULL; } - if (exp->proto.gre.keymap_reply) { - DEBUGP("removing %p from list\n", exp->proto.gre.keymap_reply); - list_del(&exp->proto.gre.keymap_reply->list); - kfree(exp->proto.gre.keymap_reply); - exp->proto.gre.keymap_reply = NULL; + if (ct->help.ct_pptp_info.keymap_reply) { + DEBUGP("removing %p from list\n", + ct->help.ct_pptp_info.keymap_reply); + list_del(&ct->help.ct_pptp_info.keymap_reply->list); + kfree(ct->help.ct_pptp_info.keymap_reply); + ct->help.ct_pptp_info.keymap_reply = NULL; } WRITE_UNLOCK(&ip_ct_gre_lock); } @@ -208,7 +233,7 @@ static int gre_pkt_to_tuple(const struct sk_buff *skb, DEBUGP("GRE_VERSION_PPTP but unknown proto\n"); return 0; } - tuple->dst.u.gre.key = htonl(ntohs(pgrehdr->call_id)); + tuple->dst.u.gre.key = pgrehdr->call_id; break; default: @@ -221,7 +246,7 @@ static int gre_pkt_to_tuple(const struct sk_buff *skb, tuple->src.u.gre.key = srckey; #if 0 - DEBUGP("found src key %x for tuple ", ntohl(srckey)); + DEBUGP("found src key %x for tuple ", ntohs(srckey)); DUMP_TUPLE_GRE(tuple); #endif @@ -229,21 +254,21 @@ static int gre_pkt_to_tuple(const struct sk_buff *skb, } /* print gre part of tuple */ -static unsigned int gre_print_tuple(char *buffer, - const struct ip_conntrack_tuple *tuple) +static int gre_print_tuple(struct seq_file *s, + const struct ip_conntrack_tuple *tuple) { - return sprintf(buffer, "srckey=0x%x dstkey=0x%x ", - ntohl(tuple->src.u.gre.key), - ntohl(tuple->dst.u.gre.key)); + return seq_printf(s, "srckey=0x%x dstkey=0x%x ", + ntohs(tuple->src.u.gre.key), + ntohs(tuple->dst.u.gre.key)); } /* print private data for conntrack */ -static unsigned int gre_print_conntrack(char *buffer, - const struct ip_conntrack *ct) +static int gre_print_conntrack(struct seq_file *s, + const struct ip_conntrack *ct) { - return sprintf(buffer, "timeout=%u, stream_timeout=%u ", - (ct->proto.gre.timeout / HZ), - (ct->proto.gre.stream_timeout / HZ)); + return seq_printf(s, "timeout=%u, stream_timeout=%u ", + (ct->proto.gre.timeout / HZ), + (ct->proto.gre.stream_timeout / HZ)); } /* Returns verdict for packet, and may modify conntrack */ @@ -284,16 +309,13 @@ static int gre_new(struct ip_conntrack *ct, * and is about to be deleted from memory */ static void gre_destroy(struct ip_conntrack *ct) { - struct ip_conntrack_expect *master = ct->master; - + struct ip_conntrack *master = ct->master; DEBUGP(" entering\n"); - if (!master) { - DEBUGP("no master exp for ct %p\n", ct); - return; - } - - ip_ct_gre_keymap_destroy(master); + if (!master) + DEBUGP("no master !?!\n"); + else + ip_ct_gre_keymap_destroy(master); } /* protocol helper struct */ @@ -307,7 +329,6 @@ static struct ip_conntrack_protocol gre = { .packet = gre_packet, .new = gre_new, .destroy = gre_destroy, - .exp_matches_pkt = NULL, .me = THIS_MODULE }; @@ -342,7 +363,6 @@ static void __exit fini(void) } EXPORT_SYMBOL(ip_ct_gre_keymap_add); -EXPORT_SYMBOL(ip_ct_gre_keymap_change); EXPORT_SYMBOL(ip_ct_gre_keymap_destroy); module_init(init); diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c index 87f56a319..83a668c87 100644 --- a/net/ipv4/netfilter/ip_conntrack_standalone.c +++ b/net/ipv4/netfilter/ip_conntrack_standalone.c @@ -998,6 +998,8 @@ EXPORT_SYMBOL(ip_conntrack_lock); EXPORT_SYMBOL(ip_conntrack_hash); EXPORT_SYMBOL(ip_conntrack_untracked); EXPORT_SYMBOL_GPL(ip_conntrack_find_get); +EXPORT_SYMBOL_GPL(__ip_conntrack_find); +EXPORT_SYMBOL_GPL(__ip_conntrack_exp_find); EXPORT_SYMBOL_GPL(ip_conntrack_put); #ifdef CONFIG_IP_NF_NAT_NEEDED EXPORT_SYMBOL(ip_conntrack_tcp_update); diff --git a/net/ipv4/netfilter/ip_nat_pptp.c b/net/ipv4/netfilter/ip_nat_pptp.c index 2bbb815e9..6063972d6 100644 --- a/net/ipv4/netfilter/ip_nat_pptp.c +++ b/net/ipv4/netfilter/ip_nat_pptp.c @@ -1,5 +1,5 @@ /* - * ip_nat_pptp.c - Version 2.0 + * ip_nat_pptp.c - Version 3.0 * * NAT support for PPTP (Point to Point Tunneling Protocol). * PPTP is a a protocol for creating virtual private networks. @@ -9,13 +9,11 @@ * GRE is defined in RFC 1701 and RFC 1702. Documentation of * PPTP can be found in RFC 2637 * - * (C) 2000-2004 by Harald Welte + * (C) 2000-2005 by Harald Welte * * Development of this code funded by Astaro AG (http://www.astaro.com/) * - * TODO: - Support for multiple calls within one session - * (needs netfilter newnat code) - * - NAT to a unique tuple, not to TCP source port + * TODO: - NAT to a unique tuple, not to TCP source port * (needs netfilter tuple reservation) * * Changes: @@ -31,6 +29,9 @@ * TCP header is mangled (Philip Craig ) * 2004-10-22 - Version 2.0 * - kernel 2.6.x version + * 2005-06-10 - Version 3.0 + * - kernel >= 2.6.11 version, + * funded by Oxcoda NetBox Blue (http://www.netboxblue.com/) * */ @@ -39,129 +40,92 @@ #include #include #include + #include #include #include #include +#include #include #include #include -#define IP_NAT_PPTP_VERSION "2.0" +#define IP_NAT_PPTP_VERSION "3.0" MODULE_LICENSE("GPL"); MODULE_AUTHOR("Harald Welte "); MODULE_DESCRIPTION("Netfilter NAT helper module for PPTP"); -#if 0 +#if 1 #include "ip_conntrack_pptp_priv.h" -#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \ - ": " format, ## args) +#define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s: " format, __FILE__, \ + __FUNCTION__, ## args) #else #define DEBUGP(format, args...) #endif -static unsigned int -pptp_nat_expected(struct sk_buff **pskb, - unsigned int hooknum, - struct ip_conntrack *ct, - struct ip_nat_info *info) +static void pptp_nat_expected(struct ip_conntrack *ct, + struct ip_conntrack_expect *exp) { - struct ip_conntrack *master = master_ct(ct); - struct ip_nat_multi_range mr; + struct ip_conntrack *master = ct->master; + struct ip_conntrack_expect *other_exp; + struct ip_conntrack_tuple t; struct ip_ct_pptp_master *ct_pptp_info; struct ip_nat_pptp *nat_pptp_info; - u_int32_t newip, newcid; - int ret; - - IP_NF_ASSERT(info); - IP_NF_ASSERT(master); - IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum)))); - - DEBUGP("we have a connection!\n"); - LOCK_BH(&ip_pptp_lock); ct_pptp_info = &master->help.ct_pptp_info; nat_pptp_info = &master->nat.help.nat_pptp_info; - /* need to alter GRE tuple because conntrack expectfn() used 'wrong' - * (unmanipulated) values */ - if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) { - DEBUGP("completing tuples with NAT info \n"); - /* we can do this, since we're unconfirmed */ - if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key == - htonl(ct_pptp_info->pac_call_id)) { - /* assume PNS->PAC */ - ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key = - htonl(nat_pptp_info->pns_call_id); - ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key = - htonl(nat_pptp_info->pns_call_id); - newip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; - newcid = htonl(nat_pptp_info->pac_call_id); - } else { - /* assume PAC->PNS */ - ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key = - htonl(nat_pptp_info->pac_call_id); - ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key = - htonl(nat_pptp_info->pac_call_id); - newip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; - newcid = htonl(nat_pptp_info->pns_call_id); - } + /* And here goes the grand finale of corrosion... */ + + if (exp->dir == IP_CT_DIR_ORIGINAL) { + DEBUGP("we are PNS->PAC\n"); + /* therefore, build tuple for PAC->PNS */ + t.src.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; + t.src.u.gre.key = htons(master->help.ct_pptp_info.pac_call_id); + t.dst.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; + t.dst.u.gre.key = htons(master->help.ct_pptp_info.pns_call_id); + t.dst.protonum = IPPROTO_GRE; } else { - if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key == - htonl(ct_pptp_info->pac_call_id)) { - /* assume PNS->PAC */ - newip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; - newcid = htonl(ct_pptp_info->pns_call_id); - } - else { - /* assume PAC->PNS */ - newip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; - newcid = htonl(ct_pptp_info->pac_call_id); - } + DEBUGP("we are PAC->PNS\n"); + /* build tuple for PNS->PAC */ + t.src.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; + t.src.u.gre.key = + htons(master->nat.help.nat_pptp_info.pns_call_id); + t.dst.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; + t.dst.u.gre.key = + htons(master->nat.help.nat_pptp_info.pac_call_id); + t.dst.protonum = IPPROTO_GRE; } - mr.rangesize = 1; - mr.range[0].flags = IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED; - mr.range[0].min_ip = mr.range[0].max_ip = newip; - mr.range[0].min = mr.range[0].max = - ((union ip_conntrack_manip_proto ) { newcid }); - DEBUGP("change ip to %u.%u.%u.%u\n", - NIPQUAD(newip)); - DEBUGP("change key to 0x%x\n", ntohl(newcid)); - ret = ip_nat_setup_info(ct, &mr, hooknum); - - UNLOCK_BH(&ip_pptp_lock); - - return ret; + DEBUGP("trying to unexpect other dir: "); + DUMP_TUPLE(&t); + other_exp = __ip_conntrack_exp_find(&t); + if (other_exp) { + ip_conntrack_unexpect_related(other_exp); + DEBUGP("success\n"); + } else { + DEBUGP("not found!\n"); + } + ip_nat_follow_master(ct, exp); } /* outbound packets == from PNS to PAC */ -static inline unsigned int +static int pptp_outbound_pkt(struct sk_buff **pskb, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo, - struct ip_conntrack_expect *exp) + struct PptpControlHeader *ctlh, + union pptp_ctrl_union *pptpReq) { - struct iphdr *iph = (*pskb)->nh.iph; - struct tcphdr *tcph = (void *) iph + iph->ihl*4; - struct pptp_pkt_hdr *pptph = (struct pptp_pkt_hdr *) - ((void *)tcph + tcph->doff*4); - - struct PptpControlHeader *ctlh; - union pptp_ctrl_union *pptpReq; struct ip_ct_pptp_master *ct_pptp_info = &ct->help.ct_pptp_info; struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info; u_int16_t msg, *cid = NULL, new_callid; - /* FIXME: size checks !!! */ - ctlh = (struct PptpControlHeader *) ((void *) pptph + sizeof(*pptph)); - pptpReq = (void *) ((void *) ctlh + sizeof(*ctlh)); - new_callid = htons(ct_pptp_info->pns_call_id); switch (msg = ntohs(ctlh->messageType)) { @@ -205,45 +169,113 @@ pptp_outbound_pkt(struct sk_buff **pskb, return NF_ACCEPT; } + /* only OUT_CALL_REQUEST, IN_CALL_REPLY, CALL_CLEAR_REQUEST pass + * down to here */ + IP_NF_ASSERT(cid); DEBUGP("altering call id from 0x%04x to 0x%04x\n", ntohs(*cid), ntohs(new_callid)); /* mangle packet */ - ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, (void *)cid - (void *)pptph, - sizeof(new_callid), (char *)&new_callid, - sizeof(new_callid)); + if (ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, + (void *)cid - ((void *)ctlh - sizeof(struct pptp_pkt_hdr)), + sizeof(new_callid), + (char *)&new_callid, + sizeof(new_callid)) == 0) + return NF_DROP; return NF_ACCEPT; } +static int +pptp_exp_gre(struct ip_conntrack_expect *expect_orig, + struct ip_conntrack_expect *expect_reply) +{ + struct ip_ct_pptp_master *ct_pptp_info = + &expect_orig->master->help.ct_pptp_info; + struct ip_nat_pptp *nat_pptp_info = + &expect_orig->master->nat.help.nat_pptp_info; + + struct ip_conntrack *ct = expect_orig->master; + + struct ip_conntrack_tuple inv_t; + struct ip_conntrack_tuple *orig_t, *reply_t; + + /* save original PAC call ID in nat_info */ + nat_pptp_info->pac_call_id = ct_pptp_info->pac_call_id; + + /* alter expectation */ + orig_t = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; + reply_t = &ct->tuplehash[IP_CT_DIR_REPLY].tuple; + + /* alter expectation for PNS->PAC direction */ + invert_tuplepr(&inv_t, &expect_orig->tuple); + expect_orig->saved_proto.gre.key = htons(nat_pptp_info->pac_call_id); + expect_orig->tuple.src.u.gre.key = htons(nat_pptp_info->pns_call_id); + expect_orig->tuple.dst.u.gre.key = htons(ct_pptp_info->pac_call_id); + inv_t.src.ip = reply_t->src.ip; + inv_t.dst.ip = reply_t->dst.ip; + inv_t.src.u.gre.key = htons(nat_pptp_info->pac_call_id); + inv_t.dst.u.gre.key = htons(ct_pptp_info->pns_call_id); + + if (!ip_conntrack_expect_related(expect_orig)) { + DEBUGP("successfully registered expect\n"); + } else { + DEBUGP("can't expect_related(expect_orig)\n"); + ip_conntrack_expect_free(expect_orig); + return 1; + } + + /* alter expectation for PAC->PNS direction */ + invert_tuplepr(&inv_t, &expect_reply->tuple); + expect_reply->saved_proto.gre.key = htons(nat_pptp_info->pns_call_id); + expect_reply->tuple.src.u.gre.key = htons(nat_pptp_info->pac_call_id); + expect_reply->tuple.dst.u.gre.key = htons(ct_pptp_info->pns_call_id); + inv_t.src.ip = orig_t->src.ip; + inv_t.dst.ip = orig_t->dst.ip; + inv_t.src.u.gre.key = htons(nat_pptp_info->pns_call_id); + inv_t.dst.u.gre.key = htons(ct_pptp_info->pac_call_id); + + if (!ip_conntrack_expect_related(expect_reply)) { + DEBUGP("successfully registered expect\n"); + } else { + DEBUGP("can't expect_related(expect_reply)\n"); + ip_conntrack_unexpect_related(expect_orig); + ip_conntrack_expect_free(expect_reply); + return 1; + } + + if (ip_ct_gre_keymap_add(ct, &expect_reply->tuple, 0) < 0) { + DEBUGP("can't register original keymap\n"); + ip_conntrack_unexpect_related(expect_orig); + ip_conntrack_unexpect_related(expect_reply); + return 1; + } + + if (ip_ct_gre_keymap_add(ct, &inv_t, 1) < 0) { + DEBUGP("can't register reply keymap\n"); + ip_conntrack_unexpect_related(expect_orig); + ip_conntrack_unexpect_related(expect_reply); + ip_ct_gre_keymap_destroy(ct); + return 1; + } + + return 0; +} + /* inbound packets == from PAC to PNS */ -static inline unsigned int +static int pptp_inbound_pkt(struct sk_buff **pskb, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo, - struct ip_conntrack_expect *oldexp) + struct PptpControlHeader *ctlh, + union pptp_ctrl_union *pptpReq) { - struct iphdr *iph = (*pskb)->nh.iph; - struct tcphdr *tcph = (void *) iph + iph->ihl*4; - struct pptp_pkt_hdr *pptph = (struct pptp_pkt_hdr *) - ((void *)tcph + tcph->doff*4); - - struct PptpControlHeader *ctlh; - union pptp_ctrl_union *pptpReq; - struct ip_ct_pptp_master *ct_pptp_info = &ct->help.ct_pptp_info; struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info; - u_int16_t msg, new_cid = 0, new_pcid, *pcid = NULL, *cid = NULL; - u_int32_t old_dst_ip; - - struct ip_conntrack_tuple t, inv_t; - struct ip_conntrack_tuple *orig_t, *reply_t; - /* FIXME: size checks !!! */ - ctlh = (struct PptpControlHeader *) ((void *) pptph + sizeof(*pptph)); - pptpReq = (void *) ((void *) ctlh + sizeof(*ctlh)); + int ret = NF_ACCEPT, rv; new_pcid = htons(nat_pptp_info->pns_call_id); @@ -251,67 +283,9 @@ pptp_inbound_pkt(struct sk_buff **pskb, case PPTP_OUT_CALL_REPLY: pcid = &pptpReq->ocack.peersCallID; cid = &pptpReq->ocack.callID; - if (!oldexp) { - DEBUGP("outcall but no expectation\n"); - break; - } - old_dst_ip = oldexp->tuple.dst.ip; - t = oldexp->tuple; - invert_tuplepr(&inv_t, &t); - - /* save original PAC call ID in nat_info */ - nat_pptp_info->pac_call_id = ct_pptp_info->pac_call_id; - - /* alter expectation */ - orig_t = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; - reply_t = &ct->tuplehash[IP_CT_DIR_REPLY].tuple; - if (t.src.ip == orig_t->src.ip && t.dst.ip == orig_t->dst.ip) { - /* expectation for PNS->PAC direction */ - t.src.u.gre.key = htonl(nat_pptp_info->pns_call_id); - t.dst.u.gre.key = htonl(ct_pptp_info->pac_call_id); - inv_t.src.ip = reply_t->src.ip; - inv_t.dst.ip = reply_t->dst.ip; - inv_t.src.u.gre.key = htonl(nat_pptp_info->pac_call_id); - inv_t.dst.u.gre.key = htonl(ct_pptp_info->pns_call_id); - } else { - /* expectation for PAC->PNS direction */ - t.src.u.gre.key = htonl(nat_pptp_info->pac_call_id); - t.dst.u.gre.key = htonl(ct_pptp_info->pns_call_id); - inv_t.src.ip = orig_t->src.ip; - inv_t.dst.ip = orig_t->dst.ip; - inv_t.src.u.gre.key = htonl(nat_pptp_info->pns_call_id); - inv_t.dst.u.gre.key = htonl(ct_pptp_info->pac_call_id); - } - - if (!ip_conntrack_change_expect(oldexp, &t)) { - DEBUGP("successfully changed expect\n"); - } else { - DEBUGP("can't change expect\n"); - } - ip_ct_gre_keymap_change(oldexp->proto.gre.keymap_orig, &t); - ip_ct_gre_keymap_change(oldexp->proto.gre.keymap_reply, &inv_t); break; case PPTP_IN_CALL_CONNECT: pcid = &pptpReq->iccon.peersCallID; - if (!oldexp) - break; - old_dst_ip = oldexp->tuple.dst.ip; - t = oldexp->tuple; - - /* alter expectation, no need for callID */ - if (t.dst.ip == ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip) { - /* expectation for PNS->PAC direction */ - t.src.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; - } else { - /* expectation for PAC->PNS direction */ - t.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; - } - - if (!ip_conntrack_change_expect(oldexp, &t)) { - DEBUGP("successfully changed expect\n"); - } else { - DEBUGP("can't change expect\n"); - } break; case PPTP_IN_CALL_REQUEST: /* only need to nat in case PAC is behind NAT box */ @@ -338,129 +312,58 @@ pptp_inbound_pkt(struct sk_buff **pskb, return NF_ACCEPT; } + /* only OUT_CALL_REPLY, IN_CALL_CONNECT, IN_CALL_REQUEST, + * WAN_ERROR_NOTIFY, CALL_DISCONNECT_NOTIFY pass down here */ + /* mangle packet */ IP_NF_ASSERT(pcid); DEBUGP("altering peer call id from 0x%04x to 0x%04x\n", ntohs(*pcid), ntohs(new_pcid)); - ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, (void *)pcid - (void *)pptph, - sizeof(new_pcid), (char *)&new_pcid, - sizeof(new_pcid)); + + rv = ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, + (void *)pcid - ((void *)ctlh - sizeof(struct pptp_pkt_hdr)), + sizeof(new_pcid), (char *)&new_pcid, + sizeof(new_pcid)); + if (rv != NF_ACCEPT) + return rv; if (new_cid) { IP_NF_ASSERT(cid); DEBUGP("altering call id from 0x%04x to 0x%04x\n", ntohs(*cid), ntohs(new_cid)); - ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, - (void *)cid - (void *)pptph, - sizeof(new_cid), (char *)&new_cid, - sizeof(new_cid)); + rv = ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, + (void *)cid - ((void *)ctlh - sizeof(struct pptp_pkt_hdr)), + sizeof(new_cid), + (char *)&new_cid, + sizeof(new_cid)); + if (rv != NF_ACCEPT) + return rv; } + /* check for earlier return value of 'switch' above */ + if (ret != NF_ACCEPT) + return ret; + /* great, at least we don't need to resize packets */ return NF_ACCEPT; } -static unsigned int tcp_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) +static int __init init(void) { - struct iphdr *iph = (*pskb)->nh.iph; - struct tcphdr *tcph = (void *) iph + iph->ihl*4; - unsigned int datalen = (*pskb)->len - iph->ihl*4 - tcph->doff*4; - struct pptp_pkt_hdr *pptph; - - int dir; - - DEBUGP("entering\n"); - - /* Only mangle things once: DST for original direction - and SRC for reply direction. */ - dir = CTINFO2DIR(ctinfo); - if (!((HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC - && dir == IP_CT_DIR_ORIGINAL) - || (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST - && dir == IP_CT_DIR_REPLY))) { - DEBUGP("Not touching dir %s at hook %s\n", - dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY", - hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" - : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" - : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" - : hooknum == NF_IP_LOCAL_IN ? "INPUT" : "???"); - return NF_ACCEPT; - } - - /* if packet is too small, just skip it */ - if (datalen < sizeof(struct pptp_pkt_hdr)+ - sizeof(struct PptpControlHeader)) { - DEBUGP("pptp packet too short\n"); - return NF_ACCEPT; - } - - pptph = (struct pptp_pkt_hdr *) ((void *)tcph + tcph->doff*4); - - /* if it's not a control message, we can't handle it */ - if (ntohs(pptph->packetType) != PPTP_PACKET_CONTROL || - ntohl(pptph->magicCookie) != PPTP_MAGIC_COOKIE) { - DEBUGP("not a pptp control packet\n"); - return NF_ACCEPT; - } + DEBUGP("%s: registering NAT helper\n", __FILE__); - LOCK_BH(&ip_pptp_lock); + BUG_ON(ip_nat_pptp_hook_outbound); + ip_nat_pptp_hook_outbound = &pptp_outbound_pkt; - if (dir == IP_CT_DIR_ORIGINAL) { - /* reuqests sent by client to server (PNS->PAC) */ - pptp_outbound_pkt(pskb, ct, ctinfo, exp); - } else { - /* response from the server to the client (PAC->PNS) */ - pptp_inbound_pkt(pskb, ct, ctinfo, exp); - } + BUG_ON(ip_nat_pptp_hook_inbound); + ip_nat_pptp_hook_inbound = &pptp_inbound_pkt; - UNLOCK_BH(&ip_pptp_lock); + BUG_ON(ip_nat_pptp_hook_exp_gre); + ip_nat_pptp_hook_exp_gre = &pptp_exp_gre; - return NF_ACCEPT; -} - -/* nat helper struct for control connection */ -static struct ip_nat_helper pptp_tcp_helper = { - .list = { NULL, NULL }, - .name = "pptp", - .flags = IP_NAT_HELPER_F_ALWAYS, - .me = THIS_MODULE, - .tuple = { .src = { .ip = 0, - .u = { .tcp = { .port = - __constant_htons(PPTP_CONTROL_PORT) } - } - }, - .dst = { .ip = 0, - .u = { .all = 0 }, - .protonum = IPPROTO_TCP - } - }, - - .mask = { .src = { .ip = 0, - .u = { .tcp = { .port = 0xFFFF } } - }, - .dst = { .ip = 0, - .u = { .all = 0 }, - .protonum = 0xFFFF - } - }, - .help = tcp_help, - .expect = pptp_nat_expected -}; - - -static int __init init(void) -{ - DEBUGP("%s: registering NAT helper\n", __FILE__); - if (ip_nat_helper_register(&pptp_tcp_helper)) { - printk(KERN_ERR "Unable to register NAT application helper " - "for pptp\n"); - return -EIO; - } + BUG_ON(ip_nat_pptp_hook_expectfn); + ip_nat_pptp_hook_expectfn = &pptp_nat_expected; printk("ip_nat_pptp version %s loaded\n", IP_NAT_PPTP_VERSION); return 0; @@ -469,7 +372,15 @@ static int __init init(void) static void __exit fini(void) { DEBUGP("cleanup_module\n" ); - ip_nat_helper_unregister(&pptp_tcp_helper); + + ip_nat_pptp_hook_expectfn = NULL; + ip_nat_pptp_hook_exp_gre = NULL; + ip_nat_pptp_hook_inbound = NULL; + ip_nat_pptp_hook_outbound = NULL; + + /* Make sure noone calls it, meanwhile */ + synchronize_net(); + printk("ip_nat_pptp version %s unloaded\n", IP_NAT_PPTP_VERSION); } diff --git a/net/ipv4/netfilter/ip_nat_proto_gre.c b/net/ipv4/netfilter/ip_nat_proto_gre.c index 5691a102a..691f641a3 100644 --- a/net/ipv4/netfilter/ip_nat_proto_gre.c +++ b/net/ipv4/netfilter/ip_nat_proto_gre.c @@ -36,8 +36,8 @@ MODULE_AUTHOR("Harald Welte "); MODULE_DESCRIPTION("Netfilter NAT protocol helper module for GRE"); #if 0 -#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \ - ": " format, ## args) +#define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s: " format, __FILE__, \ + __FUNCTION__, ## args) #else #define DEBUGP(x, args...) #endif @@ -68,7 +68,7 @@ gre_unique_tuple(struct ip_conntrack_tuple *tuple, const struct ip_conntrack *conntrack) { u_int32_t min, i, range_size; - u_int32_t key = 0, *keyptr; + u_int16_t key = 0, *keyptr; if (maniptype == IP_NAT_MANIP_SRC) keyptr = &tuple->src.u.gre.key; @@ -100,14 +100,18 @@ gre_unique_tuple(struct ip_conntrack_tuple *tuple, /* manipulate a GRE packet according to maniptype */ static int gre_manip_pkt(struct sk_buff **pskb, - unsigned int hdroff, - const struct ip_conntrack_manip *manip, + unsigned int iphdroff, + const struct ip_conntrack_tuple *tuple, enum ip_nat_manip_type maniptype) { struct gre_hdr *greh; struct gre_hdr_pptp *pgreh; + struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff); + unsigned int hdroff = iphdroff + iph->ihl*4; - if (!skb_ip_make_writable(pskb, hdroff + sizeof(*pgreh))) + /* pgreh includes two optional 32bit fields which are not required + * to be there. That's where the magic '8' comes from */ + if (!skb_ip_make_writable(pskb, hdroff + sizeof(*pgreh)-8)) return 0; greh = (void *)(*pskb)->data + hdroff; @@ -127,15 +131,15 @@ gre_manip_pkt(struct sk_buff **pskb, /* FIXME: Never tested this code... */ *(gre_csum(greh)) = ip_nat_cheat_check(~*(gre_key(greh)), - manip->u.gre.key, + tuple->dst.u.gre.key, *(gre_csum(greh))); } - *(gre_key(greh)) = manip->u.gre.key; + *(gre_key(greh)) = tuple->dst.u.gre.key; break; case GRE_VERSION_PPTP: DEBUGP("call_id -> 0x%04x\n", - ntohl(manip->u.gre.key)); - pgreh->call_id = htons(ntohl(manip->u.gre.key)); + ntohl(tuple->dst.u.gre.key)); + pgreh->call_id = htons(ntohl(tuple->dst.u.gre.key)); break; default: DEBUGP("can't nat unknown GRE version\n");