FreeBSD kernel IPv4 code
alias_pptp.c
Go to the documentation of this file.
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
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
82fingerprint(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
92static int
93fingerprintgre(struct libalias *la, struct alias_data *ah)
94{
95 return (0);
96}
97
98static int
99protohandlerin(struct libalias *la, struct ip *pip, struct alias_data *ah)
100{
101 AliasHandlePptpIn(la, pip, ah->lnk);
102 return (0);
103}
104
105static int
106protohandlerout(struct libalias *la, struct ip *pip, struct alias_data *ah)
107{
108 AliasHandlePptpOut(la, pip, ah->lnk);
109 return (0);
110}
111
112static int
113protohandlergrein(struct libalias *la, struct ip *pip, struct alias_data *ah)
114{
116 AliasHandlePptpGreIn(la, pip) == 0)
117 return (0);
118 return (-1);
119}
120
121static int
122protohandlergreout(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. */
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};
166static int
167mod_handler(module_t mod, int type, void *data)
168{
169 int error;
170
171 switch (type) {
172 case MOD_LOAD:
173 error = 0;
175 break;
176 case MOD_UNLOAD:
177 error = 0;
179 break;
180 default:
181 error = EINVAL;
182 }
183 return (error);
184}
185
186#ifdef _KERNEL
187static
188#endif
189moduledata_t alias_mod = {
190 "alias_pptp", mod_handler, NULL
191};
192
193#ifdef _KERNEL
194DECLARE_MODULE(alias_pptp, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
195MODULE_VERSION(alias_pptp, 1);
196MODULE_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
228struct 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};
237typedef 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
249enum {
266
267/* Message structures */
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};
275typedef struct pptpMsgHead *PptpMsgHead;
276
277struct pptpCodes {
278 u_int8_t resCode;/* Result Code */
279 u_int8_t errCode;/* Error Code */
280};
281typedef struct pptpCodes *PptpCode;
282
284 u_int16_t cid1; /* Call ID field #1 */
285 u_int16_t cid2; /* Call ID field #2 */
286};
287typedef struct pptpCallIds *PptpCallId;
288
289static PptpCallId AliasVerifyPptp(struct ip *, u_int16_t *);
290
291static void
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) {
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;
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) {
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;
356 /* Connection closed. */
357 SetExpire(pptp_lnk, 0);
358 break;
359 }
360 }
361}
362
363static void
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:
382 case PPTP_SetLinkInfo:
383 pcall_id = &cptr->cid1;
384 break;
386 case PPTP_InCallReply:
387 pcall_id = &cptr->cid2;
388 break;
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
430static PptpCallId
431AliasVerifyPptp(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
467static int
468AliasHandlePptpGreOut(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. */
485 &alias_addr, &pip->ip_src, 2);
486 pip->ip_src = alias_addr;
487 }
488 return (0);
489}
490
491static int
492AliasHandlePptpGreIn(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. */
512 &src_addr, &pip->ip_dst, 2);
513 pip->ip_dst = src_addr;
514 }
515 return (0);
516}
#define PKT_ALIAS_PROXY_ONLY
Definition: alias.h:199
u_short GetAliasPort(struct alias_link *lnk)
Definition: alias_db.c:1529
struct in_addr GetAliasAddress(struct alias_link *lnk)
Definition: alias_db.c:1500
struct alias_link * FindPptpOutByPeerCallId(struct libalias *la, struct in_addr src_addr, struct in_addr dst_addr, u_int16_t dst_call_id)
Definition: alias_db.c:1244
struct in_addr GetDestAddress(struct alias_link *lnk)
Definition: alias_db.c:1494
void SetExpire(struct alias_link *lnk, int expire)
Definition: alias_db.c:1699
struct alias_link * FindPptpInByPeerCallId(struct libalias *la, struct in_addr dst_addr, struct in_addr alias_addr, u_int16_t alias_call_id)
Definition: alias_db.c:1279
struct alias_link * FindPptpOutByCallId(struct libalias *la, struct in_addr src_addr, struct in_addr dst_addr, u_int16_t src_call_id)
Definition: alias_db.c:1227
struct alias_link * AddPptp(struct libalias *la, struct in_addr src_addr, struct in_addr dst_addr, struct in_addr alias_addr, u_int16_t src_call_id)
Definition: alias_db.c:1211
struct alias_link * FindPptpInByCallId(struct libalias *la, struct in_addr dst_addr, struct in_addr alias_addr, u_int16_t dst_call_id)
Definition: alias_db.c:1261
struct in_addr GetOriginalAddress(struct alias_link *lnk)
Definition: alias_db.c:1485
void SetDestCallId(struct alias_link *lnk, u_int16_t cid)
Definition: alias_db.c:1729
u_short GetOriginalPort(struct alias_link *lnk)
Definition: alias_db.c:1523
#define ADJUST_CHECKSUM(acc, cksum)
Definition: alias_local.h:194
void DifferentialChecksum(u_short *_cksum, void *_new, void *_old, int _n)
Definition: alias_util.c:154
int LibAliasAttachHandlers(struct proto_handler *p)
Definition: alias_mod.c:82
int LibAliasDetachHandlers(struct proto_handler *p)
Definition: alias_mod.c:98
#define TCP
Definition: alias_mod.h:58
#define EOH
Definition: alias_mod.h:92
#define IN
Definition: alias_mod.h:52
#define OUT
Definition: alias_mod.h:53
#define IP
Definition: alias_mod.h:57
static int mod_handler(module_t mod, int type, void *data)
Definition: alias_pptp.c:167
@ PPTP_EchoReply
Definition: alias_pptp.c:255
@ PPTP_OutCallRequest
Definition: alias_pptp.c:256
@ PPTP_InCallRequest
Definition: alias_pptp.c:258
@ PPTP_StartCtrlConnReply
Definition: alias_pptp.c:251
@ PPTP_StopCtrlConnReply
Definition: alias_pptp.c:253
@ PPTP_StopCtrlConnRequest
Definition: alias_pptp.c:252
@ PPTP_InCallConn
Definition: alias_pptp.c:260
@ PPTP_OutCallReply
Definition: alias_pptp.c:257
@ PPTP_SetLinkInfo
Definition: alias_pptp.c:264
@ PPTP_CallClearRequest
Definition: alias_pptp.c:261
@ PPTP_CallDiscNotify
Definition: alias_pptp.c:262
@ PPTP_StartCtrlConnRequest
Definition: alias_pptp.c:250
@ PPTP_InCallReply
Definition: alias_pptp.c:259
@ PPTP_EchoRequest
Definition: alias_pptp.c:254
@ PPTP_WanErrorNotify
Definition: alias_pptp.c:263
static int protohandlergreout(struct libalias *la, struct ip *pip, struct alias_data *ah)
Definition: alias_pptp.c:122
#define PPTP_CONTROL_PORT_NUMBER
Definition: alias_pptp.c:67
DECLARE_MODULE(alias_pptp, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND)
static void AliasHandlePptpOut(struct libalias *, struct ip *, struct alias_link *)
Definition: alias_pptp.c:292
#define PPTP_INIT_MASK
Definition: alias_pptp.c:244
static PptpCallId AliasVerifyPptp(struct ip *, u_int16_t *)
Definition: alias_pptp.c:431
static int AliasHandlePptpGreIn(struct libalias *, struct ip *)
Definition: alias_pptp.c:492
#define PPTP_MAGIC
Definition: alias_pptp.c:246
static int fingerprint(struct libalias *la, struct alias_data *ah)
Definition: alias_pptp.c:82
static moduledata_t alias_mod
Definition: alias_pptp.c:189
static int fingerprintgre(struct libalias *la, struct alias_data *ah)
Definition: alias_pptp.c:93
struct pptpMsgHead * PptpMsgHead
Definition: alias_pptp.c:275
static int AliasHandlePptpGreOut(struct libalias *, struct ip *)
Definition: alias_pptp.c:468
#define PPTP_INIT_VALUE
Definition: alias_pptp.c:243
struct pptpCodes * PptpCode
Definition: alias_pptp.c:281
__FBSDID("$FreeBSD$")
struct pptpCallIds * PptpCallId
Definition: alias_pptp.c:287
static int protohandlerout(struct libalias *la, struct ip *pip, struct alias_data *ah)
Definition: alias_pptp.c:106
static int protohandlerin(struct libalias *la, struct ip *pip, struct alias_data *ah)
Definition: alias_pptp.c:99
struct proto_handler handlers[]
Definition: alias_pptp.c:130
static int protohandlergrein(struct libalias *la, struct ip *pip, struct alias_data *ah)
Definition: alias_pptp.c:113
MODULE_VERSION(alias_pptp, 1)
static void AliasHandlePptpIn(struct libalias *, struct ip *, struct alias_link *)
Definition: alias_pptp.c:364
MODULE_DEPEND(alias_pptp, libalias, 1, 1, 1)
#define PPTP_CTRL_MSG_TYPE
Definition: alias_pptp.c:247
uint16_t * dport
Definition: alias_mod.h:71
uint16_t * sport
Definition: alias_mod.h:71
struct alias_link * lnk
Definition: alias_mod.h:67
u_int16_t gh_call_id
Definition: alias_pptp.c:232
u_int32_t gh_ack_no
Definition: alias_pptp.c:234
u_int16_t gh_length
Definition: alias_pptp.c:231
u_int32_t gh_seq_no
Definition: alias_pptp.c:233
u_int16_t gh_protocol
Definition: alias_pptp.c:230
u_int16_t gh_flags
Definition: alias_pptp.c:229
Definition: in.h:83
Definition: ip.h:51
struct in_addr ip_src ip_dst
Definition: ip.h:71
u_char ip_hl
Definition: ip.h:53
u_short ip_sum
Definition: ip.h:70
u_short ip_len
Definition: ip.h:61
int packetAliasMode
Definition: alias_local.h:92
u_int16_t cid2
Definition: alias_pptp.c:285
u_int16_t cid1
Definition: alias_pptp.c:284
u_int8_t errCode
Definition: alias_pptp.c:279
u_int8_t resCode
Definition: alias_pptp.c:278
u_int16_t msgType
Definition: alias_pptp.c:270
u_int16_t resv0
Definition: alias_pptp.c:273
u_int16_t type
Definition: alias_pptp.c:272
u_int16_t length
Definition: alias_pptp.c:269
u_int32_t magic
Definition: alias_pptp.c:271