diff options
Diffstat (limited to 'package/linux/kernel-patches/308-netfilter-nat-pptp')
| -rw-r--r-- | package/linux/kernel-patches/308-netfilter-nat-pptp | 2412 | 
1 files changed, 2412 insertions, 0 deletions
diff --git a/package/linux/kernel-patches/308-netfilter-nat-pptp b/package/linux/kernel-patches/308-netfilter-nat-pptp new file mode 100644 index 000000000..6c7d6e6f2 --- /dev/null +++ b/package/linux/kernel-patches/308-netfilter-nat-pptp @@ -0,0 +1,2412 @@ +diff -urN linux-2.4.29-old/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.4.29-dev/include/linux/netfilter_ipv4/ip_conntrack.h +--- linux-2.4.29-old/include/linux/netfilter_ipv4/ip_conntrack.h	2005-04-02 19:04:11.000000000 +0200 ++++ linux-2.4.29-dev/include/linux/netfilter_ipv4/ip_conntrack.h	2005-04-02 19:41:05.000000000 +0200 +@@ -50,16 +50,19 @@ +  + #include <linux/netfilter_ipv4/ip_conntrack_tcp.h> + #include <linux/netfilter_ipv4/ip_conntrack_icmp.h> ++#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h> +  + /* per conntrack: protocol private data */ + union ip_conntrack_proto { + 	/* insert conntrack proto private data here */ + 	struct ip_ct_tcp tcp; + 	struct ip_ct_icmp icmp; ++	struct ip_ct_gre gre; + }; +  + union ip_conntrack_expect_proto { + 	/* insert expect proto private data here */ ++	struct ip_ct_gre_expect gre; + }; +  + /* Add protocol helper include file here */ +@@ -67,6 +70,7 @@ +  + #include <linux/netfilter_ipv4/ip_conntrack_ftp.h> + #include <linux/netfilter_ipv4/ip_conntrack_irc.h> ++#include <linux/netfilter_ipv4/ip_conntrack_pptp.h> +  + /* per expectation: application helper private data */ + union ip_conntrack_expect_help { +@@ -74,6 +78,7 @@ + 	struct ip_ct_amanda_expect exp_amanda_info; + 	struct ip_ct_ftp_expect exp_ftp_info; + 	struct ip_ct_irc_expect exp_irc_info; ++	struct ip_ct_pptp_expect exp_pptp_info; +  + #ifdef CONFIG_IP_NF_NAT_NEEDED + 	union { +@@ -87,14 +92,17 @@ + 	/* insert conntrack helper private data (master) here */ + 	struct ip_ct_ftp_master ct_ftp_info; + 	struct ip_ct_irc_master ct_irc_info; ++	struct ip_ct_pptp_master ct_pptp_info; + }; +  + #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 +  +diff -urN linux-2.4.29-old/include/linux/netfilter_ipv4/ip_conntrack_pptp.h linux-2.4.29-dev/include/linux/netfilter_ipv4/ip_conntrack_pptp.h +--- linux-2.4.29-old/include/linux/netfilter_ipv4/ip_conntrack_pptp.h	1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.29-dev/include/linux/netfilter_ipv4/ip_conntrack_pptp.h	2005-04-02 19:09:07.000000000 +0200 +@@ -0,0 +1,313 @@ ++/* PPTP constants and structs */ ++#ifndef _CONNTRACK_PPTP_H ++#define _CONNTRACK_PPTP_H ++ ++/* state of the control session */ ++enum pptp_ctrlsess_state { ++	PPTP_SESSION_NONE,			/* no session present */ ++	PPTP_SESSION_ERROR,			/* some session error */ ++	PPTP_SESSION_STOPREQ,			/* stop_sess request seen */ ++	PPTP_SESSION_REQUESTED,			/* start_sess request seen */ ++	PPTP_SESSION_CONFIRMED,			/* session established */ ++}; ++ ++/* state of the call inside the control session */ ++enum pptp_ctrlcall_state { ++	PPTP_CALL_NONE, ++	PPTP_CALL_ERROR, ++	PPTP_CALL_OUT_REQ, ++	PPTP_CALL_OUT_CONF, ++	PPTP_CALL_IN_REQ, ++	PPTP_CALL_IN_REP, ++	PPTP_CALL_IN_CONF, ++	PPTP_CALL_CLEAR_REQ, ++}; ++ ++ ++/* conntrack private data */ ++struct ip_ct_pptp_master { ++	enum pptp_ctrlsess_state sstate;	/* session state */ ++ ++	/* everything below is going to be per-expectation in newnat, ++	 * since there could be more than one call within one session */ ++	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 */ ++}; ++ ++/* conntrack_expect private member */ ++struct ip_ct_pptp_expect { ++	enum pptp_ctrlcall_state cstate; 	/* call state */ ++	u_int16_t pac_call_id;			/* call id of PAC */ ++	u_int16_t pns_call_id;			/* call id of PNS */ ++}; ++ ++ ++#ifdef __KERNEL__ ++ ++#include <linux/netfilter_ipv4/lockhelp.h> ++DECLARE_LOCK_EXTERN(ip_pptp_lock); ++ ++#define IP_CONNTR_PPTP		PPTP_CONTROL_PORT ++ ++union pptp_ctrl_union { ++                void				*rawreq; ++		struct PptpStartSessionRequest	*sreq; ++		struct PptpStartSessionReply	*srep; ++		struct PptpStopSessionRequest	*streq; ++		struct PptpStopSessionReply	*strep; ++                struct PptpOutCallRequest       *ocreq; ++                struct PptpOutCallReply         *ocack; ++                struct PptpInCallRequest        *icreq; ++                struct PptpInCallReply          *icack; ++                struct PptpInCallConnected      *iccon; ++		struct PptpClearCallRequest	*clrreq; ++                struct PptpCallDisconnectNotify *disc; ++                struct PptpWanErrorNotify       *wanerr; ++                struct PptpSetLinkInfo          *setlink; ++}; ++ ++ ++ ++#define PPTP_CONTROL_PORT	1723 ++ ++#define PPTP_PACKET_CONTROL	1 ++#define PPTP_PACKET_MGMT	2 ++ ++#define PPTP_MAGIC_COOKIE	0x1a2b3c4d ++ ++struct pptp_pkt_hdr { ++	__u16	packetLength; ++	__u16	packetType; ++	__u32	magicCookie; ++}; ++ ++/* PptpControlMessageType values */ ++#define PPTP_START_SESSION_REQUEST	1 ++#define PPTP_START_SESSION_REPLY	2 ++#define PPTP_STOP_SESSION_REQUEST	3 ++#define PPTP_STOP_SESSION_REPLY		4 ++#define PPTP_ECHO_REQUEST		5 ++#define PPTP_ECHO_REPLY			6 ++#define PPTP_OUT_CALL_REQUEST		7 ++#define PPTP_OUT_CALL_REPLY		8 ++#define PPTP_IN_CALL_REQUEST		9 ++#define PPTP_IN_CALL_REPLY		10 ++#define PPTP_IN_CALL_CONNECT		11 ++#define PPTP_CALL_CLEAR_REQUEST		12 ++#define PPTP_CALL_DISCONNECT_NOTIFY	13 ++#define PPTP_WAN_ERROR_NOTIFY		14 ++#define PPTP_SET_LINK_INFO		15 ++ ++#define PPTP_MSG_MAX			15 ++ ++/* PptpGeneralError values */ ++#define PPTP_ERROR_CODE_NONE		0 ++#define PPTP_NOT_CONNECTED		1 ++#define PPTP_BAD_FORMAT			2 ++#define PPTP_BAD_VALUE			3 ++#define PPTP_NO_RESOURCE		4 ++#define PPTP_BAD_CALLID			5 ++#define PPTP_REMOVE_DEVICE_ERROR	6 ++ ++struct PptpControlHeader { ++	__u16	messageType; ++	__u16	reserved; ++}; ++ ++/* FramingCapability Bitmap Values */ ++#define PPTP_FRAME_CAP_ASYNC		0x1 ++#define PPTP_FRAME_CAP_SYNC		0x2 ++ ++/* BearerCapability Bitmap Values */ ++#define PPTP_BEARER_CAP_ANALOG		0x1 ++#define PPTP_BEARER_CAP_DIGITAL		0x2 ++ ++struct PptpStartSessionRequest { ++	__u16	protocolVersion; ++	__u8	reserved1; ++	__u8	reserved2; ++	__u32	framingCapability; ++	__u32	bearerCapability; ++	__u16	maxChannels; ++	__u16	firmwareRevision; ++	__u8	hostName[64]; ++	__u8	vendorString[64]; ++}; ++ ++/* PptpStartSessionResultCode Values */ ++#define PPTP_START_OK			1 ++#define PPTP_START_GENERAL_ERROR	2 ++#define PPTP_START_ALREADY_CONNECTED	3 ++#define PPTP_START_NOT_AUTHORIZED	4 ++#define PPTP_START_UNKNOWN_PROTOCOL	5 ++ ++struct PptpStartSessionReply { ++	__u16	protocolVersion; ++	__u8	resultCode; ++	__u8	generalErrorCode; ++	__u32	framingCapability; ++	__u32	bearerCapability; ++	__u16	maxChannels; ++	__u16	firmwareRevision; ++	__u8	hostName[64]; ++	__u8	vendorString[64]; ++}; ++ ++/* PptpStopReasons */ ++#define PPTP_STOP_NONE			1 ++#define PPTP_STOP_PROTOCOL		2 ++#define PPTP_STOP_LOCAL_SHUTDOWN	3 ++ ++struct PptpStopSessionRequest { ++	__u8	reason; ++}; ++ ++/* PptpStopSessionResultCode */ ++#define PPTP_STOP_OK			1 ++#define PPTP_STOP_GENERAL_ERROR		2 ++ ++struct PptpStopSessionReply { ++	__u8	resultCode; ++	__u8	generalErrorCode; ++}; ++ ++struct PptpEchoRequest { ++	__u32 identNumber; ++}; ++ ++/* PptpEchoReplyResultCode */ ++#define PPTP_ECHO_OK			1 ++#define PPTP_ECHO_GENERAL_ERROR		2 ++ ++struct PptpEchoReply { ++	__u32	identNumber; ++	__u8	resultCode; ++	__u8	generalErrorCode; ++	__u16	reserved; ++}; ++ ++/* PptpFramingType */ ++#define PPTP_ASYNC_FRAMING		1 ++#define PPTP_SYNC_FRAMING		2 ++#define PPTP_DONT_CARE_FRAMING		3 ++ ++/* PptpCallBearerType */ ++#define PPTP_ANALOG_TYPE		1 ++#define PPTP_DIGITAL_TYPE		2 ++#define PPTP_DONT_CARE_BEARER_TYPE	3 ++ ++struct PptpOutCallRequest { ++	__u16	callID; ++	__u16	callSerialNumber; ++	__u32	minBPS; ++	__u32	maxBPS; ++	__u32	bearerType; ++	__u32	framingType; ++	__u16	packetWindow; ++	__u16	packetProcDelay; ++	__u16	reserved1; ++	__u16	phoneNumberLength; ++	__u16	reserved2; ++	__u8	phoneNumber[64]; ++	__u8	subAddress[64]; ++}; ++ ++/* PptpCallResultCode */ ++#define PPTP_OUTCALL_CONNECT		1 ++#define PPTP_OUTCALL_GENERAL_ERROR	2 ++#define PPTP_OUTCALL_NO_CARRIER		3 ++#define PPTP_OUTCALL_BUSY		4 ++#define PPTP_OUTCALL_NO_DIAL_TONE	5 ++#define PPTP_OUTCALL_TIMEOUT		6 ++#define PPTP_OUTCALL_DONT_ACCEPT	7 ++ ++struct PptpOutCallReply { ++	__u16	callID; ++	__u16	peersCallID; ++	__u8	resultCode; ++	__u8	generalErrorCode; ++	__u16	causeCode; ++	__u32	connectSpeed; ++	__u16	packetWindow; ++	__u16	packetProcDelay; ++	__u32	physChannelID; ++}; ++ ++struct PptpInCallRequest { ++	__u16	callID; ++	__u16	callSerialNumber; ++	__u32	callBearerType; ++	__u32	physChannelID; ++	__u16	dialedNumberLength; ++	__u16	dialingNumberLength; ++	__u8	dialedNumber[64]; ++	__u8	dialingNumber[64]; ++	__u8	subAddress[64]; ++}; ++ ++/* PptpInCallResultCode */ ++#define PPTP_INCALL_ACCEPT		1 ++#define PPTP_INCALL_GENERAL_ERROR	2 ++#define PPTP_INCALL_DONT_ACCEPT		3 ++ ++struct PptpInCallReply { ++	__u16	callID; ++	__u16	peersCallID; ++	__u8	resultCode; ++	__u8	generalErrorCode; ++	__u16	packetWindow; ++	__u16	packetProcDelay; ++	__u16	reserved; ++}; ++ ++struct PptpInCallConnected { ++	__u16	peersCallID; ++	__u16	reserved; ++	__u32	connectSpeed; ++	__u16	packetWindow; ++	__u16	packetProcDelay; ++	__u32	callFramingType; ++}; ++ ++struct PptpClearCallRequest { ++	__u16	callID; ++	__u16	reserved; ++}; ++ ++struct PptpCallDisconnectNotify { ++	__u16	callID; ++	__u8	resultCode; ++	__u8	generalErrorCode; ++	__u16	causeCode; ++	__u16	reserved; ++	__u8	callStatistics[128]; ++}; ++ ++struct PptpWanErrorNotify { ++	__u16	peersCallID; ++	__u16	reserved; ++	__u32	crcErrors; ++	__u32	framingErrors; ++	__u32	hardwareOverRuns; ++	__u32	bufferOverRuns; ++	__u32	timeoutErrors; ++	__u32	alignmentErrors; ++}; ++ ++struct PptpSetLinkInfo { ++	__u16	peersCallID; ++	__u16	reserved; ++	__u32	sendAccm; ++	__u32	recvAccm; ++}; ++ ++ ++struct pptp_priv_data { ++	__u16	call_id; ++	__u16	mcall_id; ++	__u16	pcall_id; ++}; ++ ++#endif /* __KERNEL__ */ ++#endif /* _CONNTRACK_PPTP_H */ +diff -urN linux-2.4.29-old/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h linux-2.4.29-dev/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h +--- linux-2.4.29-old/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h	1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.29-dev/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h	2005-04-02 19:10:45.000000000 +0200 +@@ -0,0 +1,123 @@ ++#ifndef _CONNTRACK_PROTO_GRE_H ++#define _CONNTRACK_PROTO_GRE_H ++#include <asm/byteorder.h> ++ ++/* GRE PROTOCOL HEADER */ ++ ++/* GRE Version field */ ++#define GRE_VERSION_1701	0x0 ++#define GRE_VERSION_PPTP	0x1 ++ ++/* GRE Protocol field */ ++#define GRE_PROTOCOL_PPTP	0x880B ++ ++/* GRE Flags */ ++#define GRE_FLAG_C		0x80 ++#define GRE_FLAG_R		0x40 ++#define GRE_FLAG_K		0x20 ++#define GRE_FLAG_S		0x10 ++#define GRE_FLAG_A		0x80 ++ ++#define GRE_IS_C(f)	((f)&GRE_FLAG_C) ++#define GRE_IS_R(f)	((f)&GRE_FLAG_R) ++#define GRE_IS_K(f)	((f)&GRE_FLAG_K) ++#define GRE_IS_S(f)	((f)&GRE_FLAG_S) ++#define GRE_IS_A(f)	((f)&GRE_FLAG_A) ++ ++/* GRE is a mess: Four different standards */ ++struct gre_hdr { ++#if defined(__LITTLE_ENDIAN_BITFIELD) ++	__u16	rec:3, ++		srr:1, ++		seq:1, ++		key:1, ++		routing:1, ++		csum:1, ++		version:3, ++		reserved:4, ++		ack:1; ++#elif defined(__BIG_ENDIAN_BITFIELD) ++	__u16	csum:1, ++		routing:1, ++		key:1, ++		seq:1, ++		srr:1, ++		rec:3, ++		ack:1, ++		reserved:4, ++		version:3; ++#else ++#error "Adjust your <asm/byteorder.h> defines" ++#endif ++	__u16	protocol; ++}; ++ ++/* modified GRE header for PPTP */ ++struct gre_hdr_pptp { ++	__u8  flags;		/* bitfield */ ++	__u8  version;		/* should be GRE_VERSION_PPTP */ ++	__u16 protocol;		/* should be GRE_PROTOCOL_PPTP */ ++	__u16 payload_len;	/* size of ppp payload, not inc. gre header */ ++	__u16 call_id;		/* peer's call_id for this session */ ++	__u32 seq;		/* sequence number.  Present if S==1 */ ++	__u32 ack;		/* seq number of highest packet recieved by */ ++				/*  sender in this session */ ++}; ++ ++ ++/* this is part of ip_conntrack */ ++struct ip_ct_gre { ++	unsigned int stream_timeout; ++	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; ++ ++/* structure for original <-> reply keymap */ ++struct ip_ct_gre_keymap { ++	struct list_head list; ++ ++	struct ip_conntrack_tuple tuple; ++}; ++ ++ ++/* add new tuple->key_reply pair to keymap */ ++int ip_ct_gre_keymap_add(struct ip_conntrack_expect *exp, ++			 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); ++ ++ ++/* get pointer to gre key, if present */ ++static inline u_int32_t *gre_key(struct gre_hdr *greh) ++{ ++	if (!greh->key) ++		return NULL; ++	if (greh->csum || greh->routing) ++		return (u_int32_t *) (greh+sizeof(*greh)+4); ++	return (u_int32_t *) (greh+sizeof(*greh)); ++} ++ ++/* get pointer ot gre csum, if present */ ++static inline u_int16_t *gre_csum(struct gre_hdr *greh) ++{ ++	if (!greh->csum) ++		return NULL; ++	return (u_int16_t *) (greh+sizeof(*greh)); ++} ++ ++#endif /* __KERNEL__ */ ++ ++#endif /* _CONNTRACK_PROTO_GRE_H */ +diff -urN linux-2.4.29-old/include/linux/netfilter_ipv4/ip_conntrack_tuple.h linux-2.4.29-dev/include/linux/netfilter_ipv4/ip_conntrack_tuple.h +--- linux-2.4.29-old/include/linux/netfilter_ipv4/ip_conntrack_tuple.h	2003-11-28 19:26:21.000000000 +0100 ++++ linux-2.4.29-dev/include/linux/netfilter_ipv4/ip_conntrack_tuple.h	2005-04-02 19:07:18.000000000 +0200 +@@ -14,7 +14,7 @@ + union ip_conntrack_manip_proto + { + 	/* Add other protocols here. */ +-	u_int16_t all; ++	u_int32_t all; +  + 	struct { + 		u_int16_t port; +@@ -25,6 +25,9 @@ + 	struct { + 		u_int16_t id; + 	} icmp; ++	struct { ++		u_int32_t key; ++	} gre; + }; +  + /* The manipulable part of the tuple. */ +@@ -44,7 +47,7 @@ + 		u_int32_t ip; + 		union { + 			/* Add other protocols here. */ +-			u_int16_t all; ++			u_int32_t all; +  + 			struct { + 				u_int16_t port; +@@ -55,6 +58,9 @@ + 			struct { + 				u_int8_t type, code; + 			} icmp; ++			struct { ++				u_int32_t key; ++			} gre; + 		} u; +  + 		/* The protocol. */ +@@ -80,10 +86,16 @@ + #ifdef __KERNEL__ +  + #define DUMP_TUPLE(tp)						\ +-DEBUGP("tuple %p: %u %u.%u.%u.%u:%hu -> %u.%u.%u.%u:%hu\n",	\ ++DEBUGP("tuple %p: %u %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u\n",	\ +        (tp), (tp)->dst.protonum,				\ +-       NIPQUAD((tp)->src.ip), ntohs((tp)->src.u.all),		\ +-       NIPQUAD((tp)->dst.ip), ntohs((tp)->dst.u.all)) ++       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)) +  + #define CTINFO2DIR(ctinfo) ((ctinfo) >= IP_CT_IS_REPLY ? IP_CT_DIR_REPLY : IP_CT_DIR_ORIGINAL) +  +diff -urN linux-2.4.29-old/include/linux/netfilter_ipv4/ip_nat_pptp.h linux-2.4.29-dev/include/linux/netfilter_ipv4/ip_nat_pptp.h +--- linux-2.4.29-old/include/linux/netfilter_ipv4/ip_nat_pptp.h	1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.29-dev/include/linux/netfilter_ipv4/ip_nat_pptp.h	2005-04-02 19:07:18.000000000 +0200 +@@ -0,0 +1,11 @@ ++/* PPTP constants and structs */ ++#ifndef _NAT_PPTP_H ++#define _NAT_PPTP_H ++ ++/* conntrack private data */ ++struct ip_nat_pptp { ++	u_int16_t pns_call_id;		/* NAT'ed PNS call id */ ++	u_int16_t pac_call_id;		/* NAT'ed PAC call id */ ++}; ++ ++#endif /* _NAT_PPTP_H */ +diff -urN linux-2.4.29-old/net/ipv4/netfilter/Config.in linux-2.4.29-dev/net/ipv4/netfilter/Config.in +--- linux-2.4.29-old/net/ipv4/netfilter/Config.in	2005-04-02 19:04:11.000000000 +0200 ++++ linux-2.4.29-dev/net/ipv4/netfilter/Config.in	2005-04-02 19:07:18.000000000 +0200 +@@ -10,6 +10,8 @@ +   dep_tristate '  Amanda protocol support' CONFIG_IP_NF_AMANDA $CONFIG_IP_NF_CONNTRACK +   dep_tristate '  TFTP protocol support' CONFIG_IP_NF_TFTP $CONFIG_IP_NF_CONNTRACK +   dep_tristate '  IRC protocol support' CONFIG_IP_NF_IRC $CONFIG_IP_NF_CONNTRACK ++  dep_tristate '  GRE protocol support' CONFIG_IP_NF_CT_PROTO_GRE $CONFIG_IP_NF_CONNTRACK ++  dep_tristate '   PPTP protocol support' CONFIG_IP_NF_PPTP $CONFIG_IP_NF_CT_PROTO_GRE + fi +  + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then +@@ -67,6 +69,20 @@ +       define_bool CONFIG_IP_NF_NAT_NEEDED y +       dep_tristate '    MASQUERADE target support' CONFIG_IP_NF_TARGET_MASQUERADE $CONFIG_IP_NF_NAT +       dep_tristate '    REDIRECT target support' CONFIG_IP_NF_TARGET_REDIRECT $CONFIG_IP_NF_NAT ++      if [ "$CONFIG_IP_NF_PPTP" = "m" ]; then ++        define_tristate CONFIG_IP_NF_NAT_PPTP m ++      else ++        if [ "$CONFIG_IP_NF_PPTP" = "y" ]; then ++          define_tristate CONFIG_IP_NF_NAT_PPTP $CONFIG_IP_NF_NAT ++        fi ++      fi ++      if [ "$CONFIG_IP_NF_CT_PROTO_GRE" = "m" ]; then ++        define_tristate CONFIG_IP_NF_NAT_PROTO_GRE m ++      else ++        if [ "$CONFIG_IP_NF_CT_PROTO_GRE" = "y" ]; then ++          define_tristate CONFIG_IP_NF_NAT_PROTO_GRE $CONFIG_IP_NF_NAT ++        fi ++      fi +       if [ "$CONFIG_IP_NF_AMANDA" = "m" ]; then +         define_tristate CONFIG_IP_NF_NAT_AMANDA m +       else +diff -urN linux-2.4.29-old/net/ipv4/netfilter/ip_conntrack_core.c linux-2.4.29-dev/net/ipv4/netfilter/ip_conntrack_core.c +--- linux-2.4.29-old/net/ipv4/netfilter/ip_conntrack_core.c	2005-04-02 19:04:11.000000000 +0200 ++++ linux-2.4.29-dev/net/ipv4/netfilter/ip_conntrack_core.c	2005-04-02 19:07:18.000000000 +0200 +@@ -142,6 +142,8 @@ + 	tuple->dst.ip = iph->daddr; + 	tuple->dst.protonum = iph->protocol; +  ++	tuple->src.u.all = tuple->dst.u.all = 0; ++ + 	ret = protocol->pkt_to_tuple((u_int32_t *)iph + iph->ihl, + 				     len - 4*iph->ihl, + 				     tuple); +@@ -157,6 +159,8 @@ + 	inverse->dst.ip = orig->src.ip; + 	inverse->dst.protonum = orig->dst.protonum; +  ++	inverse->src.u.all = inverse->dst.u.all = 0; ++ + 	return protocol->invert_tuple(inverse, orig); + } +  +@@ -954,8 +958,8 @@ + 	 * so there is no need to use the tuple lock too */ +  + 	DEBUGP("ip_conntrack_expect_related %p\n", related_to); +-	DEBUGP("tuple: "); DUMP_TUPLE(&expect->tuple); +-	DEBUGP("mask:  "); DUMP_TUPLE(&expect->mask); ++	DEBUGP("tuple: "); DUMP_TUPLE_RAW(&expect->tuple); ++	DEBUGP("mask:  "); DUMP_TUPLE_RAW(&expect->mask); +  + 	old = LIST_FIND(&ip_conntrack_expect_list, resent_expect, + 		        struct ip_conntrack_expect *, &expect->tuple,  +@@ -1072,15 +1076,14 @@ +  + 	MUST_BE_READ_LOCKED(&ip_conntrack_lock); + 	WRITE_LOCK(&ip_conntrack_expect_tuple_lock); +- + 	DEBUGP("change_expect:\n"); +-	DEBUGP("exp tuple: "); DUMP_TUPLE(&expect->tuple); +-	DEBUGP("exp mask:  "); DUMP_TUPLE(&expect->mask); +-	DEBUGP("newtuple:  "); DUMP_TUPLE(newtuple); ++	DEBUGP("exp tuple: "); DUMP_TUPLE_RAW(&expect->tuple); ++	DEBUGP("exp mask:  "); DUMP_TUPLE_RAW(&expect->mask); ++	DEBUGP("newtuple:  "); DUMP_TUPLE_RAW(newtuple); + 	if (expect->ct_tuple.dst.protonum == 0) { + 		/* Never seen before */ + 		DEBUGP("change expect: never seen before\n"); +-		if (!ip_ct_tuple_equal(&expect->tuple, newtuple)  ++		if (!ip_ct_tuple_mask_cmp(&expect->tuple, newtuple, &expect->mask) + 		    && LIST_FIND(&ip_conntrack_expect_list, expect_clash, + 			         struct ip_conntrack_expect *, newtuple, &expect->mask)) { + 			/* Force NAT to find an unused tuple */ +diff -urN linux-2.4.29-old/net/ipv4/netfilter/ip_conntrack_pptp.c linux-2.4.29-dev/net/ipv4/netfilter/ip_conntrack_pptp.c +--- linux-2.4.29-old/net/ipv4/netfilter/ip_conntrack_pptp.c	1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.29-dev/net/ipv4/netfilter/ip_conntrack_pptp.c	2005-04-02 19:13:21.000000000 +0200 +@@ -0,0 +1,633 @@ ++/* ++ * ip_conntrack_pptp.c	- Version 1.9 ++ * ++ * Connection tracking support for PPTP (Point to Point Tunneling Protocol). ++ * PPTP is a a protocol for creating virtual private networks. ++ * It is a specification defined by Microsoft and some vendors ++ * working with Microsoft.  PPTP is built on top of a modified ++ * version of the Internet Generic Routing Encapsulation Protocol. ++ * 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> ++ * ++ * Development of this code funded by Astaro AG (http://www.astaro.com/) ++ * ++ * Limitations: ++ * 	 - We blindly assume that control connections are always ++ * 	   established in PNS->PAC direction.  This is a violation ++ * 	   of RFFC2673 ++ * ++ * TODO: - finish support for multiple calls within one session ++ * 	   (needs expect reservations in newnat) ++ *	 - testing of incoming PPTP calls  ++ * ++ * Changes:  ++ * 	2002-02-05 - Version 1.3 ++ * 	  - Call ip_conntrack_unexpect_related() from  ++ * 	    pptp_timeout_related() to destroy expectations in case ++ * 	    CALL_DISCONNECT_NOTIFY or tcp fin packet was seen ++ * 	    (Philip Craig <philipc@snapgear.com>) ++ * 	  - Add Version information at module loadtime ++ * 	2002-02-10 - Version 1.6 ++ * 	  - move to C99 style initializers ++ * 	  - remove second expectation if first arrives ++ * ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/netfilter.h> ++#include <linux/ip.h> ++#include <net/checksum.h> ++#include <net/tcp.h> ++ ++#include <linux/netfilter_ipv4/lockhelp.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 "1.9" ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>"); ++MODULE_DESCRIPTION("Netfilter connection tracking helper module for PPTP"); ++ ++DECLARE_LOCK(ip_pptp_lock); ++ ++#if 0 ++#include "ip_conntrack_pptp_priv.h" ++#define DEBUGP(format, args...)	printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \ ++					": " format, ## args) ++#else ++#define DEBUGP(format, args...) ++#endif ++ ++#define SECS *HZ ++#define MINS * 60 SECS ++#define HOURS * 60 MINS ++#define DAYS * 24 HOURS ++ ++#define PPTP_GRE_TIMEOUT 		(10 MINS) ++#define PPTP_GRE_STREAM_TIMEOUT 	(5 DAYS) ++ ++static int pptp_expectfn(struct ip_conntrack *ct) ++{ ++	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; ++	} ++ ++	exp = ct->master; ++	if (!exp) { ++		DEBUGP("no expectation!!\n"); ++		return 0; ++	} ++ ++	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); ++	} 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); ++	} ++	 ++	/* 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); ++			} ++		} ++	} ++ ++	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; ++ ++	/* 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); ++ ++		ip_ct_gre_keymap_destroy(exp); ++		if (!exp->sibling) { ++			ip_conntrack_unexpect_related(exp); ++			continue; ++		} ++ ++		DEBUGP("setting timeout of conntrack %p to 0\n", ++			exp->sibling); ++		exp->sibling->proto.gre.timeout = 0; ++		exp->sibling->proto.gre.stream_timeout = 0; ++		ip_ct_refresh(exp->sibling, 0); ++	} ++ ++	return 0; ++} ++ ++/* expect GRE connections (PNS->PAC and PAC->PNS direction) */ ++static inline int ++exp_gre(struct ip_conntrack *master, ++	u_int32_t seq, ++	u_int16_t callid, ++	u_int16_t peer_callid) ++{ ++	struct ip_conntrack_expect exp; ++	struct ip_conntrack_tuple inv_tuple; ++ ++	memset(&exp, 0, sizeof(exp)); ++	/* tuple in original direction, PNS->PAC */ ++	exp.tuple.src.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; ++	exp.tuple.src.u.gre.key = htonl(ntohs(peer_callid)); ++	exp.tuple.dst.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; ++	exp.tuple.dst.u.gre.key = htonl(ntohs(callid)); ++	exp.tuple.dst.protonum = IPPROTO_GRE; ++ ++	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; ++ ++	exp.help.exp_pptp_info.pac_call_id = ntohs(callid); ++	exp.help.exp_pptp_info.pns_call_id = ntohs(peer_callid); ++ ++	DEBUGP("calling expect_related "); ++	DUMP_TUPLE_RAW(&exp.tuple); ++	 ++	/* Add GRE keymap entries */ ++	if (ip_ct_gre_keymap_add(&exp, &exp.tuple, 0) != 0) ++		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); ++		return 1; ++	} ++	 ++	if (ip_conntrack_expect_related(master, &exp) != 0) { ++		ip_ct_gre_keymap_destroy(&exp); ++		DEBUGP("cannot expect_related()\n"); ++		return 1; ++	} ++ ++	/* tuple in reply direction, PAC->PNS */ ++	exp.tuple.src.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; ++	exp.tuple.src.u.gre.key = htonl(ntohs(callid)); ++	exp.tuple.dst.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; ++	exp.tuple.dst.u.gre.key = htonl(ntohs(peer_callid)); ++ ++	DEBUGP("calling expect_related "); ++	DUMP_TUPLE_RAW(&exp.tuple); ++	 ++	/* Add GRE keymap entries */ ++	ip_ct_gre_keymap_add(&exp, &exp.tuple, 0); ++	invert_tuplepr(&inv_tuple, &exp.tuple); ++	ip_ct_gre_keymap_add(&exp, &inv_tuple, 1); ++	/* FIXME: cannot handle error correctly, since we need to free ++	 * the above keymap :( */ ++	 ++	if (ip_conntrack_expect_related(master, &exp) != 0) { ++		/* free the second pair of keypmaps */ ++		ip_ct_gre_keymap_destroy(&exp); ++		DEBUGP("cannot expect_related():\n"); ++		return 1; ++	} ++ ++	return 0; ++} ++ ++static inline int  ++pptp_inbound_pkt(struct tcphdr *tcph, ++		 struct pptp_pkt_hdr *pptph,  ++		 size_t datalen, ++		 struct ip_conntrack *ct, ++		 enum ip_conntrack_info ctinfo) ++{ ++	struct PptpControlHeader *ctlh; ++        union pptp_ctrl_union pptpReq; ++	 ++	struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info; ++	u_int16_t msg, *cid, *pcid; ++	u_int32_t seq;	 ++ ++	ctlh = (struct PptpControlHeader *)  ++		((char *) pptph + sizeof(struct pptp_pkt_hdr)); ++	pptpReq.rawreq = (void *)  ++		((char *) ctlh + sizeof(struct PptpControlHeader)); ++ ++	msg = ntohs(ctlh->messageType); ++	DEBUGP("inbound control message %s\n", strMName[msg]); ++ ++	switch (msg) { ++	case PPTP_START_SESSION_REPLY: ++		/* server confirms new control session */ ++		if (info->sstate < PPTP_SESSION_REQUESTED) { ++			DEBUGP("%s without START_SESS_REQUEST\n", ++				strMName[msg]); ++			break; ++		} ++		if (pptpReq.srep->resultCode == PPTP_START_OK) ++			info->sstate = PPTP_SESSION_CONFIRMED; ++		else  ++			info->sstate = PPTP_SESSION_ERROR; ++		break; ++ ++	case PPTP_STOP_SESSION_REPLY: ++		/* server confirms end of control session */ ++		if (info->sstate > PPTP_SESSION_STOPREQ) { ++			DEBUGP("%s without STOP_SESS_REQUEST\n", ++				strMName[msg]); ++			break; ++		} ++		if (pptpReq.strep->resultCode == PPTP_STOP_OK) ++			info->sstate = PPTP_SESSION_NONE; ++		else ++			info->sstate = PPTP_SESSION_ERROR; ++		break; ++ ++	case PPTP_OUT_CALL_REPLY: ++		/* server accepted call, we now expect GRE frames */ ++		if (info->sstate != PPTP_SESSION_CONFIRMED) { ++			DEBUGP("%s but no session\n", strMName[msg]); ++			break; ++		} ++		if (info->cstate != PPTP_CALL_OUT_REQ && ++		    info->cstate != PPTP_CALL_OUT_CONF) { ++			DEBUGP("%s without OUTCALL_REQ\n", strMName[msg]); ++			break; ++		} ++		if (pptpReq.ocack->resultCode != PPTP_OUTCALL_CONNECT) { ++			info->cstate = PPTP_CALL_NONE; ++			break; ++		} ++ ++		cid = &pptpReq.ocack->callID; ++		pcid = &pptpReq.ocack->peersCallID; ++ ++		info->pac_call_id = ntohs(*cid); ++		 ++		if (htons(info->pns_call_id) != *pcid) { ++			DEBUGP("%s for unknown callid %u\n", ++				strMName[msg], ntohs(*pcid)); ++			break; ++		} ++ ++		DEBUGP("%s, CID=%X, PCID=%X\n", strMName[msg],  ++			ntohs(*cid), ntohs(*pcid)); ++		 ++		info->cstate = PPTP_CALL_OUT_CONF; ++ ++		seq = ntohl(tcph->seq) + ((void *)pcid - (void *)pptph); ++		if (exp_gre(ct, seq, *cid, *pcid) != 0) ++			printk("ip_conntrack_pptp: error during exp_gre\n"); ++		break; ++ ++	case PPTP_IN_CALL_REQUEST: ++		/* server tells us about incoming call request */ ++		if (info->sstate != PPTP_SESSION_CONFIRMED) { ++			DEBUGP("%s but no session\n", strMName[msg]); ++			break; ++		} ++		pcid = &pptpReq.icack->peersCallID; ++		DEBUGP("%s, PCID=%X\n", strMName[msg], ntohs(*pcid)); ++		info->cstate = PPTP_CALL_IN_REQ; ++		info->pac_call_id= ntohs(*pcid); ++		break; ++ ++	case PPTP_IN_CALL_CONNECT: ++		/* server tells us about incoming call established */ ++		if (info->sstate != PPTP_SESSION_CONFIRMED) { ++			DEBUGP("%s but no session\n", strMName[msg]); ++			break; ++		} ++		if (info->sstate != PPTP_CALL_IN_REP ++		    && info->sstate != PPTP_CALL_IN_CONF) { ++			DEBUGP("%s but never sent IN_CALL_REPLY\n", ++				strMName[msg]); ++			break; ++		} ++ ++		pcid = &pptpReq.iccon->peersCallID; ++		cid = &info->pac_call_id; ++ ++		if (info->pns_call_id != ntohs(*pcid)) { ++			DEBUGP("%s for unknown CallID %u\n",  ++				strMName[msg], ntohs(*cid)); ++			break; ++		} ++ ++		DEBUGP("%s, PCID=%X\n", strMName[msg], ntohs(*pcid)); ++		info->cstate = PPTP_CALL_IN_CONF; ++ ++		/* we expect a GRE connection from PAC to PNS */ ++		seq = ntohl(tcph->seq) + ((void *)pcid - (void *)pptph); ++		if (exp_gre(ct, seq, *cid, *pcid) != 0) ++			printk("ip_conntrack_pptp: error during exp_gre\n"); ++ ++		break; ++ ++	case PPTP_CALL_DISCONNECT_NOTIFY: ++		/* server confirms disconnect */ ++		cid = &pptpReq.disc->callID; ++		DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*cid)); ++		info->cstate = PPTP_CALL_NONE; ++ ++		/* untrack this call id, unexpect GRE packets */ ++		pptp_timeout_related(ct); ++		break; ++ ++	case PPTP_WAN_ERROR_NOTIFY: ++		break; ++ ++	case PPTP_ECHO_REQUEST: ++	case PPTP_ECHO_REPLY: ++		/* I don't have to explain these ;) */ ++		break; ++	default: ++		DEBUGP("invalid %s (TY=%d)\n", (msg <= PPTP_MSG_MAX) ++			? strMName[msg]:strMName[0], msg); ++		break; ++	} ++ ++	return NF_ACCEPT; ++ ++} ++ ++static inline int ++pptp_outbound_pkt(struct tcphdr *tcph, ++		  struct pptp_pkt_hdr *pptph, ++		  size_t datalen, ++		  struct ip_conntrack *ct, ++		  enum ip_conntrack_info ctinfo) ++{ ++	struct PptpControlHeader *ctlh; ++        union pptp_ctrl_union pptpReq; ++	struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info; ++	u_int16_t msg, *cid, *pcid; ++ ++	ctlh = (struct PptpControlHeader *) ((void *) pptph + sizeof(*pptph)); ++	pptpReq.rawreq = (void *) ((void *) ctlh + sizeof(*ctlh)); ++ ++	msg = ntohs(ctlh->messageType); ++	DEBUGP("outbound control message %s\n", strMName[msg]); ++ ++	switch (msg) { ++	case PPTP_START_SESSION_REQUEST: ++		/* client requests for new control session */ ++		if (info->sstate != PPTP_SESSION_NONE) { ++			DEBUGP("%s but we already have one", ++				strMName[msg]); ++		} ++		info->sstate = PPTP_SESSION_REQUESTED; ++		break; ++	case PPTP_STOP_SESSION_REQUEST: ++		/* client requests end of control session */ ++		info->sstate = PPTP_SESSION_STOPREQ; ++		break; ++ ++	case PPTP_OUT_CALL_REQUEST: ++		/* client initiating connection to server */ ++		if (info->sstate != PPTP_SESSION_CONFIRMED) { ++			DEBUGP("%s but no session\n", ++				strMName[msg]); ++			break; ++		} ++		info->cstate = PPTP_CALL_OUT_REQ; ++		/* track PNS call id */ ++		cid = &pptpReq.ocreq->callID; ++		DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*cid)); ++		info->pns_call_id = ntohs(*cid); ++		break; ++	case PPTP_IN_CALL_REPLY: ++		/* client answers incoming call */ ++		if (info->cstate != PPTP_CALL_IN_REQ ++		    && info->cstate != PPTP_CALL_IN_REP) { ++			DEBUGP("%s without incall_req\n",  ++				strMName[msg]); ++			break; ++		} ++		if (pptpReq.icack->resultCode != PPTP_INCALL_ACCEPT) { ++			info->cstate = PPTP_CALL_NONE; ++			break; ++		} ++		pcid = &pptpReq.icack->peersCallID; ++		if (info->pac_call_id != ntohs(*pcid)) { ++			DEBUGP("%s for unknown call %u\n",  ++				strMName[msg], ntohs(*pcid)); ++			break; ++		} ++		DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*pcid)); ++		/* part two of the three-way handshake */ ++		info->cstate = PPTP_CALL_IN_REP; ++		info->pns_call_id = ntohs(pptpReq.icack->callID); ++		break; ++ ++	case PPTP_CALL_CLEAR_REQUEST: ++		/* client requests hangup of call */ ++		if (info->sstate != PPTP_SESSION_CONFIRMED) { ++			DEBUGP("CLEAR_CALL but no session\n"); ++			break; ++		} ++		/* FUTURE: iterate over all calls and check if ++		 * call ID is valid.  We don't do this without newnat, ++		 * because we only know about last call */ ++		info->cstate = PPTP_CALL_CLEAR_REQ; ++		break; ++	case PPTP_SET_LINK_INFO: ++		break; ++	case PPTP_ECHO_REQUEST: ++	case PPTP_ECHO_REPLY: ++		/* I don't have to explain these ;) */ ++		break; ++	default: ++		DEBUGP("invalid %s (TY=%d)\n", (msg <= PPTP_MSG_MAX)?  ++			strMName[msg]:strMName[0], msg); ++		/* unknown: no need to create GRE masq table entry */ ++		break; ++	} ++ ++	return NF_ACCEPT; ++} ++ ++ ++/* track caller id inside control connection, call expect_related */ ++static int  ++conntrack_pptp_help(const struct iphdr *iph, size_t len, ++		    struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) ++ ++{ ++	struct pptp_pkt_hdr *pptph; ++	 ++	struct tcphdr *tcph = (void *) iph + iph->ihl * 4; ++	u_int32_t tcplen = len - iph->ihl * 4; ++	u_int32_t datalen = tcplen - tcph->doff * 4; ++	void *datalimit; ++	int dir = CTINFO2DIR(ctinfo); ++	struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info; ++ ++	int oldsstate, oldcstate; ++	int ret; ++ ++	/* don't do any tracking before tcp handshake complete */ ++	if (ctinfo != IP_CT_ESTABLISHED  ++	    && ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY) { ++		DEBUGP("ctinfo = %u, skipping\n", ctinfo); ++		return NF_ACCEPT; ++	} ++	 ++	/* not a complete TCP header? */ ++	if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) { ++		DEBUGP("tcplen = %u\n", tcplen); ++		return NF_ACCEPT; ++	} ++ ++	/* checksum invalid? */ ++	if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, ++			csum_partial((char *) tcph, tcplen, 0))) { ++		printk(KERN_NOTICE __FILE__ ": bad csum\n"); ++		/* W2K PPTP server sends TCP packets with wrong checksum :(( */ ++		//return NF_ACCEPT; ++	} ++ ++	if (tcph->fin || tcph->rst) { ++		DEBUGP("RST/FIN received, timeouting GRE\n"); ++		/* can't do this after real newnat */ ++		info->cstate = PPTP_CALL_NONE; ++ ++		/* untrack this call id, unexpect GRE packets */ ++		pptp_timeout_related(ct); ++	} ++ ++ ++	pptph = (struct pptp_pkt_hdr *) ((void *) tcph + tcph->doff * 4); ++	datalimit = (void *) pptph + datalen; ++ ++	/* not a full pptp packet header? */ ++	if ((void *) pptph+sizeof(*pptph) >= datalimit) { ++		DEBUGP("no full PPTP header, can't track\n"); ++		return NF_ACCEPT; ++	} ++	 ++	/* if it's not a control message we can't do anything with it */ ++        if (ntohs(pptph->packetType) != PPTP_PACKET_CONTROL || ++	    ntohl(pptph->magicCookie) != PPTP_MAGIC_COOKIE) { ++		DEBUGP("not a control packet\n"); ++		return NF_ACCEPT; ++	} ++ ++	oldsstate = info->sstate; ++	oldcstate = info->cstate; ++ ++	LOCK_BH(&ip_pptp_lock); ++ ++	/* FIXME: We just blindly assume that the control connection is always ++	 * established from PNS->PAC.  However, RFC makes no guarantee */ ++	if (dir == IP_CT_DIR_ORIGINAL) ++		/* client -> server (PNS -> PAC) */ ++		ret = pptp_outbound_pkt(tcph, pptph, datalen, ct, ctinfo); ++	else ++		/* server -> client (PAC -> PNS) */ ++		ret = pptp_inbound_pkt(tcph, pptph, datalen, ct, ctinfo); ++	DEBUGP("sstate: %d->%d, cstate: %d->%d\n", ++		oldsstate, info->sstate, oldcstate, info->cstate); ++	UNLOCK_BH(&ip_pptp_lock); ++ ++	return ret; ++} ++ ++/* control protocol helper */ ++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, ++	.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 = conntrack_pptp_help ++}; ++ ++/* ip_conntrack_pptp initialization */ ++static int __init init(void) ++{ ++	int retcode; ++ ++	DEBUGP(__FILE__ ": registering helper\n"); ++	if ((retcode = ip_conntrack_helper_register(&pptp))) { ++                printk(KERN_ERR "Unable to register conntrack application " ++				"helper for pptp: %d\n", retcode); ++		return -EIO; ++	} ++ ++	printk("ip_conntrack_pptp version %s loaded\n", IP_CT_PPTP_VERSION); ++	return 0; ++} ++ ++static void __exit fini(void) ++{ ++	ip_conntrack_helper_unregister(&pptp); ++	printk("ip_conntrack_pptp version %s unloaded\n", IP_CT_PPTP_VERSION); ++} ++ ++module_init(init); ++module_exit(fini); ++ ++EXPORT_SYMBOL(ip_pptp_lock); +diff -urN linux-2.4.29-old/net/ipv4/netfilter/ip_conntrack_pptp_priv.h linux-2.4.29-dev/net/ipv4/netfilter/ip_conntrack_pptp_priv.h +--- linux-2.4.29-old/net/ipv4/netfilter/ip_conntrack_pptp_priv.h	1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.29-dev/net/ipv4/netfilter/ip_conntrack_pptp_priv.h	2005-04-02 19:14:10.000000000 +0200 +@@ -0,0 +1,24 @@ ++#ifndef _IP_CT_PPTP_PRIV_H ++#define _IP_CT_PPTP_PRIV_H ++ ++/* PptpControlMessageType names */ ++static const char *strMName[] = { ++	"UNKNOWN_MESSAGE", ++	"START_SESSION_REQUEST", ++	"START_SESSION_REPLY", ++	"STOP_SESSION_REQUEST", ++	"STOP_SESSION_REPLY", ++	"ECHO_REQUEST", ++	"ECHO_REPLY", ++	"OUT_CALL_REQUEST", ++	"OUT_CALL_REPLY", ++	"IN_CALL_REQUEST", ++	"IN_CALL_REPLY", ++	"IN_CALL_CONNECT", ++	"CALL_CLEAR_REQUEST", ++	"CALL_DISCONNECT_NOTIFY", ++	"WAN_ERROR_NOTIFY", ++	"SET_LINK_INFO" ++}; ++ ++#endif +diff -urN linux-2.4.29-old/net/ipv4/netfilter/ip_conntrack_proto_gre.c linux-2.4.29-dev/net/ipv4/netfilter/ip_conntrack_proto_gre.c +--- linux-2.4.29-old/net/ipv4/netfilter/ip_conntrack_proto_gre.c	1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.29-dev/net/ipv4/netfilter/ip_conntrack_proto_gre.c	2005-04-02 19:14:31.000000000 +0200 +@@ -0,0 +1,333 @@ ++/* ++ * ip_conntrack_proto_gre.c - Version 1.2  ++ * ++ * Connection tracking protocol helper module for GRE. ++ * ++ * GRE is a generic encapsulation protocol, which is generally not very ++ * suited for NAT, as it has no protocol-specific part as port numbers. ++ * ++ * It has an optional key field, which may help us distinguishing two  ++ * connections between the same two hosts. ++ * ++ * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784  ++ * ++ * PPTP is built on top of a modified version of GRE, and has a mandatory ++ * field called "CallID", which serves us for the same purpose as the key ++ * field in plain GRE. ++ * ++ * Documentation about PPTP can be found in RFC 2637 ++ * ++ * (C) 2000-2003 by Harald Welte <laforge@gnumonks.org> ++ * ++ * Development of this code funded by Astaro AG (http://www.astaro.com/) ++ * ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/types.h> ++#include <linux/timer.h> ++#include <linux/netfilter.h> ++#include <linux/ip.h> ++#include <linux/in.h> ++#include <linux/list.h> ++ ++#include <linux/netfilter_ipv4/lockhelp.h> ++ ++DECLARE_RWLOCK(ip_ct_gre_lock); ++#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_ct_gre_lock) ++#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_ct_gre_lock) ++ ++#include <linux/netfilter_ipv4/listhelp.h> ++#include <linux/netfilter_ipv4/ip_conntrack_protocol.h> ++#include <linux/netfilter_ipv4/ip_conntrack_helper.h> ++#include <linux/netfilter_ipv4/ip_conntrack_core.h> ++ ++#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h> ++#include <linux/netfilter_ipv4/ip_conntrack_pptp.h> ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>"); ++MODULE_DESCRIPTION("netfilter connection tracking protocol helper for GRE"); ++ ++/* shamelessly stolen from ip_conntrack_proto_udp.c */ ++#define GRE_TIMEOUT		(30*HZ) ++#define GRE_STREAM_TIMEOUT	(180*HZ) ++ ++#if 0 ++#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \ ++		                       ": " format, ## args) ++#define DUMP_TUPLE_GRE(x) printk("%u.%u.%u.%u:0x%x -> %u.%u.%u.%u:0x%x:%u:0x%x\n", \ ++			NIPQUAD((x)->src.ip), ntohl((x)->src.u.gre.key), \ ++			NIPQUAD((x)->dst.ip), ntohl((x)->dst.u.gre.key)) ++#else ++#define DEBUGP(x, args...) ++#define DUMP_TUPLE_GRE(x) ++#endif ++				 ++/* GRE KEYMAP HANDLING FUNCTIONS */ ++static LIST_HEAD(gre_keymap_list); ++ ++static inline int gre_key_cmpfn(const struct ip_ct_gre_keymap *km, ++				const struct ip_conntrack_tuple *t) ++{ ++	return ((km->tuple.src.ip == t->src.ip) && ++		(km->tuple.dst.ip == t->dst.ip) && ++	        (km->tuple.dst.protonum == t->dst.protonum) && ++	        (km->tuple.dst.u.all == t->dst.u.all)); ++} ++ ++/* look up the source key for a given tuple */ ++static u_int32_t gre_keymap_lookup(struct ip_conntrack_tuple *t) ++{ ++	struct ip_ct_gre_keymap *km; ++	u_int32_t key; ++ ++	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; ++	READ_UNLOCK(&ip_ct_gre_lock); ++ ++	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) ++{ ++	struct ip_ct_gre_keymap *km; ++ ++	km = kmalloc(sizeof(*km), GFP_ATOMIC); ++	if (!km) ++		return -1; ++ ++	/* initializing list head should be sufficient */ ++	memset(km, 0, sizeof(*km)); ++ ++	memcpy(&km->tuple, t, sizeof(*t)); ++ ++	if (!reply) ++		exp->proto.gre.keymap_orig = km; ++	else ++		exp->proto.gre.keymap_reply = km; ++ ++	DEBUGP("adding new entry %p: ", km); ++	DUMP_TUPLE_GRE(&km->tuple); ++ ++	WRITE_LOCK(&ip_ct_gre_lock); ++	list_append(&gre_keymap_list, km); ++	WRITE_UNLOCK(&ip_ct_gre_lock); ++ ++	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) ++{ ++	DEBUGP("changing entry %p to: ", km); ++	DUMP_TUPLE_GRE(t); ++ ++	WRITE_LOCK(&ip_ct_gre_lock); ++	memcpy(&km->tuple, t, sizeof(km->tuple)); ++	WRITE_UNLOCK(&ip_ct_gre_lock); ++} ++ ++/* 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 (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; ++	} ++	WRITE_UNLOCK(&ip_ct_gre_lock); ++} ++ ++ ++/* PUBLIC CONNTRACK PROTO HELPER FUNCTIONS */ ++ ++/* invert gre part of tuple */ ++static int gre_invert_tuple(struct ip_conntrack_tuple *tuple, ++			    const struct ip_conntrack_tuple *orig) ++{ ++	tuple->dst.u.gre.key = orig->src.u.gre.key; ++	tuple->src.u.gre.key = orig->dst.u.gre.key; ++ ++	return 1; ++} ++ ++/* gre hdr info to tuple */ ++static int gre_pkt_to_tuple(const void *datah, size_t datalen, ++			    struct ip_conntrack_tuple *tuple) ++{ ++	struct gre_hdr *grehdr = (struct gre_hdr *) datah; ++	struct gre_hdr_pptp *pgrehdr = (struct gre_hdr_pptp *) datah; ++	u_int32_t srckey; ++ ++	/* core guarantees 8 protocol bytes, no need for size check */ ++ ++	switch (grehdr->version) { ++		case GRE_VERSION_1701: ++			if (!grehdr->key) { ++				DEBUGP("Can't track GRE without key\n"); ++				return 0; ++			} ++			tuple->dst.u.gre.key = *(gre_key(grehdr)); ++			break; ++ ++		case GRE_VERSION_PPTP: ++			if (ntohs(grehdr->protocol) != GRE_PROTOCOL_PPTP) { ++				DEBUGP("GRE_VERSION_PPTP but unknown proto\n"); ++				return 0; ++			} ++			tuple->dst.u.gre.key = htonl(ntohs(pgrehdr->call_id)); ++			break; ++ ++		default: ++			printk(KERN_WARNING "unknown GRE version %hu\n", ++				grehdr->version); ++			return 0; ++	} ++ ++	srckey = gre_keymap_lookup(tuple); ++ ++#if 0 ++	DEBUGP("found src key %x for tuple ", ntohl(srckey)); ++	DUMP_TUPLE_GRE(tuple); ++#endif ++	tuple->src.u.gre.key = srckey; ++ ++	return 1; ++} ++ ++/* print gre part of tuple */ ++static unsigned int gre_print_tuple(char *buffer, ++				    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)); ++} ++ ++/* print private data for conntrack */ ++static unsigned int gre_print_conntrack(char *buffer, ++					const struct ip_conntrack *ct) ++{ ++	return sprintf(buffer, "timeout=%u, stream_timeout=%u ", ++		       (ct->proto.gre.timeout / HZ), ++		       (ct->proto.gre.stream_timeout / HZ)); ++} ++ ++/* Returns verdict for packet, and may modify conntrack */ ++static int gre_packet(struct ip_conntrack *ct, ++		      struct iphdr *iph, size_t len, ++		      enum ip_conntrack_info conntrackinfo) ++{ ++	/* If we've seen traffic both ways, this is a GRE connection. ++	 * Extend timeout. */ ++	if (ct->status & IPS_SEEN_REPLY) { ++		ip_ct_refresh(ct, ct->proto.gre.stream_timeout); ++		/* Also, more likely to be important, and not a probe. */ ++		set_bit(IPS_ASSURED_BIT, &ct->status); ++	} else ++		ip_ct_refresh(ct, ct->proto.gre.timeout); ++	 ++	return NF_ACCEPT; ++} ++ ++/* Called when a new connection for this protocol found. */ ++static int gre_new(struct ip_conntrack *ct, ++		   struct iphdr *iph, size_t len) ++{  ++	DEBUGP(": "); ++	DUMP_TUPLE_GRE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); ++ ++	/* initialize to sane value.  Ideally a conntrack helper ++	 * (e.g. in case of pptp) is increasing them */ ++	ct->proto.gre.stream_timeout = GRE_STREAM_TIMEOUT; ++	ct->proto.gre.timeout = GRE_TIMEOUT; ++ ++	return 1; ++} ++ ++/* Called when a conntrack entry has already been removed from the hashes ++ * and is about to be deleted from memory */ ++static void gre_destroy(struct ip_conntrack *ct) ++{ ++	struct ip_conntrack_expect *master = ct->master; ++ ++	DEBUGP(" entering\n"); ++ ++	if (!master) { ++		DEBUGP("no master exp for ct %p\n", ct); ++		return; ++	} ++ ++	ip_ct_gre_keymap_destroy(master); ++} ++ ++/* protocol helper struct */ ++static struct ip_conntrack_protocol gre = { { NULL, NULL }, IPPROTO_GRE, ++					    "gre",  ++					    gre_pkt_to_tuple, ++					    gre_invert_tuple, ++					    gre_print_tuple, ++					    gre_print_conntrack, ++					    gre_packet, ++					    gre_new, ++					    gre_destroy, ++					    NULL, ++					    THIS_MODULE }; ++ ++/* ip_conntrack_proto_gre initialization */ ++static int __init init(void) ++{ ++	int retcode; ++ ++	if ((retcode = ip_conntrack_protocol_register(&gre))) { ++                printk(KERN_ERR "Unable to register conntrack protocol " ++			        "helper for gre: %d\n",	retcode); ++		return -EIO; ++	} ++ ++	return 0; ++} ++ ++static void __exit fini(void) ++{ ++	struct list_head *pos, *n; ++ ++	/* delete all keymap entries */ ++	WRITE_LOCK(&ip_ct_gre_lock); ++	list_for_each_safe(pos, n, &gre_keymap_list) { ++		DEBUGP("deleting keymap %p at module unload time\n", pos); ++		list_del(pos); ++		kfree(pos); ++	} ++	WRITE_UNLOCK(&ip_ct_gre_lock); ++ ++	ip_conntrack_protocol_unregister(&gre);  ++} ++ ++EXPORT_SYMBOL(ip_ct_gre_keymap_add); ++EXPORT_SYMBOL(ip_ct_gre_keymap_change); ++EXPORT_SYMBOL(ip_ct_gre_keymap_destroy); ++ ++module_init(init); ++module_exit(fini); +diff -urN linux-2.4.29-old/net/ipv4/netfilter/ip_nat_core.c linux-2.4.29-dev/net/ipv4/netfilter/ip_nat_core.c +--- linux-2.4.29-old/net/ipv4/netfilter/ip_nat_core.c	2005-01-19 15:10:13.000000000 +0100 ++++ linux-2.4.29-dev/net/ipv4/netfilter/ip_nat_core.c	2005-04-02 19:07:18.000000000 +0200 +@@ -424,7 +424,7 @@ + 	*tuple = *orig_tuple; + 	while ((rptr = find_best_ips_proto_fast(tuple, mr, conntrack, hooknum)) + 	       != NULL) { +-		DEBUGP("Found best for "); DUMP_TUPLE(tuple); ++		DEBUGP("Found best for "); DUMP_TUPLE_RAW(tuple); + 		/* 3) The per-protocol part of the manip is made to + 		   map into the range to make a unique tuple. */ +  +@@ -564,9 +564,9 @@ + 		       HOOK2MANIP(hooknum)==IP_NAT_MANIP_SRC ? "SRC" : "DST", + 		       conntrack); + 		DEBUGP("Original: "); +-		DUMP_TUPLE(&orig_tp); ++		DUMP_TUPLE_RAW(&orig_tp); + 		DEBUGP("New: "); +-		DUMP_TUPLE(&new_tuple); ++		DUMP_TUPLE_RAW(&new_tuple); + #endif +  + 		/* We now have two tuples (SRCIP/SRCPT/DSTIP/DSTPT): +diff -urN linux-2.4.29-old/net/ipv4/netfilter/ip_nat_pptp.c linux-2.4.29-dev/net/ipv4/netfilter/ip_nat_pptp.c +--- linux-2.4.29-old/net/ipv4/netfilter/ip_nat_pptp.c	1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.29-dev/net/ipv4/netfilter/ip_nat_pptp.c	2005-04-02 19:14:52.000000000 +0200 +@@ -0,0 +1,475 @@ ++/* ++ * ip_nat_pptp.c	- Version 1.5 ++ * ++ * NAT support for PPTP (Point to Point Tunneling Protocol). ++ * PPTP is a a protocol for creating virtual private networks. ++ * It is a specification defined by Microsoft and some vendors ++ * working with Microsoft.  PPTP is built on top of a modified ++ * version of the Internet Generic Routing Encapsulation Protocol. ++ * 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> ++ * ++ * 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 ++ * 	   (needs netfilter tuple reservation) ++ * ++ * Changes: ++ *     2002-02-10 - Version 1.3 ++ *       - Use ip_nat_mangle_tcp_packet() because of cloned skb's ++ *	   in local connections (Philip Craig <philipc@snapgear.com>) ++ *       - add checks for magicCookie and pptp version ++ *       - make argument list of pptp_{out,in}bound_packet() shorter ++ *       - move to C99 style initializers ++ *       - print version number at module loadtime ++ *     2003-09-22 - Version 1.5 ++ *       - use SNATed tcp sourceport as callid, since we get called before ++ *         TCP header is mangled (Philip Craig <philipc@snapgear.com>) ++ *  ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++#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_helper.h> ++#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h> ++#include <linux/netfilter_ipv4/ip_conntrack_pptp.h> ++ ++#define IP_NAT_PPTP_VERSION "1.5" ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>"); ++MODULE_DESCRIPTION("Netfilter NAT helper module for PPTP"); ++ ++ ++#if 0 ++#include "ip_conntrack_pptp_priv.h" ++#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \ ++				       ": " format, ## 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) ++{ ++	struct ip_conntrack *master = master_ct(ct); ++	struct ip_nat_multi_range mr; ++	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); ++		} ++	} 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); ++		} ++	} ++ ++	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; ++ ++} ++ ++/* outbound packets == from PNS to PAC */ ++static inline unsigned int ++pptp_outbound_pkt(struct sk_buff **pskb, ++		  struct ip_conntrack *ct, ++		  enum ip_conntrack_info ctinfo, ++		  struct ip_conntrack_expect *exp) ++ ++{ ++	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.rawreq = (void *) ((void *) ctlh + sizeof(*ctlh)); ++ ++	new_callid = htons(ct_pptp_info->pns_call_id); ++	 ++	switch (msg = ntohs(ctlh->messageType)) { ++		case PPTP_OUT_CALL_REQUEST: ++			cid = &pptpReq.ocreq->callID; ++			/* FIXME: ideally we would want to reserve a call ID ++			 * here.  current netfilter NAT core is not able to do ++			 * this :( For now we use TCP source port. This breaks ++			 * multiple calls within one control session */ ++ ++			/* save original call ID in nat_info */ ++			nat_pptp_info->pns_call_id = ct_pptp_info->pns_call_id; ++ ++			/* don't use tcph->source since we are at a DSTmanip ++			 * hook (e.g. PREROUTING) and pkt is not mangled yet */ ++			new_callid = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.tcp.port; ++ ++			/* save new call ID in ct info */ ++			ct_pptp_info->pns_call_id = ntohs(new_callid); ++			break; ++		case PPTP_IN_CALL_REPLY: ++			cid = &pptpReq.icreq->callID; ++			break; ++		case PPTP_CALL_CLEAR_REQUEST: ++			cid = &pptpReq.clrreq->callID; ++			break; ++		default: ++			DEBUGP("unknown outbound packet 0x%04x:%s\n", msg, ++			      (msg <= PPTP_MSG_MAX)? strMName[msg]:strMName[0]); ++			/* fall through */ ++ ++		case PPTP_SET_LINK_INFO: ++			/* only need to NAT in case PAC is behind NAT box */ ++		case PPTP_START_SESSION_REQUEST: ++		case PPTP_START_SESSION_REPLY: ++		case PPTP_STOP_SESSION_REQUEST: ++		case PPTP_STOP_SESSION_REPLY: ++		case PPTP_ECHO_REQUEST: ++		case PPTP_ECHO_REPLY: ++			/* no need to alter packet */ ++			return NF_ACCEPT; ++	} ++ ++	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)); ++ ++	return NF_ACCEPT; ++} ++ ++/* inbound packets == from PAC to PNS */ ++static inline unsigned int ++pptp_inbound_pkt(struct sk_buff **pskb, ++		 struct ip_conntrack *ct, ++		 enum ip_conntrack_info ctinfo, ++		 struct ip_conntrack_expect *oldexp) ++{ ++	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.rawreq = (void *) ((void *) ctlh + sizeof(*ctlh)); ++ ++	new_pcid = htons(nat_pptp_info->pns_call_id); ++ ++	switch (msg = ntohs(ctlh->messageType)) { ++	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 */ ++		break; ++	case PPTP_WAN_ERROR_NOTIFY: ++		pcid = &pptpReq.wanerr->peersCallID; ++		break; ++	case PPTP_CALL_DISCONNECT_NOTIFY: ++		pcid = &pptpReq.disc->callID; ++		break; ++ ++	default: ++		DEBUGP("unknown inbound packet %s\n", ++			(msg <= PPTP_MSG_MAX)? strMName[msg]:strMName[0]); ++		/* fall through */ ++ ++	case PPTP_START_SESSION_REQUEST: ++	case PPTP_START_SESSION_REPLY: ++	case PPTP_STOP_SESSION_REQUEST: ++	case PPTP_STOP_SESSION_REPLY: ++	case PPTP_ECHO_REQUEST: ++	case PPTP_ECHO_REPLY: ++		/* no need to alter packet */ ++		return NF_ACCEPT; ++	} ++ ++	/* 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)); ++ ++	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)); ++	} ++ ++	/* 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) ++{ ++	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; ++	} ++ ++	LOCK_BH(&ip_pptp_lock); ++ ++	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); ++	} ++ ++	UNLOCK_BH(&ip_pptp_lock); ++ ++	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; ++	} ++ ++	printk("ip_nat_pptp version %s loaded\n", IP_NAT_PPTP_VERSION); ++	return 0; ++} ++ ++static void __exit fini(void) ++{ ++	DEBUGP("cleanup_module\n" ); ++	ip_nat_helper_unregister(&pptp_tcp_helper); ++	printk("ip_nat_pptp version %s unloaded\n", IP_NAT_PPTP_VERSION); ++} ++ ++module_init(init); ++module_exit(fini); +Binary files linux-2.4.29-old/net/ipv4/netfilter/.ip_nat_pptp.c.swp and linux-2.4.29-dev/net/ipv4/netfilter/.ip_nat_pptp.c.swp differ +diff -urN linux-2.4.29-old/net/ipv4/netfilter/ip_nat_proto_gre.c linux-2.4.29-dev/net/ipv4/netfilter/ip_nat_proto_gre.c +--- linux-2.4.29-old/net/ipv4/netfilter/ip_nat_proto_gre.c	1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.29-dev/net/ipv4/netfilter/ip_nat_proto_gre.c	2005-04-02 19:15:10.000000000 +0200 +@@ -0,0 +1,202 @@ ++/* ++ * ip_nat_proto_gre.c - Version 1.2 ++ * ++ * NAT protocol helper module for GRE. ++ * ++ * GRE is a generic encapsulation protocol, which is generally not very ++ * suited for NAT, as it has no protocol-specific part as port numbers. ++ * ++ * It has an optional key field, which may help us distinguishing two  ++ * connections between the same two hosts. ++ * ++ * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784  ++ * ++ * PPTP is built on top of a modified version of GRE, and has a mandatory ++ * field called "CallID", which serves us for the same purpose as the key ++ * field in plain GRE. ++ * ++ * Documentation about PPTP can be found in RFC 2637 ++ * ++ * (C) 2000-2003 by Harald Welte <laforge@gnumonks.org> ++ * ++ * Development of this code funded by Astaro AG (http://www.astaro.com/) ++ * ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/ip.h> ++#include <linux/netfilter_ipv4/ip_nat.h> ++#include <linux/netfilter_ipv4/ip_nat_rule.h> ++#include <linux/netfilter_ipv4/ip_nat_protocol.h> ++#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h> ++ ++MODULE_LICENSE("GPL"); ++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) ++#else ++#define DEBUGP(x, args...) ++#endif ++ ++/* is key in given range between min and max */ ++static int ++gre_in_range(const struct ip_conntrack_tuple *tuple, ++	     enum ip_nat_manip_type maniptype, ++	     const union ip_conntrack_manip_proto *min, ++	     const union ip_conntrack_manip_proto *max) ++{ ++	u_int32_t key; ++ ++	if (maniptype == IP_NAT_MANIP_SRC) ++		key = tuple->src.u.gre.key; ++	else ++		key = tuple->dst.u.gre.key; ++ ++	return ntohl(key) >= ntohl(min->gre.key) ++		&& ntohl(key) <= ntohl(max->gre.key); ++} ++ ++/* generate unique tuple ... */ ++static int  ++gre_unique_tuple(struct ip_conntrack_tuple *tuple, ++		 const struct ip_nat_range *range, ++		 enum ip_nat_manip_type maniptype, ++		 const struct ip_conntrack *conntrack) ++{ ++	u_int32_t min, i, range_size; ++	u_int32_t key = 0, *keyptr; ++ ++	if (maniptype == IP_NAT_MANIP_SRC) ++		keyptr = &tuple->src.u.gre.key; ++	else ++		keyptr = &tuple->dst.u.gre.key; ++ ++	if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) { ++ ++		DEBUGP("%p: NATing GRE PPTP\n", conntrack); ++		min = 1; ++		range_size = 0xffff; ++ ++	} else { ++		min = ntohl(range->min.gre.key); ++		range_size = ntohl(range->max.gre.key) - min + 1; ++	} ++ ++	DEBUGP("min = %u, range_size = %u\n", min, range_size);  ++ ++	for (i = 0; i < range_size; i++, key++) { ++		*keyptr = htonl(min + key % range_size); ++		if (!ip_nat_used_tuple(tuple, conntrack)) ++			return 1; ++	} ++ ++	DEBUGP("%p: no NAT mapping\n", conntrack); ++ ++	return 0; ++} ++ ++/* manipulate a GRE packet according to maniptype */ ++static void  ++gre_manip_pkt(struct iphdr *iph, size_t len,  ++	      const struct ip_conntrack_manip *manip, ++	      enum ip_nat_manip_type maniptype) ++{ ++	struct gre_hdr *greh = (struct gre_hdr *)((u_int32_t *)iph+iph->ihl); ++	struct gre_hdr_pptp *pgreh = (struct gre_hdr_pptp *) greh; ++ ++	/* we only have destination manip of a packet, since 'source key'  ++	 * is not present in the packet itself */ ++	if (maniptype == IP_NAT_MANIP_DST) { ++		/* key manipulation is always dest */ ++		switch (greh->version) { ++		case 0: ++			if (!greh->key) { ++				DEBUGP("can't nat GRE w/o key\n"); ++				break; ++			} ++			if (greh->csum) { ++				/* FIXME: Never tested this code... */ ++				*(gre_csum(greh)) =  ++					ip_nat_cheat_check(~*(gre_key(greh)), ++							manip->u.gre.key, ++							*(gre_csum(greh))); ++			} ++			*(gre_key(greh)) = manip->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)); ++			break; ++		default: ++			DEBUGP("can't nat unknown GRE version\n"); ++			break; ++		} ++	} ++} ++ ++/* print out a nat tuple */ ++static unsigned int  ++gre_print(char *buffer,  ++	  const struct ip_conntrack_tuple *match, ++	  const struct ip_conntrack_tuple *mask) ++{ ++	unsigned int len = 0; ++ ++	if (mask->src.u.gre.key) ++		len += sprintf(buffer + len, "srckey=0x%x ",  ++				ntohl(match->src.u.gre.key)); ++ ++	if (mask->dst.u.gre.key) ++		len += sprintf(buffer + len, "dstkey=0x%x ", ++				ntohl(match->src.u.gre.key)); ++ ++	return len; ++} ++ ++/* print a range of keys */ ++static unsigned int  ++gre_print_range(char *buffer, const struct ip_nat_range *range) ++{ ++	if (range->min.gre.key != 0  ++	    || range->max.gre.key != 0xFFFF) { ++		if (range->min.gre.key == range->max.gre.key) ++			return sprintf(buffer, "key 0x%x ", ++					ntohl(range->min.gre.key)); ++		else ++			return sprintf(buffer, "keys 0x%u-0x%u ", ++					ntohl(range->min.gre.key), ++					ntohl(range->max.gre.key)); ++	} else ++		return 0; ++} ++ ++/* nat helper struct */ ++static struct ip_nat_protocol gre =  ++	{ { NULL, NULL }, "GRE", IPPROTO_GRE, ++	  gre_manip_pkt, ++	  gre_in_range, ++	  gre_unique_tuple, ++	  gre_print, ++	  gre_print_range  ++	}; ++				   ++static int __init init(void) ++{ ++        if (ip_nat_protocol_register(&gre)) ++                return -EIO; ++ ++        return 0; ++} ++ ++static void __exit fini(void) ++{ ++        ip_nat_protocol_unregister(&gre); ++} ++ ++module_init(init); ++module_exit(fini); +diff -urN linux-2.4.29-old/net/ipv4/netfilter/Makefile linux-2.4.29-dev/net/ipv4/netfilter/Makefile +--- linux-2.4.29-old/net/ipv4/netfilter/Makefile	2005-04-02 19:04:11.000000000 +0200 ++++ linux-2.4.29-dev/net/ipv4/netfilter/Makefile	2005-04-02 19:07:18.000000000 +0200 +@@ -36,23 +36,32 @@ + ifdef CONFIG_IP_NF_AMANDA + 	export-objs += ip_conntrack_amanda.o + endif +- + obj-$(CONFIG_IP_NF_TFTP) += ip_conntrack_tftp.o + obj-$(CONFIG_IP_NF_FTP) += ip_conntrack_ftp.o + ifdef CONFIG_IP_NF_FTP + 	export-objs += ip_conntrack_ftp.o + endif +- + obj-$(CONFIG_IP_NF_IRC) += ip_conntrack_irc.o + ifdef CONFIG_IP_NF_IRC + 	export-objs += ip_conntrack_irc.o + endif ++obj-$(CONFIG_IP_NF_CT_PROTO_GRE) += ip_conntrack_proto_gre.o ++ifdef CONFIG_IP_NF_CT_PROTO_GRE ++	export-objs += ip_conntrack_proto_gre.o ++endif ++obj-$(CONFIG_IP_NF_PPTP) += ip_conntrack_pptp.o ++ifdef CONFIG_IP_NF_NAT_PPTP ++	export-objs += ip_conntrack_pptp.o ++endif ++ +  + # NAT helpers  + 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_PROTO_GRE) += ip_nat_proto_gre.o ++obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.o +  + # generic IP tables  + obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o  | 
