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/netgraph/ng_mppc.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  * ng_mppc.c
    3  */
    4 
    5 /*-
    6  * Copyright (c) 1996-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: Archie Cobbs <archie@freebsd.org>
   39  *
   40  * $Whistle: ng_mppc.c,v 1.4 1999/11/25 00:10:12 archie Exp $
   41  * $FreeBSD$
   42  */
   43 
   44 /*
   45  * Microsoft PPP compression (MPPC) and encryption (MPPE) netgraph node type.
   46  *
   47  * You must define one or both of the NETGRAPH_MPPC_COMPRESSION and/or
   48  * NETGRAPH_MPPC_ENCRYPTION options for this node type to be useful.
   49  */
   50 
   51 #include <sys/param.h>
   52 #include <sys/systm.h>
   53 #include <sys/kernel.h>
   54 #include <sys/mbuf.h>
   55 #include <sys/malloc.h>
   56 #include <sys/endian.h>
   57 #include <sys/errno.h>
   58 #include <sys/sysctl.h>
   59 #include <sys/syslog.h>
   60 
   61 #include <netgraph/ng_message.h>
   62 #include <netgraph/netgraph.h>
   63 #include <netgraph/ng_mppc.h>
   64 
   65 #include "opt_netgraph.h"
   66 
   67 #if !defined(NETGRAPH_MPPC_COMPRESSION) && !defined(NETGRAPH_MPPC_ENCRYPTION)
   68 #ifdef KLD_MODULE
   69 #define NETGRAPH_MPPC_COMPRESSION
   70 #define NETGRAPH_MPPC_ENCRYPTION
   71 #else
   72 /* This case is indicative of an error in sys/conf files */
   73 #error Need either NETGRAPH_MPPC_COMPRESSION or NETGRAPH_MPPC_ENCRYPTION
   74 #endif
   75 #endif
   76 
   77 #ifdef NG_SEPARATE_MALLOC
   78 static MALLOC_DEFINE(M_NETGRAPH_MPPC, "netgraph_mppc", "netgraph mppc node");
   79 #else
   80 #define M_NETGRAPH_MPPC M_NETGRAPH
   81 #endif
   82 
   83 #ifdef NETGRAPH_MPPC_COMPRESSION
   84 #include <net/mppc.h>
   85 #endif
   86 #ifdef NETGRAPH_MPPC_ENCRYPTION
   87 #include <crypto/rc4/rc4.h>
   88 #endif
   89 #include <crypto/sha1.h>
   90 
   91 /* Decompression blowup */
   92 #define MPPC_DECOMP_BUFSIZE     8092            /* allocate buffer this big */
   93 #define MPPC_DECOMP_SAFETY      100             /*   plus this much margin */
   94 
   95 /* MPPC/MPPE header length */
   96 #define MPPC_HDRLEN             2
   97 
   98 /* Key length */
   99 #define KEYLEN(b)               (((b) & MPPE_128) ? 16 : 8)
  100 
  101 /*
  102  * When packets are lost with MPPE, we may have to re-key arbitrarily
  103  * many times to 'catch up' to the new jumped-ahead sequence number.
  104  * Since this can be expensive, we pose a limit on how many re-keyings
  105  * we will do at one time to avoid a possible D.O.S. vulnerability.
  106  * This should instead be a configurable parameter.
  107  */
  108 #define MPPE_MAX_REKEY          1000
  109 
  110 SYSCTL_NODE(_net_graph, OID_AUTO, mppe, CTLFLAG_RW, 0, "MPPE");
  111 
  112 static int mppe_block_on_max_rekey = 0;
  113 SYSCTL_INT(_net_graph_mppe, OID_AUTO, block_on_max_rekey, CTLFLAG_RWTUN,
  114     &mppe_block_on_max_rekey, 0, "Block node on max MPPE key re-calculations");
  115 
  116 static int mppe_log_max_rekey = 1;
  117 SYSCTL_INT(_net_graph_mppe, OID_AUTO, log_max_rekey, CTLFLAG_RWTUN,
  118     &mppe_log_max_rekey, 0, "Log max MPPE key re-calculations event");
  119 
  120 static int mppe_max_rekey = MPPE_MAX_REKEY;
  121 SYSCTL_INT(_net_graph_mppe, OID_AUTO, max_rekey, CTLFLAG_RWTUN,
  122     &mppe_max_rekey, 0, "Maximum number of MPPE key re-calculations");
  123 
  124 /* MPPC packet header bits */
  125 #define MPPC_FLAG_FLUSHED       0x8000          /* xmitter reset state */
  126 #define MPPC_FLAG_RESTART       0x4000          /* compress history restart */
  127 #define MPPC_FLAG_COMPRESSED    0x2000          /* packet is compresed */
  128 #define MPPC_FLAG_ENCRYPTED     0x1000          /* packet is encrypted */
  129 #define MPPC_CCOUNT_MASK        0x0fff          /* sequence number mask */
  130 
  131 #define MPPC_CCOUNT_INC(d)      ((d) = (((d) + 1) & MPPC_CCOUNT_MASK))
  132 
  133 #define MPPE_UPDATE_MASK        0xff            /* coherency count when we're */
  134 #define MPPE_UPDATE_FLAG        0xff            /*   supposed to update key */
  135 
  136 #define MPPC_COMP_OK            0x05
  137 #define MPPC_DECOMP_OK          0x05
  138 
  139 /* Per direction info */
  140 struct ng_mppc_dir {
  141         struct ng_mppc_config   cfg;            /* configuration */
  142         hook_p                  hook;           /* netgraph hook */
  143         u_int16_t               cc:12;          /* coherency count */
  144         u_char                  flushed;        /* clean history (xmit only) */
  145 #ifdef NETGRAPH_MPPC_COMPRESSION
  146         u_char                  *history;       /* compression history */
  147 #endif
  148 #ifdef NETGRAPH_MPPC_ENCRYPTION
  149         u_char                  key[MPPE_KEY_LEN];      /* session key */
  150         struct rc4_state        rc4;                    /* rc4 state */
  151 #endif
  152 };
  153 
  154 /* Node private data */
  155 struct ng_mppc_private {
  156         struct ng_mppc_dir      xmit;           /* compress/encrypt config */
  157         struct ng_mppc_dir      recv;           /* decompress/decrypt config */
  158         ng_ID_t                 ctrlnode;       /* path to controlling node */
  159 };
  160 typedef struct ng_mppc_private *priv_p;
  161 
  162 /* Netgraph node methods */
  163 static ng_constructor_t ng_mppc_constructor;
  164 static ng_rcvmsg_t      ng_mppc_rcvmsg;
  165 static ng_shutdown_t    ng_mppc_shutdown;
  166 static ng_newhook_t     ng_mppc_newhook;
  167 static ng_rcvdata_t     ng_mppc_rcvdata;
  168 static ng_disconnect_t  ng_mppc_disconnect;
  169 
  170 /* Helper functions */
  171 static int      ng_mppc_compress(node_p node,
  172                         struct mbuf **datap);
  173 static int      ng_mppc_decompress(node_p node,
  174                         struct mbuf **datap);
  175 #ifdef NETGRAPH_MPPC_ENCRYPTION
  176 static void     ng_mppc_getkey(const u_char *h, u_char *h2, int len);
  177 static void     ng_mppc_updatekey(u_int32_t bits,
  178                         u_char *key0, u_char *key, struct rc4_state *rc4);
  179 #endif
  180 static void     ng_mppc_reset_req(node_p node);
  181 
  182 /* Node type descriptor */
  183 static struct ng_type ng_mppc_typestruct = {
  184         .version =      NG_ABI_VERSION,
  185         .name =         NG_MPPC_NODE_TYPE,
  186         .constructor =  ng_mppc_constructor,
  187         .rcvmsg =       ng_mppc_rcvmsg,
  188         .shutdown =     ng_mppc_shutdown,
  189         .newhook =      ng_mppc_newhook,
  190         .rcvdata =      ng_mppc_rcvdata,
  191         .disconnect =   ng_mppc_disconnect,
  192 };
  193 NETGRAPH_INIT(mppc, &ng_mppc_typestruct);
  194 
  195 #ifdef NETGRAPH_MPPC_ENCRYPTION
  196 /* Depend on separate rc4 module */
  197 MODULE_DEPEND(ng_mppc, rc4, 1, 1, 1);
  198 #endif
  199 
  200 /* Fixed bit pattern to weaken keysize down to 40 or 56 bits */
  201 static const u_char ng_mppe_weakenkey[3] = { 0xd1, 0x26, 0x9e };
  202 
  203 #define ERROUT(x)       do { error = (x); goto done; } while (0)
  204 
  205 /************************************************************************
  206                         NETGRAPH NODE STUFF
  207  ************************************************************************/
  208 
  209 /*
  210  * Node type constructor
  211  */
  212 static int
  213 ng_mppc_constructor(node_p node)
  214 {
  215         priv_p priv;
  216 
  217         /* Allocate private structure */
  218         priv = malloc(sizeof(*priv), M_NETGRAPH_MPPC, M_WAITOK | M_ZERO);
  219 
  220         NG_NODE_SET_PRIVATE(node, priv);
  221 
  222         /* This node is not thread safe. */
  223         NG_NODE_FORCE_WRITER(node);
  224 
  225         /* Done */
  226         return (0);
  227 }
  228 
  229 /*
  230  * Give our OK for a hook to be added
  231  */
  232 static int
  233 ng_mppc_newhook(node_p node, hook_p hook, const char *name)
  234 {
  235         const priv_p priv = NG_NODE_PRIVATE(node);
  236         hook_p *hookPtr;
  237 
  238         /* Check hook name */
  239         if (strcmp(name, NG_MPPC_HOOK_COMP) == 0)
  240                 hookPtr = &priv->xmit.hook;
  241         else if (strcmp(name, NG_MPPC_HOOK_DECOMP) == 0)
  242                 hookPtr = &priv->recv.hook;
  243         else
  244                 return (EINVAL);
  245 
  246         /* See if already connected */
  247         if (*hookPtr != NULL)
  248                 return (EISCONN);
  249 
  250         /* OK */
  251         *hookPtr = hook;
  252         return (0);
  253 }
  254 
  255 /*
  256  * Receive a control message
  257  */
  258 static int
  259 ng_mppc_rcvmsg(node_p node, item_p item, hook_p lasthook)
  260 {
  261         const priv_p priv = NG_NODE_PRIVATE(node);
  262         struct ng_mesg *resp = NULL;
  263         int error = 0;
  264         struct ng_mesg *msg;
  265 
  266         NGI_GET_MSG(item, msg);
  267         switch (msg->header.typecookie) {
  268         case NGM_MPPC_COOKIE:
  269                 switch (msg->header.cmd) {
  270                 case NGM_MPPC_CONFIG_COMP:
  271                 case NGM_MPPC_CONFIG_DECOMP:
  272                     {
  273                         struct ng_mppc_config *const cfg
  274                             = (struct ng_mppc_config *)msg->data;
  275                         const int isComp =
  276                             msg->header.cmd == NGM_MPPC_CONFIG_COMP;
  277                         struct ng_mppc_dir *const d = isComp ?
  278                             &priv->xmit : &priv->recv;
  279 
  280                         /* Check configuration */
  281                         if (msg->header.arglen != sizeof(*cfg))
  282                                 ERROUT(EINVAL);
  283                         if (cfg->enable) {
  284                                 if ((cfg->bits & ~MPPC_VALID_BITS) != 0)
  285                                         ERROUT(EINVAL);
  286 #ifndef NETGRAPH_MPPC_COMPRESSION
  287                                 if ((cfg->bits & MPPC_BIT) != 0)
  288                                         ERROUT(EPROTONOSUPPORT);
  289 #endif
  290 #ifndef NETGRAPH_MPPC_ENCRYPTION
  291                                 if ((cfg->bits & MPPE_BITS) != 0)
  292                                         ERROUT(EPROTONOSUPPORT);
  293 #endif
  294                         } else
  295                                 cfg->bits = 0;
  296 
  297                         /* Save return address so we can send reset-req's */
  298                         if (!isComp)
  299                                 priv->ctrlnode = NGI_RETADDR(item);
  300 
  301                         /* Configuration is OK, reset to it */
  302                         d->cfg = *cfg;
  303 
  304 #ifdef NETGRAPH_MPPC_COMPRESSION
  305                         /* Initialize state buffers for compression */
  306                         if (d->history != NULL) {
  307                                 free(d->history, M_NETGRAPH_MPPC);
  308                                 d->history = NULL;
  309                         }
  310                         if ((cfg->bits & MPPC_BIT) != 0) {
  311                                 d->history = malloc(isComp ?
  312                                     MPPC_SizeOfCompressionHistory() :
  313                                     MPPC_SizeOfDecompressionHistory(),
  314                                     M_NETGRAPH_MPPC, M_NOWAIT);
  315                                 if (d->history == NULL)
  316                                         ERROUT(ENOMEM);
  317                                 if (isComp)
  318                                         MPPC_InitCompressionHistory(d->history);
  319                                 else {
  320                                         MPPC_InitDecompressionHistory(
  321                                             d->history);
  322                                 }
  323                         }
  324 #endif
  325 
  326 #ifdef NETGRAPH_MPPC_ENCRYPTION
  327                         /* Generate initial session keys for encryption */
  328                         if ((cfg->bits & MPPE_BITS) != 0) {
  329                                 const int keylen = KEYLEN(cfg->bits);
  330 
  331                                 bcopy(cfg->startkey, d->key, keylen);
  332                                 ng_mppc_getkey(cfg->startkey, d->key, keylen);
  333                                 if ((cfg->bits & MPPE_40) != 0)
  334                                         bcopy(&ng_mppe_weakenkey, d->key, 3);
  335                                 else if ((cfg->bits & MPPE_56) != 0)
  336                                         bcopy(&ng_mppe_weakenkey, d->key, 1);
  337                                 rc4_init(&d->rc4, d->key, keylen);
  338                         }
  339 #endif
  340 
  341                         /* Initialize other state */
  342                         d->cc = 0;
  343                         d->flushed = 0;
  344                         break;
  345                     }
  346 
  347                 case NGM_MPPC_RESETREQ:
  348                         ng_mppc_reset_req(node);
  349                         break;
  350 
  351                 default:
  352                         error = EINVAL;
  353                         break;
  354                 }
  355                 break;
  356         default:
  357                 error = EINVAL;
  358                 break;
  359         }
  360 done:
  361         NG_RESPOND_MSG(error, node, item, resp);
  362         NG_FREE_MSG(msg);
  363         return (error);
  364 }
  365 
  366 /*
  367  * Receive incoming data on our hook.
  368  */
  369 static int
  370 ng_mppc_rcvdata(hook_p hook, item_p item)
  371 {
  372         const node_p node = NG_HOOK_NODE(hook);
  373         const priv_p priv = NG_NODE_PRIVATE(node);
  374         int error;
  375         struct mbuf *m;
  376 
  377         NGI_GET_M(item, m);
  378         /* Compress and/or encrypt */
  379         if (hook == priv->xmit.hook) {
  380                 if (!priv->xmit.cfg.enable) {
  381                         NG_FREE_M(m);
  382                         NG_FREE_ITEM(item);
  383                         return (ENXIO);
  384                 }
  385                 if ((error = ng_mppc_compress(node, &m)) != 0) {
  386                         NG_FREE_ITEM(item);
  387                         return(error);
  388                 }
  389                 NG_FWD_NEW_DATA(error, item, priv->xmit.hook, m);
  390                 return (error);
  391         }
  392 
  393         /* Decompress and/or decrypt */
  394         if (hook == priv->recv.hook) {
  395                 if (!priv->recv.cfg.enable) {
  396                         NG_FREE_M(m);
  397                         NG_FREE_ITEM(item);
  398                         return (ENXIO);
  399                 }
  400                 if ((error = ng_mppc_decompress(node, &m)) != 0) {
  401                         NG_FREE_ITEM(item);
  402                         if (error == EINVAL && priv->ctrlnode != 0) {
  403                                 struct ng_mesg *msg;
  404 
  405                                 /* Need to send a reset-request */
  406                                 NG_MKMESSAGE(msg, NGM_MPPC_COOKIE,
  407                                     NGM_MPPC_RESETREQ, 0, M_NOWAIT);
  408                                 if (msg == NULL)
  409                                         return (error);
  410                                 NG_SEND_MSG_ID(error, node, msg,
  411                                         priv->ctrlnode, 0); 
  412                         }
  413                         return (error);
  414                 }
  415                 NG_FWD_NEW_DATA(error, item, priv->recv.hook, m);
  416                 return (error);
  417         }
  418 
  419         /* Oops */
  420         panic("%s: unknown hook", __func__);
  421 }
  422 
  423 /*
  424  * Destroy node
  425  */
  426 static int
  427 ng_mppc_shutdown(node_p node)
  428 {
  429         const priv_p priv = NG_NODE_PRIVATE(node);
  430 
  431         /* Take down netgraph node */
  432 #ifdef NETGRAPH_MPPC_COMPRESSION
  433         if (priv->xmit.history != NULL)
  434                 free(priv->xmit.history, M_NETGRAPH_MPPC);
  435         if (priv->recv.history != NULL)
  436                 free(priv->recv.history, M_NETGRAPH_MPPC);
  437 #endif
  438         bzero(priv, sizeof(*priv));
  439         free(priv, M_NETGRAPH_MPPC);
  440         NG_NODE_SET_PRIVATE(node, NULL);
  441         NG_NODE_UNREF(node);            /* let the node escape */
  442         return (0);
  443 }
  444 
  445 /*
  446  * Hook disconnection
  447  */
  448 static int
  449 ng_mppc_disconnect(hook_p hook)
  450 {
  451         const node_p node = NG_HOOK_NODE(hook);
  452         const priv_p priv = NG_NODE_PRIVATE(node);
  453 
  454         /* Zero out hook pointer */
  455         if (hook == priv->xmit.hook)
  456                 priv->xmit.hook = NULL;
  457         if (hook == priv->recv.hook)
  458                 priv->recv.hook = NULL;
  459 
  460         /* Go away if no longer connected */
  461         if ((NG_NODE_NUMHOOKS(node) == 0)
  462         && NG_NODE_IS_VALID(node))
  463                 ng_rmnode_self(node);
  464         return (0);
  465 }
  466 
  467 /************************************************************************
  468                         HELPER STUFF
  469  ************************************************************************/
  470 
  471 /*
  472  * Compress/encrypt a packet and put the result in a new mbuf at *resultp.
  473  * The original mbuf is not free'd.
  474  */
  475 static int
  476 ng_mppc_compress(node_p node, struct mbuf **datap)
  477 {
  478         const priv_p priv = NG_NODE_PRIVATE(node);
  479         struct ng_mppc_dir *const d = &priv->xmit;
  480         u_int16_t header;
  481         struct mbuf *m = *datap;
  482 
  483         /* We must own the mbuf chain exclusively to modify it. */
  484         m = m_unshare(m, M_NOWAIT);
  485         if (m == NULL)
  486                 return (ENOMEM);
  487 
  488         /* Initialize */
  489         header = d->cc;
  490 
  491         /* Always set the flushed bit in stateless mode */
  492         if (d->flushed || ((d->cfg.bits & MPPE_STATELESS) != 0)) {
  493                 header |= MPPC_FLAG_FLUSHED;
  494                 d->flushed = 0;
  495         }
  496 
  497         /* Compress packet (if compression enabled) */
  498 #ifdef NETGRAPH_MPPC_COMPRESSION
  499         if ((d->cfg.bits & MPPC_BIT) != 0) {
  500                 u_short flags = MPPC_MANDATORY_COMPRESS_FLAGS;
  501                 u_char *inbuf, *outbuf;
  502                 int outlen, inlen, ina;
  503                 u_char *source, *dest;
  504                 u_long sourceCnt, destCnt;
  505                 int rtn;
  506 
  507                 /* Work with contiguous regions of memory. */
  508                 inlen = m->m_pkthdr.len;
  509                 if (m->m_next == NULL) {
  510                         inbuf = mtod(m, u_char *);
  511                         ina = 0;
  512                 } else {
  513                         inbuf = malloc(inlen, M_NETGRAPH_MPPC, M_NOWAIT);
  514                         if (inbuf == NULL)
  515                                 goto err1;
  516                         m_copydata(m, 0, inlen, (caddr_t)inbuf);
  517                         ina = 1;
  518                 }
  519 
  520                 outlen = MPPC_MAX_BLOWUP(inlen);
  521                 outbuf = malloc(outlen, M_NETGRAPH_MPPC, M_NOWAIT);
  522                 if (outbuf == NULL) {
  523                         if (ina)
  524                                 free(inbuf, M_NETGRAPH_MPPC);
  525 err1:
  526                         m_freem(m);
  527                         MPPC_InitCompressionHistory(d->history);
  528                         d->flushed = 1;
  529                         return (ENOMEM);
  530                 }
  531 
  532                 /* Prepare to compress */
  533                 source = inbuf;
  534                 sourceCnt = inlen;
  535                 dest = outbuf;
  536                 destCnt = outlen;
  537                 if ((d->cfg.bits & MPPE_STATELESS) == 0)
  538                         flags |= MPPC_SAVE_HISTORY;
  539 
  540                 /* Compress */
  541                 rtn = MPPC_Compress(&source, &dest, &sourceCnt,
  542                         &destCnt, d->history, flags, 0);
  543 
  544                 /* Check return value */
  545                 /* KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__)); */
  546                 if ((rtn & MPPC_EXPANDED) == 0
  547                     && (rtn & MPPC_COMP_OK) == MPPC_COMP_OK) {
  548                         outlen -= destCnt;     
  549                         header |= MPPC_FLAG_COMPRESSED;
  550                         if ((rtn & MPPC_RESTART_HISTORY) != 0)
  551                                 header |= MPPC_FLAG_RESTART;  
  552                                 
  553                         /* Replace m by the compresed one. */
  554                         m_copyback(m, 0, outlen, (caddr_t)outbuf);
  555                         if (m->m_pkthdr.len < outlen) {
  556                                 m_freem(m);
  557                                 m = NULL;
  558                         } else if (outlen < m->m_pkthdr.len)
  559                                 m_adj(m, outlen - m->m_pkthdr.len);
  560                 }
  561                 d->flushed = (rtn & MPPC_EXPANDED) != 0
  562                     || (flags & MPPC_SAVE_HISTORY) == 0;
  563 
  564                 if (ina)
  565                         free(inbuf, M_NETGRAPH_MPPC);
  566                 free(outbuf, M_NETGRAPH_MPPC);
  567 
  568                 /* Check mbuf chain reload result. */
  569                 if (m == NULL) {
  570                         if (!d->flushed) {
  571                                 MPPC_InitCompressionHistory(d->history);
  572                                 d->flushed = 1;
  573                         }
  574                         return (ENOMEM);
  575                 }
  576         }
  577 #endif
  578 
  579         /* Now encrypt packet (if encryption enabled) */
  580 #ifdef NETGRAPH_MPPC_ENCRYPTION
  581         if ((d->cfg.bits & MPPE_BITS) != 0) {
  582                 struct mbuf *m1;
  583 
  584                 /* Set header bits */
  585                 header |= MPPC_FLAG_ENCRYPTED;
  586 
  587                 /* Update key if it's time */
  588                 if ((d->cfg.bits & MPPE_STATELESS) != 0
  589                     || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) {
  590                         ng_mppc_updatekey(d->cfg.bits,
  591                             d->cfg.startkey, d->key, &d->rc4);
  592                 } else if ((header & MPPC_FLAG_FLUSHED) != 0) {
  593                         /* Need to reset key if we say we did 
  594                            and ng_mppc_updatekey wasn't called to do it also. */
  595                         rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
  596                 }
  597 
  598                 /* Encrypt packet */
  599                 m1 = m;
  600                 while (m1) {
  601                         rc4_crypt(&d->rc4, mtod(m1, u_char *),
  602                             mtod(m1, u_char *), m1->m_len);
  603                         m1 = m1->m_next;
  604                 }
  605         }
  606 #endif
  607 
  608         /* Update coherency count for next time (12 bit arithmetic) */
  609         MPPC_CCOUNT_INC(d->cc);
  610 
  611         /* Install header */
  612         M_PREPEND(m, MPPC_HDRLEN, M_NOWAIT);
  613         if (m != NULL)
  614                 be16enc(mtod(m, void *), header);
  615 
  616         *datap = m;
  617         return (*datap == NULL ? ENOBUFS : 0);
  618 }
  619 
  620 /*
  621  * Decompress/decrypt packet and put the result in a new mbuf at *resultp.
  622  * The original mbuf is not free'd.
  623  */
  624 static int
  625 ng_mppc_decompress(node_p node, struct mbuf **datap)
  626 {
  627         const priv_p priv = NG_NODE_PRIVATE(node);
  628         struct ng_mppc_dir *const d = &priv->recv;
  629         u_int16_t header, cc;
  630         u_int numLost;
  631         struct mbuf *m = *datap;
  632 
  633         /* We must own the mbuf chain exclusively to modify it. */
  634         m = m_unshare(m, M_NOWAIT);
  635         if (m == NULL)
  636                 return (ENOMEM);
  637 
  638         /* Pull off header */
  639         if (m->m_pkthdr.len < MPPC_HDRLEN) {
  640                 m_freem(m);
  641                 return (EINVAL);
  642         }
  643         header = be16dec(mtod(m, void *));
  644         cc = (header & MPPC_CCOUNT_MASK);
  645         m_adj(m, MPPC_HDRLEN);
  646 
  647         /* Check for an unexpected jump in the sequence number */
  648         numLost = ((cc - d->cc) & MPPC_CCOUNT_MASK);
  649 
  650         /* If flushed bit set, we can always handle packet */
  651         if ((header & MPPC_FLAG_FLUSHED) != 0) {
  652 #ifdef NETGRAPH_MPPC_COMPRESSION
  653                 if (d->history != NULL)
  654                         MPPC_InitDecompressionHistory(d->history);
  655 #endif
  656 #ifdef NETGRAPH_MPPC_ENCRYPTION
  657                 if ((d->cfg.bits & MPPE_BITS) != 0) {
  658                         u_int rekey;
  659 
  660                         /* How many times are we going to have to re-key? */
  661                         rekey = ((d->cfg.bits & MPPE_STATELESS) != 0) ?
  662                             numLost : (numLost / (MPPE_UPDATE_MASK + 1));
  663                         if (rekey > mppe_max_rekey) {
  664                             if (mppe_block_on_max_rekey) {
  665                                 if (mppe_log_max_rekey) {
  666                                     log(LOG_ERR, "%s: too many (%d) packets"
  667                                         " dropped, disabling node %p!\n",
  668                                         __func__, numLost, node);
  669                                 }
  670                                 priv->recv.cfg.enable = 0;
  671                                 goto failed;
  672                             } else {
  673                                 if (mppe_log_max_rekey) {
  674                                     log(LOG_ERR, "%s: %d packets"
  675                                         " dropped, node %p\n",
  676                                         __func__, numLost, node);
  677                                 }
  678                                 goto failed;
  679                             }
  680                         }
  681 
  682                         /* Re-key as necessary to catch up to peer */
  683                         while (d->cc != cc) {
  684                                 if ((d->cfg.bits & MPPE_STATELESS) != 0
  685                                     || (d->cc & MPPE_UPDATE_MASK)
  686                                       == MPPE_UPDATE_FLAG) {
  687                                         ng_mppc_updatekey(d->cfg.bits,
  688                                             d->cfg.startkey, d->key, &d->rc4);
  689                                 }
  690                                 MPPC_CCOUNT_INC(d->cc);
  691                         }
  692 
  693                         /* Reset key (except in stateless mode, see below) */
  694                         if ((d->cfg.bits & MPPE_STATELESS) == 0)
  695                                 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
  696                 }
  697 #endif
  698                 d->cc = cc;             /* skip over lost seq numbers */
  699                 numLost = 0;            /* act like no packets were lost */
  700         }
  701 
  702         /* Can't decode non-sequential packets without a flushed bit */
  703         if (numLost != 0)
  704                 goto failed;
  705 
  706         /* Decrypt packet */
  707         if ((header & MPPC_FLAG_ENCRYPTED) != 0) {
  708 #ifdef NETGRAPH_MPPC_ENCRYPTION
  709                 struct mbuf *m1;
  710 #endif
  711 
  712                 /* Are we not expecting encryption? */
  713                 if ((d->cfg.bits & MPPE_BITS) == 0) {
  714                         log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
  715                                 __func__, "encrypted");
  716                         goto failed;
  717                 }
  718 
  719 #ifdef NETGRAPH_MPPC_ENCRYPTION
  720                 /* Update key if it's time (always in stateless mode) */
  721                 if ((d->cfg.bits & MPPE_STATELESS) != 0
  722                     || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) {
  723                         ng_mppc_updatekey(d->cfg.bits,
  724                             d->cfg.startkey, d->key, &d->rc4);
  725                 }
  726 
  727                 /* Decrypt packet */
  728                 m1 = m;
  729                 while (m1 != NULL) {
  730                         rc4_crypt(&d->rc4, mtod(m1, u_char *),
  731                             mtod(m1, u_char *), m1->m_len);
  732                         m1 = m1->m_next;
  733                 }
  734 #endif
  735         } else {
  736 
  737                 /* Are we expecting encryption? */
  738                 if ((d->cfg.bits & MPPE_BITS) != 0) {
  739                         log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
  740                                 __func__, "unencrypted");
  741                         goto failed;
  742                 }
  743         }
  744 
  745         /* Update coherency count for next time (12 bit arithmetic) */
  746         MPPC_CCOUNT_INC(d->cc);
  747 
  748         /* Check for unexpected compressed packet */
  749         if ((header & MPPC_FLAG_COMPRESSED) != 0
  750             && (d->cfg.bits & MPPC_BIT) == 0) {
  751                 log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
  752                         __func__, "compressed");
  753 failed:
  754                 m_freem(m);
  755                 return (EINVAL);
  756         }
  757 
  758 #ifdef NETGRAPH_MPPC_COMPRESSION
  759         /* Decompress packet */
  760         if ((header & MPPC_FLAG_COMPRESSED) != 0) {
  761                 int flags = MPPC_MANDATORY_DECOMPRESS_FLAGS;
  762                 u_char *inbuf, *outbuf;
  763                 int inlen, outlen, ina;
  764                 u_char *source, *dest;
  765                 u_long sourceCnt, destCnt;
  766                 int rtn;
  767 
  768                 /* Copy payload into a contiguous region of memory. */
  769                 inlen = m->m_pkthdr.len;
  770                 if (m->m_next == NULL) {
  771                         inbuf = mtod(m, u_char *);
  772                         ina = 0;
  773                 } else {
  774                         inbuf = malloc(inlen, M_NETGRAPH_MPPC, M_NOWAIT);
  775                         if (inbuf == NULL) {
  776                                 m_freem(m);
  777                                 return (ENOMEM);
  778                         }
  779                         m_copydata(m, 0, inlen, (caddr_t)inbuf);
  780                         ina = 1;
  781                 }
  782 
  783                 /* Allocate a buffer for decompressed data */
  784                 outbuf = malloc(MPPC_DECOMP_BUFSIZE + MPPC_DECOMP_SAFETY,
  785                     M_NETGRAPH_MPPC, M_NOWAIT);
  786                 if (outbuf == NULL) {
  787                         m_freem(m);
  788                         if (ina)
  789                                 free(inbuf, M_NETGRAPH_MPPC);
  790                         return (ENOMEM);
  791                 }
  792                 outlen = MPPC_DECOMP_BUFSIZE;
  793 
  794                 /* Prepare to decompress */
  795                 source = inbuf;
  796                 sourceCnt = inlen;
  797                 dest = outbuf;
  798                 destCnt = outlen;
  799                 if ((header & MPPC_FLAG_RESTART) != 0)
  800                         flags |= MPPC_RESTART_HISTORY;
  801 
  802                 /* Decompress */
  803                 rtn = MPPC_Decompress(&source, &dest,
  804                         &sourceCnt, &destCnt, d->history, flags);
  805 
  806                 /* Check return value */
  807                 /* KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__)); */
  808                 if ((rtn & MPPC_DEST_EXHAUSTED) != 0
  809                     || (rtn & MPPC_DECOMP_OK) != MPPC_DECOMP_OK) {
  810                         log(LOG_ERR, "%s: decomp returned 0x%x",
  811                             __func__, rtn);
  812                         if (ina)
  813                                 free(inbuf, M_NETGRAPH_MPPC);
  814                         free(outbuf, M_NETGRAPH_MPPC);
  815                         goto failed;
  816                 }
  817 
  818                 /* Replace compressed data with decompressed data */
  819                 if (ina)
  820                         free(inbuf, M_NETGRAPH_MPPC);
  821                 outlen -= destCnt;
  822         
  823                 m_copyback(m, 0, outlen, (caddr_t)outbuf);
  824                 if (m->m_pkthdr.len < outlen) {
  825                         m_freem(m);
  826                         m = NULL;
  827                 } else if (outlen < m->m_pkthdr.len)
  828                         m_adj(m, outlen - m->m_pkthdr.len);
  829                 free(outbuf, M_NETGRAPH_MPPC);
  830         }
  831 #endif
  832 
  833         /* Return result in an mbuf */
  834         *datap = m;
  835         return (*datap == NULL ? ENOBUFS : 0);
  836 }
  837 
  838 /*
  839  * The peer has sent us a CCP ResetRequest, so reset our transmit state.
  840  */
  841 static void
  842 ng_mppc_reset_req(node_p node)
  843 {   
  844         const priv_p priv = NG_NODE_PRIVATE(node);
  845         struct ng_mppc_dir *const d = &priv->xmit;
  846 
  847 #ifdef NETGRAPH_MPPC_COMPRESSION
  848         if (d->history != NULL)
  849                 MPPC_InitCompressionHistory(d->history);
  850 #endif
  851 #ifdef NETGRAPH_MPPC_ENCRYPTION
  852         if ((d->cfg.bits & MPPE_STATELESS) == 0)
  853                 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
  854 #endif
  855         d->flushed = 1;
  856 }   
  857 
  858 #ifdef NETGRAPH_MPPC_ENCRYPTION
  859 /*
  860  * Generate a new encryption key
  861  */
  862 static void
  863 ng_mppc_getkey(const u_char *h, u_char *h2, int len)
  864 {
  865         static const u_char pad1[40] =
  866             { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  867               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  868               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  869               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
  870         static const u_char pad2[40] =
  871             { 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
  872               0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
  873               0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
  874               0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2 };
  875         u_char hash[20];
  876         SHA1_CTX c;
  877 
  878         SHA1Init(&c);
  879         SHA1Update(&c, h, len);
  880         SHA1Update(&c, pad1, sizeof(pad1));
  881         SHA1Update(&c, h2, len);
  882         SHA1Update(&c, pad2, sizeof(pad2));
  883         SHA1Final(hash, &c);
  884         bcopy(hash, h2, len);
  885 }
  886 
  887 /*
  888  * Update the encryption key
  889  */
  890 static void
  891 ng_mppc_updatekey(u_int32_t bits,
  892         u_char *key0, u_char *key, struct rc4_state *rc4)
  893 { 
  894         const int keylen = KEYLEN(bits);
  895 
  896         ng_mppc_getkey(key0, key, keylen);
  897         rc4_init(rc4, key, keylen);
  898         rc4_crypt(rc4, key, key, keylen);
  899         if ((bits & MPPE_40) != 0)
  900                 bcopy(&ng_mppe_weakenkey, key, 3);
  901         else if ((bits & MPPE_56) != 0)
  902                 bcopy(&ng_mppe_weakenkey, key, 1);
  903         rc4_init(rc4, key, keylen);
  904 }
  905 #endif
  906 

Cache object: b7810e230149472be9544768d6eaa2e8


[ 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.