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

Cache object: dffa007575555d2a4587e2aaa72d1d3a


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