* [PATCH 3/3] NETFILTER: New PPTP helper
@ 2005-09-15 14:54 Harald Welte
2005-09-15 22:44 ` Patrick McHardy
0 siblings, 1 reply; 14+ messages in thread
From: Harald Welte @ 2005-09-15 14:54 UTC (permalink / raw)
To: David Miller; +Cc: Linux Netdev List, Netfilter Development Mailinglist
[-- Attachment #1: Type: text/plain, Size: 73223 bytes --]
Hi Dave, please push this to mainline. Thanks!
NETFILTER: Add new PPTP conntrack and NAT helper
Signed-off-by: Harald Welte <laforge@netfilter.org>
---
diff --git a/include/linux/netfilter_ipv4/ip_conntrack.h b/include/linux/netfilter_ipv4/ip_conntrack.h
--- a/include/linux/netfilter_ipv4/ip_conntrack.h
+++ b/include/linux/netfilter_ipv4/ip_conntrack.h
@@ -133,11 +133,13 @@ enum ip_conntrack_expect_events {
#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>
#include <linux/netfilter_ipv4/ip_conntrack_sctp.h>
/* per conntrack: protocol private data */
union ip_conntrack_proto {
/* insert conntrack proto private data here */
+ struct ip_ct_gre gre;
struct ip_ct_sctp sctp;
struct ip_ct_tcp tcp;
struct ip_ct_icmp icmp;
@@ -148,6 +150,7 @@ union ip_conntrack_expect_proto {
};
/* Add protocol helper include file here */
+#include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
#include <linux/netfilter_ipv4/ip_conntrack_amanda.h>
#include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
#include <linux/netfilter_ipv4/ip_conntrack_irc.h>
@@ -155,12 +158,20 @@ union ip_conntrack_expect_proto {
/* per conntrack: application helper private data */
union ip_conntrack_help {
/* insert conntrack helper private data (master) here */
+ struct ip_ct_pptp_master ct_pptp_info;
struct ip_ct_ftp_master ct_ftp_info;
struct ip_ct_irc_master ct_irc_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
#include <linux/types.h>
@@ -223,6 +234,7 @@ struct ip_conntrack
#ifdef CONFIG_IP_NF_NAT_NEEDED
struct {
struct ip_nat_info info;
+ union ip_conntrack_nat_help help;
#if defined(CONFIG_IP_NF_TARGET_MASQUERADE) || \
defined(CONFIG_IP_NF_TARGET_MASQUERADE_MODULE)
int masq_index;
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_pptp.h b/include/linux/netfilter_ipv4/ip_conntrack_pptp.h
new file mode 100644
--- /dev/null
+++ b/include/linux/netfilter_ipv4/ip_conntrack_pptp.h
@@ -0,0 +1,332 @@
+/* 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 */
+
+ /* 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 */
+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__
+
+#define IP_CONNTR_PPTP PPTP_CONTROL_PORT
+
+#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;
+};
+
+union pptp_ctrl_union {
+ 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;
+};
+
+extern int
+(*ip_nat_pptp_hook_outbound)(struct sk_buff **pskb,
+ struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo,
+ struct PptpControlHeader *ctlh,
+ union pptp_ctrl_union *pptpReq);
+
+extern int
+(*ip_nat_pptp_hook_inbound)(struct sk_buff **pskb,
+ struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo,
+ struct PptpControlHeader *ctlh,
+ union pptp_ctrl_union *pptpReq);
+
+extern int
+(*ip_nat_pptp_hook_exp_gre)(struct ip_conntrack_expect *exp_orig,
+ struct ip_conntrack_expect *exp_reply);
+
+extern void
+(*ip_nat_pptp_hook_expectfn)(struct ip_conntrack *ct,
+ struct ip_conntrack_expect *exp);
+#endif /* __KERNEL__ */
+#endif /* _CONNTRACK_PPTP_H */
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h b/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h
new file mode 100644
--- /dev/null
+++ b/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h
@@ -0,0 +1,114 @@
+#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;
+};
+
+#ifdef __KERNEL__
+struct ip_conntrack_expect;
+struct ip_conntrack;
+
+/* 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 *ct,
+ struct ip_conntrack_tuple *t,
+ int reply);
+
+/* delete keymap entries */
+void ip_ct_gre_keymap_destroy(struct ip_conntrack *ct);
+
+
+/* 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 --git a/include/linux/netfilter_ipv4/ip_conntrack_tuple.h b/include/linux/netfilter_ipv4/ip_conntrack_tuple.h
--- a/include/linux/netfilter_ipv4/ip_conntrack_tuple.h
+++ b/include/linux/netfilter_ipv4/ip_conntrack_tuple.h
@@ -28,6 +28,9 @@ union ip_conntrack_manip_proto
struct {
u_int16_t port;
} sctp;
+ struct {
+ u_int16_t key; /* key is 32bit, pptp only uses 16 */
+ } gre;
};
/* The manipulable part of the tuple. */
@@ -61,6 +64,10 @@ struct ip_conntrack_tuple
struct {
u_int16_t port;
} sctp;
+ struct {
+ u_int16_t key; /* key is 32bit,
+ * pptp only uses 16 */
+ } gre;
} u;
/* The protocol. */
diff --git a/include/linux/netfilter_ipv4/ip_nat_pptp.h b/include/linux/netfilter_ipv4/ip_nat_pptp.h
new file mode 100644
--- /dev/null
+++ b/include/linux/netfilter_ipv4/ip_nat_pptp.h
@@ -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 --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -129,6 +129,22 @@ config IP_NF_AMANDA
To compile it as a module, choose M here. If unsure, say Y.
+config IP_NF_PPTP
+ tristate 'PPTP protocol support'
+ help
+ 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.
+
+ 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
+
+ If you want to compile it as a module, say M here and read
+ Documentation/modules.txt. If unsure, say `N'.
+
config IP_NF_QUEUE
tristate "IP Userspace queueing via NETLINK (OBSOLETE)"
help
@@ -613,6 +629,12 @@ config IP_NF_NAT_AMANDA
default IP_NF_NAT if IP_NF_AMANDA=y
default m if IP_NF_AMANDA=m
+config IP_NF_NAT_PPTP
+ tristate
+ depends on IP_NF_NAT!=n && IP_NF_PPTP!=n
+ default IP_NF_NAT if IP_NF_PPTP=y
+ default m if IP_NF_PPTP=m
+
# mangle + specific targets
config IP_NF_MANGLE
tristate "Packet mangling"
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile
--- a/net/ipv4/netfilter/Makefile
+++ b/net/ipv4/netfilter/Makefile
@@ -6,6 +6,9 @@
ip_conntrack-objs := ip_conntrack_standalone.o ip_conntrack_core.o ip_conntrack_proto_generic.o ip_conntrack_proto_tcp.o ip_conntrack_proto_udp.o ip_conntrack_proto_icmp.o
iptable_nat-objs := ip_nat_standalone.o ip_nat_rule.o ip_nat_core.o ip_nat_helper.o ip_nat_proto_unknown.o ip_nat_proto_tcp.o ip_nat_proto_udp.o ip_nat_proto_icmp.o
+ip_conntrack_pptp-objs := ip_conntrack_helper_pptp.o ip_conntrack_proto_gre.o
+ip_nat_pptp-objs := ip_nat_helper_pptp.o ip_nat_proto_gre.o
+
# connection tracking
obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o
@@ -17,6 +20,7 @@ obj-$(CONFIG_IP_NF_CONNTRACK_NETLINK) +=
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
@@ -24,6 +28,7 @@ obj-$(CONFIG_IP_NF_IRC) += ip_conntrack_
obj-$(CONFIG_IP_NF_NETBIOS_NS) += ip_conntrack_netbios_ns.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
diff --git a/net/ipv4/netfilter/ip_conntrack_helper_pptp.c b/net/ipv4/netfilter/ip_conntrack_helper_pptp.c
new file mode 100644
--- /dev/null
+++ b/net/ipv4/netfilter/ip_conntrack_helper_pptp.c
@@ -0,0 +1,801 @@
+/*
+ * 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.
+ * 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-2005 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
+ * - We can only support one single call within each session
+ *
+ * TODO:
+ * - 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
+ * 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/)
+ * 2005-07-30 - Version 3.1
+ * - port helper to 2.6.13 API changes
+ *
+ */
+
+#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/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 "3.1"
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
+MODULE_DESCRIPTION("Netfilter connection tracking helper module for PPTP");
+
+static DEFINE_SPINLOCK(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)
+#else
+#define DEBUGP(format, args...)
+#endif
+
+#define SECS *HZ
+#define MINS * 60 SECS
+#define HOURS * 60 MINS
+
+#define PPTP_GRE_TIMEOUT (10 MINS)
+#define PPTP_GRE_STREAM_TIMEOUT (5 HOURS)
+
+static void pptp_expectfn(struct ip_conntrack *ct,
+ 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;
+
+ /* 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 */
+
+ if (!ip_nat_pptp_hook_expectfn) {
+ struct ip_conntrack_tuple inv_t;
+ struct ip_conntrack_expect *exp_other;
+
+ /* 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_expect_find(&inv_t);
+ if (exp_other) {
+ /* delete other expectation. */
+ DEBUGP("found\n");
+ ip_conntrack_unexpect_related(exp_other);
+ } else {
+ DEBUGP("not found\n");
+ }
+ } else {
+ /* we need more than simple inversion */
+ ip_nat_pptp_hook_expectfn(ct, 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_expect_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 ip_conntrack_tuple t;
+ int ret;
+
+ /* 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 */
+
+ /* 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);
+
+ ret = timeout_ct_or_exp(&t);
+
+ /* 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) */
+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_tuple inv_tuple;
+ 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 = peer_callid } }
+ },
+ .dst = { .ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip,
+ .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 = callid } }
+ },
+ .dst = { .ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip,
+ .u = { .gre = { .key = peer_callid } },
+ .protonum = IPPROTO_GRE
+ },
+ }
+ };
+
+ struct ip_conntrack_expect *exp_orig, *exp_reply;
+
+ exp_orig = ip_conntrack_expect_alloc(master);
+ if (exp_orig == NULL)
+ return 1;
+
+ exp_reply = ip_conntrack_expect_alloc(master);
+ if (exp_reply == NULL) {
+ ip_conntrack_expect_put(exp_orig);
+ return 1;
+ }
+
+ memcpy(&exp_orig->tuple, &exp_tuples[0], sizeof(exp_orig->tuple));
+
+ 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;
+
+ 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_put(exp_orig);
+ ip_conntrack_expect_put(exp_reply);
+ DEBUGP("cannot expect_related()\n");
+ return 1;
+ }
+
+ 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_put(exp_reply);
+ DEBUGP("cannot expect_related()\n");
+ return 1;
+ }
+
+ /* 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;
+ }
+
+ }
+
+ ip_conntrack_expect_put(exp_orig);
+ ip_conntrack_expect_put(exp_reply);
+ return 0;
+}
+
+static inline int
+pptp_inbound_pkt(struct sk_buff **pskb,
+ struct tcphdr *tcph,
+ unsigned int ctlhoff,
+ size_t datalen,
+ struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo)
+{
+ struct PptpControlHeader _ctlh, *ctlh;
+ unsigned int reqlen;
+ union pptp_ctrl_union _pptpReq, *pptpReq;
+ struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
+ u_int16_t msg, *cid, *pcid;
+ u_int32_t seq;
+
+ 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(*pskb, ctlhoff+sizeof(_ctlh),
+ reqlen, &_pptpReq);
+ if (unlikely(!pptpReq)) {
+ DEBUGP("error during skb_header_pointer\n");
+ return NF_ACCEPT;
+ }
+
+ msg = ntohs(ctlh->messageType);
+ DEBUGP("inbound control message %s\n", strMName[msg]);
+
+ switch (msg) {
+ case PPTP_START_SESSION_REPLY:
+ if (reqlen < sizeof(_pptpReq.srep)) {
+ DEBUGP("%s: short packet\n", strMName[msg]);
+ break;
+ }
+
+ /* 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:
+ if (reqlen < sizeof(_pptpReq.strep)) {
+ DEBUGP("%s: short packet\n", strMName[msg]);
+ break;
+ }
+
+ /* 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:
+ if (reqlen < sizeof(_pptpReq.ocack)) {
+ DEBUGP("%s: short packet\n", strMName[msg]);
+ break;
+ }
+
+ /* 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) + sizeof(struct pptp_pkt_hdr)
+ + sizeof(struct PptpControlHeader)
+ + ((void *)pcid - (void *)pptpReq);
+
+ if (exp_gre(ct, seq, *cid, *pcid) != 0)
+ printk("ip_conntrack_pptp: error during exp_gre\n");
+ break;
+
+ case PPTP_IN_CALL_REQUEST:
+ if (reqlen < sizeof(_pptpReq.icack)) {
+ DEBUGP("%s: short packet\n", strMName[msg]);
+ break;
+ }
+
+ /* 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:
+ if (reqlen < sizeof(_pptpReq.iccon)) {
+ DEBUGP("%s: short packet\n", strMName[msg]);
+ break;
+ }
+
+ /* 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) + sizeof(struct pptp_pkt_hdr)
+ + sizeof(struct PptpControlHeader)
+ + ((void *)pcid - (void *)pptpReq);
+
+ if (exp_gre(ct, seq, *cid, *pcid) != 0)
+ printk("ip_conntrack_pptp: error during exp_gre\n");
+
+ break;
+
+ case PPTP_CALL_DISCONNECT_NOTIFY:
+ if (reqlen < sizeof(_pptpReq.disc)) {
+ DEBUGP("%s: short packet\n", strMName[msg]);
+ break;
+ }
+
+ /* 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;
+ }
+
+
+ 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 **pskb,
+ struct tcphdr *tcph,
+ unsigned int ctlhoff,
+ size_t datalen,
+ struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo)
+{
+ struct PptpControlHeader _ctlh, *ctlh;
+ unsigned int reqlen;
+ union pptp_ctrl_union _pptpReq, *pptpReq;
+ struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
+ u_int16_t msg, *cid, *pcid;
+
+ 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(*pskb, ctlhoff+sizeof(_ctlh), reqlen,
+ &_pptpReq);
+ if (!pptpReq)
+ return NF_ACCEPT;
+
+ 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:
+ if (reqlen < sizeof(_pptpReq.ocreq)) {
+ DEBUGP("%s: short packet\n", strMName[msg]);
+ /* FIXME: break; */
+ }
+
+ /* 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:
+ if (reqlen < sizeof(_pptpReq.icack)) {
+ DEBUGP("%s: short packet\n", strMName[msg]);
+ break;
+ }
+
+ /* 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;
+ }
+
+ if (ip_nat_pptp_hook_outbound)
+ return ip_nat_pptp_hook_outbound(pskb, ct, ctinfo, ctlh,
+ pptpReq);
+
+ return NF_ACCEPT;
+}
+
+
+/* track caller id inside control connection, call expect_related */
+static int
+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 = (*pskb)->len - (*pskb)->nh.iph->ihl * 4;
+ u_int32_t datalen;
+ void *datalimit;
+ int dir = CTINFO2DIR(ctinfo);
+ struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
+ unsigned int nexthdr_off;
+
+ 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;
+ }
+
+ 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;
+
+ /* not a complete TCP header? */
+ if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) {
+ DEBUGP("tcplen = %u\n", tcplen);
+ return NF_ACCEPT;
+ }
+
+
+ datalen = tcplen - tcph->doff * 4;
+
+ /* checksum invalid? */
+ 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 */
+ }
+
+ 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);
+ }
+
+ nexthdr_off += 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");
+ return NF_ACCEPT;
+ }
+
+ datalimit = (void *) pptph + datalen;
+
+ /* 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;
+
+ spin_lock_bh(&ip_pptp_lock);
+
+ nexthdr_off += sizeof(_pptph);
+ /* 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(pskb, tcph, nexthdr_off, datalen, ct,
+ ctinfo);
+ else
+ /* server -> client (PAC -> PNS) */
+ 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);
+ spin_unlock_bh(&ip_pptp_lock);
+
+ return ret;
+}
+
+/* control protocol helper */
+static struct ip_conntrack_helper pptp = {
+ .list = { NULL, NULL },
+ .name = "pptp",
+ .me = THIS_MODULE,
+ .max_expected = 2,
+ .timeout = 5 * 60,
+ .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 = 0xff
+ }
+ },
+ .help = conntrack_pptp_help
+};
+
+extern void __exit ip_ct_proto_gre_fini(void);
+extern int __init ip_ct_proto_gre_init(void);
+
+/* ip_conntrack_pptp initialization */
+static int __init init(void)
+{
+ int retcode;
+
+ retcode = ip_ct_proto_gre_init();
+ if (retcode < 0)
+ return retcode;
+
+ 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);
+ ip_ct_proto_gre_fini();
+ 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);
+ ip_ct_proto_gre_fini();
+ printk("ip_conntrack_pptp version %s unloaded\n", IP_CT_PPTP_VERSION);
+}
+
+module_init(init);
+module_exit(fini);
+
+EXPORT_SYMBOL(ip_pptp_lock);
+EXPORT_SYMBOL(ip_nat_pptp_hook_outbound);
+EXPORT_SYMBOL(ip_nat_pptp_hook_inbound);
+EXPORT_SYMBOL(ip_nat_pptp_hook_exp_gre);
+EXPORT_SYMBOL(ip_nat_pptp_hook_expectfn);
diff --git a/net/ipv4/netfilter/ip_conntrack_pptp_priv.h b/net/ipv4/netfilter/ip_conntrack_pptp_priv.h
new file mode 100644
--- /dev/null
+++ b/net/ipv4/netfilter/ip_conntrack_pptp_priv.h
@@ -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 --git a/net/ipv4/netfilter/ip_conntrack_proto_gre.c b/net/ipv4/netfilter/ip_conntrack_proto_gre.c
new file mode 100644
--- /dev/null
+++ b/net/ipv4/netfilter/ip_conntrack_proto_gre.c
@@ -0,0 +1,354 @@
+/*
+ * ip_conntrack_proto_gre.c - Version 3.0
+ *
+ * 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-2005 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>
+
+static DEFINE_RWLOCK(ip_ct_gre_lock);
+#define ASSERT_READ_LOCK(x)
+#define ASSERT_WRITE_LOCK(x)
+
+#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 "%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), 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)
+#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 = 0;
+
+ read_lock_bh(&ip_ct_gre_lock);
+ km = LIST_FIND(&gre_keymap_list, gre_key_cmpfn,
+ struct ip_ct_gre_keymap *, t);
+ if (km)
+ key = km->tuple.src.u.gre.key;
+ read_unlock_bh(&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 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, *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)
+ return -1;
+
+ /* initializing list head should be sufficient */
+ memset(km, 0, sizeof(*km));
+
+ memcpy(&km->tuple, t, sizeof(*t));
+
+ 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);
+
+ write_lock_bh(&ip_ct_gre_lock);
+ list_append(&gre_keymap_list, km);
+ write_unlock_bh(&ip_ct_gre_lock);
+
+ return 0;
+}
+
+/* destroy the keymap entries associated with specified master ct */
+void ip_ct_gre_keymap_destroy(struct ip_conntrack *ct)
+{
+ DEBUGP("entering for ct %p\n", ct);
+
+ if (!ct->helper || strcmp(ct->helper->name, "pptp")) {
+ DEBUGP("refusing to destroy GRE keymap to non-pptp session\n");
+ return;
+ }
+
+ write_lock_bh(&ip_ct_gre_lock);
+ 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 (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_bh(&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 struct sk_buff *skb,
+ unsigned int dataoff,
+ struct ip_conntrack_tuple *tuple)
+{
+ struct gre_hdr_pptp _pgrehdr, *pgrehdr;
+ u_int32_t srckey;
+ struct gre_hdr _grehdr, *grehdr;
+
+ /* first only delinearize old RFC1701 GRE header */
+ grehdr = skb_header_pointer(skb, dataoff, sizeof(_grehdr), &_grehdr);
+ if (!grehdr || grehdr->version != GRE_VERSION_PPTP) {
+ /* try to behave like "ip_conntrack_proto_generic" */
+ tuple->src.u.all = 0;
+ tuple->dst.u.all = 0;
+ return 1;
+ }
+
+ /* PPTP header is variable length, only need up to the call_id field */
+ pgrehdr = skb_header_pointer(skb, dataoff, 8, &_pgrehdr);
+ if (!pgrehdr)
+ return 1;
+
+ if (ntohs(grehdr->protocol) != GRE_PROTOCOL_PPTP) {
+ DEBUGP("GRE_VERSION_PPTP but unknown proto\n");
+ return 0;
+ }
+
+ tuple->dst.u.gre.key = pgrehdr->call_id;
+ srckey = gre_keymap_lookup(tuple);
+ tuple->src.u.gre.key = srckey;
+
+ return 1;
+}
+
+/* print gre part of tuple */
+static int gre_print_tuple(struct seq_file *s,
+ const struct ip_conntrack_tuple *tuple)
+{
+ 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 int gre_print_conntrack(struct seq_file *s,
+ const struct ip_conntrack *ct)
+{
+ 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 */
+static int gre_packet(struct ip_conntrack *ct,
+ const struct sk_buff *skb,
+ 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_acct(ct, conntrackinfo, skb,
+ 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_acct(ct, conntrackinfo, skb,
+ ct->proto.gre.timeout);
+
+ return NF_ACCEPT;
+}
+
+/* Called when a new connection for this protocol found. */
+static int gre_new(struct ip_conntrack *ct,
+ const struct sk_buff *skb)
+{
+ 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 *master = ct->master;
+ DEBUGP(" entering\n");
+
+ if (!master)
+ DEBUGP("no master !?!\n");
+ else
+ ip_ct_gre_keymap_destroy(master);
+}
+
+/* protocol helper struct */
+static struct ip_conntrack_protocol gre = {
+ .proto = IPPROTO_GRE,
+ .name = "gre",
+ .pkt_to_tuple = gre_pkt_to_tuple,
+ .invert_tuple = gre_invert_tuple,
+ .print_tuple = gre_print_tuple,
+ .print_conntrack = gre_print_conntrack,
+ .packet = gre_packet,
+ .new = gre_new,
+ .destroy = gre_destroy,
+ .me = THIS_MODULE,
+#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \
+ defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE)
+ .tuple_to_nfattr = ip_ct_port_tuple_to_nfattr,
+ .nfattr_to_tuple = ip_ct_port_nfattr_to_tuple,
+#endif
+};
+
+/* ip_conntrack_proto_gre initialization */
+int __init ip_ct_proto_gre_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;
+}
+
+void __exit ip_ct_proto_gre_fini(void)
+{
+ struct list_head *pos, *n;
+
+ /* delete all keymap entries */
+ write_lock_bh(&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_bh(&ip_ct_gre_lock);
+
+ ip_conntrack_protocol_unregister(&gre);
+}
+
+EXPORT_SYMBOL(ip_ct_gre_keymap_add);
+EXPORT_SYMBOL(ip_ct_gre_keymap_destroy);
diff --git a/net/ipv4/netfilter/ip_nat_helper_pptp.c b/net/ipv4/netfilter/ip_nat_helper_pptp.c
new file mode 100644
--- /dev/null
+++ b/net/ipv4/netfilter/ip_nat_helper_pptp.c
@@ -0,0 +1,401 @@
+/*
+ * 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.
+ * 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-2005 by Harald Welte <laforge@gnumonks.org>
+ *
+ * Development of this code funded by Astaro AG (http://www.astaro.com/)
+ *
+ * TODO: - 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>)
+ * 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/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_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 "3.0"
+
+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 "%s:%s: " format, __FILE__, \
+ __FUNCTION__, ## args)
+#else
+#define DEBUGP(format, args...)
+#endif
+
+static void pptp_nat_expected(struct ip_conntrack *ct,
+ struct ip_conntrack_expect *exp)
+{
+ 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;
+
+ ct_pptp_info = &master->help.ct_pptp_info;
+ nat_pptp_info = &master->nat.help.nat_pptp_info;
+
+ /* 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 {
+ 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;
+ }
+
+ DEBUGP("trying to unexpect other dir: ");
+ DUMP_TUPLE(&t);
+ other_exp = __ip_conntrack_expect_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 int
+pptp_outbound_pkt(struct sk_buff **pskb,
+ struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo,
+ 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;
+
+ 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;
+ }
+
+ /* 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 */
+ 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_put(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_put(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 int
+pptp_inbound_pkt(struct sk_buff **pskb,
+ struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo,
+ struct PptpControlHeader *ctlh,
+ union pptp_ctrl_union *pptpReq)
+{
+ 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;
+
+ int ret = NF_ACCEPT, rv;
+
+ 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;
+ break;
+ case PPTP_IN_CALL_CONNECT:
+ pcid = &pptpReq->iccon.peersCallID;
+ 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;
+ case PPTP_SET_LINK_INFO:
+ pcid = &pptpReq->setlink.peersCallID;
+ 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;
+ }
+
+ /* 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));
+
+ 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));
+ 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;
+}
+
+
+extern int __init ip_nat_proto_gre_init(void);
+extern void __exit ip_nat_proto_gre_fini(void);
+
+static int __init init(void)
+{
+ int ret;
+
+ DEBUGP("%s: registering NAT helper\n", __FILE__);
+
+ ret = ip_nat_proto_gre_init();
+ if (ret < 0)
+ return ret;
+
+ BUG_ON(ip_nat_pptp_hook_outbound);
+ ip_nat_pptp_hook_outbound = &pptp_outbound_pkt;
+
+ BUG_ON(ip_nat_pptp_hook_inbound);
+ ip_nat_pptp_hook_inbound = &pptp_inbound_pkt;
+
+ BUG_ON(ip_nat_pptp_hook_exp_gre);
+ ip_nat_pptp_hook_exp_gre = &pptp_exp_gre;
+
+ 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;
+}
+
+static void __exit fini(void)
+{
+ DEBUGP("cleanup_module\n" );
+
+ 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;
+
+ ip_nat_proto_gre_fini();
+ /* Make sure noone calls it, meanwhile */
+ synchronize_net();
+
+ printk("ip_nat_pptp version %s unloaded\n", IP_NAT_PPTP_VERSION);
+}
+
+module_init(init);
+module_exit(fini);
diff --git a/net/ipv4/netfilter/ip_nat_proto_gre.c b/net/ipv4/netfilter/ip_nat_proto_gre.c
new file mode 100644
--- /dev/null
+++ b/net/ipv4/netfilter/ip_nat_proto_gre.c
@@ -0,0 +1,216 @@
+/*
+ * ip_nat_proto_gre.c - Version 2.0
+ *
+ * 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-2005 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 "%s:%s: " format, __FILE__, \
+ __FUNCTION__, ## 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_int16_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 int
+gre_manip_pkt(struct sk_buff **pskb,
+ 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;
+
+ /* pgreh includes two optional 32bit fields which are not required
+ * to be there. That's where the magic '8' comes from */
+ if (!skb_make_writable(pskb, hdroff + sizeof(*pgreh)-8))
+ return 0;
+
+ greh = (void *)(*pskb)->data + hdroff;
+ 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)),
+ tuple->dst.u.gre.key,
+ *(gre_csum(greh)));
+ }
+ *(gre_key(greh)) = tuple->dst.u.gre.key;
+ break;
+ case GRE_VERSION_PPTP:
+ DEBUGP("call_id -> 0x%04x\n",
+ 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");
+ return 0;
+ break;
+ }
+ }
+ return 1;
+}
+
+/* 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 = {
+ .name = "GRE",
+ .protonum = IPPROTO_GRE,
+ .manip_pkt = gre_manip_pkt,
+ .in_range = gre_in_range,
+ .unique_tuple = gre_unique_tuple,
+ .print = gre_print,
+ .print_range = gre_print_range,
+#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \
+ defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE)
+ .range_to_nfattr = ip_nat_port_range_to_nfattr,
+ .nfattr_to_range = ip_nat_port_nfattr_to_range,
+#endif
+};
+
+int __init ip_nat_proto_gre_init(void)
+{
+ if (ip_nat_protocol_register(&gre))
+ return -EIO;
+
+ return 0;
+}
+
+void __exit ip_nat_proto_gre_fini(void)
+{
+ ip_nat_protocol_unregister(&gre);
+}
diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c
--- a/net/ipv4/netfilter/ip_nat_standalone.c
+++ b/net/ipv4/netfilter/ip_nat_standalone.c
@@ -405,4 +405,6 @@ EXPORT_SYMBOL(ip_nat_mangle_tcp_packet);
EXPORT_SYMBOL(ip_nat_mangle_udp_packet);
EXPORT_SYMBOL(ip_nat_used_tuple);
EXPORT_SYMBOL(ip_nat_follow_master);
+EXPORT_SYMBOL_GPL(ip_nat_port_nfattr_to_range);
+EXPORT_SYMBOL_GPL(ip_nat_port_range_to_nfattr);
MODULE_LICENSE("GPL");
--
- Harald Welte <laforge@netfilter.org> http://netfilter.org/
============================================================================
"Fragmentation is like classful addressing -- an interesting early
architectural error that shows how much experimentation was going
on while IP was being designed." -- Paul Vixie
[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 3/3] NETFILTER: New PPTP helper
2005-09-15 14:54 [PATCH 3/3] NETFILTER: New PPTP helper Harald Welte
@ 2005-09-15 22:44 ` Patrick McHardy
2005-09-16 9:15 ` Harald Welte
0 siblings, 1 reply; 14+ messages in thread
From: Patrick McHardy @ 2005-09-15 22:44 UTC (permalink / raw)
To: Harald Welte; +Cc: Netfilter Development Mailinglist, David Miller
Harald Welte wrote:
> NETFILTER: Add new PPTP conntrack and NAT helper
I noticed a number of problems, this first batch of patches
fixes the worst ones I hope. There's also one or two small
cleanup patches. I can't test them here, please review and
ACK/NACK for Dave.
[NETFILTER]: pptp helper: propagate errors instead of using -EIO in init
functions
[NETFILTER]: pptp helper: fix expectation leaks
[NETFILTER]: Rename misnamed function
[NETFILTER]: pptp helper: use locked variants of ip_conntrack_find_*
functions
[NETFILTER]: pptp helper: fix leaks when issuing expectations
[NETFILTER]: pptp helper: fix buffer overflow
[NETFILTER]: pptp helper: clean up conntrack_pptp_help() a bit
[NETFILTER]: pptp helper: missing expectation flags initialisation
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 3/3] NETFILTER: New PPTP helper
2005-09-15 22:44 ` Patrick McHardy
@ 2005-09-16 9:15 ` Harald Welte
2005-09-16 22:45 ` David S. Miller
0 siblings, 1 reply; 14+ messages in thread
From: Harald Welte @ 2005-09-16 9:15 UTC (permalink / raw)
To: Patrick McHardy; +Cc: Netfilter Development Mailinglist, David Miller
[-- Attachment #1: Type: text/plain, Size: 878 bytes --]
On Fri, Sep 16, 2005 at 12:44:30AM +0200, Patrick McHardy wrote:
> Harald Welte wrote:
> >NETFILTER: Add new PPTP conntrack and NAT helper
>
> I noticed a number of problems, this first batch of patches
> fixes the worst ones I hope. There's also one or two small
> cleanup patches. I can't test them here, please review and
> ACK/NACK for Dave.
Ok, I'm at the moment hunting down some strange linux-2.6.13 <-> solaris
9 TCP window scaling problems. Will look into your patches later today.
--
- Harald Welte <laforge@netfilter.org> http://netfilter.org/
============================================================================
"Fragmentation is like classful addressing -- an interesting early
architectural error that shows how much experimentation was going
on while IP was being designed." -- Paul Vixie
[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 3/3] NETFILTER: New PPTP helper
2005-09-16 9:15 ` Harald Welte
@ 2005-09-16 22:45 ` David S. Miller
2005-09-16 22:51 ` Harald Welte
0 siblings, 1 reply; 14+ messages in thread
From: David S. Miller @ 2005-09-16 22:45 UTC (permalink / raw)
To: laforge; +Cc: netfilter-devel, kaber
From: Harald Welte <laforge@netfilter.org>
Date: Fri, 16 Sep 2005 11:15:48 +0200
> On Fri, Sep 16, 2005 at 12:44:30AM +0200, Patrick McHardy wrote:
> > Harald Welte wrote:
> > >NETFILTER: Add new PPTP conntrack and NAT helper
> >
> > I noticed a number of problems, this first batch of patches
> > fixes the worst ones I hope. There's also one or two small
> > cleanup patches. I can't test them here, please review and
> > ACK/NACK for Dave.
>
> Ok, I'm at the moment hunting down some strange linux-2.6.13 <-> solaris
> 9 TCP window scaling problems. Will look into your patches later today.
Since Linus GIT doesn't have the PPTP addition changes yet, I think
I'm going to hold off on merging it for now.
Why don't you guys work together to integrate all of the fixes, and
then resubmit PPTP as one changeset with all the bug fixes already
applied? I think that would work best and prevent changeset bloat.
I will, however, integrate all of the non-PPTP changes as they were
seemingly all bug fixes in one way or another.
Thanks.
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 3/3] NETFILTER: New PPTP helper
2005-09-16 22:45 ` David S. Miller
@ 2005-09-16 22:51 ` Harald Welte
2005-09-17 16:28 ` Patrick McHardy
0 siblings, 1 reply; 14+ messages in thread
From: Harald Welte @ 2005-09-16 22:51 UTC (permalink / raw)
To: David S. Miller; +Cc: netfilter-devel, kaber
[-- Attachment #1: Type: text/plain, Size: 1737 bytes --]
On Fri, Sep 16, 2005 at 03:45:56PM -0700, David S. Miller wrote:
> From: Harald Welte <laforge@netfilter.org>
> Date: Fri, 16 Sep 2005 11:15:48 +0200
>
> > On Fri, Sep 16, 2005 at 12:44:30AM +0200, Patrick McHardy wrote:
> > > Harald Welte wrote:
> > > >NETFILTER: Add new PPTP conntrack and NAT helper
> > >
> > > I noticed a number of problems, this first batch of patches
> > > fixes the worst ones I hope. There's also one or two small
> > > cleanup patches. I can't test them here, please review and
> > > ACK/NACK for Dave.
> >
> > Ok, I'm at the moment hunting down some strange linux-2.6.13 <-> solaris
> > 9 TCP window scaling problems. Will look into your patches later today.
>
> Since Linus GIT doesn't have the PPTP addition changes yet, I think
> I'm going to hold off on merging it for now.
ok, that's fine.
> Why don't you guys work together to integrate all of the fixes, and
> then resubmit PPTP as one changeset with all the bug fixes already
> applied? I think that would work best and prevent changeset bloat.
yes, ideally that would be the way for it to happen. Unfortuantely the
PPTP helper has been around for many years (patch-o-matic-ng, latest
version in my git tree, ...) and it apparently still didn't receive the
kind of review it required.
I'll test and resubmit PPTP on saturday or sunday.
--
- Harald Welte <laforge@netfilter.org> http://netfilter.org/
============================================================================
"Fragmentation is like classful addressing -- an interesting early
architectural error that shows how much experimentation was going
on while IP was being designed." -- Paul Vixie
[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 3/3] NETFILTER: New PPTP helper
2005-09-16 22:51 ` Harald Welte
@ 2005-09-17 16:28 ` Patrick McHardy
2005-09-17 17:45 ` Patrick McHardy
2005-09-17 18:33 ` Harald Welte
0 siblings, 2 replies; 14+ messages in thread
From: Patrick McHardy @ 2005-09-17 16:28 UTC (permalink / raw)
To: Harald Welte; +Cc: netfilter-devel, David S. Miller
Harald Welte wrote:
> On Fri, Sep 16, 2005 at 03:45:56PM -0700, David S. Miller wrote:
>
>>Why don't you guys work together to integrate all of the fixes, and
>>then resubmit PPTP as one changeset with all the bug fixes already
>>applied? I think that would work best and prevent changeset bloat.
>
> yes, ideally that would be the way for it to happen. Unfortuantely the
> PPTP helper has been around for many years (patch-o-matic-ng, latest
> version in my git tree, ...) and it apparently still didn't receive the
> kind of review it required.
The thing with patch-o-matic is that it includes tons of crap and you
never know if it includes the latest version of something, so I focus
on things submitted to the kernel. So maybe a heads-up one or two days
before submission would help. Anyway, I was just writing a mail
including some more suggestions when Dave applied the patch. I'll
go over the patch again later and send you my remaining suggestions.
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 3/3] NETFILTER: New PPTP helper
2005-09-17 16:28 ` Patrick McHardy
@ 2005-09-17 17:45 ` Patrick McHardy
2005-09-18 13:28 ` Harald Welte
2005-09-17 18:33 ` Harald Welte
1 sibling, 1 reply; 14+ messages in thread
From: Patrick McHardy @ 2005-09-17 17:45 UTC (permalink / raw)
To: Harald Welte; +Cc: netfilter-devel, David S. Miller
Following are my remaining suggestions. Mostly really minor things.
First, wouldn't it make sense to make ip_{conntrack,nat}_proto_gre
usable without pptp as well?
diff --git a/net/ipv4/netfilter/ip_conntrack_helper_pptp.c
b/net/ipv4/netfilter/ip_conntrack_helper_pptp.c
new file mode 100644
--- /dev/null
+++ b/net/ipv4/netfilter/ip_conntrack_helper_pptp.c
I would prefer the name ip_conntrack_pptp.c for consisteny with
other helpers. Same for ip_nat_helper_pptp.c.
+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);
The regular way of doing this (del_timer, call ct->timeout.function)
seems cleaner too me.
+/* timeout GRE data connections */
+static int pptp_timeout_related(struct ip_conntrack *ct)
+{
+ struct ip_conntrack_tuple t;
+ int ret;
+
+ /* 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 */
+
+ /* 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);
+
+ ret = timeout_ct_or_exp(&t);
+
+ /* 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);
The return value of this function isn't used, so timeout_ct_or_exp and
itself can be made void. The name also seems a bit misleading since it
wants to destroy related conntracks and is not used in any function
dealing with timouts - how about pptp_destroy_related()?
+EXPORT_SYMBOL(ip_pptp_lock);
This export is not used.
diff --git a/net/ipv4/netfilter/ip_conntrack_pptp_priv.h
b/net/ipv4/netfilter/ip_conntrack_pptp_priv.h
new file mode 100644
--- /dev/null
+++ b/net/ipv4/netfilter/ip_conntrack_pptp_priv.h
+@@ -0,0 +1,24 @@
+#ifndef _IP_CT_PPTP_PRIV_H
+#define _IP_CT_PPTP_PRIV_H
+
+/* PptpControlMessageType names */
+static const char *strMName[] = {
This should go in the pptp helper itself.
+int
+ip_ct_gre_keymap_add(struct ip_conntrack *ct,
+ struct ip_conntrack_tuple *t, int reply)
+{
+ 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)
+ return -1;
+
+ /* initializing list head should be sufficient */
+ memset(km, 0, sizeof(*km));
The comment doesn't match the code.
+
+ memcpy(&km->tuple, t, sizeof(*t));
+
+ 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;
All users only check for <= 0, using -1 or -EEXIST or something seems
cleaner than using magic values.
+ }
+ 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;
It looks like the above blocks could be merged by using a pointer
to ct->help.ct_pptp_info.keymap_{orig,reply}. Memory allocation
can then be moved below the "if (!reply)" block.
+void __exit ip_ct_proto_gre_fini(void)
+{
+ struct list_head *pos, *n;
+
+ /* delete all keymap entries */
+ write_lock_bh(&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);
break;
+ }
+ write_unlock_bh(&ip_ct_gre_lock);
+/* 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_int16_t key = 0, *keyptr;
How about using the same static u_int16_t key trick used in
the other NAT helpers to increase chances of finding an unused
tuple at the first try?
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 3/3] NETFILTER: New PPTP helper
2005-09-17 16:28 ` Patrick McHardy
2005-09-17 17:45 ` Patrick McHardy
@ 2005-09-17 18:33 ` Harald Welte
2005-09-17 19:05 ` Patrick McHardy
2005-09-18 6:46 ` David S. Miller
1 sibling, 2 replies; 14+ messages in thread
From: Harald Welte @ 2005-09-17 18:33 UTC (permalink / raw)
To: Patrick McHardy; +Cc: netfilter-devel, David S. Miller
[-- Attachment #1: Type: text/plain, Size: 1208 bytes --]
On Sat, Sep 17, 2005 at 06:28:44PM +0200, Patrick McHardy wrote:
> So maybe a heads-up one or two days before submission would help.
ok, I'll try that.
> Anyway, I was just writing a mail including some more suggestions when
> Dave applied the patch. I'll go over the patch again later and send
> you my remaining suggestions.
Ok, in case you're interested in the latest code (confirmed to work in
my testcases) including all 8 of your patches, please check my
netfilter-2.6.14 tree (loacal "pptp" branch) on people.netfilter.org.
I'll wait for your remaining suggestions and only submit to davem after
that.
I've noticed that Dave's tree already contains my original pptp patch.
Dave: Do you want me to submit one big incremental patch to your tree,
or rather a patch against current torvalds/linux-2.6.git ?
--
- Harald Welte <laforge@netfilter.org> http://netfilter.org/
============================================================================
"Fragmentation is like classful addressing -- an interesting early
architectural error that shows how much experimentation was going
on while IP was being designed." -- Paul Vixie
[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 3/3] NETFILTER: New PPTP helper
2005-09-17 18:33 ` Harald Welte
@ 2005-09-17 19:05 ` Patrick McHardy
2005-09-18 9:14 ` Harald Welte
2005-09-18 6:46 ` David S. Miller
1 sibling, 1 reply; 14+ messages in thread
From: Patrick McHardy @ 2005-09-17 19:05 UTC (permalink / raw)
To: Harald Welte; +Cc: netfilter-devel, David S. Miller
Harald Welte wrote:
> On Sat, Sep 17, 2005 at 06:28:44PM +0200, Patrick McHardy wrote:
>
>>Anyway, I was just writing a mail including some more suggestions when
>>Dave applied the patch. I'll go over the patch again later and send
>>you my remaining suggestions.
>
> Ok, in case you're interested in the latest code (confirmed to work in
> my testcases) including all 8 of your patches, please check my
> netfilter-2.6.14 tree (loacal "pptp" branch) on people.netfilter.org.
I tried cloning it using cogito, but get this error:
kaber@krusty:~/src/nf$ cg-clone
http://people.netfilter.org./laforge/scm/netfilter-2.6.14.git#pptp
nf-2.6.14-laforge
defaulting to local storage area
warning: templates not found /home/kaber/share/git-core/templates/
20:59:02
URL:http://people.netfilter.org./laforge/scm/netfilter-2.6.14.git/refs/heads/pptp
[41/41] -> "refs/heads/origin" [1]
progress: 3 objects, 1452 bytes
Getting pack list
Getting index for pack e3117bbaf6a59cb53c3f6f0d9b17b9433f0e4135
Getting index for pack c60dc6f7486e34043bd6861d6b2c0d21756dde76
error: Couldn't get ca442d313d86dc67e0a2e5d584b465bd382cbf5c: not
separate or in any pack
error: Tried
http://people.netfilter.org./laforge/scm/netfilter-2.6.14.git/objects/ca/442d313d86dc67e0a2e5d584b465bd382cbf5c
Cannot obtain needed blob ca442d313d86dc67e0a2e5d584b465bd382cbf5c
while processing commit 4736abe4dcc715c9b20942cf1245623a95fe4370.
cg-pull: objects pull failed
cg-clone: pull failed
I'll try if a new version helps, but it looks like some files are
missing.
> I'll wait for your remaining suggestions and only submit to davem after
> that.
Please see my other mail. I hope I'm not too anoying, but I prefer
to do these minor changes before submission because its often not
worth the time for sending patches afterwards.
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 3/3] NETFILTER: New PPTP helper
2005-09-17 18:33 ` Harald Welte
2005-09-17 19:05 ` Patrick McHardy
@ 2005-09-18 6:46 ` David S. Miller
1 sibling, 0 replies; 14+ messages in thread
From: David S. Miller @ 2005-09-18 6:46 UTC (permalink / raw)
To: laforge; +Cc: netfilter-devel, kaber
From: Harald Welte <laforge@netfilter.org>
Date: Sat, 17 Sep 2005 20:33:21 +0200
> I've noticed that Dave's tree already contains my original pptp patch.
> Dave: Do you want me to submit one big incremental patch to your tree,
> or rather a patch against current torvalds/linux-2.6.git ?
Please recheck my tree, I rebased and didn't put it back in.
So you should be able to just create a clean "add pptp" diff
against that tree.
Thanks a lot.
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 3/3] NETFILTER: New PPTP helper
2005-09-17 19:05 ` Patrick McHardy
@ 2005-09-18 9:14 ` Harald Welte
2005-09-18 14:37 ` Patrick McHardy
0 siblings, 1 reply; 14+ messages in thread
From: Harald Welte @ 2005-09-18 9:14 UTC (permalink / raw)
To: Patrick McHardy; +Cc: netfilter-devel, David S. Miller
[-- Attachment #1: Type: text/plain, Size: 3504 bytes --]
On Sat, Sep 17, 2005 at 09:05:52PM +0200, Patrick McHardy wrote:
> Harald Welte wrote:
> >On Sat, Sep 17, 2005 at 06:28:44PM +0200, Patrick McHardy wrote:
> >>Anyway, I was just writing a mail including some more suggestions when
> >>Dave applied the patch. I'll go over the patch again later and send
> >>you my remaining suggestions.
> >Ok, in case you're interested in the latest code (confirmed to work in
> >my testcases) including all 8 of your patches, please check my
> >netfilter-2.6.14 tree (loacal "pptp" branch) on people.netfilter.org.
>
> I tried cloning it using cogito, but get this error:
Are you sure you're not running an outdated cogito version? At least
via rsync everything seems to work fine here:
cg-clone rsync://people.netfilter.org/users/laforge/scm/netfilter-2.6.14.git\#pptp
defaulting to local storage area
receiving file list ... done
pptp
sent 138 bytes received 150 bytes 192.00 bytes/sec
total size is 41 speedup is 0.14
receiving file list ... done
progress: 7898 objects, 26077547 bytes, 99% done
progress: 7977 objects, 26276658 bytes, 100% done
info/
info/packs
pack/pack-011d837bd60b7e2544fa0f095ae4ca0d61c3c1ea.idx
pack/pack-011d837bd60b7e2544fa0f095ae4ca0d61c3c1ea.pack
pack/pack-be6bf83523a3a82fdff5544390a2dae7788bd0c8.idx
pack/pack-be6bf83523a3a82fdff5544390a2dae7788bd0c8.pack
pack/pack-c24bb5025e835a3d8733931ce7cc440f7bfbaaed.idx
pack/pack-c24bb5025e835a3d8733931ce7cc440f7bfbaaed.pack
pack/pack-c60dc6f7486e34043bd6861d6b2c0d21756dde76.idx
pack/pack-c60dc6f7486e34043bd6861d6b2c0d21756dde76.pack
pack/pack-e3117bbaf6a59cb53c3f6f0d9b17b9433f0e4135.idx
pack/pack-e3117bbaf6a59cb53c3f6f0d9b17b9433f0e4135.pack
pack/pack-eceba3479417b338c2e156b1c6dfd69f3f0eaad1.idx
pack/pack-eceba3479417b338c2e156b1c6dfd69f3f0eaad1.pack
sent 175896 bytes received 217784838 bytes 232491.45 bytes/sec
total size is 216999773 speedup is 1.00
receiving file list ... done
v2.6.11
v2.6.11-tree
v2.6.12
v2.6.12-rc2
v2.6.12-rc3
v2.6.12-rc4
v2.6.12-rc5
v2.6.12-rc6
v2.6.13
v2.6.13-rc1
v2.6.13-rc2
v2.6.13-rc3
v2.6.13-rc4
v2.6.13-rc5
v2.6.13-rc6
v2.6.13-rc7
v2.6.14-rc1
sent 486 bytes received 1765 bytes 1500.67 bytes/sec
total size is 697 speedup is 0.31
New branch: 4b2f955c1b41198c0deee48924f3100fa6131b5f
Cloned to netfilter-2.6.14.git#pptp/ (origin
rsync://people.netfilter.org/users/laforge/scm/netfilter-2.6.14.git#pptp
available as branch "origin")
> >I'll wait for your remaining suggestions and only submit to davem after
> >that.
>
> Please see my other mail. I hope I'm not too anoying, but I prefer
> to do these minor changes before submission because its often not
> worth the time for sending patches afterwards.
No, you're not annoying at all. We just need to find a workflow that
creates as little overhead as possible. (and yes, I wish I'd come up
with your fixes/suggestions myself, but that's apparently not going to
happen).
What about me posting the patches to netfilter-devel first. Then I'll
wait for 3 days, and then I'll send them to Davem and cc netdev for
final submission?
--
- Harald Welte <laforge@netfilter.org> http://netfilter.org/
============================================================================
"Fragmentation is like classful addressing -- an interesting early
architectural error that shows how much experimentation was going
on while IP was being designed." -- Paul Vixie
[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 3/3] NETFILTER: New PPTP helper
2005-09-17 17:45 ` Patrick McHardy
@ 2005-09-18 13:28 ` Harald Welte
2005-09-18 14:26 ` Patrick McHardy
0 siblings, 1 reply; 14+ messages in thread
From: Harald Welte @ 2005-09-18 13:28 UTC (permalink / raw)
To: Patrick McHardy; +Cc: netfilter-devel, David S. Miller
[-- Attachment #1: Type: text/plain, Size: 8901 bytes --]
Hi Patrkick, thanks for your comments.
On Sat, Sep 17, 2005 at 07:45:33PM +0200, Patrick McHardy wrote:
> Following are my remaining suggestions. Mostly really minor things.
>
> First, wouldn't it make sense to make ip_{conntrack,nat}_proto_gre
> usable without pptp as well?
That's how all helpers up to kernel 2.6.12 looked like. However, you
cannot track GRE without some higher-level module. The reason is that
GRE (if at all) uses a single KEY instead of source destination port.
In netfilter-speak, the "key" is part of tuple.dst.u, and if
pkt_to_tuple() has to resolve the full tuple. Without some higher level
module (such as pptp) telling the GRE tracking code which key belongs to
the key in the opposite direction, there is no way it could work.
Since a lot of GRE applications (such as ip-over-gre) don't even use the
optional key, you're back to the good old "generic" conntrack, and you
can't distinguish multiple sessions between two IP's.
Since for PPTP the "four modules" approach caused many user problems,
and there was no other sensible use of the GRE code in sight, I dropped
that idea.
> diff --git a/net/ipv4/netfilter/ip_conntrack_helper_pptp.c
> b/net/ipv4/netfilter/ip_conntrack_helper_pptp.c
> new file mode 100644
> --- /dev/null
> +++ b/net/ipv4/netfilter/ip_conntrack_helper_pptp.c
>
> I would prefer the name ip_conntrack_pptp.c for consisteny with
> other helpers. Same for ip_nat_helper_pptp.c.
AFAIK, that's not possible, since the resulting module is called
ip_conntrack_pptp.ko , but it is a multi-object module. Again, this
change was only introduced in the 2.6.13 version when gre and pptp files
were linked together for a single kernel module.
I don't think that consistency in soucre file naming is a valid reason
to abandon this combination, though.
And if at all, I would argue that the existing code is inconsistently
named and that we should introduce _helper into the existing ones [like
we have _proto for protocoks] ;)
> +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);
>
> The regular way of doing this (del_timer, call ct->timeout.function)
> seems cleaner too me.
ok, no problem with that. I thought it was better to not expose
conntrack details into the helper, but I'll change it.
> +/* timeout GRE data connections */
> +static int pptp_timeout_related(struct ip_conntrack *ct)
>
> The return value of this function isn't used, so timeout_ct_or_exp and
> itself can be made void.
Ok, old versions of the code presumably used that value, that's probably
the reason why it returns something. I've resolved it now.
> The name also seems a bit misleading since it wants to destroy related
> conntracks and is not used in any function dealing with timouts - how
> about pptp_destroy_related()?
Well, it sets the timeout to zero. So the name refers to the verbal
form "to timeout the connection". But I'm happy to rename it.
> +EXPORT_SYMBOL(ip_pptp_lock);
>
> This export is not used.
ok, removed
> diff --git a/net/ipv4/netfilter/ip_conntrack_pptp_priv.h
> b/net/ipv4/netfilter/ip_conntrack_pptp_priv.h
> new file mode 100644
> --- /dev/null
> +++ b/net/ipv4/netfilter/ip_conntrack_pptp_priv.h
> +@@ -0,0 +1,24 @@
> +#ifndef _IP_CT_PPTP_PRIV_H
> +#define _IP_CT_PPTP_PRIV_H
> +
> +/* PptpControlMessageType names */
> +static const char *strMName[] = {
>
> This should go in the pptp helper itself.
It's used from both the conntrack and the NAT helper - and only
conditional to #defining some DEBUG value. That's why it's in a
separate header file. The only way to avoid that would be to
conditionally EXPORT_SYMBOL() it from the conntrack helper, which is
what I did now in the git tree.
> +int
> +ip_ct_gre_keymap_add(struct ip_conntrack *ct,
> + struct ip_conntrack_tuple *t, int reply)
> +{
> + 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)
> + return -1;
> +
> + /* initializing list head should be sufficient */
> + memset(km, 0, sizeof(*km));
>
> The comment doesn't match the code.
exactly, thats why there is a comment. It should be sufficient, but
when I wrote the code I wanted to be sure. Maybe I should be prefixed
with "FIXME:". Anyway, I'll check if list initialization is really
enough, and then either do it or use kzalloc()
As it turned out, initialization is not needed for the whole structure.
> + memcpy(&km->tuple, t, sizeof(*t));
> +
> + 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;
>
> All users only check for <= 0, using -1 or -EEXIST or something seems
> cleaner than using magic values.
ack.
>
> + }
> + 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;
>
> It looks like the above blocks could be merged by using a pointer
> to ct->help.ct_pptp_info.keymap_{orig,reply}. Memory allocation
> can then be moved below the "if (!reply)" block.
ack.
>
> +void __exit ip_ct_proto_gre_fini(void)
> +{
> + struct list_head *pos, *n;
> +
> + /* delete all keymap entries */
> + write_lock_bh(&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);
>
> break;
>
> + }
> + write_unlock_bh(&ip_ct_gre_lock);
Why would you want to have a break statement? We really want to iterate
over the list and delete all (for some strange reason) not yet kfree'd
keymaps at module unload time.
I originally added the code during development to notify me of (and
clean up) any keymap memory leaks. I don't know of any such leaks
being left for quite some time, so we could make the whole block #ifdef
DEBUG_PPTP. However, it doesn't hurt to make sure by leaving it in.
What do you think?
> +/* 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_int16_t key = 0, *keyptr;
>
> How about using the same static u_int16_t key trick used in
> the other NAT helpers to increase chances of finding an unused
> tuple at the first try?
Sure. The PPTP code predates that trick by a couple of years, and I
forgot to add it later on.
The resulting code is now in my netfilter-2.6.14 tree. I'll submit
later today.
--
- Harald Welte <laforge@netfilter.org> http://netfilter.org/
============================================================================
"Fragmentation is like classful addressing -- an interesting early
architectural error that shows how much experimentation was going
on while IP was being designed." -- Paul Vixie
[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 3/3] NETFILTER: New PPTP helper
2005-09-18 13:28 ` Harald Welte
@ 2005-09-18 14:26 ` Patrick McHardy
0 siblings, 0 replies; 14+ messages in thread
From: Patrick McHardy @ 2005-09-18 14:26 UTC (permalink / raw)
To: Harald Welte; +Cc: netfilter-devel, David S. Miller
Harald Welte wrote:
> On Sat, Sep 17, 2005 at 07:45:33PM +0200, Patrick McHardy wrote:
>
>>First, wouldn't it make sense to make ip_{conntrack,nat}_proto_gre
>>usable without pptp as well?
>
> That's how all helpers up to kernel 2.6.12 looked like. However, you
> cannot track GRE without some higher-level module. The reason is that
> GRE (if at all) uses a single KEY instead of source destination port.
>
> In netfilter-speak, the "key" is part of tuple.dst.u, and if
> pkt_to_tuple() has to resolve the full tuple. Without some higher level
> module (such as pptp) telling the GRE tracking code which key belongs to
> the key in the opposite direction, there is no way it could work.
>
> Since a lot of GRE applications (such as ip-over-gre) don't even use the
> optional key, you're back to the good old "generic" conntrack, and you
> can't distinguish multiple sessions between two IP's.
>
> Since for PPTP the "four modules" approach caused many user problems,
> and there was no other sensible use of the GRE code in sight, I dropped
> that idea.
Thanks for the explanation.
>>diff --git a/net/ipv4/netfilter/ip_conntrack_helper_pptp.c
>>b/net/ipv4/netfilter/ip_conntrack_helper_pptp.c
>>new file mode 100644
>>--- /dev/null
>>+++ b/net/ipv4/netfilter/ip_conntrack_helper_pptp.c
>>
>>I would prefer the name ip_conntrack_pptp.c for consisteny with
>>other helpers. Same for ip_nat_helper_pptp.c.
>
> AFAIK, that's not possible, since the resulting module is called
> ip_conntrack_pptp.ko , but it is a multi-object module. Again, this
> change was only introduced in the 2.6.13 version when gre and pptp files
> were linked together for a single kernel module.
>
> I don't think that consistency in soucre file naming is a valid reason
> to abandon this combination, though.
>
> And if at all, I would argue that the existing code is inconsistently
> named and that we should introduce _helper into the existing ones [like
> we have _proto for protocoks] ;)
That would make even more sense, but would cause incompatiblities.
I agree its not important, so lets just leave it for now.
>>+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);
>>
>>The regular way of doing this (del_timer, call ct->timeout.function)
>>seems cleaner too me.
>
> ok, no problem with that. I thought it was better to not expose
> conntrack details into the helper, but I'll change it.
As a cleanup for other helpers as well we can put this in a function.
>>+void __exit ip_ct_proto_gre_fini(void)
>>+{
>>+ struct list_head *pos, *n;
>>+
>>+ /* delete all keymap entries */
>>+ write_lock_bh(&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);
>>
>>break;
>>
>>+ }
>>+ write_unlock_bh(&ip_ct_gre_lock);
>
> Why would you want to have a break statement? We really want to iterate
> over the list and delete all (for some strange reason) not yet kfree'd
> keymaps at module unload time.
Sorry, that was a misunderstanding, I somehow thought it wanted
to clean up a single entry. The break is wrong of course.
> I originally added the code during development to notify me of (and
> clean up) any keymap memory leaks. I don't know of any such leaks
> being left for quite some time, so we could make the whole block #ifdef
> DEBUG_PPTP. However, it doesn't hurt to make sure by leaving it in.
> What do you think?
Maybe a BUG_ON(!list_empty(&gre_keymap_list)) then?
> The resulting code is now in my netfilter-2.6.14 tree. I'll submit
> later today.
Great, nice to finally see this going in.
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 3/3] NETFILTER: New PPTP helper
2005-09-18 9:14 ` Harald Welte
@ 2005-09-18 14:37 ` Patrick McHardy
0 siblings, 0 replies; 14+ messages in thread
From: Patrick McHardy @ 2005-09-18 14:37 UTC (permalink / raw)
To: Harald Welte; +Cc: netfilter-devel, David S. Miller
Harald Welte wrote:
> On Sat, Sep 17, 2005 at 09:05:52PM +0200, Patrick McHardy wrote:
>
>>Harald Welte wrote:
>>
>>>Ok, in case you're interested in the latest code (confirmed to work in
>>>my testcases) including all 8 of your patches, please check my
>>>netfilter-2.6.14 tree (loacal "pptp" branch) on people.netfilter.org.
>>
>>I tried cloning it using cogito, but get this error:
>
> Are you sure you're not running an outdated cogito version? At least
> via rsync everything seems to work fine here:
I've tried the latest version using http, it also fails. I didn't knew
we were running rsync, this works fine for me.
> What about me posting the patches to netfilter-devel first. Then I'll
> wait for 3 days, and then I'll send them to Davem and cc netdev for
> final submission?
For patches that didn't went through the list before it sounds like a
good idea, I'll try to do the same. Three days may be a little too
long, I usually read the list every day, so a single day should be
enough.
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2005-09-18 14:37 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-09-15 14:54 [PATCH 3/3] NETFILTER: New PPTP helper Harald Welte
2005-09-15 22:44 ` Patrick McHardy
2005-09-16 9:15 ` Harald Welte
2005-09-16 22:45 ` David S. Miller
2005-09-16 22:51 ` Harald Welte
2005-09-17 16:28 ` Patrick McHardy
2005-09-17 17:45 ` Patrick McHardy
2005-09-18 13:28 ` Harald Welte
2005-09-18 14:26 ` Patrick McHardy
2005-09-17 18:33 ` Harald Welte
2005-09-17 19:05 ` Patrick McHardy
2005-09-18 9:14 ` Harald Welte
2005-09-18 14:37 ` Patrick McHardy
2005-09-18 6:46 ` David S. Miller
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.