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$");
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
69 static void
70 AliasHandlePptpOut(struct libalias *, struct ip *, struct alias_link *);
71
72 static void
73 AliasHandlePptpIn(struct libalias *, struct ip *, struct alias_link *);
74
75 static int
76 AliasHandlePptpGreOut(struct libalias *, struct ip *);
77
78 static int
79 AliasHandlePptpGreIn(struct libalias *, struct ip *);
80
81 static int
82 fingerprint(struct libalias *la, struct alias_data *ah)
83 {
84 if (ah->dport == NULL || ah->sport == NULL || ah->lnk == NULL)
85 return (-1);
86 if (ntohs(*ah->dport) == PPTP_CONTROL_PORT_NUMBER
87 || ntohs(*ah->sport) == PPTP_CONTROL_PORT_NUMBER)
88 return (0);
89 return (-1);
90 }
91
92 static int
93 fingerprintgre(struct libalias *la, struct alias_data *ah)
94 {
95 return (0);
96 }
97
98 static int
99 protohandlerin(struct libalias *la, struct ip *pip, struct alias_data *ah)
100 {
101 AliasHandlePptpIn(la, pip, ah->lnk);
102 return (0);
103 }
104
105 static int
106 protohandlerout(struct libalias *la, struct ip *pip, struct alias_data *ah)
107 {
108 AliasHandlePptpOut(la, pip, ah->lnk);
109 return (0);
110 }
111
112 static int
113 protohandlergrein(struct libalias *la, struct ip *pip, struct alias_data *ah)
114 {
115 if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY ||
116 AliasHandlePptpGreIn(la, pip) == 0)
117 return (0);
118 return (-1);
119 }
120
121 static int
122 protohandlergreout(struct libalias *la, struct ip *pip, struct alias_data *ah)
123 {
124 if (AliasHandlePptpGreOut(la, pip) == 0)
125 return (0);
126 return (-1);
127 }
128
129 /* Kernel module definition. */
130 struct proto_handler handlers[] = {
131 {
132 .pri = 200,
133 .dir = IN,
134 .proto = TCP,
135 .fingerprint = &fingerprint,
136 .protohandler = &protohandlerin
137 },
138 {
139 .pri = 210,
140 .dir = OUT,
141 .proto = TCP,
142 .fingerprint = &fingerprint,
143 .protohandler = &protohandlerout
144 },
145 /*
146 * WATCH OUT!!! these 2 handlers NEED a priority of INT_MAX (highest possible)
147 * cause they will ALWAYS process packets, so they must be the last one
148 * in chain: look fingerprintgre() above.
149 */
150 {
151 .pri = INT_MAX,
152 .dir = IN,
153 .proto = IP,
154 .fingerprint = &fingerprintgre,
155 .protohandler = &protohandlergrein
156 },
157 {
158 .pri = INT_MAX,
159 .dir = OUT,
160 .proto = IP,
161 .fingerprint = &fingerprintgre,
162 .protohandler = &protohandlergreout
163 },
164 { EOH }
165 };
166 static int
167 mod_handler(module_t mod, int type, void *data)
168 {
169 int error;
170
171 switch (type) {
172 case MOD_LOAD:
173 error = 0;
174 LibAliasAttachHandlers(handlers);
175 break;
176 case MOD_UNLOAD:
177 error = 0;
178 LibAliasDetachHandlers(handlers);
179 break;
180 default:
181 error = EINVAL;
182 }
183 return (error);
184 }
185
186 #ifdef _KERNEL
187 static
188 #endif
189 moduledata_t alias_mod = {
190 "alias_pptp", mod_handler, NULL
191 };
192
193 #ifdef _KERNEL
194 DECLARE_MODULE(alias_pptp, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
195 MODULE_VERSION(alias_pptp, 1);
196 MODULE_DEPEND(alias_pptp, libalias, 1, 1, 1);
197 #endif
198
199 /*
200 Alias_pptp.c performs special processing for PPTP sessions under TCP.
201 Specifically, watch PPTP control messages and alias the Call ID or the
202 Peer's Call ID in the appropriate messages. Note, PPTP requires
203 "de-aliasing" of incoming packets, this is different than any other
204 TCP applications that are currently (ie. FTP, IRC and RTSP) aliased.
205
206 For Call IDs encountered for the first time, a PPTP alias link is created.
207 The PPTP alias link uses the Call ID in place of the original port number.
208 An alias Call ID is created.
209
210 For this routine to work, the PPTP control messages must fit entirely
211 into a single TCP packet. This is typically the case, but is not
212 required by the spec.
213
214 Unlike some of the other TCP applications that are aliased (ie. FTP,
215 IRC and RTSP), the PPTP control messages that need to be aliased are
216 guaranteed to remain the same length. The aliased Call ID is a fixed
217 length field.
218
219 Reference: RFC 2637
220
221 Initial version: May, 2000 (eds)
222 */
223
224 /*
225 * PPTP definitions
226 */
227
228 struct grehdr { /* Enhanced GRE header. */
229 u_int16_t gh_flags; /* Flags. */
230 u_int16_t gh_protocol; /* Protocol type. */
231 u_int16_t gh_length; /* Payload length. */
232 u_int16_t gh_call_id; /* Call ID. */
233 u_int32_t gh_seq_no; /* Sequence number (optional). */
234 u_int32_t gh_ack_no; /* Acknowledgment number
235 * (optional). */
236 };
237 typedef struct grehdr GreHdr;
238
239 /* The PPTP protocol ID used in the GRE 'proto' field. */
240 #define PPTP_GRE_PROTO 0x880b
241
242 /* Bits that must be set a certain way in all PPTP/GRE packets. */
243 #define PPTP_INIT_VALUE ((0x2001 << 16) | PPTP_GRE_PROTO)
244 #define PPTP_INIT_MASK 0xef7fffff
245
246 #define PPTP_MAGIC 0x1a2b3c4d
247 #define PPTP_CTRL_MSG_TYPE 1
248
249 enum {
250 PPTP_StartCtrlConnRequest = 1,
251 PPTP_StartCtrlConnReply = 2,
252 PPTP_StopCtrlConnRequest = 3,
253 PPTP_StopCtrlConnReply = 4,
254 PPTP_EchoRequest = 5,
255 PPTP_EchoReply = 6,
256 PPTP_OutCallRequest = 7,
257 PPTP_OutCallReply = 8,
258 PPTP_InCallRequest = 9,
259 PPTP_InCallReply = 10,
260 PPTP_InCallConn = 11,
261 PPTP_CallClearRequest = 12,
262 PPTP_CallDiscNotify = 13,
263 PPTP_WanErrorNotify = 14,
264 PPTP_SetLinkInfo = 15
265 };
266
267 /* Message structures */
268 struct pptpMsgHead {
269 u_int16_t length; /* total length */
270 u_int16_t msgType;/* PPTP message type */
271 u_int32_t magic; /* magic cookie */
272 u_int16_t type; /* control message type */
273 u_int16_t resv0; /* reserved */
274 };
275 typedef struct pptpMsgHead *PptpMsgHead;
276
277 struct pptpCodes {
278 u_int8_t resCode;/* Result Code */
279 u_int8_t errCode;/* Error Code */
280 };
281 typedef struct pptpCodes *PptpCode;
282
283 struct pptpCallIds {
284 u_int16_t cid1; /* Call ID field #1 */
285 u_int16_t cid2; /* Call ID field #2 */
286 };
287 typedef struct pptpCallIds *PptpCallId;
288
289 static PptpCallId AliasVerifyPptp(struct ip *, u_int16_t *);
290
291 static void
292 AliasHandlePptpOut(struct libalias *la,
293 struct ip *pip, /* IP packet to examine/patch */
294 struct alias_link *lnk) /* The PPTP control link */
295 {
296 struct alias_link *pptp_lnk;
297 PptpCallId cptr;
298 PptpCode codes;
299 u_int16_t ctl_type; /* control message type */
300 struct tcphdr *tc;
301
302 /* Verify valid PPTP control message */
303 if ((cptr = AliasVerifyPptp(pip, &ctl_type)) == NULL)
304 return;
305
306 /* Modify certain PPTP messages */
307 switch (ctl_type) {
308 case PPTP_OutCallRequest:
309 case PPTP_OutCallReply:
310 case PPTP_InCallRequest:
311 case PPTP_InCallReply:
312 /*
313 * Establish PPTP link for address and Call ID found in
314 * control message.
315 */
316 pptp_lnk = AddPptp(la, GetOriginalAddress(lnk), GetDestAddress(lnk),
317 GetAliasAddress(lnk), cptr->cid1);
318 break;
319 case PPTP_CallClearRequest:
320 case PPTP_CallDiscNotify:
321 /*
322 * Find PPTP link for address and Call ID found in control
323 * message.
324 */
325 pptp_lnk = FindPptpOutByCallId(la, GetOriginalAddress(lnk),
326 GetDestAddress(lnk), cptr->cid1);
327 break;
328 default:
329 return;
330 }
331
332 if (pptp_lnk != NULL) {
333 int accumulate = cptr->cid1;
334
335 /* alias the Call Id */
336 cptr->cid1 = GetAliasPort(pptp_lnk);
337
338 /* Compute TCP checksum for revised packet */
339 tc = (struct tcphdr *)ip_next(pip);
340 accumulate -= cptr->cid1;
341 ADJUST_CHECKSUM(accumulate, tc->th_sum);
342
343 switch (ctl_type) {
344 case PPTP_OutCallReply:
345 case PPTP_InCallReply:
346 codes = (PptpCode)(cptr + 1);
347 if (codes->resCode == 1)
348 /* Connection established,
349 * note the Peer's Call ID. */
350 SetDestCallId(pptp_lnk, cptr->cid2);
351 else
352 /* Connection refused. */
353 SetExpire(pptp_lnk, 0);
354 break;
355 case PPTP_CallDiscNotify:
356 /* Connection closed. */
357 SetExpire(pptp_lnk, 0);
358 break;
359 }
360 }
361 }
362
363 static void
364 AliasHandlePptpIn(struct libalias *la,
365 struct ip *pip, /* IP packet to examine/patch */
366 struct alias_link *lnk) /* The PPTP control link */
367 {
368 struct alias_link *pptp_lnk;
369 PptpCallId cptr;
370 u_int16_t *pcall_id;
371 u_int16_t ctl_type; /* control message type */
372 struct tcphdr *tc;
373
374 /* Verify valid PPTP control message */
375 if ((cptr = AliasVerifyPptp(pip, &ctl_type)) == NULL)
376 return;
377
378 /* Modify certain PPTP messages */
379 switch (ctl_type) {
380 case PPTP_InCallConn:
381 case PPTP_WanErrorNotify:
382 case PPTP_SetLinkInfo:
383 pcall_id = &cptr->cid1;
384 break;
385 case PPTP_OutCallReply:
386 case PPTP_InCallReply:
387 pcall_id = &cptr->cid2;
388 break;
389 case PPTP_CallDiscNotify:
390 /* Connection closed. */
391 pptp_lnk = FindPptpInByCallId(la, GetDestAddress(lnk),
392 GetAliasAddress(lnk), cptr->cid1);
393 if (pptp_lnk != NULL)
394 SetExpire(pptp_lnk, 0);
395 return;
396 default:
397 return;
398 }
399
400 /* Find PPTP link for address and Call ID found in PPTP Control Msg */
401 pptp_lnk = FindPptpInByPeerCallId(la, GetDestAddress(lnk),
402 GetAliasAddress(lnk), *pcall_id);
403
404 if (pptp_lnk != NULL) {
405 int accumulate = *pcall_id;
406
407 /* De-alias the Peer's Call Id. */
408 *pcall_id = GetOriginalPort(pptp_lnk);
409
410 /* Compute TCP checksum for modified packet */
411 tc = (struct tcphdr *)ip_next(pip);
412 accumulate -= *pcall_id;
413 ADJUST_CHECKSUM(accumulate, tc->th_sum);
414
415 if (ctl_type == PPTP_OutCallReply ||
416 ctl_type == PPTP_InCallReply) {
417 PptpCode codes = (PptpCode)(cptr + 1);
418
419 if (codes->resCode == 1)
420 /* Connection established,
421 * note the Call ID. */
422 SetDestCallId(pptp_lnk, cptr->cid1);
423 else
424 /* Connection refused. */
425 SetExpire(pptp_lnk, 0);
426 }
427 }
428 }
429
430 static PptpCallId
431 AliasVerifyPptp(struct ip *pip, u_int16_t * ptype) /* IP packet to examine/patch */
432 {
433 int hlen, tlen, dlen;
434 PptpMsgHead hptr;
435 struct tcphdr *tc;
436
437 /* Calculate some lengths */
438 tc = (struct tcphdr *)ip_next(pip);
439 hlen = (pip->ip_hl + tc->th_off) << 2;
440 tlen = ntohs(pip->ip_len);
441 dlen = tlen - hlen;
442
443 /* Verify data length */
444 if (dlen < (int)(sizeof(struct pptpMsgHead) + sizeof(struct pptpCallIds)))
445 return (NULL);
446
447 /* Move up to PPTP message header */
448 hptr = (PptpMsgHead)tcp_next(tc);
449
450 /* Return the control message type */
451 *ptype = ntohs(hptr->type);
452
453 /* Verify PPTP Control Message */
454 if ((ntohs(hptr->msgType) != PPTP_CTRL_MSG_TYPE) ||
455 (ntohl(hptr->magic) != PPTP_MAGIC))
456 return (NULL);
457
458 /* Verify data length. */
459 if ((*ptype == PPTP_OutCallReply || *ptype == PPTP_InCallReply) &&
460 (dlen < (int)(sizeof(struct pptpMsgHead) + sizeof(struct pptpCallIds) +
461 sizeof(struct pptpCodes))))
462 return (NULL);
463 else
464 return ((PptpCallId)(hptr + 1));
465 }
466
467 static int
468 AliasHandlePptpGreOut(struct libalias *la, struct ip *pip)
469 {
470 GreHdr *gr;
471 struct alias_link *lnk;
472
473 gr = (GreHdr *)ip_next(pip);
474
475 /* Check GRE header bits. */
476 if ((ntohl(*((u_int32_t *)gr)) & PPTP_INIT_MASK) != PPTP_INIT_VALUE)
477 return (-1);
478
479 lnk = FindPptpOutByPeerCallId(la, pip->ip_src, pip->ip_dst, gr->gh_call_id);
480 if (lnk != NULL) {
481 struct in_addr alias_addr = GetAliasAddress(lnk);
482
483 /* Change source IP address. */
484 DifferentialChecksum(&pip->ip_sum,
485 &alias_addr, &pip->ip_src, 2);
486 pip->ip_src = alias_addr;
487 }
488 return (0);
489 }
490
491 static int
492 AliasHandlePptpGreIn(struct libalias *la, struct ip *pip)
493 {
494 GreHdr *gr;
495 struct alias_link *lnk;
496
497 gr = (GreHdr *)ip_next(pip);
498
499 /* Check GRE header bits. */
500 if ((ntohl(*((u_int32_t *)gr)) & PPTP_INIT_MASK) != PPTP_INIT_VALUE)
501 return (-1);
502
503 lnk = FindPptpInByPeerCallId(la, pip->ip_src, pip->ip_dst, gr->gh_call_id);
504 if (lnk != NULL) {
505 struct in_addr src_addr = GetOriginalAddress(lnk);
506
507 /* De-alias the Peer's Call Id. */
508 gr->gh_call_id = GetOriginalPort(lnk);
509
510 /* Restore original IP address. */
511 DifferentialChecksum(&pip->ip_sum,
512 &src_addr, &pip->ip_dst, 2);
513 pip->ip_dst = src_addr;
514 }
515 return (0);
516 }
Cache object: cb37a52cad7f5f48fbd135fb3cf58505
|