ng_mppc.c revision 184205
159109Sarchie/* 259109Sarchie * ng_mppc.c 3139823Simp */ 4139823Simp 5139823Simp/*- 659109Sarchie * Copyright (c) 1996-2000 Whistle Communications, Inc. 759109Sarchie * All rights reserved. 859109Sarchie * 959109Sarchie * Subject to the following obligations and disclaimer of warranty, use and 1059109Sarchie * redistribution of this software, in source or object code forms, with or 1159109Sarchie * without modifications are expressly permitted by Whistle Communications; 1259109Sarchie * provided, however, that: 1359109Sarchie * 1. Any and all reproductions of the source or object code must include the 1459109Sarchie * copyright notice above and the following disclaimer of warranties; and 1559109Sarchie * 2. No rights are granted, in any manner or form, to use Whistle 1659109Sarchie * Communications, Inc. trademarks, including the mark "WHISTLE 1759109Sarchie * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 1859109Sarchie * such appears in the above copyright notice or in the software. 1959109Sarchie * 2059109Sarchie * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 2159109Sarchie * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 2259109Sarchie * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 2359109Sarchie * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 2459109Sarchie * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 2559109Sarchie * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 2659109Sarchie * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 2759109Sarchie * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 2859109Sarchie * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 2959109Sarchie * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 3059109Sarchie * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 3159109Sarchie * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 3259109Sarchie * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 3359109Sarchie * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3459109Sarchie * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3559109Sarchie * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 3659109Sarchie * OF SUCH DAMAGE. 3759109Sarchie * 3867506Sjulian * Author: Archie Cobbs <archie@freebsd.org> 3959109Sarchie * 4059109Sarchie * $Whistle: ng_mppc.c,v 1.4 1999/11/25 00:10:12 archie Exp $ 4159109Sarchie * $FreeBSD: head/sys/netgraph/ng_mppc.c 184205 2008-10-23 15:53:51Z des $ 4259109Sarchie */ 4359109Sarchie 4459109Sarchie/* 4559109Sarchie * Microsoft PPP compression (MPPC) and encryption (MPPE) netgraph node type. 4659109Sarchie * 4759109Sarchie * You must define one or both of the NETGRAPH_MPPC_COMPRESSION and/or 4859109Sarchie * NETGRAPH_MPPC_ENCRYPTION options for this node type to be useful. 4959109Sarchie */ 5059109Sarchie 5159109Sarchie#include <sys/param.h> 5259109Sarchie#include <sys/systm.h> 5359109Sarchie#include <sys/kernel.h> 5459109Sarchie#include <sys/mbuf.h> 5559109Sarchie#include <sys/malloc.h> 5659109Sarchie#include <sys/errno.h> 5759109Sarchie#include <sys/syslog.h> 5859109Sarchie 5959109Sarchie#include <netgraph/ng_message.h> 6059109Sarchie#include <netgraph/netgraph.h> 6159109Sarchie#include <netgraph/ng_mppc.h> 6259109Sarchie 6359109Sarchie#include "opt_netgraph.h" 6459109Sarchie 6559109Sarchie#if !defined(NETGRAPH_MPPC_COMPRESSION) && !defined(NETGRAPH_MPPC_ENCRYPTION) 66151349Syar#ifdef KLD_MODULE 67151349Syar/* XXX NETGRAPH_MPPC_COMPRESSION isn't functional yet */ 68151349Syar#define NETGRAPH_MPPC_ENCRYPTION 69151349Syar#else 70151349Syar/* This case is indicative of an error in sys/conf files */ 7159109Sarchie#error Need either NETGRAPH_MPPC_COMPRESSION or NETGRAPH_MPPC_ENCRYPTION 7259109Sarchie#endif 73151349Syar#endif 7459109Sarchie 7570870Sjulian#ifdef NG_SEPARATE_MALLOC 7670870SjulianMALLOC_DEFINE(M_NETGRAPH_MPPC, "netgraph_mppc", "netgraph mppc node "); 7770870Sjulian#else 7870870Sjulian#define M_NETGRAPH_MPPC M_NETGRAPH 7970870Sjulian#endif 8070870Sjulian 8159109Sarchie#ifdef NETGRAPH_MPPC_COMPRESSION 8259109Sarchie/* XXX this file doesn't exist yet, but hopefully someday it will... */ 8359109Sarchie#include <net/mppc.h> 8459109Sarchie#endif 8559109Sarchie#ifdef NETGRAPH_MPPC_ENCRYPTION 8659109Sarchie#include <crypto/rc4/rc4.h> 8759109Sarchie#endif 8859109Sarchie#include <crypto/sha1.h> 8959109Sarchie 9059109Sarchie/* Decompression blowup */ 9159109Sarchie#define MPPC_DECOMP_BUFSIZE 8092 /* allocate buffer this big */ 9259109Sarchie#define MPPC_DECOMP_SAFETY 100 /* plus this much margin */ 9359109Sarchie 9459109Sarchie/* MPPC/MPPE header length */ 9559109Sarchie#define MPPC_HDRLEN 2 9659109Sarchie 9759109Sarchie/* Key length */ 9859109Sarchie#define KEYLEN(b) (((b) & MPPE_128) ? 16 : 8) 9959109Sarchie 100107845Sarchie/* 101107845Sarchie * When packets are lost with MPPE, we may have to re-key arbitrarily 102107845Sarchie * many times to 'catch up' to the new jumped-ahead sequence number. 103107845Sarchie * Since this can be expensive, we pose a limit on how many re-keyings 104107845Sarchie * we will do at one time to avoid a possible D.O.S. vulnerability. 105107845Sarchie * This should instead be a configurable parameter. 106107845Sarchie */ 107107845Sarchie#define MPPE_MAX_REKEY 1000 10859109Sarchie 10959109Sarchie/* MPPC packet header bits */ 11059109Sarchie#define MPPC_FLAG_FLUSHED 0x8000 /* xmitter reset state */ 11159109Sarchie#define MPPC_FLAG_RESTART 0x4000 /* compress history restart */ 11259109Sarchie#define MPPC_FLAG_COMPRESSED 0x2000 /* packet is compresed */ 11359109Sarchie#define MPPC_FLAG_ENCRYPTED 0x1000 /* packet is encrypted */ 11459109Sarchie#define MPPC_CCOUNT_MASK 0x0fff /* sequence number mask */ 11559109Sarchie 116169261Smav#define MPPC_CCOUNT_INC(d) ((d) = (((d) + 1) & MPPC_CCOUNT_MASK)) 117169261Smav 11859109Sarchie#define MPPE_UPDATE_MASK 0xff /* coherency count when we're */ 11959109Sarchie#define MPPE_UPDATE_FLAG 0xff /* supposed to update key */ 12059109Sarchie 12159109Sarchie#define MPPC_COMP_OK 0x05 12259109Sarchie#define MPPC_DECOMP_OK 0x05 12359109Sarchie 12459109Sarchie/* Per direction info */ 12559109Sarchiestruct ng_mppc_dir { 12659109Sarchie struct ng_mppc_config cfg; /* configuration */ 12759109Sarchie hook_p hook; /* netgraph hook */ 12859109Sarchie u_int16_t cc:12; /* coherency count */ 12959109Sarchie u_char flushed; /* clean history (xmit only) */ 13059109Sarchie#ifdef NETGRAPH_MPPC_COMPRESSION 13159109Sarchie u_char *history; /* compression history */ 13259109Sarchie#endif 13359109Sarchie#ifdef NETGRAPH_MPPC_ENCRYPTION 13459109Sarchie u_char key[MPPE_KEY_LEN]; /* session key */ 13559109Sarchie struct rc4_state rc4; /* rc4 state */ 13659109Sarchie#endif 13759109Sarchie}; 13859109Sarchie 13959109Sarchie/* Node private data */ 14059109Sarchiestruct ng_mppc_private { 14159109Sarchie struct ng_mppc_dir xmit; /* compress/encrypt config */ 14259109Sarchie struct ng_mppc_dir recv; /* decompress/decrypt config */ 14370700Sjulian ng_ID_t ctrlnode; /* path to controlling node */ 14459109Sarchie}; 14559109Sarchietypedef struct ng_mppc_private *priv_p; 14659109Sarchie 14759109Sarchie/* Netgraph node methods */ 14859109Sarchiestatic ng_constructor_t ng_mppc_constructor; 14959109Sarchiestatic ng_rcvmsg_t ng_mppc_rcvmsg; 15070700Sjulianstatic ng_shutdown_t ng_mppc_shutdown; 15159109Sarchiestatic ng_newhook_t ng_mppc_newhook; 15259109Sarchiestatic ng_rcvdata_t ng_mppc_rcvdata; 15359109Sarchiestatic ng_disconnect_t ng_mppc_disconnect; 15459109Sarchie 15559109Sarchie/* Helper functions */ 15659109Sarchiestatic int ng_mppc_compress(node_p node, 157169474Smav struct mbuf **datap); 15859109Sarchiestatic int ng_mppc_decompress(node_p node, 159169474Smav struct mbuf **datap); 160169678Smav#ifdef NETGRAPH_MPPC_ENCRYPTION 16159109Sarchiestatic void ng_mppc_getkey(const u_char *h, u_char *h2, int len); 16259109Sarchiestatic void ng_mppc_updatekey(u_int32_t bits, 16359109Sarchie u_char *key0, u_char *key, struct rc4_state *rc4); 164169678Smav#endif 16559109Sarchiestatic void ng_mppc_reset_req(node_p node); 16659109Sarchie 16759109Sarchie/* Node type descriptor */ 16859109Sarchiestatic struct ng_type ng_mppc_typestruct = { 169129823Sjulian .version = NG_ABI_VERSION, 170129823Sjulian .name = NG_MPPC_NODE_TYPE, 171129823Sjulian .constructor = ng_mppc_constructor, 172129823Sjulian .rcvmsg = ng_mppc_rcvmsg, 173129823Sjulian .shutdown = ng_mppc_shutdown, 174129823Sjulian .newhook = ng_mppc_newhook, 175129823Sjulian .rcvdata = ng_mppc_rcvdata, 176129823Sjulian .disconnect = ng_mppc_disconnect, 17759109Sarchie}; 17859109SarchieNETGRAPH_INIT(mppc, &ng_mppc_typestruct); 17959109Sarchie 180110409Sambrisko#ifdef NETGRAPH_MPPC_ENCRYPTION 181110409Sambrisko/* Depend on separate rc4 module */ 182110409SambriskoMODULE_DEPEND(ng_mppc, rc4, 1, 1, 1); 183110409Sambrisko#endif 184110409Sambrisko 18587971Sarchie/* Fixed bit pattern to weaken keysize down to 40 or 56 bits */ 18659109Sarchiestatic const u_char ng_mppe_weakenkey[3] = { 0xd1, 0x26, 0x9e }; 18759109Sarchie 18859109Sarchie#define ERROUT(x) do { error = (x); goto done; } while (0) 18959109Sarchie 19059109Sarchie/************************************************************************ 19159109Sarchie NETGRAPH NODE STUFF 19259109Sarchie ************************************************************************/ 19359109Sarchie 19459109Sarchie/* 19559109Sarchie * Node type constructor 19659109Sarchie */ 19759109Sarchiestatic int 19870700Sjulianng_mppc_constructor(node_p node) 19959109Sarchie{ 20059109Sarchie priv_p priv; 20159109Sarchie 20259109Sarchie /* Allocate private structure */ 203184205Sdes priv = malloc(sizeof(*priv), M_NETGRAPH_MPPC, M_NOWAIT | M_ZERO); 20459109Sarchie if (priv == NULL) 20559109Sarchie return (ENOMEM); 20659109Sarchie 20770784Sjulian NG_NODE_SET_PRIVATE(node, priv); 20859109Sarchie 209146919Sglebius /* This node is not thread safe. */ 210146919Sglebius NG_NODE_FORCE_WRITER(node); 211146919Sglebius 21259109Sarchie /* Done */ 21359109Sarchie return (0); 21459109Sarchie} 21559109Sarchie 21659109Sarchie/* 21759109Sarchie * Give our OK for a hook to be added 21859109Sarchie */ 21959109Sarchiestatic int 22059109Sarchieng_mppc_newhook(node_p node, hook_p hook, const char *name) 22159109Sarchie{ 22270784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 22359109Sarchie hook_p *hookPtr; 22459109Sarchie 22559109Sarchie /* Check hook name */ 22659109Sarchie if (strcmp(name, NG_MPPC_HOOK_COMP) == 0) 22759109Sarchie hookPtr = &priv->xmit.hook; 22859109Sarchie else if (strcmp(name, NG_MPPC_HOOK_DECOMP) == 0) 22959109Sarchie hookPtr = &priv->recv.hook; 23059109Sarchie else 23159109Sarchie return (EINVAL); 23259109Sarchie 23359109Sarchie /* See if already connected */ 23459109Sarchie if (*hookPtr != NULL) 23559109Sarchie return (EISCONN); 23659109Sarchie 23759109Sarchie /* OK */ 23859109Sarchie *hookPtr = hook; 23959109Sarchie return (0); 24059109Sarchie} 24159109Sarchie 24259109Sarchie/* 24359109Sarchie * Receive a control message 24459109Sarchie */ 24559109Sarchiestatic int 24670700Sjulianng_mppc_rcvmsg(node_p node, item_p item, hook_p lasthook) 24759109Sarchie{ 24870784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 24959109Sarchie struct ng_mesg *resp = NULL; 25059109Sarchie int error = 0; 25170700Sjulian struct ng_mesg *msg; 25259109Sarchie 25370700Sjulian NGI_GET_MSG(item, msg); 25459109Sarchie switch (msg->header.typecookie) { 25559109Sarchie case NGM_MPPC_COOKIE: 25659109Sarchie switch (msg->header.cmd) { 25759109Sarchie case NGM_MPPC_CONFIG_COMP: 25859109Sarchie case NGM_MPPC_CONFIG_DECOMP: 25959109Sarchie { 26059109Sarchie struct ng_mppc_config *const cfg 26159109Sarchie = (struct ng_mppc_config *)msg->data; 26259109Sarchie const int isComp = 26359109Sarchie msg->header.cmd == NGM_MPPC_CONFIG_COMP; 26459109Sarchie struct ng_mppc_dir *const d = isComp ? 26559109Sarchie &priv->xmit : &priv->recv; 26659109Sarchie 26759109Sarchie /* Check configuration */ 26859109Sarchie if (msg->header.arglen != sizeof(*cfg)) 26959109Sarchie ERROUT(EINVAL); 27059109Sarchie if (cfg->enable) { 27159109Sarchie if ((cfg->bits & ~MPPC_VALID_BITS) != 0) 27259109Sarchie ERROUT(EINVAL); 27359109Sarchie#ifndef NETGRAPH_MPPC_COMPRESSION 27459109Sarchie if ((cfg->bits & MPPC_BIT) != 0) 27559109Sarchie ERROUT(EPROTONOSUPPORT); 27659109Sarchie#endif 27759109Sarchie#ifndef NETGRAPH_MPPC_ENCRYPTION 27859109Sarchie if ((cfg->bits & MPPE_BITS) != 0) 27959109Sarchie ERROUT(EPROTONOSUPPORT); 28059109Sarchie#endif 28159109Sarchie } else 28259109Sarchie cfg->bits = 0; 28359109Sarchie 28459109Sarchie /* Save return address so we can send reset-req's */ 285107845Sarchie if (!isComp) 286107845Sarchie priv->ctrlnode = NGI_RETADDR(item); 28759109Sarchie 28859109Sarchie /* Configuration is OK, reset to it */ 28959109Sarchie d->cfg = *cfg; 29059109Sarchie 29159109Sarchie#ifdef NETGRAPH_MPPC_COMPRESSION 29259109Sarchie /* Initialize state buffers for compression */ 29359109Sarchie if (d->history != NULL) { 294184205Sdes free(d->history, M_NETGRAPH_MPPC); 29559109Sarchie d->history = NULL; 29659109Sarchie } 29759109Sarchie if ((cfg->bits & MPPC_BIT) != 0) { 298184205Sdes d->history = malloc( isComp ? MPPC_SizeOfCompressionHistory() : 29959109Sarchie MPPC_SizeOfDecompressionHistory(), 30070870Sjulian M_NETGRAPH_MPPC, M_NOWAIT); 30159109Sarchie if (d->history == NULL) 30259109Sarchie ERROUT(ENOMEM); 30359109Sarchie if (isComp) 30459109Sarchie MPPC_InitCompressionHistory(d->history); 30559109Sarchie else { 30659109Sarchie MPPC_InitDecompressionHistory( 30759109Sarchie d->history); 30859109Sarchie } 30959109Sarchie } 31059109Sarchie#endif 31159109Sarchie 31259109Sarchie#ifdef NETGRAPH_MPPC_ENCRYPTION 31359109Sarchie /* Generate initial session keys for encryption */ 31459109Sarchie if ((cfg->bits & MPPE_BITS) != 0) { 31559109Sarchie const int keylen = KEYLEN(cfg->bits); 31659109Sarchie 31759109Sarchie bcopy(cfg->startkey, d->key, keylen); 31859109Sarchie ng_mppc_getkey(cfg->startkey, d->key, keylen); 31987971Sarchie if ((cfg->bits & MPPE_40) != 0) 32087971Sarchie bcopy(&ng_mppe_weakenkey, d->key, 3); 32187971Sarchie else if ((cfg->bits & MPPE_56) != 0) 32287971Sarchie bcopy(&ng_mppe_weakenkey, d->key, 1); 32359109Sarchie rc4_init(&d->rc4, d->key, keylen); 32459109Sarchie } 32559109Sarchie#endif 32659109Sarchie 32759109Sarchie /* Initialize other state */ 32859109Sarchie d->cc = 0; 32959109Sarchie d->flushed = 0; 33059109Sarchie break; 33159109Sarchie } 33259109Sarchie 33359109Sarchie case NGM_MPPC_RESETREQ: 33459109Sarchie ng_mppc_reset_req(node); 33559109Sarchie break; 33659109Sarchie 33759109Sarchie default: 33859109Sarchie error = EINVAL; 33959109Sarchie break; 34059109Sarchie } 34159109Sarchie break; 34259109Sarchie default: 34359109Sarchie error = EINVAL; 34459109Sarchie break; 34559109Sarchie } 34659109Sarchiedone: 34770700Sjulian NG_RESPOND_MSG(error, node, item, resp); 34870700Sjulian NG_FREE_MSG(msg); 34959109Sarchie return (error); 35059109Sarchie} 35159109Sarchie 35259109Sarchie/* 35359109Sarchie * Receive incoming data on our hook. 35459109Sarchie */ 35559109Sarchiestatic int 35670700Sjulianng_mppc_rcvdata(hook_p hook, item_p item) 35759109Sarchie{ 35870784Sjulian const node_p node = NG_HOOK_NODE(hook); 35970784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 36059109Sarchie int error; 36170700Sjulian struct mbuf *m; 36259109Sarchie 36370700Sjulian NGI_GET_M(item, m); 36459109Sarchie /* Compress and/or encrypt */ 36559109Sarchie if (hook == priv->xmit.hook) { 36659109Sarchie if (!priv->xmit.cfg.enable) { 36770700Sjulian NG_FREE_M(m); 36870700Sjulian NG_FREE_ITEM(item); 36959109Sarchie return (ENXIO); 37059109Sarchie } 371169474Smav if ((error = ng_mppc_compress(node, &m)) != 0) { 37270700Sjulian NG_FREE_ITEM(item); 37359109Sarchie return(error); 37459109Sarchie } 375169474Smav NG_FWD_NEW_DATA(error, item, priv->xmit.hook, m); 37659109Sarchie return (error); 37759109Sarchie } 37859109Sarchie 37959109Sarchie /* Decompress and/or decrypt */ 38059109Sarchie if (hook == priv->recv.hook) { 38159109Sarchie if (!priv->recv.cfg.enable) { 38270700Sjulian NG_FREE_M(m); 38370700Sjulian NG_FREE_ITEM(item); 38459109Sarchie return (ENXIO); 38559109Sarchie } 386169474Smav if ((error = ng_mppc_decompress(node, &m)) != 0) { 38770700Sjulian NG_FREE_ITEM(item); 388102244Sarchie if (error == EINVAL && priv->ctrlnode != 0) { 38959109Sarchie struct ng_mesg *msg; 39059109Sarchie 39159109Sarchie /* Need to send a reset-request */ 39259109Sarchie NG_MKMESSAGE(msg, NGM_MPPC_COOKIE, 39359109Sarchie NGM_MPPC_RESETREQ, 0, M_NOWAIT); 39459109Sarchie if (msg == NULL) 39559109Sarchie return (error); 39670700Sjulian NG_SEND_MSG_ID(error, node, msg, 397102244Sarchie priv->ctrlnode, 0); 39859109Sarchie } 39959109Sarchie return (error); 40059109Sarchie } 401169474Smav NG_FWD_NEW_DATA(error, item, priv->recv.hook, m); 40259109Sarchie return (error); 40359109Sarchie } 40459109Sarchie 40559109Sarchie /* Oops */ 40687599Sobrien panic("%s: unknown hook", __func__); 40783366Sjulian#ifdef RESTARTABLE_PANICS 40883366Sjulian return (EINVAL); 40983366Sjulian#endif 41059109Sarchie} 41159109Sarchie 41259109Sarchie/* 41359109Sarchie * Destroy node 41459109Sarchie */ 41559109Sarchiestatic int 41670700Sjulianng_mppc_shutdown(node_p node) 41759109Sarchie{ 41870784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 41959109Sarchie 42059109Sarchie /* Take down netgraph node */ 42159109Sarchie#ifdef NETGRAPH_MPPC_COMPRESSION 42259109Sarchie if (priv->xmit.history != NULL) 423184205Sdes free(priv->xmit.history, M_NETGRAPH_MPPC); 42459109Sarchie if (priv->recv.history != NULL) 425184205Sdes free(priv->recv.history, M_NETGRAPH_MPPC); 42659109Sarchie#endif 42759109Sarchie bzero(priv, sizeof(*priv)); 428184205Sdes free(priv, M_NETGRAPH_MPPC); 42970784Sjulian NG_NODE_SET_PRIVATE(node, NULL); 43070784Sjulian NG_NODE_UNREF(node); /* let the node escape */ 43159109Sarchie return (0); 43259109Sarchie} 43359109Sarchie 43459109Sarchie/* 43559109Sarchie * Hook disconnection 43659109Sarchie */ 43759109Sarchiestatic int 43859109Sarchieng_mppc_disconnect(hook_p hook) 43959109Sarchie{ 44070784Sjulian const node_p node = NG_HOOK_NODE(hook); 44170784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 44259109Sarchie 44359109Sarchie /* Zero out hook pointer */ 44459109Sarchie if (hook == priv->xmit.hook) 44559109Sarchie priv->xmit.hook = NULL; 44659109Sarchie if (hook == priv->recv.hook) 44759109Sarchie priv->recv.hook = NULL; 44859109Sarchie 44959109Sarchie /* Go away if no longer connected */ 45070784Sjulian if ((NG_NODE_NUMHOOKS(node) == 0) 45170784Sjulian && NG_NODE_IS_VALID(node)) 45270700Sjulian ng_rmnode_self(node); 45359109Sarchie return (0); 45459109Sarchie} 45559109Sarchie 45659109Sarchie/************************************************************************ 45759109Sarchie HELPER STUFF 45859109Sarchie ************************************************************************/ 45959109Sarchie 46059109Sarchie/* 46159109Sarchie * Compress/encrypt a packet and put the result in a new mbuf at *resultp. 46259109Sarchie * The original mbuf is not free'd. 46359109Sarchie */ 46459109Sarchiestatic int 465169474Smavng_mppc_compress(node_p node, struct mbuf **datap) 46659109Sarchie{ 46770784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 46859109Sarchie struct ng_mppc_dir *const d = &priv->xmit; 46959109Sarchie u_int16_t header; 470169474Smav struct mbuf *m = *datap; 47159109Sarchie 47259109Sarchie /* Initialize */ 47359109Sarchie header = d->cc; 474169262Smav 475169262Smav /* Always set the flushed bit in stateless mode */ 476169262Smav if (d->flushed || ((d->cfg.bits & MPPE_STATELESS) != 0)) { 47759109Sarchie header |= MPPC_FLAG_FLUSHED; 47859109Sarchie d->flushed = 0; 47959109Sarchie } 48059109Sarchie 481169474Smav /* Compress packet (if compression enabled) */ 48259109Sarchie#ifdef NETGRAPH_MPPC_COMPRESSION 48359109Sarchie if ((d->cfg.bits & MPPC_BIT) != 0) { 48459109Sarchie u_short flags = MPPC_MANDATORY_COMPRESS_FLAGS; 485169474Smav u_char *inbuf, *outbuf; 486169474Smav int outlen, inlen; 48759109Sarchie u_char *source, *dest; 48859109Sarchie u_long sourceCnt, destCnt; 48959109Sarchie int rtn; 49059109Sarchie 491169474Smav /* Work with contiguous regions of memory. */ 492169474Smav inlen = m->m_pkthdr.len; 493169474Smav inbuf = malloc(inlen, M_NETGRAPH_MPPC, M_NOWAIT); 494169474Smav if (inbuf == NULL) { 495169474Smav m_freem(m); 496169474Smav return (ENOMEM); 497169474Smav } 498169474Smav m_copydata(m, 0, inlen, (caddr_t)inbuf); 499169474Smav 500169474Smav outlen = MPPC_MAX_BLOWUP(inlen); 501169474Smav outbuf = malloc(outlen, M_NETGRAPH_MPPC, M_NOWAIT); 502169474Smav if (outbuf == NULL) { 503169474Smav m_freem(m); 504169474Smav free(inbuf, M_NETGRAPH_MPPC); 505169474Smav return (ENOMEM); 506169474Smav } 507169474Smav 50859109Sarchie /* Prepare to compress */ 50959109Sarchie source = inbuf; 51059109Sarchie sourceCnt = inlen; 511169474Smav dest = outbuf; 512169474Smav destCnt = outlen; 51359109Sarchie if ((d->cfg.bits & MPPE_STATELESS) == 0) 51459109Sarchie flags |= MPPC_SAVE_HISTORY; 51559109Sarchie 51659109Sarchie /* Compress */ 51759109Sarchie rtn = MPPC_Compress(&source, &dest, &sourceCnt, 51859109Sarchie &destCnt, d->history, flags, 0); 51959109Sarchie 52059109Sarchie /* Check return value */ 52187599Sobrien KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__)); 52259109Sarchie if ((rtn & MPPC_EXPANDED) == 0 52359109Sarchie && (rtn & MPPC_COMP_OK) == MPPC_COMP_OK) { 52459109Sarchie outlen -= destCnt; 52559109Sarchie header |= MPPC_FLAG_COMPRESSED; 52659109Sarchie if ((rtn & MPPC_RESTART_HISTORY) != 0) 52759109Sarchie header |= MPPC_FLAG_RESTART; 528169474Smav 529169474Smav /* Replace m by the compresed one. */ 530169474Smav m_freem(m); 531169474Smav m = m_devget((caddr_t)outbuf, outlen, 0, NULL, NULL); 53259109Sarchie } 53359109Sarchie d->flushed = (rtn & MPPC_EXPANDED) != 0 53459109Sarchie || (flags & MPPC_SAVE_HISTORY) == 0; 535169474Smav 536169474Smav free(inbuf, M_NETGRAPH_MPPC); 537169474Smav free(outbuf, M_NETGRAPH_MPPC); 538169474Smav 539169474Smav /* Check m_devget() result. */ 540169474Smav if (m == NULL) 541169474Smav return (ENOMEM); 54259109Sarchie } 54359109Sarchie#endif 54459109Sarchie 54559109Sarchie /* Now encrypt packet (if encryption enabled) */ 54659109Sarchie#ifdef NETGRAPH_MPPC_ENCRYPTION 54759109Sarchie if ((d->cfg.bits & MPPE_BITS) != 0) { 548169474Smav struct mbuf *m1; 54959109Sarchie 550169263Smav /* Set header bits */ 55159109Sarchie header |= MPPC_FLAG_ENCRYPTED; 55259109Sarchie 55359109Sarchie /* Update key if it's time */ 55459109Sarchie if ((d->cfg.bits & MPPE_STATELESS) != 0 55559109Sarchie || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) { 556169263Smav ng_mppc_updatekey(d->cfg.bits, 557169263Smav d->cfg.startkey, d->key, &d->rc4); 558169263Smav } else if ((header & MPPC_FLAG_FLUSHED) != 0) { 559169263Smav /* Need to reset key if we say we did 560169263Smav and ng_mppc_updatekey wasn't called to do it also. */ 561169263Smav rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits)); 56259109Sarchie } 56359109Sarchie 564169474Smav /* We must own the mbuf chain exclusively to modify it. */ 565169474Smav m = m_unshare(m, M_DONTWAIT); 566169474Smav if (m == NULL) 567169474Smav return (ENOMEM); 568169474Smav 56959109Sarchie /* Encrypt packet */ 570169474Smav m1 = m; 571169474Smav while (m1) { 572169474Smav rc4_crypt(&d->rc4, mtod(m1, u_char *), 573169474Smav mtod(m1, u_char *), m1->m_len); 574169474Smav m1 = m1->m_next; 575169474Smav } 57659109Sarchie } 57759109Sarchie#endif 57859109Sarchie 579169261Smav /* Update coherency count for next time (12 bit arithmetic) */ 580169261Smav MPPC_CCOUNT_INC(d->cc); 58159109Sarchie 58259109Sarchie /* Install header */ 583169474Smav M_PREPEND(m, MPPC_HDRLEN, M_DONTWAIT); 584169474Smav if (m != NULL) 585169474Smav *(mtod(m, uint16_t *)) = htons(header); 58659109Sarchie 587169474Smav *datap = m; 588169474Smav return (*datap == NULL ? ENOBUFS : 0); 58959109Sarchie} 59059109Sarchie 59159109Sarchie/* 59259109Sarchie * Decompress/decrypt packet and put the result in a new mbuf at *resultp. 59359109Sarchie * The original mbuf is not free'd. 59459109Sarchie */ 59559109Sarchiestatic int 596169474Smavng_mppc_decompress(node_p node, struct mbuf **datap) 59759109Sarchie{ 59870784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 59959109Sarchie struct ng_mppc_dir *const d = &priv->recv; 600107845Sarchie u_int16_t header, cc; 601107845Sarchie u_int numLost; 602169474Smav struct mbuf *m = *datap; 60359109Sarchie 60459109Sarchie /* Pull off header */ 605169474Smav if (m->m_pkthdr.len < MPPC_HDRLEN) { 606169474Smav m_freem(m); 60759109Sarchie return (EINVAL); 608169474Smav } 60959109Sarchie m_copydata(m, 0, MPPC_HDRLEN, (caddr_t)&header); 61090868Smike header = ntohs(header); 61159109Sarchie cc = (header & MPPC_CCOUNT_MASK); 612169474Smav m_adj(m, MPPC_HDRLEN); 61359109Sarchie 614107845Sarchie /* Check for an unexpected jump in the sequence number */ 61559109Sarchie numLost = ((cc - d->cc) & MPPC_CCOUNT_MASK); 61659109Sarchie 61759109Sarchie /* If flushed bit set, we can always handle packet */ 61859109Sarchie if ((header & MPPC_FLAG_FLUSHED) != 0) { 61959109Sarchie#ifdef NETGRAPH_MPPC_COMPRESSION 62059109Sarchie if (d->history != NULL) 62159109Sarchie MPPC_InitDecompressionHistory(d->history); 62259109Sarchie#endif 62359109Sarchie#ifdef NETGRAPH_MPPC_ENCRYPTION 62459109Sarchie if ((d->cfg.bits & MPPE_BITS) != 0) { 625107845Sarchie u_int rekey; 62659109Sarchie 627107845Sarchie /* How many times are we going to have to re-key? */ 628107845Sarchie rekey = ((d->cfg.bits & MPPE_STATELESS) != 0) ? 629107845Sarchie numLost : (numLost / (MPPE_UPDATE_MASK + 1)); 630107845Sarchie if (rekey > MPPE_MAX_REKEY) { 631107845Sarchie log(LOG_ERR, "%s: too many (%d) packets" 632107845Sarchie " dropped, disabling node %p!", 633107845Sarchie __func__, numLost, node); 634107845Sarchie priv->recv.cfg.enable = 0; 635107845Sarchie goto failed; 636107845Sarchie } 637107845Sarchie 638107845Sarchie /* Re-key as necessary to catch up to peer */ 63959109Sarchie while (d->cc != cc) { 640107845Sarchie if ((d->cfg.bits & MPPE_STATELESS) != 0 64159109Sarchie || (d->cc & MPPE_UPDATE_MASK) 64259109Sarchie == MPPE_UPDATE_FLAG) { 64359109Sarchie ng_mppc_updatekey(d->cfg.bits, 64459109Sarchie d->cfg.startkey, d->key, &d->rc4); 64559109Sarchie } 646169261Smav MPPC_CCOUNT_INC(d->cc); 64759109Sarchie } 64859109Sarchie 64959109Sarchie /* Reset key (except in stateless mode, see below) */ 65059109Sarchie if ((d->cfg.bits & MPPE_STATELESS) == 0) 65159109Sarchie rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits)); 65259109Sarchie } 65359109Sarchie#endif 65459109Sarchie d->cc = cc; /* skip over lost seq numbers */ 65559109Sarchie numLost = 0; /* act like no packets were lost */ 65659109Sarchie } 65759109Sarchie 65859109Sarchie /* Can't decode non-sequential packets without a flushed bit */ 65959109Sarchie if (numLost != 0) 66059109Sarchie goto failed; 66159109Sarchie 66259109Sarchie /* Decrypt packet */ 66359109Sarchie if ((header & MPPC_FLAG_ENCRYPTED) != 0) { 664169474Smav#ifdef NETGRAPH_MPPC_ENCRYPTION 665169474Smav struct mbuf *m1; 666169474Smav#endif 66759109Sarchie 66859109Sarchie /* Are we not expecting encryption? */ 66959109Sarchie if ((d->cfg.bits & MPPE_BITS) == 0) { 67059109Sarchie log(LOG_ERR, "%s: rec'd unexpectedly %s packet", 67187599Sobrien __func__, "encrypted"); 67259109Sarchie goto failed; 67359109Sarchie } 67459109Sarchie 67559109Sarchie#ifdef NETGRAPH_MPPC_ENCRYPTION 67659109Sarchie /* Update key if it's time (always in stateless mode) */ 67759109Sarchie if ((d->cfg.bits & MPPE_STATELESS) != 0 67859109Sarchie || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) { 67959109Sarchie ng_mppc_updatekey(d->cfg.bits, 68059109Sarchie d->cfg.startkey, d->key, &d->rc4); 68159109Sarchie } 68259109Sarchie 683169474Smav /* We must own the mbuf chain exclusively to modify it. */ 684169474Smav m = m_unshare(m, M_DONTWAIT); 685169474Smav if (m == NULL) 686169474Smav return (ENOMEM); 687169474Smav 68859109Sarchie /* Decrypt packet */ 689169474Smav m1 = m; 690169474Smav while (m1 != NULL) { 691169474Smav rc4_crypt(&d->rc4, mtod(m1, u_char *), 692169474Smav mtod(m1, u_char *), m1->m_len); 693169474Smav m1 = m1->m_next; 694169474Smav } 69559109Sarchie#endif 69659109Sarchie } else { 69759109Sarchie 69859109Sarchie /* Are we expecting encryption? */ 69959109Sarchie if ((d->cfg.bits & MPPE_BITS) != 0) { 70059109Sarchie log(LOG_ERR, "%s: rec'd unexpectedly %s packet", 70187599Sobrien __func__, "unencrypted"); 70259109Sarchie goto failed; 70359109Sarchie } 70459109Sarchie } 70559109Sarchie 70659109Sarchie /* Update coherency count for next time (12 bit arithmetic) */ 707169261Smav MPPC_CCOUNT_INC(d->cc); 70859109Sarchie 70959109Sarchie /* Check for unexpected compressed packet */ 71059109Sarchie if ((header & MPPC_FLAG_COMPRESSED) != 0 71159109Sarchie && (d->cfg.bits & MPPC_BIT) == 0) { 71259109Sarchie log(LOG_ERR, "%s: rec'd unexpectedly %s packet", 71387599Sobrien __func__, "compressed"); 71459109Sarchiefailed: 715169474Smav m_freem(m); 71659109Sarchie return (EINVAL); 71759109Sarchie } 71859109Sarchie 71959109Sarchie#ifdef NETGRAPH_MPPC_COMPRESSION 72059109Sarchie /* Decompress packet */ 72159109Sarchie if ((header & MPPC_FLAG_COMPRESSED) != 0) { 72259109Sarchie int flags = MPPC_MANDATORY_DECOMPRESS_FLAGS; 72359109Sarchie u_char *decompbuf, *source, *dest; 72459109Sarchie u_long sourceCnt, destCnt; 72559109Sarchie int decomplen, rtn; 726169474Smav u_char *buf; 727169474Smav int len; 72859109Sarchie 729169474Smav /* Copy payload into a contiguous region of memory. */ 730169474Smav len = m->m_pkthdr.len; 731169474Smav buf = malloc(len, M_NETGRAPH_MPPC, M_NOWAIT); 732169474Smav if (buf == NULL) { 733169474Smav m_freem(m); 734169474Smav return (ENOMEM); 735169474Smav } 736169474Smav m_copydata(m, 0, len, (caddr_t)buf); 737169474Smav 73859109Sarchie /* Allocate a buffer for decompressed data */ 739169474Smav decompbuf = malloc(MPPC_DECOMP_BUFSIZE + MPPC_DECOMP_SAFETY, 740169474Smav M_NETGRAPH_MPPC, M_NOWAIT); 74159109Sarchie if (decompbuf == NULL) { 742169474Smav m_freem(m); 743169474Smav free(buf, M_NETGRAPH_MPPC); 74459109Sarchie return (ENOMEM); 74559109Sarchie } 74659109Sarchie decomplen = MPPC_DECOMP_BUFSIZE; 74759109Sarchie 74859109Sarchie /* Prepare to decompress */ 74959109Sarchie source = buf; 75059109Sarchie sourceCnt = len; 75159109Sarchie dest = decompbuf; 75259109Sarchie destCnt = decomplen; 75359109Sarchie if ((header & MPPC_FLAG_RESTART) != 0) 75459109Sarchie flags |= MPPC_RESTART_HISTORY; 75559109Sarchie 75659109Sarchie /* Decompress */ 75759109Sarchie rtn = MPPC_Decompress(&source, &dest, 75859109Sarchie &sourceCnt, &destCnt, d->history, flags); 75959109Sarchie 76059109Sarchie /* Check return value */ 76187599Sobrien KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__)); 76259109Sarchie if ((rtn & MPPC_DEST_EXHAUSTED) != 0 76359109Sarchie || (rtn & MPPC_DECOMP_OK) != MPPC_DECOMP_OK) { 76459109Sarchie log(LOG_ERR, "%s: decomp returned 0x%x", 76587599Sobrien __func__, rtn); 766169474Smav free(buf, M_NETGRAPH_MPPC); 767169474Smav free(decompbuf, M_NETGRAPH_MPPC); 76859109Sarchie goto failed; 76959109Sarchie } 77059109Sarchie 77159109Sarchie /* Replace compressed data with decompressed data */ 772169474Smav free(buf, M_NETGRAPH_MPPC); 77359109Sarchie len = decomplen - destCnt; 774169474Smav 775169474Smav m_freem(m); 776169474Smav m = m_devget((caddr_t)decompbuf, len, 0, NULL, NULL); 777169474Smav free(decompbuf, M_NETGRAPH_MPPC); 77859109Sarchie } 77959109Sarchie#endif 78059109Sarchie 78159109Sarchie /* Return result in an mbuf */ 782169474Smav *datap = m; 783169474Smav return (*datap == NULL ? ENOBUFS : 0); 78459109Sarchie} 78559109Sarchie 78659109Sarchie/* 78759109Sarchie * The peer has sent us a CCP ResetRequest, so reset our transmit state. 78859109Sarchie */ 78959109Sarchiestatic void 79059109Sarchieng_mppc_reset_req(node_p node) 79159109Sarchie{ 79270784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 79359109Sarchie struct ng_mppc_dir *const d = &priv->xmit; 79459109Sarchie 79559109Sarchie#ifdef NETGRAPH_MPPC_COMPRESSION 79659109Sarchie if (d->history != NULL) 79759109Sarchie MPPC_InitCompressionHistory(d->history); 79859109Sarchie#endif 79959109Sarchie#ifdef NETGRAPH_MPPC_ENCRYPTION 80059109Sarchie if ((d->cfg.bits & MPPE_STATELESS) == 0) 80159109Sarchie rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits)); 80259109Sarchie#endif 80359109Sarchie d->flushed = 1; 80459109Sarchie} 80559109Sarchie 806169678Smav#ifdef NETGRAPH_MPPC_ENCRYPTION 80759109Sarchie/* 80859109Sarchie * Generate a new encryption key 80959109Sarchie */ 81059109Sarchiestatic void 81159109Sarchieng_mppc_getkey(const u_char *h, u_char *h2, int len) 81259109Sarchie{ 81359109Sarchie static const u_char pad1[10] = 81459109Sarchie { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; 81559109Sarchie static const u_char pad2[10] = 81659109Sarchie { 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, }; 81759109Sarchie u_char hash[20]; 81859109Sarchie SHA1_CTX c; 81959109Sarchie int k; 82059109Sarchie 82159109Sarchie SHA1Init(&c); 82259109Sarchie SHA1Update(&c, h, len); 82359109Sarchie for (k = 0; k < 4; k++) 824169258Smav SHA1Update(&c, pad1, sizeof(pad1)); 82559109Sarchie SHA1Update(&c, h2, len); 82659109Sarchie for (k = 0; k < 4; k++) 82759109Sarchie SHA1Update(&c, pad2, sizeof(pad2)); 82859109Sarchie SHA1Final(hash, &c); 82959109Sarchie bcopy(hash, h2, len); 83059109Sarchie} 83159109Sarchie 83259109Sarchie/* 83359109Sarchie * Update the encryption key 83459109Sarchie */ 83559109Sarchiestatic void 83659109Sarchieng_mppc_updatekey(u_int32_t bits, 83759109Sarchie u_char *key0, u_char *key, struct rc4_state *rc4) 83859109Sarchie{ 83959109Sarchie const int keylen = KEYLEN(bits); 84059109Sarchie 84159109Sarchie ng_mppc_getkey(key0, key, keylen); 84259109Sarchie rc4_init(rc4, key, keylen); 84359109Sarchie rc4_crypt(rc4, key, key, keylen); 84487971Sarchie if ((bits & MPPE_40) != 0) 84587971Sarchie bcopy(&ng_mppe_weakenkey, key, 3); 84687971Sarchie else if ((bits & MPPE_56) != 0) 84787971Sarchie bcopy(&ng_mppe_weakenkey, key, 1); 84859109Sarchie rc4_init(rc4, key, keylen); 84959109Sarchie} 850169678Smav#endif 85159109Sarchie 852