📄 ccp.c
字号:
/* * ccp.c - PPP Compression Control Protocol. * * Copyright (c) 1994-2002 Paul Mackerras. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. The name(s) of the authors of this software must not be used to * endorse or promote products derived from this software without * prior written permission. * * 3. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by Paul Mackerras * <paulus@samba.org>". * * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */#define RCSID "$Id: ccp.c,v 1.50 2005/06/26 19:34:41 carlsonj Exp $"#include <stdlib.h>#include <string.h>#include "pppd.h"#include "fsm.h"#include "ccp.h"#include <net/ppp-comp.h>#ifdef MPPE#include "chap_ms.h" /* mppe_xxxx_key, mppe_keys_set */#include "lcp.h" /* lcp_close(), lcp_fsm */#endifstatic const char rcsid[] = RCSID;/* * Unfortunately there is a bug in zlib which means that using a * size of 8 (window size = 256) for Deflate compression will cause * buffer overruns and kernel crashes in the deflate module. * Until this is fixed we only accept sizes in the range 9 .. 15. * Thanks to James Carlson for pointing this out. */#define DEFLATE_MIN_WORKS 9/* * Command-line options. */static int setbsdcomp __P((char **));static int setdeflate __P((char **));static char bsd_value[8];static char deflate_value[8];/* * Option variables. */#ifdef MPPEbool refuse_mppe_stateful = 1; /* Allow stateful mode? */#endifstatic option_t ccp_option_list[] = { { "noccp", o_bool, &ccp_protent.enabled_flag, "Disable CCP negotiation" }, { "-ccp", o_bool, &ccp_protent.enabled_flag, "Disable CCP negotiation", OPT_ALIAS }, { "bsdcomp", o_special, (void *)setbsdcomp, "Request BSD-Compress packet compression", OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, bsd_value }, { "nobsdcomp", o_bool, &ccp_wantoptions[0].bsd_compress, "don't allow BSD-Compress", OPT_PRIOSUB | OPT_A2CLR, &ccp_allowoptions[0].bsd_compress }, { "-bsdcomp", o_bool, &ccp_wantoptions[0].bsd_compress, "don't allow BSD-Compress", OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR, &ccp_allowoptions[0].bsd_compress }, { "deflate", o_special, (void *)setdeflate, "request Deflate compression", OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, deflate_value }, { "nodeflate", o_bool, &ccp_wantoptions[0].deflate, "don't allow Deflate compression", OPT_PRIOSUB | OPT_A2CLR, &ccp_allowoptions[0].deflate }, { "-deflate", o_bool, &ccp_wantoptions[0].deflate, "don't allow Deflate compression", OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR, &ccp_allowoptions[0].deflate }, { "nodeflatedraft", o_bool, &ccp_wantoptions[0].deflate_draft, "don't use draft deflate #", OPT_A2COPY, &ccp_allowoptions[0].deflate_draft }, { "predictor1", o_bool, &ccp_wantoptions[0].predictor_1, "request Predictor-1", OPT_PRIO | 1 }, { "nopredictor1", o_bool, &ccp_wantoptions[0].predictor_1, "don't allow Predictor-1", OPT_PRIOSUB | OPT_A2CLR, &ccp_allowoptions[0].predictor_1 }, { "-predictor1", o_bool, &ccp_wantoptions[0].predictor_1, "don't allow Predictor-1", OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR, &ccp_allowoptions[0].predictor_1 },#ifdef MPPE /* MPPE options are symmetrical ... we only set wantoptions here */ { "require-mppe", o_bool, &ccp_wantoptions[0].mppe, "require MPPE encryption", OPT_PRIO | MPPE_OPT_40 | MPPE_OPT_128 }, { "+mppe", o_bool, &ccp_wantoptions[0].mppe, "require MPPE encryption", OPT_ALIAS | OPT_PRIO | MPPE_OPT_40 | MPPE_OPT_128 }, { "nomppe", o_bool, &ccp_wantoptions[0].mppe, "don't allow MPPE encryption", OPT_PRIO }, { "-mppe", o_bool, &ccp_wantoptions[0].mppe, "don't allow MPPE encryption", OPT_ALIAS | OPT_PRIO }, /* We use ccp_allowoptions[0].mppe as a junk var ... it is reset later */ { "require-mppe-40", o_bool, &ccp_allowoptions[0].mppe, "require MPPE 40-bit encryption", OPT_PRIO | OPT_A2OR | MPPE_OPT_40, &ccp_wantoptions[0].mppe }, { "+mppe-40", o_bool, &ccp_allowoptions[0].mppe, "require MPPE 40-bit encryption", OPT_PRIO | OPT_A2OR | MPPE_OPT_40, &ccp_wantoptions[0].mppe }, { "nomppe-40", o_bool, &ccp_allowoptions[0].mppe, "don't allow MPPE 40-bit encryption", OPT_PRIOSUB | OPT_A2CLRB | MPPE_OPT_40, &ccp_wantoptions[0].mppe }, { "-mppe-40", o_bool, &ccp_allowoptions[0].mppe, "don't allow MPPE 40-bit encryption", OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLRB | MPPE_OPT_40, &ccp_wantoptions[0].mppe }, { "require-mppe-128", o_bool, &ccp_allowoptions[0].mppe, "require MPPE 128-bit encryption", OPT_PRIO | OPT_A2OR | MPPE_OPT_128, &ccp_wantoptions[0].mppe }, { "+mppe-128", o_bool, &ccp_allowoptions[0].mppe, "require MPPE 128-bit encryption", OPT_ALIAS | OPT_PRIO | OPT_A2OR | MPPE_OPT_128, &ccp_wantoptions[0].mppe }, { "nomppe-128", o_bool, &ccp_allowoptions[0].mppe, "don't allow MPPE 128-bit encryption", OPT_PRIOSUB | OPT_A2CLRB | MPPE_OPT_128, &ccp_wantoptions[0].mppe }, { "-mppe-128", o_bool, &ccp_allowoptions[0].mppe, "don't allow MPPE 128-bit encryption", OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLRB | MPPE_OPT_128, &ccp_wantoptions[0].mppe }, /* strange one; we always request stateless, but will we allow stateful? */ { "mppe-stateful", o_bool, &refuse_mppe_stateful, "allow MPPE stateful mode", OPT_PRIO }, { "nomppe-stateful", o_bool, &refuse_mppe_stateful, "disallow MPPE stateful mode", OPT_PRIO | 1 },#endif /* MPPE */ { NULL }};/* * Protocol entry points from main code. */static void ccp_init __P((int unit));static void ccp_open __P((int unit));static void ccp_close __P((int unit, char *));static void ccp_lowerup __P((int unit));static void ccp_lowerdown __P((int));static void ccp_input __P((int unit, u_char *pkt, int len));static void ccp_protrej __P((int unit));static int ccp_printpkt __P((u_char *pkt, int len, void (*printer) __P((void *, char *, ...)), void *arg));static void ccp_datainput __P((int unit, u_char *pkt, int len));struct protent ccp_protent = { PPP_CCP, ccp_init, ccp_input, ccp_protrej, ccp_lowerup, ccp_lowerdown, ccp_open, ccp_close, ccp_printpkt, ccp_datainput, 1, "CCP", "Compressed", ccp_option_list, NULL, NULL, NULL};fsm ccp_fsm[NUM_PPP];ccp_options ccp_wantoptions[NUM_PPP]; /* what to request the peer to use */ccp_options ccp_gotoptions[NUM_PPP]; /* what the peer agreed to do */ccp_options ccp_allowoptions[NUM_PPP]; /* what we'll agree to do */ccp_options ccp_hisoptions[NUM_PPP]; /* what we agreed to do *//* * Callbacks for fsm code. */static void ccp_resetci __P((fsm *));static int ccp_cilen __P((fsm *));static void ccp_addci __P((fsm *, u_char *, int *));static int ccp_ackci __P((fsm *, u_char *, int));static int ccp_nakci __P((fsm *, u_char *, int, int));static int ccp_rejci __P((fsm *, u_char *, int));static int ccp_reqci __P((fsm *, u_char *, int *, int));static void ccp_up __P((fsm *));static void ccp_down __P((fsm *));static int ccp_extcode __P((fsm *, int, int, u_char *, int));static void ccp_rack_timeout __P((void *));static char *method_name __P((ccp_options *, ccp_options *));static fsm_callbacks ccp_callbacks = { ccp_resetci, ccp_cilen, ccp_addci, ccp_ackci, ccp_nakci, ccp_rejci, ccp_reqci, ccp_up, ccp_down, NULL, NULL, NULL, NULL, ccp_extcode, "CCP"};/* * Do we want / did we get any compression? */#define ANY_COMPRESS(opt) ((opt).deflate || (opt).bsd_compress \ || (opt).predictor_1 || (opt).predictor_2 \ || (opt).mppe)/* * Local state (mainly for handling reset-reqs and reset-acks). */static int ccp_localstate[NUM_PPP];#define RACK_PENDING 1 /* waiting for reset-ack */#define RREQ_REPEAT 2 /* send another reset-req if no reset-ack */#define RACKTIMEOUT 1 /* second */static int all_rejected[NUM_PPP]; /* we rejected all peer's options *//* * Option parsing. */static intsetbsdcomp(argv) char **argv;{ int rbits, abits; char *str, *endp; str = *argv; abits = rbits = strtol(str, &endp, 0); if (endp != str && *endp == ',') { str = endp + 1; abits = strtol(str, &endp, 0); } if (*endp != 0 || endp == str) { option_error("invalid parameter '%s' for bsdcomp option", *argv); return 0; } if ((rbits != 0 && (rbits < BSD_MIN_BITS || rbits > BSD_MAX_BITS)) || (abits != 0 && (abits < BSD_MIN_BITS || abits > BSD_MAX_BITS))) { option_error("bsdcomp option values must be 0 or %d .. %d", BSD_MIN_BITS, BSD_MAX_BITS); return 0; } if (rbits > 0) { ccp_wantoptions[0].bsd_compress = 1; ccp_wantoptions[0].bsd_bits = rbits; } else ccp_wantoptions[0].bsd_compress = 0; if (abits > 0) { ccp_allowoptions[0].bsd_compress = 1; ccp_allowoptions[0].bsd_bits = abits; } else ccp_allowoptions[0].bsd_compress = 0; slprintf(bsd_value, sizeof(bsd_value), rbits == abits? "%d": "%d,%d", rbits, abits); return 1;}static intsetdeflate(argv) char **argv;{ int rbits, abits; char *str, *endp; str = *argv; abits = rbits = strtol(str, &endp, 0); if (endp != str && *endp == ',') { str = endp + 1; abits = strtol(str, &endp, 0); } if (*endp != 0 || endp == str) { option_error("invalid parameter '%s' for deflate option", *argv); return 0; } if ((rbits != 0 && (rbits < DEFLATE_MIN_SIZE || rbits > DEFLATE_MAX_SIZE)) || (abits != 0 && (abits < DEFLATE_MIN_SIZE || abits > DEFLATE_MAX_SIZE))) { option_error("deflate option values must be 0 or %d .. %d", DEFLATE_MIN_SIZE, DEFLATE_MAX_SIZE); return 0; } if (rbits == DEFLATE_MIN_SIZE || abits == DEFLATE_MIN_SIZE) { if (rbits == DEFLATE_MIN_SIZE) rbits = DEFLATE_MIN_WORKS; if (abits == DEFLATE_MIN_SIZE) abits = DEFLATE_MIN_WORKS; warn("deflate option value of %d changed to %d to avoid zlib bug", DEFLATE_MIN_SIZE, DEFLATE_MIN_WORKS); } if (rbits > 0) { ccp_wantoptions[0].deflate = 1; ccp_wantoptions[0].deflate_size = rbits; } else ccp_wantoptions[0].deflate = 0; if (abits > 0) { ccp_allowoptions[0].deflate = 1; ccp_allowoptions[0].deflate_size = abits; } else ccp_allowoptions[0].deflate = 0; slprintf(deflate_value, sizeof(deflate_value), rbits == abits? "%d": "%d,%d", rbits, abits); return 1;}/* * ccp_init - initialize CCP. */static voidccp_init(unit) int unit;{ fsm *f = &ccp_fsm[unit]; f->unit = unit; f->protocol = PPP_CCP; f->callbacks = &ccp_callbacks; fsm_init(f); memset(&ccp_wantoptions[unit], 0, sizeof(ccp_options)); memset(&ccp_gotoptions[unit], 0, sizeof(ccp_options)); memset(&ccp_allowoptions[unit], 0, sizeof(ccp_options)); memset(&ccp_hisoptions[unit], 0, sizeof(ccp_options)); ccp_wantoptions[0].deflate = 1; ccp_wantoptions[0].deflate_size = DEFLATE_MAX_SIZE; ccp_wantoptions[0].deflate_correct = 1; ccp_wantoptions[0].deflate_draft = 1; ccp_allowoptions[0].deflate = 1; ccp_allowoptions[0].deflate_size = DEFLATE_MAX_SIZE; ccp_allowoptions[0].deflate_correct = 1; ccp_allowoptions[0].deflate_draft = 1; ccp_wantoptions[0].bsd_compress = 1; ccp_wantoptions[0].bsd_bits = BSD_MAX_BITS; ccp_allowoptions[0].bsd_compress = 1; ccp_allowoptions[0].bsd_bits = BSD_MAX_BITS; ccp_allowoptions[0].predictor_1 = 1;}/* * ccp_open - CCP is allowed to come up. */static voidccp_open(unit) int unit;{ fsm *f = &ccp_fsm[unit]; if (f->state != OPENED) ccp_flags_set(unit, 1, 0); /* * Find out which compressors the kernel supports before * deciding whether to open in silent mode. */ ccp_resetci(f); if (!ANY_COMPRESS(ccp_gotoptions[unit])) f->flags |= OPT_SILENT; fsm_open(f);}/* * ccp_close - Terminate CCP. */static voidccp_close(unit, reason) int unit; char *reason;{ ccp_flags_set(unit, 0, 0); fsm_close(&ccp_fsm[unit], reason);}/* * ccp_lowerup - we may now transmit CCP packets. */static voidccp_lowerup(unit) int unit;{ fsm_lowerup(&ccp_fsm[unit]);}/* * ccp_lowerdown - we may not transmit CCP packets. */static voidccp_lowerdown(unit) int unit;{ fsm_lowerdown(&ccp_fsm[unit]);}/* * ccp_input - process a received CCP packet. */static voidccp_input(unit, p, len) int unit; u_char *p; int len;{ fsm *f = &ccp_fsm[unit]; int oldstate; /* * Check for a terminate-request so we can print a message. */ oldstate = f->state; fsm_input(f, p, len); if (oldstate == OPENED && p[0] == TERMREQ && f->state != OPENED) { notice("Compression disabled by peer.");#ifdef MPPE if (ccp_gotoptions[unit].mppe) { error("MPPE disabled, closing LCP"); lcp_close(unit, "MPPE disabled by peer"); }#endif } /* * If we get a terminate-ack and we're not asking for compression, * close CCP. */ if (oldstate == REQSENT && p[0] == TERMACK && !ANY_COMPRESS(ccp_gotoptions[unit])) ccp_close(unit, "No compression negotiated");}/* * Handle a CCP-specific code. */static intccp_extcode(f, code, id, p, len) fsm *f; int code, id; u_char *p; int len;{ switch (code) { case CCP_RESETREQ: if (f->state != OPENED) break; /* send a reset-ack, which the transmitter will see and reset its compression state. */ fsm_sdata(f, CCP_RESETACK, id, NULL, 0); break; case CCP_RESETACK: if (ccp_localstate[f->unit] & RACK_PENDING && id == f->reqid) { ccp_localstate[f->unit] &= ~(RACK_PENDING | RREQ_REPEAT); UNTIMEOUT(ccp_rack_timeout, f); } break; default: return 0; } return 1;}/* * ccp_protrej - peer doesn't talk CCP. */static voidccp_protrej(unit) int unit;{ ccp_flags_set(unit, 0, 0); fsm_lowerdown(&ccp_fsm[unit]);#ifdef MPPE if (ccp_gotoptions[unit].mppe) { error("MPPE required but peer negotiation failed"); lcp_close(unit, "MPPE required but peer negotiation failed"); }#endif}/* * ccp_resetci - initialize at start of negotiation. */static voidccp_resetci(f) fsm *f;{ ccp_options *go = &ccp_gotoptions[f->unit]; u_char opt_buf[CCP_MAX_OPTION_LENGTH]; *go = ccp_wantoptions[f->unit]; all_rejected[f->unit] = 0;#ifdef MPPE if (go->mppe) { ccp_options *ao = &ccp_allowoptions[f->unit]; int auth_mschap_bits = auth_done[f->unit]; int numbits; /* * Start with a basic sanity check: mschap[v2] auth must be in * exactly one direction. RFC 3079 says that the keys are * 'derived from the credentials of the peer that initiated the call', * however the PPP protocol doesn't have such a concept, and pppd * cannot get this info externally. Instead we do the best we can. * NB: If MPPE is required, all other compression opts are invalid. * So, we return right away if we can't do it. */ /* Leave only the mschap auth bits set */ auth_mschap_bits &= (CHAP_MS_WITHPEER | CHAP_MS_PEER | CHAP_MS2_WITHPEER | CHAP_MS2_PEER); /* Count the mschap auths */ auth_mschap_bits >>= CHAP_MS_SHIFT; numbits = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -