patch-o-matic-ng-20050810 pptp-conntrack-nat
authorMark Huang <mlhuang@cs.princeton.edu>
Thu, 11 Aug 2005 20:53:44 +0000 (20:53 +0000)
committerMark Huang <mlhuang@cs.princeton.edu>
Thu, 11 Aug 2005 20:53:44 +0000 (20:53 +0000)
13 files changed:
include/linux/netfilter_ipv4/ip_conntrack.h
include/linux/netfilter_ipv4/ip_conntrack_core.h
include/linux/netfilter_ipv4/ip_conntrack_pptp.h
include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h
include/linux/netfilter_ipv4/ip_conntrack_tuple.h
net/ipv4/netfilter/Kconfig
net/ipv4/netfilter/Makefile
net/ipv4/netfilter/ip_conntrack_core.c
net/ipv4/netfilter/ip_conntrack_pptp.c
net/ipv4/netfilter/ip_conntrack_proto_gre.c
net/ipv4/netfilter/ip_conntrack_standalone.c
net/ipv4/netfilter/ip_nat_pptp.c
net/ipv4/netfilter/ip_nat_proto_gre.c

index f32a889..0ea861a 100644 (file)
@@ -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 <linux/netfilter_ipv4/ip_nat.h>
+#include <linux/netfilter_ipv4/ip_nat_pptp.h>
+
+/* 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 <linux/types.h>
@@ -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;
index d84be02..16d0f0d 100644 (file)
@@ -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. */
index 0fbec88..0c3e102 100644 (file)
@@ -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 <linux/netfilter_ipv4/lockhelp.h>
 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 */
index 0764685..8d090ef 100644 (file)
@@ -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 */
index a378663..ca2021e 100644 (file)
@@ -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)
 
index 5ef8dae..e9c730d 100644 (file)
@@ -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
-         <file:Documentation/modules.txt>.  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
-         <file:Documentation/modules.txt>.  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'.
index c2f4503..512a630 100644 (file)
@@ -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
index 1956c79..d11386a 100644 (file)
@@ -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",
index 29ab1a4..574a171 100644 (file)
@@ -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 <laforge@gnumonks.org>
+ * (C) 2000-2005 by Harald Welte <laforge@gnumonks.org>
  *
  * 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: 
  *     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/)
  *
  */
 
 #include <net/tcp.h>
 
 #include <linux/netfilter_ipv4/lockhelp.h>
+#include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <linux/netfilter_ipv4/ip_conntrack_core.h>
 #include <linux/netfilter_ipv4/ip_conntrack_helper.h>
 #include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
 #include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
 
-#define IP_CT_PPTP_VERSION "2.0"
+#define IP_CT_PPTP_VERSION "3.0"
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
@@ -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);
index 013f759..c386e57 100644 (file)
@@ -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 <laforge@gnumonks.org>
+ * (C) 2000-2005 by Harald Welte <laforge@gnumonks.org>
  *
  * 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);
index 87f56a3..83a668c 100644 (file)
@@ -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);
index 2bbb815..6063972 100644 (file)
@@ -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 <laforge@gnumonks.org>
+ * (C) 2000-2005 by Harald Welte <laforge@gnumonks.org>
  *
  * 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 <philipc@snapgear.com>)
  *     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/)
  * 
  */
 
 #include <linux/ip.h>
 #include <linux/tcp.h>
 #include <net/tcp.h>
+
 #include <linux/netfilter_ipv4/ip_nat.h>
 #include <linux/netfilter_ipv4/ip_nat_rule.h>
 #include <linux/netfilter_ipv4/ip_nat_helper.h>
 #include <linux/netfilter_ipv4/ip_nat_pptp.h>
+#include <linux/netfilter_ipv4/ip_conntrack_core.h>
 #include <linux/netfilter_ipv4/ip_conntrack_helper.h>
 #include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
 #include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
 
-#define IP_NAT_PPTP_VERSION "2.0"
+#define IP_NAT_PPTP_VERSION "3.0"
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
 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);
 }
 
index 5691a10..691f641 100644 (file)
@@ -36,8 +36,8 @@ MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
 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");