2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
28 * Copyright (c) 2000 Whistle Communications, Inc.
29 * All rights reserved.
31 * Subject to the following obligations and disclaimer of warranty, use and
32 * redistribution of this software, in source or object code forms, with or
33 * without modifications are expressly permitted by Whistle Communications;
34 * provided, however, that:
35 * 1. Any and all reproductions of the source or object code must include the
36 * copyright notice above and the following disclaimer of warranties; and
37 * 2. No rights are granted, in any manner or form, to use Whistle
38 * Communications, Inc. trademarks, including the mark "WHISTLE
39 * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
40 * such appears in the above copyright notice or in the software.
42 * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
43 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
44 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
45 * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
46 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
47 * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
48 * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
49 * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
50 * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
51 * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
52 * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
53 * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
54 * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
55 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
56 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
57 * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
60 * Author: Erik Salander <erik@whistle.com>
63 * $FreeBSD: src/lib/libalias/alias_pptp.c,v 1.1.2.4 2001/08/01 09:52:27 obrien Exp $
67 Alias_pptp.c performs special processing for PPTP sessions under TCP.
68 Specifically, watch PPTP control messages and alias the Call ID or the
69 Peer's Call ID in the appropriate messages. Note, PPTP requires
70 "de-aliasing" of incoming packets, this is different than any other
71 TCP applications that are currently (ie. FTP, IRC and RTSP) aliased.
73 For Call IDs encountered for the first time, a PPTP alias link is created.
74 The PPTP alias link uses the Call ID in place of the original port number.
75 An alias Call ID is created.
77 For this routine to work, the PPTP control messages must fit entirely
78 into a single TCP packet. This is typically the case, but is not
81 Unlike some of the other TCP applications that are aliased (ie. FTP,
82 IRC and RTSP), the PPTP control messages that need to be aliased are
83 guaranteed to remain the same length. The aliased Call ID is a fixed
88 Initial version: May, 2000 (eds)
93 #include <sys/types.h>
94 #include <netinet/in_systm.h>
95 #include <netinet/in.h>
96 #include <netinet/ip.h>
97 #include <netinet/tcp.h>
101 #include "alias_local.h"
107 struct grehdr
/* Enhanced GRE header. */
109 u_int16_t gh_flags
; /* Flags. */
110 u_int16_t gh_protocol
; /* Protocol type. */
111 u_int16_t gh_length
; /* Payload length. */
112 u_int16_t gh_call_id
; /* Call ID. */
113 u_int32_t gh_seq_no
; /* Sequence number (optional). */
114 u_int32_t gh_ack_no
; /* Acknowledgment number (optional). */
116 typedef struct grehdr GreHdr
;
118 /* The PPTP protocol ID used in the GRE 'proto' field. */
119 #define PPTP_GRE_PROTO 0x880b
121 /* Bits that must be set a certain way in all PPTP/GRE packets. */
122 #define PPTP_INIT_VALUE ((0x2001 << 16) | PPTP_GRE_PROTO)
123 #define PPTP_INIT_MASK 0xef7fffff
125 #define PPTP_MAGIC 0x1a2b3c4d
126 #define PPTP_CTRL_MSG_TYPE 1
129 PPTP_StartCtrlConnRequest
= 1,
130 PPTP_StartCtrlConnReply
= 2,
131 PPTP_StopCtrlConnRequest
= 3,
132 PPTP_StopCtrlConnReply
= 4,
133 PPTP_EchoRequest
= 5,
135 PPTP_OutCallRequest
= 7,
136 PPTP_OutCallReply
= 8,
137 PPTP_InCallRequest
= 9,
138 PPTP_InCallReply
= 10,
139 PPTP_InCallConn
= 11,
140 PPTP_CallClearRequest
= 12,
141 PPTP_CallDiscNotify
= 13,
142 PPTP_WanErrorNotify
= 14,
143 PPTP_SetLinkInfo
= 15
146 /* Message structures */
148 u_int16_t length
; /* total length */
149 u_int16_t msgType
; /* PPTP message type */
150 u_int32_t magic
; /* magic cookie */
151 u_int16_t type
; /* control message type */
152 u_int16_t resv0
; /* reserved */
154 typedef struct pptpMsgHead
*PptpMsgHead
;
157 u_int8_t resCode
; /* Result Code */
158 u_int8_t errCode
; /* Error Code */
160 typedef struct pptpCodes
*PptpCode
;
163 u_int16_t cid1
; /* Call ID field #1 */
164 u_int16_t cid2
; /* Call ID field #2 */
166 typedef struct pptpCallIds
*PptpCallId
;
168 static PptpCallId
AliasVerifyPptp(struct ip
*, u_int16_t
*);
172 AliasHandlePptpOut(struct ip
*pip
, /* IP packet to examine/patch */
173 struct alias_link
*link
) /* The PPTP control link */
175 struct alias_link
*pptp_link
;
178 u_int16_t ctl_type
; /* control message type */
181 /* Verify valid PPTP control message */
182 if ((cptr
= AliasVerifyPptp(pip
, &ctl_type
)) == NULL
)
185 /* Modify certain PPTP messages */
187 case PPTP_OutCallRequest
:
188 case PPTP_OutCallReply
:
189 case PPTP_InCallRequest
:
190 case PPTP_InCallReply
:
191 /* Establish PPTP link for address and Call ID found in control message. */
192 pptp_link
= AddPptp(GetOriginalAddress(link
), GetDestAddress(link
),
193 GetAliasAddress(link
), cptr
->cid1
);
195 case PPTP_CallClearRequest
:
196 case PPTP_CallDiscNotify
:
197 /* Find PPTP link for address and Call ID found in control message. */
198 pptp_link
= FindPptpOutByCallId(GetOriginalAddress(link
),
199 GetDestAddress(link
),
206 if (pptp_link
!= NULL
) {
207 int accumulate
= cptr
->cid1
;
209 /* alias the Call Id */
210 cptr
->cid1
= GetAliasPort(pptp_link
);
212 /* Compute TCP checksum for revised packet */
213 tc
= (struct tcphdr
*) ((char *) pip
+ (pip
->ip_hl
<< 2));
214 accumulate
-= cptr
->cid1
;
215 ADJUST_CHECKSUM(accumulate
, tc
->th_sum
);
218 case PPTP_OutCallReply
:
219 case PPTP_InCallReply
:
220 codes
= (PptpCode
)(cptr
+ 1);
221 if (codes
->resCode
== 1) /* Connection established, */
222 SetDestCallId(pptp_link
, /* note the Peer's Call ID. */
225 SetExpire(pptp_link
, 0); /* Connection refused. */
227 case PPTP_CallDiscNotify
: /* Connection closed. */
228 SetExpire(pptp_link
, 0);
235 AliasHandlePptpIn(struct ip
*pip
, /* IP packet to examine/patch */
236 struct alias_link
*link
) /* The PPTP control link */
238 struct alias_link
*pptp_link
;
241 u_int16_t ctl_type
; /* control message type */
244 /* Verify valid PPTP control message */
245 if ((cptr
= AliasVerifyPptp(pip
, &ctl_type
)) == NULL
)
248 /* Modify certain PPTP messages */
251 case PPTP_InCallConn
:
252 case PPTP_WanErrorNotify
:
253 case PPTP_SetLinkInfo
:
254 pcall_id
= &cptr
->cid1
;
256 case PPTP_OutCallReply
:
257 case PPTP_InCallReply
:
258 pcall_id
= &cptr
->cid2
;
260 case PPTP_CallDiscNotify
: /* Connection closed. */
261 pptp_link
= FindPptpInByCallId(GetDestAddress(link
),
262 GetAliasAddress(link
),
264 if (pptp_link
!= NULL
)
265 SetExpire(pptp_link
, 0);
271 /* Find PPTP link for address and Call ID found in PPTP Control Msg */
272 pptp_link
= FindPptpInByPeerCallId(GetDestAddress(link
),
273 GetAliasAddress(link
),
276 if (pptp_link
!= NULL
) {
277 int accumulate
= *pcall_id
;
279 /* De-alias the Peer's Call Id. */
280 *pcall_id
= GetOriginalPort(pptp_link
);
282 /* Compute TCP checksum for modified packet */
283 tc
= (struct tcphdr
*) ((char *) pip
+ (pip
->ip_hl
<< 2));
284 accumulate
-= *pcall_id
;
285 ADJUST_CHECKSUM(accumulate
, tc
->th_sum
);
287 if (ctl_type
== PPTP_OutCallReply
|| ctl_type
== PPTP_InCallReply
) {
288 PptpCode codes
= (PptpCode
)(cptr
+ 1);
290 if (codes
->resCode
== 1) /* Connection established, */
291 SetDestCallId(pptp_link
, /* note the Call ID. */
294 SetExpire(pptp_link
, 0); /* Connection refused. */
300 AliasVerifyPptp(struct ip
*pip
, u_int16_t
*ptype
) /* IP packet to examine/patch */
302 int hlen
, tlen
, dlen
;
306 /* Calculate some lengths */
307 tc
= (struct tcphdr
*) ((char *) pip
+ (pip
->ip_hl
<< 2));
308 hlen
= (pip
->ip_hl
+ tc
->th_off
) << 2;
309 tlen
= ntohs(pip
->ip_len
);
312 /* Verify data length */
313 if (dlen
< (sizeof(struct pptpMsgHead
) + sizeof(struct pptpCallIds
)))
316 /* Move up to PPTP message header */
317 hptr
= (PptpMsgHead
)(((char *) pip
) + hlen
);
319 /* Return the control message type */
320 *ptype
= ntohs(hptr
->type
);
322 /* Verify PPTP Control Message */
323 if ((ntohs(hptr
->msgType
) != PPTP_CTRL_MSG_TYPE
) ||
324 (ntohl(hptr
->magic
) != PPTP_MAGIC
))
327 /* Verify data length. */
328 if ((*ptype
== PPTP_OutCallReply
|| *ptype
== PPTP_InCallReply
) &&
329 (dlen
< sizeof(struct pptpMsgHead
) + sizeof(struct pptpCallIds
) +
330 sizeof(struct pptpCodes
)))
333 return (PptpCallId
)(hptr
+ 1);
338 AliasHandlePptpGreOut(struct ip
*pip
)
341 struct alias_link
*link
;
343 gr
= (GreHdr
*)((char *)pip
+ (pip
->ip_hl
<< 2));
345 /* Check GRE header bits. */
346 if ((ntohl(*((u_int32_t
*)gr
)) & PPTP_INIT_MASK
) != PPTP_INIT_VALUE
)
349 link
= FindPptpOutByPeerCallId(pip
->ip_src
, pip
->ip_dst
, gr
->gh_call_id
);
351 struct in_addr alias_addr
= GetAliasAddress(link
);
353 /* Change source IP address. */
354 DifferentialChecksum(&pip
->ip_sum
,
355 (u_short
*)&alias_addr
,
356 (u_short
*)&pip
->ip_src
,
358 pip
->ip_src
= alias_addr
;
366 AliasHandlePptpGreIn(struct ip
*pip
)
369 struct alias_link
*link
;
371 gr
= (GreHdr
*)((char *)pip
+ (pip
->ip_hl
<< 2));
373 /* Check GRE header bits. */
374 if ((ntohl(*((u_int32_t
*)gr
)) & PPTP_INIT_MASK
) != PPTP_INIT_VALUE
)
377 link
= FindPptpInByPeerCallId(pip
->ip_src
, pip
->ip_dst
, gr
->gh_call_id
);
379 struct in_addr src_addr
= GetOriginalAddress(link
);
381 /* De-alias the Peer's Call Id. */
382 gr
->gh_call_id
= GetOriginalPort(link
);
384 /* Restore original IP address. */
385 DifferentialChecksum(&pip
->ip_sum
,
386 (u_short
*)&src_addr
,
387 (u_short
*)&pip
->ip_dst
,
389 pip
->ip_dst
= src_addr
;