The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netinet/libalias/alias_pptp.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.