FreeBSD kernel netgraph code
ng_mppc.c
Go to the documentation of this file.
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
78static 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
110SYSCTL_NODE(_net_graph, OID_AUTO, mppe, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
111 "MPPE");
112
114SYSCTL_INT(_net_graph_mppe, OID_AUTO, block_on_max_rekey, CTLFLAG_RWTUN,
115 &mppe_block_on_max_rekey, 0, "Block node on max MPPE key re-calculations");
116
117static int mppe_log_max_rekey = 1;
118SYSCTL_INT(_net_graph_mppe, OID_AUTO, log_max_rekey, CTLFLAG_RWTUN,
119 &mppe_log_max_rekey, 0, "Log max MPPE key re-calculations event");
120
122SYSCTL_INT(_net_graph_mppe, OID_AUTO, max_rekey, CTLFLAG_RWTUN,
123 &mppe_max_rekey, 0, "Maximum number of MPPE key re-calculations");
124
125/* MPPC packet header bits */
126#define MPPC_FLAG_FLUSHED 0x8000 /* xmitter reset state */
127#define MPPC_FLAG_RESTART 0x4000 /* compress history restart */
128#define MPPC_FLAG_COMPRESSED 0x2000 /* packet is compresed */
129#define MPPC_FLAG_ENCRYPTED 0x1000 /* packet is encrypted */
130#define MPPC_CCOUNT_MASK 0x0fff /* sequence number mask */
131
132#define MPPC_CCOUNT_INC(d) ((d) = (((d) + 1) & MPPC_CCOUNT_MASK))
133
134#define MPPE_UPDATE_MASK 0xff /* coherency count when we're */
135#define MPPE_UPDATE_FLAG 0xff /* supposed to update key */
136
137#define MPPC_COMP_OK 0x05
138#define MPPC_DECOMP_OK 0x05
139
140/* Per direction info */
142 struct ng_mppc_config cfg; /* configuration */
143 hook_p hook; /* netgraph hook */
144 u_int16_t cc:12; /* coherency count */
145 u_char flushed; /* clean history (xmit only) */
146#ifdef NETGRAPH_MPPC_COMPRESSION
147 u_char *history; /* compression history */
148#endif
149#ifdef NETGRAPH_MPPC_ENCRYPTION
150 u_char key[MPPE_KEY_LEN]; /* session key */
151 struct rc4_state rc4; /* rc4 state */
152#endif
153};
154
155/* Node private data */
157 struct ng_mppc_dir xmit; /* compress/encrypt config */
158 struct ng_mppc_dir recv; /* decompress/decrypt config */
159 ng_ID_t ctrlnode; /* path to controlling node */
160};
161typedef struct ng_mppc_private *priv_p;
162
163/* Netgraph node methods */
170
171/* Helper functions */
172static int ng_mppc_compress(node_p node,
173 struct mbuf **datap);
174static int ng_mppc_decompress(node_p node,
175 struct mbuf **datap);
176#ifdef NETGRAPH_MPPC_ENCRYPTION
177static void ng_mppc_getkey(const u_char *h, u_char *h2, int len);
178static void ng_mppc_updatekey(u_int32_t bits,
179 u_char *key0, u_char *key, struct rc4_state *rc4);
180#endif
181static void ng_mppc_reset_req(node_p node);
182
183/* Node type descriptor */
186 .name = NG_MPPC_NODE_TYPE,
187 .constructor = ng_mppc_constructor,
188 .rcvmsg = ng_mppc_rcvmsg,
189 .shutdown = ng_mppc_shutdown,
190 .newhook = ng_mppc_newhook,
191 .rcvdata = ng_mppc_rcvdata,
192 .disconnect = ng_mppc_disconnect,
193};
195
196#ifdef NETGRAPH_MPPC_ENCRYPTION
197/* Depend on separate rc4 module */
198MODULE_DEPEND(ng_mppc, rc4, 1, 1, 1);
199#endif
200
201/* Fixed bit pattern to weaken keysize down to 40 or 56 bits */
202static const u_char ng_mppe_weakenkey[3] = { 0xd1, 0x26, 0x9e };
203
204#define ERROUT(x) do { error = (x); goto done; } while (0)
205
206/************************************************************************
207 NETGRAPH NODE STUFF
208 ************************************************************************/
209
210/*
211 * Node type constructor
212 */
213static int
215{
216 priv_p priv;
217
218 /* Allocate private structure */
219 priv = malloc(sizeof(*priv), M_NETGRAPH_MPPC, M_WAITOK | M_ZERO);
220
222
223 /* This node is not thread safe. */
225
226 /* Done */
227 return (0);
228}
229
230/*
231 * Give our OK for a hook to be added
232 */
233static int
234ng_mppc_newhook(node_p node, hook_p hook, const char *name)
235{
236 const priv_p priv = NG_NODE_PRIVATE(node);
237 hook_p *hookPtr;
238
239 /* Check hook name */
240 if (strcmp(name, NG_MPPC_HOOK_COMP) == 0)
241 hookPtr = &priv->xmit.hook;
242 else if (strcmp(name, NG_MPPC_HOOK_DECOMP) == 0)
243 hookPtr = &priv->recv.hook;
244 else
245 return (EINVAL);
246
247 /* See if already connected */
248 if (*hookPtr != NULL)
249 return (EISCONN);
250
251 /* OK */
252 *hookPtr = hook;
253 return (0);
254}
255
256/*
257 * Receive a control message
258 */
259static int
260ng_mppc_rcvmsg(node_p node, item_p item, hook_p lasthook)
261{
262 const priv_p priv = NG_NODE_PRIVATE(node);
263 struct ng_mesg *resp = NULL;
264 int error = 0;
265 struct ng_mesg *msg;
266
267 NGI_GET_MSG(item, msg);
268 switch (msg->header.typecookie) {
269 case NGM_MPPC_COOKIE:
270 switch (msg->header.cmd) {
273 {
274 struct ng_mppc_config *const cfg
275 = (struct ng_mppc_config *)msg->data;
276 const int isComp =
278 struct ng_mppc_dir *const d = isComp ?
279 &priv->xmit : &priv->recv;
280
281 /* Check configuration */
282 if (msg->header.arglen != sizeof(*cfg))
283 ERROUT(EINVAL);
284 if (cfg->enable) {
285 if ((cfg->bits & ~MPPC_VALID_BITS) != 0)
286 ERROUT(EINVAL);
287#ifndef NETGRAPH_MPPC_COMPRESSION
288 if ((cfg->bits & MPPC_BIT) != 0)
289 ERROUT(EPROTONOSUPPORT);
290#endif
291#ifndef NETGRAPH_MPPC_ENCRYPTION
292 if ((cfg->bits & MPPE_BITS) != 0)
293 ERROUT(EPROTONOSUPPORT);
294#endif
295 } else
296 cfg->bits = 0;
297
298 /* Save return address so we can send reset-req's */
299 if (!isComp)
300 priv->ctrlnode = NGI_RETADDR(item);
301
302 /* Configuration is OK, reset to it */
303 d->cfg = *cfg;
304
305#ifdef NETGRAPH_MPPC_COMPRESSION
306 /* Initialize state buffers for compression */
307 if (d->history != NULL) {
308 free(d->history, M_NETGRAPH_MPPC);
309 d->history = NULL;
310 }
311 if ((cfg->bits & MPPC_BIT) != 0) {
312 d->history = malloc(isComp ?
313 MPPC_SizeOfCompressionHistory() :
314 MPPC_SizeOfDecompressionHistory(),
315 M_NETGRAPH_MPPC, M_NOWAIT);
316 if (d->history == NULL)
317 ERROUT(ENOMEM);
318 if (isComp)
319 MPPC_InitCompressionHistory(d->history);
320 else {
321 MPPC_InitDecompressionHistory(
322 d->history);
323 }
324 }
325#endif
326
327#ifdef NETGRAPH_MPPC_ENCRYPTION
328 /* Generate initial session keys for encryption */
329 if ((cfg->bits & MPPE_BITS) != 0) {
330 const int keylen = KEYLEN(cfg->bits);
331
332 bcopy(cfg->startkey, d->key, keylen);
333 ng_mppc_getkey(cfg->startkey, d->key, keylen);
334 if ((cfg->bits & MPPE_40) != 0)
335 bcopy(&ng_mppe_weakenkey, d->key, 3);
336 else if ((cfg->bits & MPPE_56) != 0)
337 bcopy(&ng_mppe_weakenkey, d->key, 1);
338 rc4_init(&d->rc4, d->key, keylen);
339 }
340#endif
341
342 /* Initialize other state */
343 d->cc = 0;
344 d->flushed = 0;
345 break;
346 }
347
349 ng_mppc_reset_req(node);
350 break;
351
352 default:
353 error = EINVAL;
354 break;
355 }
356 break;
357 default:
358 error = EINVAL;
359 break;
360 }
361done:
362 NG_RESPOND_MSG(error, node, item, resp);
363 NG_FREE_MSG(msg);
364 return (error);
365}
366
367/*
368 * Receive incoming data on our hook.
369 */
370static int
372{
373 const node_p node = NG_HOOK_NODE(hook);
374 const priv_p priv = NG_NODE_PRIVATE(node);
375 int error;
376 struct mbuf *m;
377
378 NGI_GET_M(item, m);
379 /* Compress and/or encrypt */
380 if (hook == priv->xmit.hook) {
381 if (!priv->xmit.cfg.enable) {
382 NG_FREE_M(m);
383 NG_FREE_ITEM(item);
384 return (ENXIO);
385 }
386 if ((error = ng_mppc_compress(node, &m)) != 0) {
387 NG_FREE_ITEM(item);
388 return(error);
389 }
390 NG_FWD_NEW_DATA(error, item, priv->xmit.hook, m);
391 return (error);
392 }
393
394 /* Decompress and/or decrypt */
395 if (hook == priv->recv.hook) {
396 if (!priv->recv.cfg.enable) {
397 NG_FREE_M(m);
398 NG_FREE_ITEM(item);
399 return (ENXIO);
400 }
401 if ((error = ng_mppc_decompress(node, &m)) != 0) {
402 NG_FREE_ITEM(item);
403 if (error == EINVAL && priv->ctrlnode != 0) {
404 struct ng_mesg *msg;
405
406 /* Need to send a reset-request */
408 NGM_MPPC_RESETREQ, 0, M_NOWAIT);
409 if (msg == NULL)
410 return (error);
411 NG_SEND_MSG_ID(error, node, msg,
412 priv->ctrlnode, 0);
413 }
414 return (error);
415 }
416 NG_FWD_NEW_DATA(error, item, priv->recv.hook, m);
417 return (error);
418 }
419
420 /* Oops */
421 panic("%s: unknown hook", __func__);
422}
423
424/*
425 * Destroy node
426 */
427static int
429{
430 const priv_p priv = NG_NODE_PRIVATE(node);
431
432 /* Take down netgraph node */
433#ifdef NETGRAPH_MPPC_COMPRESSION
434 if (priv->xmit.history != NULL)
435 free(priv->xmit.history, M_NETGRAPH_MPPC);
436 if (priv->recv.history != NULL)
437 free(priv->recv.history, M_NETGRAPH_MPPC);
438#endif
439 bzero(priv, sizeof(*priv));
440 free(priv, M_NETGRAPH_MPPC);
441 NG_NODE_SET_PRIVATE(node, NULL);
442 NG_NODE_UNREF(node); /* let the node escape */
443 return (0);
444}
445
446/*
447 * Hook disconnection
448 */
449static int
451{
452 const node_p node = NG_HOOK_NODE(hook);
453 const priv_p priv = NG_NODE_PRIVATE(node);
454
455 /* Zero out hook pointer */
456 if (hook == priv->xmit.hook)
457 priv->xmit.hook = NULL;
458 if (hook == priv->recv.hook)
459 priv->recv.hook = NULL;
460
461 /* Go away if no longer connected */
462 if ((NG_NODE_NUMHOOKS(node) == 0)
463 && NG_NODE_IS_VALID(node))
464 ng_rmnode_self(node);
465 return (0);
466}
467
468/************************************************************************
469 HELPER STUFF
470 ************************************************************************/
471
472/*
473 * Compress/encrypt a packet and put the result in a new mbuf at *resultp.
474 * The original mbuf is not free'd.
475 */
476static int
477ng_mppc_compress(node_p node, struct mbuf **datap)
478{
479 const priv_p priv = NG_NODE_PRIVATE(node);
480 struct ng_mppc_dir *const d = &priv->xmit;
481 u_int16_t header;
482 struct mbuf *m = *datap;
483
484 /* We must own the mbuf chain exclusively to modify it. */
485 m = m_unshare(m, M_NOWAIT);
486 if (m == NULL)
487 return (ENOMEM);
488
489 /* Initialize */
490 header = d->cc;
491
492 /* Always set the flushed bit in stateless mode */
493 if (d->flushed || ((d->cfg.bits & MPPE_STATELESS) != 0)) {
495 d->flushed = 0;
496 }
497
498 /* Compress packet (if compression enabled) */
499#ifdef NETGRAPH_MPPC_COMPRESSION
500 if ((d->cfg.bits & MPPC_BIT) != 0) {
501 u_short flags = MPPC_MANDATORY_COMPRESS_FLAGS;
502 u_char *inbuf, *outbuf;
503 int outlen, inlen, ina;
504 u_char *source, *dest;
505 u_long sourceCnt, destCnt;
506 int rtn;
507
508 /* Work with contiguous regions of memory. */
509 inlen = m->m_pkthdr.len;
510 if (m->m_next == NULL) {
511 inbuf = mtod(m, u_char *);
512 ina = 0;
513 } else {
514 inbuf = malloc(inlen, M_NETGRAPH_MPPC, M_NOWAIT);
515 if (inbuf == NULL)
516 goto err1;
517 m_copydata(m, 0, inlen, (caddr_t)inbuf);
518 ina = 1;
519 }
520
521 outlen = MPPC_MAX_BLOWUP(inlen);
522 outbuf = malloc(outlen, M_NETGRAPH_MPPC, M_NOWAIT);
523 if (outbuf == NULL) {
524 if (ina)
525 free(inbuf, M_NETGRAPH_MPPC);
526err1:
527 m_freem(m);
528 MPPC_InitCompressionHistory(d->history);
529 d->flushed = 1;
530 return (ENOMEM);
531 }
532
533 /* Prepare to compress */
534 source = inbuf;
535 sourceCnt = inlen;
536 dest = outbuf;
537 destCnt = outlen;
538 if ((d->cfg.bits & MPPE_STATELESS) == 0)
539 flags |= MPPC_SAVE_HISTORY;
540
541 /* Compress */
542 rtn = MPPC_Compress(&source, &dest, &sourceCnt,
543 &destCnt, d->history, flags, 0);
544
545 /* Check return value */
546 /* KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__)); */
547 if ((rtn & MPPC_EXPANDED) == 0
548 && (rtn & MPPC_COMP_OK) == MPPC_COMP_OK) {
549 outlen -= destCnt;
551 if ((rtn & MPPC_RESTART_HISTORY) != 0)
553
554 /* Replace m by the compresed one. */
555 m_copyback(m, 0, outlen, (caddr_t)outbuf);
556 if (m->m_pkthdr.len < outlen) {
557 m_freem(m);
558 m = NULL;
559 } else if (outlen < m->m_pkthdr.len)
560 m_adj(m, outlen - m->m_pkthdr.len);
561 }
562 d->flushed = (rtn & MPPC_EXPANDED) != 0
563 || (flags & MPPC_SAVE_HISTORY) == 0;
564
565 if (ina)
566 free(inbuf, M_NETGRAPH_MPPC);
567 free(outbuf, M_NETGRAPH_MPPC);
568
569 /* Check mbuf chain reload result. */
570 if (m == NULL) {
571 if (!d->flushed) {
572 MPPC_InitCompressionHistory(d->history);
573 d->flushed = 1;
574 }
575 return (ENOMEM);
576 }
577 }
578#endif
579
580 /* Now encrypt packet (if encryption enabled) */
581#ifdef NETGRAPH_MPPC_ENCRYPTION
582 if ((d->cfg.bits & MPPE_BITS) != 0) {
583 struct mbuf *m1;
584
585 /* Set header bits */
587
588 /* Update key if it's time */
589 if ((d->cfg.bits & MPPE_STATELESS) != 0
590 || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) {
591 ng_mppc_updatekey(d->cfg.bits,
592 d->cfg.startkey, d->key, &d->rc4);
593 } else if ((header & MPPC_FLAG_FLUSHED) != 0) {
594 /* Need to reset key if we say we did
595 and ng_mppc_updatekey wasn't called to do it also. */
596 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
597 }
598
599 /* Encrypt packet */
600 m1 = m;
601 while (m1) {
602 rc4_crypt(&d->rc4, mtod(m1, u_char *),
603 mtod(m1, u_char *), m1->m_len);
604 m1 = m1->m_next;
605 }
606 }
607#endif
608
609 /* Update coherency count for next time (12 bit arithmetic) */
611
612 /* Install header */
613 M_PREPEND(m, MPPC_HDRLEN, M_NOWAIT);
614 if (m != NULL)
615 be16enc(mtod(m, void *), header);
616
617 *datap = m;
618 return (*datap == NULL ? ENOBUFS : 0);
619}
620
621/*
622 * Decompress/decrypt packet and put the result in a new mbuf at *resultp.
623 * The original mbuf is not free'd.
624 */
625static int
626ng_mppc_decompress(node_p node, struct mbuf **datap)
627{
628 const priv_p priv = NG_NODE_PRIVATE(node);
629 struct ng_mppc_dir *const d = &priv->recv;
630 u_int16_t header, cc;
631 u_int numLost;
632 struct mbuf *m = *datap;
633
634 /* We must own the mbuf chain exclusively to modify it. */
635 m = m_unshare(m, M_NOWAIT);
636 if (m == NULL)
637 return (ENOMEM);
638
639 /* Pull off header */
640 if (m->m_pkthdr.len < MPPC_HDRLEN) {
641 m_freem(m);
642 return (EINVAL);
643 }
644 header = be16dec(mtod(m, void *));
645 cc = (header & MPPC_CCOUNT_MASK);
646 m_adj(m, MPPC_HDRLEN);
647
648 /* Check for an unexpected jump in the sequence number */
649 numLost = ((cc - d->cc) & MPPC_CCOUNT_MASK);
650
651 /* If flushed bit set, we can always handle packet */
652 if ((header & MPPC_FLAG_FLUSHED) != 0) {
653#ifdef NETGRAPH_MPPC_COMPRESSION
654 if (d->history != NULL)
655 MPPC_InitDecompressionHistory(d->history);
656#endif
657#ifdef NETGRAPH_MPPC_ENCRYPTION
658 if ((d->cfg.bits & MPPE_BITS) != 0) {
659 u_int rekey;
660
661 /* How many times are we going to have to re-key? */
662 rekey = ((d->cfg.bits & MPPE_STATELESS) != 0) ?
663 numLost : (numLost / (MPPE_UPDATE_MASK + 1));
664 if (rekey > mppe_max_rekey) {
666 if (mppe_log_max_rekey) {
667 log(LOG_ERR, "%s: too many (%d) packets"
668 " dropped, disabling node %p!\n",
669 __func__, numLost, node);
670 }
671 priv->recv.cfg.enable = 0;
672 goto failed;
673 } else {
674 if (mppe_log_max_rekey) {
675 log(LOG_ERR, "%s: %d packets"
676 " dropped, node %p\n",
677 __func__, numLost, node);
678 }
679 goto failed;
680 }
681 }
682
683 /* Re-key as necessary to catch up to peer */
684 while (d->cc != cc) {
685 if ((d->cfg.bits & MPPE_STATELESS) != 0
686 || (d->cc & MPPE_UPDATE_MASK)
687 == MPPE_UPDATE_FLAG) {
688 ng_mppc_updatekey(d->cfg.bits,
689 d->cfg.startkey, d->key, &d->rc4);
690 }
692 }
693
694 /* Reset key (except in stateless mode, see below) */
695 if ((d->cfg.bits & MPPE_STATELESS) == 0)
696 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
697 }
698#endif
699 d->cc = cc; /* skip over lost seq numbers */
700 numLost = 0; /* act like no packets were lost */
701 }
702
703 /* Can't decode non-sequential packets without a flushed bit */
704 if (numLost != 0)
705 goto failed;
706
707 /* Decrypt packet */
708 if ((header & MPPC_FLAG_ENCRYPTED) != 0) {
709#ifdef NETGRAPH_MPPC_ENCRYPTION
710 struct mbuf *m1;
711#endif
712
713 /* Are we not expecting encryption? */
714 if ((d->cfg.bits & MPPE_BITS) == 0) {
715 log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
716 __func__, "encrypted");
717 goto failed;
718 }
719
720#ifdef NETGRAPH_MPPC_ENCRYPTION
721 /* Update key if it's time (always in stateless mode) */
722 if ((d->cfg.bits & MPPE_STATELESS) != 0
723 || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) {
724 ng_mppc_updatekey(d->cfg.bits,
725 d->cfg.startkey, d->key, &d->rc4);
726 }
727
728 /* Decrypt packet */
729 m1 = m;
730 while (m1 != NULL) {
731 rc4_crypt(&d->rc4, mtod(m1, u_char *),
732 mtod(m1, u_char *), m1->m_len);
733 m1 = m1->m_next;
734 }
735#endif
736 } else {
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) */
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");
753failed:
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 */
841static void
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 */
862static void
863ng_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 */
890static void
891ng_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
uint8_t pad2
Definition: netflow.h:15
uint16_t pad1
Definition: netflow.h:11
uint8_t flags
Definition: netflow.h:14
#define NG_HOOK_NODE(hook)
Definition: netgraph.h:339
#define NG_FREE_M(m)
Definition: netgraph.h:946
int ng_rcvmsg_t(node_p node, item_p item, hook_p lasthook)
Definition: netgraph.h:105
#define NGI_RETADDR(i)
Definition: netgraph.h:835
int ng_disconnect_t(hook_p hook)
Definition: netgraph.h:107
#define NG_NODE_SET_PRIVATE(node, val)
Definition: netgraph.h:608
#define NG_RESPOND_MSG(error, here, item, resp)
Definition: netgraph.h:1025
#define NG_NODE_IS_VALID(node)
Definition: netgraph.h:610
#define NG_NODE_FORCE_WRITER(node)
Definition: netgraph.h:612
#define NG_NODE_UNREF(node)
Definition: netgraph.h:607
int ng_rmnode_self(node_p here)
Definition: ng_base.c:1609
#define NG_FWD_NEW_DATA(error, item, hook, m)
Definition: netgraph.h:914
#define NG_SEND_MSG_ID(error, here, msg, ID, retaddr)
Definition: netgraph.h:990
int ng_rcvdata_t(hook_p hook, item_p item)
Definition: netgraph.h:106
int ng_shutdown_t(node_p node)
Definition: netgraph.h:101
#define NG_FREE_ITEM(item)
Definition: netgraph.h:847
int ng_constructor_t(node_p node)
Definition: netgraph.h:99
#define NGI_GET_M(i, m)
Definition: netgraph.h:852
#define NG_FREE_MSG(msg)
Definition: netgraph.h:938
#define NG_ABI_VERSION
Definition: netgraph.h:77
#define NG_NODE_NUMHOOKS(node)
Definition: netgraph.h:615
#define NGI_GET_MSG(i, m)
Definition: netgraph.h:858
#define NG_NODE_PRIVATE(node)
Definition: netgraph.h:609
int ng_newhook_t(node_p node, hook_p hook, const char *name)
Definition: netgraph.h:102
MODULE_DEPEND(ng_ccatm, ngatmbase, 1, 1, 1)
MALLOC_DEFINE(M_NG_CCATM, "ng_ccatm", "netgraph uni api node")
#define ng_ID_t
Definition: ng_message.h:104
#define NG_MKMESSAGE(msg, cookie, cmdid, len, how)
Definition: ng_message.h:378
#define MPPE_UPDATE_MASK
Definition: ng_mppc.c:134
#define MPPC_DECOMP_SAFETY
Definition: ng_mppc.c:93
static ng_rcvmsg_t ng_mppc_rcvmsg
Definition: ng_mppc.c:165
static void ng_mppc_reset_req(node_p node)
Definition: ng_mppc.c:842
#define MPPC_FLAG_FLUSHED
Definition: ng_mppc.c:126
#define MPPC_CCOUNT_INC(d)
Definition: ng_mppc.c:132
static ng_shutdown_t ng_mppc_shutdown
Definition: ng_mppc.c:166
static ng_constructor_t ng_mppc_constructor
Definition: ng_mppc.c:164
#define MPPE_UPDATE_FLAG
Definition: ng_mppc.c:135
#define MPPC_DECOMP_BUFSIZE
Definition: ng_mppc.c:92
#define ERROUT(x)
Definition: ng_mppc.c:204
static ng_disconnect_t ng_mppc_disconnect
Definition: ng_mppc.c:169
#define MPPC_COMP_OK
Definition: ng_mppc.c:137
static int ng_mppc_compress(node_p node, struct mbuf **datap)
Definition: ng_mppc.c:477
static int mppe_max_rekey
Definition: ng_mppc.c:121
#define MPPC_DECOMP_OK
Definition: ng_mppc.c:138
#define MPPC_CCOUNT_MASK
Definition: ng_mppc.c:130
SYSCTL_NODE(_net_graph, OID_AUTO, mppe, CTLFLAG_RW|CTLFLAG_MPSAFE, 0, "MPPE")
#define MPPC_FLAG_ENCRYPTED
Definition: ng_mppc.c:129
static int mppe_block_on_max_rekey
Definition: ng_mppc.c:113
static struct ng_type ng_mppc_typestruct
Definition: ng_mppc.c:184
NETGRAPH_INIT(mppc, &ng_mppc_typestruct)
#define KEYLEN(b)
Definition: ng_mppc.c:99
#define MPPC_FLAG_COMPRESSED
Definition: ng_mppc.c:128
#define M_NETGRAPH_MPPC
Definition: ng_mppc.c:80
SYSCTL_INT(_net_graph_mppe, OID_AUTO, block_on_max_rekey, CTLFLAG_RWTUN, &mppe_block_on_max_rekey, 0, "Block node on max MPPE key re-calculations")
static const u_char ng_mppe_weakenkey[3]
Definition: ng_mppc.c:202
#define MPPC_FLAG_RESTART
Definition: ng_mppc.c:127
struct ng_mppc_private * priv_p
Definition: ng_mppc.c:161
static ng_newhook_t ng_mppc_newhook
Definition: ng_mppc.c:167
#define MPPE_MAX_REKEY
Definition: ng_mppc.c:108
static int mppe_log_max_rekey
Definition: ng_mppc.c:117
static ng_rcvdata_t ng_mppc_rcvdata
Definition: ng_mppc.c:168
static int ng_mppc_decompress(node_p node, struct mbuf **datap)
Definition: ng_mppc.c:626
#define MPPC_HDRLEN
Definition: ng_mppc.c:96
#define MPPE_BITS
Definition: ng_mppc.h:66
#define MPPC_MAX_BLOWUP(n)
Definition: ng_mppc.h:59
#define NGM_MPPC_COOKIE
Definition: ng_mppc.h:49
#define NG_MPPC_HOOK_DECOMP
Definition: ng_mppc.h:53
#define NG_MPPC_HOOK_COMP
Definition: ng_mppc.h:52
#define MPPC_BIT
Definition: ng_mppc.h:62
#define MPPC_VALID_BITS
Definition: ng_mppc.h:68
#define MPPE_40
Definition: ng_mppc.h:63
#define MPPE_KEY_LEN
Definition: ng_mppc.h:56
#define MPPE_56
Definition: ng_mppc.h:64
#define MPPE_STATELESS
Definition: ng_mppc.h:67
#define NG_MPPC_NODE_TYPE
Definition: ng_mppc.h:48
@ NGM_MPPC_CONFIG_COMP
Definition: ng_mppc.h:79
@ NGM_MPPC_RESETREQ
Definition: ng_mppc.h:81
@ NGM_MPPC_CONFIG_DECOMP
Definition: ng_mppc.h:80
char *const name
Definition: ng_ppp.c:261
struct ubt_hci_evhdr header
Definition: ng_ubt_var.h:0
u_int32_t arglen
Definition: ng_message.h:62
u_int32_t typecookie
Definition: ng_message.h:66
struct ng_mesg::ng_msghdr header
char data[]
Definition: ng_message.h:69
u_char startkey[MPPE_KEY_LEN]
Definition: ng_mppc.h:74
u_int32_t bits
Definition: ng_mppc.h:73
u_char enable
Definition: ng_mppc.h:72
u_char flushed
Definition: ng_mppc.c:145
u_int16_t cc
Definition: ng_mppc.c:144
hook_p hook
Definition: ng_mppc.c:143
struct ng_mppc_config cfg
Definition: ng_mppc.c:142
ng_ID_t ctrlnode
Definition: ng_mppc.c:159
struct ng_mppc_dir xmit
Definition: ng_mppc.c:157
struct ng_mppc_dir recv
Definition: ng_mppc.c:158
u_int32_t version
Definition: netgraph.h:1077
Definition: ng_sscfu.c:66