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