source: rtems-libbsd/freebsd/sys/netinet/libalias/alias_pptp.c @ 0a57e1d

4.1155-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since 0a57e1d was 0a57e1d, checked in by Sebastian Huber <sebastian.huber@…>, on 11/06/13 at 08:35:05

Reduce divergence from FreeBSD sources

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