]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netinet/libalias/alias_pptp.c
net: clean up empty lines in .c and .h files
[FreeBSD/FreeBSD.git] / sys / netinet / libalias / alias_pptp.c
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
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
93 static int
94 fingerprintgre(struct libalias *la, struct alias_data *ah)
95 {
96
97         return (0);
98 }
99
100 static int
101 protohandlerin(struct libalias *la, struct ip *pip, struct alias_data *ah)
102 {
103
104         AliasHandlePptpIn(la, pip, ah->lnk);
105         return (0);
106 }
107
108 static int
109 protohandlerout(struct libalias *la, struct ip *pip, struct alias_data *ah)
110 {
111
112         AliasHandlePptpOut(la, pip, ah->lnk);
113         return (0);
114 }
115
116 static int
117 protohandlergrein(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
126 static int
127 protohandlergreout(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. */
136 struct proto_handler handlers[] = {
137         {
138           .pri = 200,
139           .dir = IN,
140           .proto = TCP,
141           .fingerprint = &fingerprint,
142           .protohandler = &protohandlerin
143         },
144         {
145           .pri = 210,
146           .dir = OUT,
147           .proto = TCP,
148           .fingerprint = &fingerprint,
149           .protohandler = &protohandlerout
150         },
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  */
156         {
157           .pri = INT_MAX,
158           .dir = IN,
159           .proto = IP,
160           .fingerprint = &fingerprintgre,
161           .protohandler = &protohandlergrein
162         },
163         {
164           .pri = INT_MAX,
165           .dir = OUT,
166           .proto = IP,
167           .fingerprint = &fingerprintgre,
168           .protohandler = &protohandlergreout
169         },
170         { EOH }
171 };
172 static int
173 mod_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
193 static
194 #endif
195 moduledata_t alias_mod = {
196        "alias_pptp", mod_handler, NULL
197 };
198
199 #ifdef  _KERNEL
200 DECLARE_MODULE(alias_pptp, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
201 MODULE_VERSION(alias_pptp, 1);
202 MODULE_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
235 struct 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 };
244 typedef 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
256 enum {
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 */
275 struct 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 };
282 typedef struct pptpMsgHead *PptpMsgHead;
283
284 struct pptpCodes {
285         u_int8_t        resCode;/* Result Code */
286         u_int8_t        errCode;/* Error Code */
287 };
288 typedef struct pptpCodes *PptpCode;
289
290 struct pptpCallIds {
291         u_int16_t       cid1;   /* Call ID field #1 */
292         u_int16_t       cid2;   /* Call ID field #2 */
293 };
294 typedef struct pptpCallIds *PptpCallId;
295
296 static PptpCallId AliasVerifyPptp(struct ip *, u_int16_t *);
297
298 static void
299 AliasHandlePptpOut(struct libalias *la,
300     struct ip *pip,             /* IP packet to examine/patch */
301     struct alias_link *lnk)
302 {                               /* The PPTP control link */
303         struct alias_link *pptp_lnk;
304         PptpCallId cptr;
305         PptpCode codes;
306         u_int16_t ctl_type;     /* control message type */
307         struct tcphdr *tc;
308
309         /* Verify valid PPTP control message */
310         if ((cptr = AliasVerifyPptp(pip, &ctl_type)) == NULL)
311                 return;
312
313         /* Modify certain PPTP messages */
314         switch (ctl_type) {
315         case PPTP_OutCallRequest:
316         case PPTP_OutCallReply:
317         case PPTP_InCallRequest:
318         case PPTP_InCallReply:
319                 /*
320                  * Establish PPTP link for address and Call ID found in
321                  * control message.
322                  */
323                 pptp_lnk = AddPptp(la, GetOriginalAddress(lnk), GetDestAddress(lnk),
324                     GetAliasAddress(lnk), cptr->cid1);
325                 break;
326         case PPTP_CallClearRequest:
327         case PPTP_CallDiscNotify:
328                 /*
329                  * Find PPTP link for address and Call ID found in control
330                  * message.
331                  */
332                 pptp_lnk = FindPptpOutByCallId(la, GetOriginalAddress(lnk),
333                     GetDestAddress(lnk),
334                     cptr->cid1);
335                 break;
336         default:
337                 return;
338         }
339
340         if (pptp_lnk != NULL) {
341                 int accumulate = cptr->cid1;
342
343                 /* alias the Call Id */
344                 cptr->cid1 = GetAliasPort(pptp_lnk);
345
346                 /* Compute TCP checksum for revised packet */
347                 tc = (struct tcphdr *)ip_next(pip);
348                 accumulate -= cptr->cid1;
349                 ADJUST_CHECKSUM(accumulate, tc->th_sum);
350
351                 switch (ctl_type) {
352                 case PPTP_OutCallReply:
353                 case PPTP_InCallReply:
354                         codes = (PptpCode) (cptr + 1);
355                         if (codes->resCode == 1)        /* Connection
356                                                          * established, */
357                                 SetDestCallId(pptp_lnk, /* note the Peer's Call
358                                                                  * ID. */
359                                     cptr->cid2);
360                         else
361                                 SetExpire(pptp_lnk, 0); /* Connection refused. */
362                         break;
363                 case PPTP_CallDiscNotify:       /* Connection closed. */
364                         SetExpire(pptp_lnk, 0);
365                         break;
366                 }
367         }
368 }
369
370 static void
371 AliasHandlePptpIn(struct libalias *la,
372     struct ip *pip,             /* IP packet to examine/patch */
373     struct alias_link *lnk)
374 {                               /* The PPTP control link */
375         struct alias_link *pptp_lnk;
376         PptpCallId cptr;
377         u_int16_t *pcall_id;
378         u_int16_t ctl_type;     /* control message type */
379         struct tcphdr *tc;
380
381         /* Verify valid PPTP control message */
382         if ((cptr = AliasVerifyPptp(pip, &ctl_type)) == NULL)
383                 return;
384
385         /* Modify certain PPTP messages */
386         switch (ctl_type) {
387         case PPTP_InCallConn:
388         case PPTP_WanErrorNotify:
389         case PPTP_SetLinkInfo:
390                 pcall_id = &cptr->cid1;
391                 break;
392         case PPTP_OutCallReply:
393         case PPTP_InCallReply:
394                 pcall_id = &cptr->cid2;
395                 break;
396         case PPTP_CallDiscNotify:       /* Connection closed. */
397                 pptp_lnk = FindPptpInByCallId(la, GetDestAddress(lnk),
398                     GetAliasAddress(lnk),
399                     cptr->cid1);
400                 if (pptp_lnk != NULL)
401                         SetExpire(pptp_lnk, 0);
402                 return;
403         default:
404                 return;
405         }
406
407         /* Find PPTP link for address and Call ID found in PPTP Control Msg */
408         pptp_lnk = FindPptpInByPeerCallId(la, GetDestAddress(lnk),
409             GetAliasAddress(lnk),
410             *pcall_id);
411
412         if (pptp_lnk != NULL) {
413                 int accumulate = *pcall_id;
414
415                 /* De-alias the Peer's Call Id. */
416                 *pcall_id = GetOriginalPort(pptp_lnk);
417
418                 /* Compute TCP checksum for modified packet */
419                 tc = (struct tcphdr *)ip_next(pip);
420                 accumulate -= *pcall_id;
421                 ADJUST_CHECKSUM(accumulate, tc->th_sum);
422
423                 if (ctl_type == PPTP_OutCallReply || ctl_type == PPTP_InCallReply) {
424                         PptpCode codes = (PptpCode) (cptr + 1);
425
426                         if (codes->resCode == 1)        /* Connection
427                                                          * established, */
428                                 SetDestCallId(pptp_lnk, /* note the Call ID. */
429                                     cptr->cid1);
430                         else
431                                 SetExpire(pptp_lnk, 0); /* Connection refused. */
432                 }
433         }
434 }
435
436 static          PptpCallId
437 AliasVerifyPptp(struct ip *pip, u_int16_t * ptype)
438 {                               /* IP packet to examine/patch */
439         int hlen, tlen, dlen;
440         PptpMsgHead hptr;
441         struct tcphdr *tc;
442
443         /* Calculate some lengths */
444         tc = (struct tcphdr *)ip_next(pip);
445         hlen = (pip->ip_hl + tc->th_off) << 2;
446         tlen = ntohs(pip->ip_len);
447         dlen = tlen - hlen;
448
449         /* Verify data length */
450         if (dlen < (int)(sizeof(struct pptpMsgHead) + sizeof(struct pptpCallIds)))
451                 return (NULL);
452
453         /* Move up to PPTP message header */
454         hptr = (PptpMsgHead) tcp_next(tc);
455
456         /* Return the control message type */
457         *ptype = ntohs(hptr->type);
458
459         /* Verify PPTP Control Message */
460         if ((ntohs(hptr->msgType) != PPTP_CTRL_MSG_TYPE) ||
461             (ntohl(hptr->magic) != PPTP_MAGIC))
462                 return (NULL);
463
464         /* Verify data length. */
465         if ((*ptype == PPTP_OutCallReply || *ptype == PPTP_InCallReply) &&
466             (dlen < (int)(sizeof(struct pptpMsgHead) + sizeof(struct pptpCallIds) +
467                 sizeof(struct pptpCodes))))
468                 return (NULL);
469         else
470                 return (PptpCallId) (hptr + 1);
471 }
472
473 static int
474 AliasHandlePptpGreOut(struct libalias *la, struct ip *pip)
475 {
476         GreHdr *gr;
477         struct alias_link *lnk;
478
479         gr = (GreHdr *) ip_next(pip);
480
481         /* Check GRE header bits. */
482         if ((ntohl(*((u_int32_t *) gr)) & PPTP_INIT_MASK) != PPTP_INIT_VALUE)
483                 return (-1);
484
485         lnk = FindPptpOutByPeerCallId(la, pip->ip_src, pip->ip_dst, gr->gh_call_id);
486         if (lnk != NULL) {
487                 struct in_addr alias_addr = GetAliasAddress(lnk);
488
489                 /* Change source IP address. */
490                 DifferentialChecksum(&pip->ip_sum,
491                     &alias_addr, &pip->ip_src, 2);
492                 pip->ip_src = alias_addr;
493         }
494         return (0);
495 }
496
497 static int
498 AliasHandlePptpGreIn(struct libalias *la, struct ip *pip)
499 {
500         GreHdr *gr;
501         struct alias_link *lnk;
502
503         gr = (GreHdr *) ip_next(pip);
504
505         /* Check GRE header bits. */
506         if ((ntohl(*((u_int32_t *) gr)) & PPTP_INIT_MASK) != PPTP_INIT_VALUE)
507                 return (-1);
508
509         lnk = FindPptpInByPeerCallId(la, pip->ip_src, pip->ip_dst, gr->gh_call_id);
510         if (lnk != NULL) {
511                 struct in_addr src_addr = GetOriginalAddress(lnk);
512
513                 /* De-alias the Peer's Call Id. */
514                 gr->gh_call_id = GetOriginalPort(lnk);
515
516                 /* Restore original IP address. */
517                 DifferentialChecksum(&pip->ip_sum,
518                     &src_addr, &pip->ip_dst, 2);
519                 pip->ip_dst = src_addr;
520         }
521         return (0);
522 }