Deleted Added
full compact
alias_pptp.c (190841) alias_pptp.c (259858)
1/*
2 * alias_pptp.c
3 *
4 * Copyright (c) 2000 Whistle Communications, Inc.
5 * All rights reserved.
6 *
7 * Subject to the following obligations and disclaimer of warranty, use and
8 * redistribution of this software, in source or object code forms, with or
9 * without modifications are expressly permitted by Whistle Communications;
10 * provided, however, that:
11 * 1. Any and all reproductions of the source or object code must include the
12 * copyright notice above and the following disclaimer of warranties; and
13 * 2. No rights are granted, in any manner or form, to use Whistle
14 * Communications, Inc. trademarks, including the mark "WHISTLE
15 * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
16 * such appears in the above copyright notice or in the software.
17 *
18 * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
19 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
20 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
21 * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
23 * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
24 * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
25 * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
26 * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
27 * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
28 * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
29 * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33 * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
34 * OF SUCH DAMAGE.
35 *
36 * Author: Erik Salander <erik@whistle.com>
37 */
38
39#include <sys/cdefs.h>
1/*
2 * alias_pptp.c
3 *
4 * Copyright (c) 2000 Whistle Communications, Inc.
5 * All rights reserved.
6 *
7 * Subject to the following obligations and disclaimer of warranty, use and
8 * redistribution of this software, in source or object code forms, with or
9 * without modifications are expressly permitted by Whistle Communications;
10 * provided, however, that:
11 * 1. Any and all reproductions of the source or object code must include the
12 * copyright notice above and the following disclaimer of warranties; and
13 * 2. No rights are granted, in any manner or form, to use Whistle
14 * Communications, Inc. trademarks, including the mark "WHISTLE
15 * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
16 * such appears in the above copyright notice or in the software.
17 *
18 * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
19 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
20 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
21 * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
23 * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
24 * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
25 * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
26 * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
27 * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
28 * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
29 * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33 * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
34 * OF SUCH DAMAGE.
35 *
36 * Author: Erik Salander <erik@whistle.com>
37 */
38
39#include <sys/cdefs.h>
40__FBSDID("$FreeBSD: head/sys/netinet/libalias/alias_pptp.c 190841 2009-04-08 11:56:49Z piso $");
40__FBSDID("$FreeBSD: head/sys/netinet/libalias/alias_pptp.c 259858 2013-12-25 02:06:57Z glebius $");
41
42/* Includes */
43#ifdef _KERNEL
44#include <sys/param.h>
45#include <sys/limits.h>
46#include <sys/kernel.h>
47#include <sys/module.h>
48#else
49#include <errno.h>
50#include <limits.h>
51#include <sys/types.h>
52#include <stdio.h>
53#endif
54
55#include <netinet/tcp.h>
56
57#ifdef _KERNEL
58#include <netinet/libalias/alias.h>
59#include <netinet/libalias/alias_local.h>
60#include <netinet/libalias/alias_mod.h>
61#else
62#include "alias.h"
63#include "alias_local.h"
64#include "alias_mod.h"
65#endif
66
67#define PPTP_CONTROL_PORT_NUMBER 1723
68
69static void
70AliasHandlePptpOut(struct libalias *, struct ip *, struct alias_link *);
71
72static void
73AliasHandlePptpIn(struct libalias *, struct ip *, struct alias_link *);
74
75static int
76AliasHandlePptpGreOut(struct libalias *, struct ip *);
77
78static int
79AliasHandlePptpGreIn(struct libalias *, struct ip *);
80
41
42/* Includes */
43#ifdef _KERNEL
44#include <sys/param.h>
45#include <sys/limits.h>
46#include <sys/kernel.h>
47#include <sys/module.h>
48#else
49#include <errno.h>
50#include <limits.h>
51#include <sys/types.h>
52#include <stdio.h>
53#endif
54
55#include <netinet/tcp.h>
56
57#ifdef _KERNEL
58#include <netinet/libalias/alias.h>
59#include <netinet/libalias/alias_local.h>
60#include <netinet/libalias/alias_mod.h>
61#else
62#include "alias.h"
63#include "alias_local.h"
64#include "alias_mod.h"
65#endif
66
67#define PPTP_CONTROL_PORT_NUMBER 1723
68
69static void
70AliasHandlePptpOut(struct libalias *, struct ip *, struct alias_link *);
71
72static void
73AliasHandlePptpIn(struct libalias *, struct ip *, struct alias_link *);
74
75static int
76AliasHandlePptpGreOut(struct libalias *, struct ip *);
77
78static int
79AliasHandlePptpGreIn(struct libalias *, struct ip *);
80
81static int
81static int
82fingerprint(struct libalias *la, struct alias_data *ah)
83{
84
85 if (ah->dport == NULL || ah->sport == NULL || ah->lnk == NULL)
86 return (-1);
87 if (ntohs(*ah->dport) == PPTP_CONTROL_PORT_NUMBER
88 || ntohs(*ah->sport) == PPTP_CONTROL_PORT_NUMBER)
89 return (0);
90 return (-1);
91}
92
82fingerprint(struct libalias *la, struct alias_data *ah)
83{
84
85 if (ah->dport == NULL || ah->sport == NULL || ah->lnk == NULL)
86 return (-1);
87 if (ntohs(*ah->dport) == PPTP_CONTROL_PORT_NUMBER
88 || ntohs(*ah->sport) == PPTP_CONTROL_PORT_NUMBER)
89 return (0);
90 return (-1);
91}
92
93static int
93static int
94fingerprintgre(struct libalias *la, struct alias_data *ah)
95{
96
97 return (0);
98}
99
94fingerprintgre(struct libalias *la, struct alias_data *ah)
95{
96
97 return (0);
98}
99
100static int
100static int
101protohandlerin(struct libalias *la, struct ip *pip, struct alias_data *ah)
102{
103
104 AliasHandlePptpIn(la, pip, ah->lnk);
105 return (0);
106}
107
101protohandlerin(struct libalias *la, struct ip *pip, struct alias_data *ah)
102{
103
104 AliasHandlePptpIn(la, pip, ah->lnk);
105 return (0);
106}
107
108static int
108static int
109protohandlerout(struct libalias *la, struct ip *pip, struct alias_data *ah)
110{
111
112 AliasHandlePptpOut(la, pip, ah->lnk);
113 return (0);
114}
115
109protohandlerout(struct libalias *la, struct ip *pip, struct alias_data *ah)
110{
111
112 AliasHandlePptpOut(la, pip, ah->lnk);
113 return (0);
114}
115
116static int
116static int
117protohandlergrein(struct libalias *la, struct ip *pip, struct alias_data *ah)
118{
119
120 if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY ||
121 AliasHandlePptpGreIn(la, pip) == 0)
122 return (0);
123 return (-1);
124}
125
117protohandlergrein(struct libalias *la, struct ip *pip, struct alias_data *ah)
118{
119
120 if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY ||
121 AliasHandlePptpGreIn(la, pip) == 0)
122 return (0);
123 return (-1);
124}
125
126static int
126static int
127protohandlergreout(struct libalias *la, struct ip *pip, struct alias_data *ah)
128{
129
130 if (AliasHandlePptpGreOut(la, pip) == 0)
131 return (0);
132 return (-1);
133}
134
135/* Kernel module definition. */
136struct proto_handler handlers[] = {
127protohandlergreout(struct libalias *la, struct ip *pip, struct alias_data *ah)
128{
129
130 if (AliasHandlePptpGreOut(la, pip) == 0)
131 return (0);
132 return (-1);
133}
134
135/* Kernel module definition. */
136struct proto_handler handlers[] = {
137 {
138 .pri = 200,
139 .dir = IN,
140 .proto = TCP,
141 .fingerprint = &fingerprint,
137 {
138 .pri = 200,
139 .dir = IN,
140 .proto = TCP,
141 .fingerprint = &fingerprint,
142 .protohandler = &protohandlerin
143 },
142 .protohandler = &protohandlerin
143 },
144 {
145 .pri = 210,
146 .dir = OUT,
147 .proto = TCP,
148 .fingerprint = &fingerprint,
144 {
145 .pri = 210,
146 .dir = OUT,
147 .proto = TCP,
148 .fingerprint = &fingerprint,
149 .protohandler = &protohandlerout
150 },
149 .protohandler = &protohandlerout
150 },
151/*
152 * WATCH OUT!!! these 2 handlers NEED a priority of INT_MAX (highest possible)
151/*
152 * WATCH OUT!!! these 2 handlers NEED a priority of INT_MAX (highest possible)
153 * cause they will ALWAYS process packets, so they must be the last one
154 * in chain: look fingerprintgre() above.
155 */
153 * cause they will ALWAYS process packets, so they must be the last one
154 * in chain: look fingerprintgre() above.
155 */
156 {
157 .pri = INT_MAX,
158 .dir = IN,
159 .proto = IP,
160 .fingerprint = &fingerprintgre,
156 {
157 .pri = INT_MAX,
158 .dir = IN,
159 .proto = IP,
160 .fingerprint = &fingerprintgre,
161 .protohandler = &protohandlergrein
162 },
161 .protohandler = &protohandlergrein
162 },
163 {
164 .pri = INT_MAX,
165 .dir = OUT,
166 .proto = IP,
167 .fingerprint = &fingerprintgre,
163 {
164 .pri = INT_MAX,
165 .dir = OUT,
166 .proto = IP,
167 .fingerprint = &fingerprintgre,
168 .protohandler = &protohandlergreout
168 .protohandler = &protohandlergreout
169 },
169 },
170 { EOH }
171};
172static int
173mod_handler(module_t mod, int type, void *data)
174{
175 int error;
176
177 switch (type) {
178 case MOD_LOAD:
179 error = 0;
180 LibAliasAttachHandlers(handlers);
181 break;
182 case MOD_UNLOAD:
183 error = 0;
184 LibAliasDetachHandlers(handlers);
185 break;
186 default:
187 error = EINVAL;
188 }
189 return (error);
190}
191
192#ifdef _KERNEL
170 { EOH }
171};
172static int
173mod_handler(module_t mod, int type, void *data)
174{
175 int error;
176
177 switch (type) {
178 case MOD_LOAD:
179 error = 0;
180 LibAliasAttachHandlers(handlers);
181 break;
182 case MOD_UNLOAD:
183 error = 0;
184 LibAliasDetachHandlers(handlers);
185 break;
186 default:
187 error = EINVAL;
188 }
189 return (error);
190}
191
192#ifdef _KERNEL
193static
193static
194#endif
195moduledata_t alias_mod = {
196 "alias_pptp", mod_handler, NULL
197};
198
199#ifdef _KERNEL
200DECLARE_MODULE(alias_pptp, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
201MODULE_VERSION(alias_pptp, 1);
202MODULE_DEPEND(alias_pptp, libalias, 1, 1, 1);
203#endif
204
205/*
206 Alias_pptp.c performs special processing for PPTP sessions under TCP.
207 Specifically, watch PPTP control messages and alias the Call ID or the
208 Peer's Call ID in the appropriate messages. Note, PPTP requires
209 "de-aliasing" of incoming packets, this is different than any other
210 TCP applications that are currently (ie. FTP, IRC and RTSP) aliased.
211
212 For Call IDs encountered for the first time, a PPTP alias link is created.
213 The PPTP alias link uses the Call ID in place of the original port number.
214 An alias Call ID is created.
215
216 For this routine to work, the PPTP control messages must fit entirely
217 into a single TCP packet. This is typically the case, but is not
218 required by the spec.
219
220 Unlike some of the other TCP applications that are aliased (ie. FTP,
221 IRC and RTSP), the PPTP control messages that need to be aliased are
222 guaranteed to remain the same length. The aliased Call ID is a fixed
223 length field.
224
225 Reference: RFC 2637
226
227 Initial version: May, 2000 (eds)
228
229*/
230
231/*
232 * PPTP definitions
233 */
234
235struct grehdr { /* Enhanced GRE header. */
236 u_int16_t gh_flags; /* Flags. */
237 u_int16_t gh_protocol; /* Protocol type. */
238 u_int16_t gh_length; /* Payload length. */
239 u_int16_t gh_call_id; /* Call ID. */
240 u_int32_t gh_seq_no; /* Sequence number (optional). */
241 u_int32_t gh_ack_no; /* Acknowledgment number
242 * (optional). */
243};
244typedef struct grehdr GreHdr;
245
246/* The PPTP protocol ID used in the GRE 'proto' field. */
247#define PPTP_GRE_PROTO 0x880b
248
249/* Bits that must be set a certain way in all PPTP/GRE packets. */
250#define PPTP_INIT_VALUE ((0x2001 << 16) | PPTP_GRE_PROTO)
251#define PPTP_INIT_MASK 0xef7fffff
252
253#define PPTP_MAGIC 0x1a2b3c4d
254#define PPTP_CTRL_MSG_TYPE 1
255
256enum {
257 PPTP_StartCtrlConnRequest = 1,
258 PPTP_StartCtrlConnReply = 2,
259 PPTP_StopCtrlConnRequest = 3,
260 PPTP_StopCtrlConnReply = 4,
261 PPTP_EchoRequest = 5,
262 PPTP_EchoReply = 6,
263 PPTP_OutCallRequest = 7,
264 PPTP_OutCallReply = 8,
265 PPTP_InCallRequest = 9,
266 PPTP_InCallReply = 10,
267 PPTP_InCallConn = 11,
268 PPTP_CallClearRequest = 12,
269 PPTP_CallDiscNotify = 13,
270 PPTP_WanErrorNotify = 14,
271 PPTP_SetLinkInfo = 15
272};
273
274 /* Message structures */
275struct pptpMsgHead {
276 u_int16_t length; /* total length */
277 u_int16_t msgType;/* PPTP message type */
278 u_int32_t magic; /* magic cookie */
279 u_int16_t type; /* control message type */
280 u_int16_t resv0; /* reserved */
281};
282typedef struct pptpMsgHead *PptpMsgHead;
283
284struct pptpCodes {
285 u_int8_t resCode;/* Result Code */
286 u_int8_t errCode;/* Error Code */
287};
288typedef struct pptpCodes *PptpCode;
289
290struct pptpCallIds {
291 u_int16_t cid1; /* Call ID field #1 */
292 u_int16_t cid2; /* Call ID field #2 */
293};
294typedef struct pptpCallIds *PptpCallId;
295
296static PptpCallId AliasVerifyPptp(struct ip *, u_int16_t *);
297
298
299static void
300AliasHandlePptpOut(struct libalias *la,
301 struct ip *pip, /* IP packet to examine/patch */
302 struct alias_link *lnk)
303{ /* The PPTP control link */
304 struct alias_link *pptp_lnk;
305 PptpCallId cptr;
306 PptpCode codes;
307 u_int16_t ctl_type; /* control message type */
308 struct tcphdr *tc;
309
310 /* Verify valid PPTP control message */
311 if ((cptr = AliasVerifyPptp(pip, &ctl_type)) == NULL)
312 return;
313
314 /* Modify certain PPTP messages */
315 switch (ctl_type) {
316 case PPTP_OutCallRequest:
317 case PPTP_OutCallReply:
318 case PPTP_InCallRequest:
319 case PPTP_InCallReply:
320 /*
321 * Establish PPTP link for address and Call ID found in
322 * control message.
323 */
324 pptp_lnk = AddPptp(la, GetOriginalAddress(lnk), GetDestAddress(lnk),
325 GetAliasAddress(lnk), cptr->cid1);
326 break;
327 case PPTP_CallClearRequest:
328 case PPTP_CallDiscNotify:
329 /*
330 * Find PPTP link for address and Call ID found in control
331 * message.
332 */
333 pptp_lnk = FindPptpOutByCallId(la, GetOriginalAddress(lnk),
334 GetDestAddress(lnk),
335 cptr->cid1);
336 break;
337 default:
338 return;
339 }
340
341 if (pptp_lnk != NULL) {
342 int accumulate = cptr->cid1;
343
344 /* alias the Call Id */
345 cptr->cid1 = GetAliasPort(pptp_lnk);
346
347 /* Compute TCP checksum for revised packet */
348 tc = (struct tcphdr *)ip_next(pip);
349 accumulate -= cptr->cid1;
350 ADJUST_CHECKSUM(accumulate, tc->th_sum);
351
352 switch (ctl_type) {
353 case PPTP_OutCallReply:
354 case PPTP_InCallReply:
355 codes = (PptpCode) (cptr + 1);
356 if (codes->resCode == 1) /* Connection
357 * established, */
358 SetDestCallId(pptp_lnk, /* note the Peer's Call
359 * ID. */
360 cptr->cid2);
361 else
362 SetExpire(pptp_lnk, 0); /* Connection refused. */
363 break;
364 case PPTP_CallDiscNotify: /* Connection closed. */
365 SetExpire(pptp_lnk, 0);
366 break;
367 }
368 }
369}
370
371static void
372AliasHandlePptpIn(struct libalias *la,
373 struct ip *pip, /* IP packet to examine/patch */
374 struct alias_link *lnk)
375{ /* The PPTP control link */
376 struct alias_link *pptp_lnk;
377 PptpCallId cptr;
378 u_int16_t *pcall_id;
379 u_int16_t ctl_type; /* control message type */
380 struct tcphdr *tc;
381
382 /* Verify valid PPTP control message */
383 if ((cptr = AliasVerifyPptp(pip, &ctl_type)) == NULL)
384 return;
385
386 /* Modify certain PPTP messages */
387 switch (ctl_type) {
388 case PPTP_InCallConn:
389 case PPTP_WanErrorNotify:
390 case PPTP_SetLinkInfo:
391 pcall_id = &cptr->cid1;
392 break;
393 case PPTP_OutCallReply:
394 case PPTP_InCallReply:
395 pcall_id = &cptr->cid2;
396 break;
397 case PPTP_CallDiscNotify: /* Connection closed. */
398 pptp_lnk = FindPptpInByCallId(la, GetDestAddress(lnk),
399 GetAliasAddress(lnk),
400 cptr->cid1);
401 if (pptp_lnk != NULL)
402 SetExpire(pptp_lnk, 0);
403 return;
404 default:
405 return;
406 }
407
408 /* Find PPTP link for address and Call ID found in PPTP Control Msg */
409 pptp_lnk = FindPptpInByPeerCallId(la, GetDestAddress(lnk),
410 GetAliasAddress(lnk),
411 *pcall_id);
412
413 if (pptp_lnk != NULL) {
414 int accumulate = *pcall_id;
415
416 /* De-alias the Peer's Call Id. */
417 *pcall_id = GetOriginalPort(pptp_lnk);
418
419 /* Compute TCP checksum for modified packet */
420 tc = (struct tcphdr *)ip_next(pip);
421 accumulate -= *pcall_id;
422 ADJUST_CHECKSUM(accumulate, tc->th_sum);
423
424 if (ctl_type == PPTP_OutCallReply || ctl_type == PPTP_InCallReply) {
425 PptpCode codes = (PptpCode) (cptr + 1);
426
427 if (codes->resCode == 1) /* Connection
428 * established, */
429 SetDestCallId(pptp_lnk, /* note the Call ID. */
430 cptr->cid1);
431 else
432 SetExpire(pptp_lnk, 0); /* Connection refused. */
433 }
434 }
435}
436
437static PptpCallId
438AliasVerifyPptp(struct ip *pip, u_int16_t * ptype)
439{ /* IP packet to examine/patch */
440 int hlen, tlen, dlen;
441 PptpMsgHead hptr;
442 struct tcphdr *tc;
443
444 /* Calculate some lengths */
445 tc = (struct tcphdr *)ip_next(pip);
446 hlen = (pip->ip_hl + tc->th_off) << 2;
447 tlen = ntohs(pip->ip_len);
448 dlen = tlen - hlen;
449
450 /* Verify data length */
451 if (dlen < (int)(sizeof(struct pptpMsgHead) + sizeof(struct pptpCallIds)))
452 return (NULL);
453
454 /* Move up to PPTP message header */
455 hptr = (PptpMsgHead) tcp_next(tc);
456
457 /* Return the control message type */
458 *ptype = ntohs(hptr->type);
459
460 /* Verify PPTP Control Message */
461 if ((ntohs(hptr->msgType) != PPTP_CTRL_MSG_TYPE) ||
462 (ntohl(hptr->magic) != PPTP_MAGIC))
463 return (NULL);
464
465 /* Verify data length. */
466 if ((*ptype == PPTP_OutCallReply || *ptype == PPTP_InCallReply) &&
467 (dlen < (int)(sizeof(struct pptpMsgHead) + sizeof(struct pptpCallIds) +
468 sizeof(struct pptpCodes))))
469 return (NULL);
470 else
471 return (PptpCallId) (hptr + 1);
472}
473
474static int
475AliasHandlePptpGreOut(struct libalias *la, struct ip *pip)
476{
477 GreHdr *gr;
478 struct alias_link *lnk;
479
480 gr = (GreHdr *) ip_next(pip);
481
482 /* Check GRE header bits. */
483 if ((ntohl(*((u_int32_t *) gr)) & PPTP_INIT_MASK) != PPTP_INIT_VALUE)
484 return (-1);
485
486 lnk = FindPptpOutByPeerCallId(la, pip->ip_src, pip->ip_dst, gr->gh_call_id);
487 if (lnk != NULL) {
488 struct in_addr alias_addr = GetAliasAddress(lnk);
489
490 /* Change source IP address. */
491 DifferentialChecksum(&pip->ip_sum,
492 &alias_addr, &pip->ip_src, 2);
493 pip->ip_src = alias_addr;
494 }
495 return (0);
496}
497
498static int
499AliasHandlePptpGreIn(struct libalias *la, struct ip *pip)
500{
501 GreHdr *gr;
502 struct alias_link *lnk;
503
504 gr = (GreHdr *) ip_next(pip);
505
506 /* Check GRE header bits. */
507 if ((ntohl(*((u_int32_t *) gr)) & PPTP_INIT_MASK) != PPTP_INIT_VALUE)
508 return (-1);
509
510 lnk = FindPptpInByPeerCallId(la, pip->ip_src, pip->ip_dst, gr->gh_call_id);
511 if (lnk != NULL) {
512 struct in_addr src_addr = GetOriginalAddress(lnk);
513
514 /* De-alias the Peer's Call Id. */
515 gr->gh_call_id = GetOriginalPort(lnk);
516
517 /* Restore original IP address. */
518 DifferentialChecksum(&pip->ip_sum,
519 &src_addr, &pip->ip_dst, 2);
520 pip->ip_dst = src_addr;
521 }
522 return (0);
523}
194#endif
195moduledata_t alias_mod = {
196 "alias_pptp", mod_handler, NULL
197};
198
199#ifdef _KERNEL
200DECLARE_MODULE(alias_pptp, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
201MODULE_VERSION(alias_pptp, 1);
202MODULE_DEPEND(alias_pptp, libalias, 1, 1, 1);
203#endif
204
205/*
206 Alias_pptp.c performs special processing for PPTP sessions under TCP.
207 Specifically, watch PPTP control messages and alias the Call ID or the
208 Peer's Call ID in the appropriate messages. Note, PPTP requires
209 "de-aliasing" of incoming packets, this is different than any other
210 TCP applications that are currently (ie. FTP, IRC and RTSP) aliased.
211
212 For Call IDs encountered for the first time, a PPTP alias link is created.
213 The PPTP alias link uses the Call ID in place of the original port number.
214 An alias Call ID is created.
215
216 For this routine to work, the PPTP control messages must fit entirely
217 into a single TCP packet. This is typically the case, but is not
218 required by the spec.
219
220 Unlike some of the other TCP applications that are aliased (ie. FTP,
221 IRC and RTSP), the PPTP control messages that need to be aliased are
222 guaranteed to remain the same length. The aliased Call ID is a fixed
223 length field.
224
225 Reference: RFC 2637
226
227 Initial version: May, 2000 (eds)
228
229*/
230
231/*
232 * PPTP definitions
233 */
234
235struct grehdr { /* Enhanced GRE header. */
236 u_int16_t gh_flags; /* Flags. */
237 u_int16_t gh_protocol; /* Protocol type. */
238 u_int16_t gh_length; /* Payload length. */
239 u_int16_t gh_call_id; /* Call ID. */
240 u_int32_t gh_seq_no; /* Sequence number (optional). */
241 u_int32_t gh_ack_no; /* Acknowledgment number
242 * (optional). */
243};
244typedef struct grehdr GreHdr;
245
246/* The PPTP protocol ID used in the GRE 'proto' field. */
247#define PPTP_GRE_PROTO 0x880b
248
249/* Bits that must be set a certain way in all PPTP/GRE packets. */
250#define PPTP_INIT_VALUE ((0x2001 << 16) | PPTP_GRE_PROTO)
251#define PPTP_INIT_MASK 0xef7fffff
252
253#define PPTP_MAGIC 0x1a2b3c4d
254#define PPTP_CTRL_MSG_TYPE 1
255
256enum {
257 PPTP_StartCtrlConnRequest = 1,
258 PPTP_StartCtrlConnReply = 2,
259 PPTP_StopCtrlConnRequest = 3,
260 PPTP_StopCtrlConnReply = 4,
261 PPTP_EchoRequest = 5,
262 PPTP_EchoReply = 6,
263 PPTP_OutCallRequest = 7,
264 PPTP_OutCallReply = 8,
265 PPTP_InCallRequest = 9,
266 PPTP_InCallReply = 10,
267 PPTP_InCallConn = 11,
268 PPTP_CallClearRequest = 12,
269 PPTP_CallDiscNotify = 13,
270 PPTP_WanErrorNotify = 14,
271 PPTP_SetLinkInfo = 15
272};
273
274 /* Message structures */
275struct pptpMsgHead {
276 u_int16_t length; /* total length */
277 u_int16_t msgType;/* PPTP message type */
278 u_int32_t magic; /* magic cookie */
279 u_int16_t type; /* control message type */
280 u_int16_t resv0; /* reserved */
281};
282typedef struct pptpMsgHead *PptpMsgHead;
283
284struct pptpCodes {
285 u_int8_t resCode;/* Result Code */
286 u_int8_t errCode;/* Error Code */
287};
288typedef struct pptpCodes *PptpCode;
289
290struct pptpCallIds {
291 u_int16_t cid1; /* Call ID field #1 */
292 u_int16_t cid2; /* Call ID field #2 */
293};
294typedef struct pptpCallIds *PptpCallId;
295
296static PptpCallId AliasVerifyPptp(struct ip *, u_int16_t *);
297
298
299static void
300AliasHandlePptpOut(struct libalias *la,
301 struct ip *pip, /* IP packet to examine/patch */
302 struct alias_link *lnk)
303{ /* The PPTP control link */
304 struct alias_link *pptp_lnk;
305 PptpCallId cptr;
306 PptpCode codes;
307 u_int16_t ctl_type; /* control message type */
308 struct tcphdr *tc;
309
310 /* Verify valid PPTP control message */
311 if ((cptr = AliasVerifyPptp(pip, &ctl_type)) == NULL)
312 return;
313
314 /* Modify certain PPTP messages */
315 switch (ctl_type) {
316 case PPTP_OutCallRequest:
317 case PPTP_OutCallReply:
318 case PPTP_InCallRequest:
319 case PPTP_InCallReply:
320 /*
321 * Establish PPTP link for address and Call ID found in
322 * control message.
323 */
324 pptp_lnk = AddPptp(la, GetOriginalAddress(lnk), GetDestAddress(lnk),
325 GetAliasAddress(lnk), cptr->cid1);
326 break;
327 case PPTP_CallClearRequest:
328 case PPTP_CallDiscNotify:
329 /*
330 * Find PPTP link for address and Call ID found in control
331 * message.
332 */
333 pptp_lnk = FindPptpOutByCallId(la, GetOriginalAddress(lnk),
334 GetDestAddress(lnk),
335 cptr->cid1);
336 break;
337 default:
338 return;
339 }
340
341 if (pptp_lnk != NULL) {
342 int accumulate = cptr->cid1;
343
344 /* alias the Call Id */
345 cptr->cid1 = GetAliasPort(pptp_lnk);
346
347 /* Compute TCP checksum for revised packet */
348 tc = (struct tcphdr *)ip_next(pip);
349 accumulate -= cptr->cid1;
350 ADJUST_CHECKSUM(accumulate, tc->th_sum);
351
352 switch (ctl_type) {
353 case PPTP_OutCallReply:
354 case PPTP_InCallReply:
355 codes = (PptpCode) (cptr + 1);
356 if (codes->resCode == 1) /* Connection
357 * established, */
358 SetDestCallId(pptp_lnk, /* note the Peer's Call
359 * ID. */
360 cptr->cid2);
361 else
362 SetExpire(pptp_lnk, 0); /* Connection refused. */
363 break;
364 case PPTP_CallDiscNotify: /* Connection closed. */
365 SetExpire(pptp_lnk, 0);
366 break;
367 }
368 }
369}
370
371static void
372AliasHandlePptpIn(struct libalias *la,
373 struct ip *pip, /* IP packet to examine/patch */
374 struct alias_link *lnk)
375{ /* The PPTP control link */
376 struct alias_link *pptp_lnk;
377 PptpCallId cptr;
378 u_int16_t *pcall_id;
379 u_int16_t ctl_type; /* control message type */
380 struct tcphdr *tc;
381
382 /* Verify valid PPTP control message */
383 if ((cptr = AliasVerifyPptp(pip, &ctl_type)) == NULL)
384 return;
385
386 /* Modify certain PPTP messages */
387 switch (ctl_type) {
388 case PPTP_InCallConn:
389 case PPTP_WanErrorNotify:
390 case PPTP_SetLinkInfo:
391 pcall_id = &cptr->cid1;
392 break;
393 case PPTP_OutCallReply:
394 case PPTP_InCallReply:
395 pcall_id = &cptr->cid2;
396 break;
397 case PPTP_CallDiscNotify: /* Connection closed. */
398 pptp_lnk = FindPptpInByCallId(la, GetDestAddress(lnk),
399 GetAliasAddress(lnk),
400 cptr->cid1);
401 if (pptp_lnk != NULL)
402 SetExpire(pptp_lnk, 0);
403 return;
404 default:
405 return;
406 }
407
408 /* Find PPTP link for address and Call ID found in PPTP Control Msg */
409 pptp_lnk = FindPptpInByPeerCallId(la, GetDestAddress(lnk),
410 GetAliasAddress(lnk),
411 *pcall_id);
412
413 if (pptp_lnk != NULL) {
414 int accumulate = *pcall_id;
415
416 /* De-alias the Peer's Call Id. */
417 *pcall_id = GetOriginalPort(pptp_lnk);
418
419 /* Compute TCP checksum for modified packet */
420 tc = (struct tcphdr *)ip_next(pip);
421 accumulate -= *pcall_id;
422 ADJUST_CHECKSUM(accumulate, tc->th_sum);
423
424 if (ctl_type == PPTP_OutCallReply || ctl_type == PPTP_InCallReply) {
425 PptpCode codes = (PptpCode) (cptr + 1);
426
427 if (codes->resCode == 1) /* Connection
428 * established, */
429 SetDestCallId(pptp_lnk, /* note the Call ID. */
430 cptr->cid1);
431 else
432 SetExpire(pptp_lnk, 0); /* Connection refused. */
433 }
434 }
435}
436
437static PptpCallId
438AliasVerifyPptp(struct ip *pip, u_int16_t * ptype)
439{ /* IP packet to examine/patch */
440 int hlen, tlen, dlen;
441 PptpMsgHead hptr;
442 struct tcphdr *tc;
443
444 /* Calculate some lengths */
445 tc = (struct tcphdr *)ip_next(pip);
446 hlen = (pip->ip_hl + tc->th_off) << 2;
447 tlen = ntohs(pip->ip_len);
448 dlen = tlen - hlen;
449
450 /* Verify data length */
451 if (dlen < (int)(sizeof(struct pptpMsgHead) + sizeof(struct pptpCallIds)))
452 return (NULL);
453
454 /* Move up to PPTP message header */
455 hptr = (PptpMsgHead) tcp_next(tc);
456
457 /* Return the control message type */
458 *ptype = ntohs(hptr->type);
459
460 /* Verify PPTP Control Message */
461 if ((ntohs(hptr->msgType) != PPTP_CTRL_MSG_TYPE) ||
462 (ntohl(hptr->magic) != PPTP_MAGIC))
463 return (NULL);
464
465 /* Verify data length. */
466 if ((*ptype == PPTP_OutCallReply || *ptype == PPTP_InCallReply) &&
467 (dlen < (int)(sizeof(struct pptpMsgHead) + sizeof(struct pptpCallIds) +
468 sizeof(struct pptpCodes))))
469 return (NULL);
470 else
471 return (PptpCallId) (hptr + 1);
472}
473
474static int
475AliasHandlePptpGreOut(struct libalias *la, struct ip *pip)
476{
477 GreHdr *gr;
478 struct alias_link *lnk;
479
480 gr = (GreHdr *) ip_next(pip);
481
482 /* Check GRE header bits. */
483 if ((ntohl(*((u_int32_t *) gr)) & PPTP_INIT_MASK) != PPTP_INIT_VALUE)
484 return (-1);
485
486 lnk = FindPptpOutByPeerCallId(la, pip->ip_src, pip->ip_dst, gr->gh_call_id);
487 if (lnk != NULL) {
488 struct in_addr alias_addr = GetAliasAddress(lnk);
489
490 /* Change source IP address. */
491 DifferentialChecksum(&pip->ip_sum,
492 &alias_addr, &pip->ip_src, 2);
493 pip->ip_src = alias_addr;
494 }
495 return (0);
496}
497
498static int
499AliasHandlePptpGreIn(struct libalias *la, struct ip *pip)
500{
501 GreHdr *gr;
502 struct alias_link *lnk;
503
504 gr = (GreHdr *) ip_next(pip);
505
506 /* Check GRE header bits. */
507 if ((ntohl(*((u_int32_t *) gr)) & PPTP_INIT_MASK) != PPTP_INIT_VALUE)
508 return (-1);
509
510 lnk = FindPptpInByPeerCallId(la, pip->ip_src, pip->ip_dst, gr->gh_call_id);
511 if (lnk != NULL) {
512 struct in_addr src_addr = GetOriginalAddress(lnk);
513
514 /* De-alias the Peer's Call Id. */
515 gr->gh_call_id = GetOriginalPort(lnk);
516
517 /* Restore original IP address. */
518 DifferentialChecksum(&pip->ip_sum,
519 &src_addr, &pip->ip_dst, 2);
520 pip->ip_dst = src_addr;
521 }
522 return (0);
523}