diff --git a/docs/src/html/manual.md b/docs/src/html/manual.md index cff4b6a..6fbccf7 100644 --- a/docs/src/html/manual.md +++ b/docs/src/html/manual.md @@ -159,6 +159,18 @@ should be set by a line like: set configstring \"value\" set ipaddress : PPP counter and timer values, as described in ยง4.1 of [RFC1661](ftp://ftp.rfc-editor.org/in-notes/rfc1661.txt). +`lcp_renegotiation` (string) + +: By default (`always`), we renegotiate LCP even if the LAC already did with + the client. + + We can avoid the LCP renegotiation (proxy LCP negotiation), unless what was + already negotiated is not fine for us (`on-mismatch`). To be noted: we will + accept not using our preferred RADIUS authentication method. + This is notably useful when the LAC cannot pass LCP configuration through, + and thus we have to try to accept what was already negotiated by the LAC + with the client. + `primary_dns` (ip address); `econdary_dns` (ip address) : Whenever a PPP connection is established, DNS servers will be sent diff --git a/l2tplac.c b/l2tplac.c index 2af1570..8347d55 100644 --- a/l2tplac.c +++ b/l2tplac.c @@ -60,11 +60,11 @@ * LNS1 --------------------> LNS2 (Session Open) * ZLB * LNS1 <-------------------- LNS2 (Session Open) - * LCP Negotiation + * LCP Renegotiation (unless proxied) * Client <------------------------------------------------------------------------> LNS2 - * PAP/CHAP Authentification + * PAP (Ack only if proxied) / CHAP Authentification * Client <------------------------------------------------------------------------> LNS2 - * DATA (ppp) + * DATA (ppp) * Client <------------------------------------------------------------------------> LNS2 * */ diff --git a/l2tpns.c b/l2tpns.c index 203fc40..4423df8 100644 --- a/l2tpns.c +++ b/l2tpns.c @@ -159,6 +159,7 @@ config_descriptt config_values[] = { CONFIG("ppp_max_configure", ppp_max_configure, INT), CONFIG("ppp_max_failure", ppp_max_failure, INT), CONFIG("ppp_keepalive", ppp_keepalive, BOOL), + CONFIG("lcp_renegotiation", lcp_renegotiation, STRING), CONFIG("primary_dns", default_dns1, IPv4), CONFIG("secondary_dns", default_dns2, IPv4), CONFIG("primary_radius", radiusserver[0], IPv4), @@ -4184,9 +4185,18 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr, uint16_t indexu uint16_t message = 0xFFFF; // message type uint8_t fatal = 0; uint8_t mandatory = 0; + uint8_t *last_sent_lcp_confreq = 0; + uint16_t last_sent_lcp_confreq_n = 0; + uint8_t *last_received_lcp_confreq = 0; + uint16_t last_received_lcp_confreq_n = 0; + uint16_t atype = 0; + uint16_t authid = 0; + char authname[MAXUSER] = ""; + char authchall[MAXPASS] = ""; + size_t authchalln = 0; + char authresp[MAXPASS] = ""; + size_t authrespn = 0; uint16_t asession = 0; // assigned session - uint32_t amagic = 0; // magic number - uint8_t aflags = 0; // flags from last LCF uint16_t version = 0x0100; // protocol version (we handle 0.0 as well and send that back just in case) char called[MAXTEL] = ""; // called number char calling[MAXTEL] = ""; // calling number @@ -4663,50 +4673,70 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr, uint16_t indexu } case 29: // Proxy Authentication Type { - uint16_t atype = ntohs(*(uint16_t *)b); + atype = ntohs(*(uint16_t *)b); LOG(4, s, t, " Proxy Auth Type %u (%s)\n", atype, ppp_auth_type(atype)); break; } case 30: // Proxy Authentication Name { - char authname[64]; memset(authname, 0, sizeof(authname)); memcpy(authname, b, (n < sizeof(authname)) ? n : sizeof(authname) - 1); - LOG(4, s, t, " Proxy Auth Name (%s)\n", - authname); + if (n < sizeof(authname)) + { + LOG(4, s, t, " Proxy Auth Name (%s)\n", authname); + } + else + { + LOG(2, s, t, " Proxy Auth Name too long (%s)\n", authname); + } break; } case 31: // Proxy Authentication Challenge { - LOG(4, s, t, " Proxy Auth Challenge\n"); + if (n <= sizeof(authchall)) + { + memcpy(authchall, b, n); + authchalln = n; + LOG(4, s, t, " Proxy Auth Challenge\n"); + } + else + { + LOG(2, s, t, " Proxy Auth Challenge too long\n"); + } break; } case 32: // Proxy Authentication ID { - uint16_t authid = ntohs(*(uint16_t *)(b)); + authid = ntohs(*(uint16_t *)(b)); LOG(4, s, t, " Proxy Auth ID (%u)\n", authid); break; } case 33: // Proxy Authentication Response - LOG(4, s, t, " Proxy Auth Response\n"); - break; - case 27: // last sent lcp - { // find magic number - uint8_t *p = b, *e = p + n; - while (p + 1 < e && p[1] && p + p[1] <= e) + { + if (n <= sizeof(authresp)) { - if (*p == 5 && p[1] == 6) // Magic-Number - amagic = ntohl(*(uint32_t *) (p + 2)); - else if (*p == 7) // Protocol-Field-Compression - aflags |= SESSION_PFC; - else if (*p == 8) // Address-and-Control-Field-Compression - aflags |= SESSION_ACFC; - p += p[1]; + memcpy(authresp, b, n); + authrespn = n; + LOG(4, s, t, " Proxy Auth Response\n"); } + else + { + LOG(2, s, t, " Proxy Auth Response too long\n"); + } + break; + } + case 27: // last sent lcp + { + last_sent_lcp_confreq = b; + last_sent_lcp_confreq_n = n; + break; } - break; case 28: // last recv lcp confreq - break; + { + last_received_lcp_confreq = b; + last_received_lcp_confreq_n = n; + break; + } case 26: // Initial Received LCP CONFREQ break; case 39: // seq required - we control it as an LNS anyway... @@ -5017,9 +5047,8 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr, uint16_t indexu break; case 12: // ICCN LOG(3, s, t, "Received ICCN\n"); - if (amagic == 0) amagic = time_now; - session[s].magic = amagic; // set magic number - session[s].flags = aflags; // set flags received + + session[s].magic = time_now; // set magic number session[s].mru = PPPoE_MRU; // default controlnull(t); // ack @@ -5034,8 +5063,39 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr, uint16_t indexu else sess_local[s].mp_epdis = 0; - sendlcp(s, t); - change_state(s, lcp, RequestSent); + if (last_sent_lcp_confreq_n && last_received_lcp_confreq_n && + processlcpproxy(s, t, last_sent_lcp_confreq, last_sent_lcp_confreq_n, + last_received_lcp_confreq, last_received_lcp_confreq_n) + && ( (sess_local[s].lcp_authtype == 0) + || (sess_local[s].lcp_authtype == AUTHPAP && authrespn) + || (sess_local[s].lcp_authtype == AUTHCHAP && authchalln == 16 && authrespn == 16))) + { + // Could reuse the LCP negotiation and don't have empty proxy auth response or unknown challenge size, don't renegotiate + LOG(3, s, t, "Reusing LCP negotiation\n"); + // Start with proxy auth id to avoid client caching challenge responses + sess_local[s].auth_id = authid; + + if (!sess_local[s].lcp_authtype) + { + // No auth, open immediately + lcp_open(s, t); + } + else + { + // Process auth + session[s].ppp.phase = Authenticate; + change_state(s, lcp, Opened); + processauthproxy(s, t, atype, authname, authchalln, authchall, authrespn, authresp); + } + } + else + { + // Have to renegotiate LCP + LOG(3, s, t, "Renegotiating LCP\n"); + sendlcp(s, t); + change_state(s, lcp, RequestSent); + } + break; case 14: // CDN @@ -7446,6 +7506,16 @@ static void update_config() MSS = MRU - TCP_HDRS; MSS6 = MRU - TCP6_HDRS; + if (!config->lcp_renegotiation[0]) + strcpy(config->lcp_renegotiation, "always"); + + if (strcmp(config->lcp_renegotiation, "always") && + strcmp(config->lcp_renegotiation, "on-mismatch")) + { + LOG(0, 0, 0, "Invalid LCP renegotiation type %s, assuming 'always'\n", config->lcp_renegotiation); + strcpy(config->lcp_renegotiation, "always"); + } + // Update radius config->numradiusservers = 0; for (i = 0; i < MAXRADSERVER; i++) diff --git a/l2tpns.h b/l2tpns.h index 39cdb3c..04a6f11 100644 --- a/l2tpns.h +++ b/l2tpns.h @@ -756,6 +756,7 @@ typedef struct int ppp_max_configure; // max lcp configure requests to send int ppp_max_failure; // max lcp configure naks to send int ppp_keepalive; // send echoes regardless + char lcp_renegotiation[12]; // LCP renegotiation (always or on-mismatch) char radiussecret[64]; char radius_require_message_authenticator[5]; @@ -992,6 +993,8 @@ void processchap(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l); void lcp_open(sessionidt s, tunnelidt t); void lcp_restart(sessionidt s); void processlcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l); +int processlcpproxy(sessionidt s, tunnelidt t, uint8_t *sent_lcp, uint16_t sent_lcp_n, uint8_t *received_lcp, uint16_t received_lcp_n); +int processauthproxy(sessionidt s, tunnelidt t, uint16_t authtype, const char *authname, size_t authchalln, const char authchall[authchalln], size_t authrespn, const char authresp[authrespn]); void processipcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l); void processipv6cp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l); void processipin(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l); diff --git a/ppp.c b/ppp.c index a7d8a2b..eed07b6 100644 --- a/ppp.c +++ b/ppp.c @@ -556,6 +556,437 @@ static void ppp_code_rej(sessionidt s, tunnelidt t, uint16_t proto, tunnelsend(buf, l + (q - buf), t); } +// Process received LCP options from o from packet p. +// Set changed to 1 if we changed configuration that should be sent to cluster slaves, fill response on nak or rej +static void processreceivedlcpconfreq(sessionidt s, tunnelidt t, uint8_t *p, uint8_t *o, uint16_t x, int *changed, uint8_t **response) +{ + static uint8_t asyncmap[4] = { 0, 0, 0, 0 }; // all zero + static uint8_t authproto[5]; + uint8_t b[MAXETHER]; + uint8_t *q = NULL; + + while (x > 2) + { + int type = o[0]; + int length = o[1]; + + if (length == 0 || length == 1 || type == 0 || x < length) break; + switch (type) + { + case 1: // Maximum-Receive-Unit + { + uint16_t mru = ntohs(*(uint16_t *)(o + 2)); + if (mru >= MINMTU) + { + session[s].mru = mru; + (*changed)++; + break; + } + + LOG(3, s, t, " Remote requesting MRU of %u. Rejecting.\n", mru); + mru = htons(MRU); + q = ppp_conf_nak(s, b, sizeof(b), PPPLCP, response, q, p, o, (uint8_t *) &mru, sizeof(mru)); + } + break; + + case 2: // Async-Control-Character-Map + if (!ntohl(*(uint32_t *)(o + 2))) // all bits zero is OK + break; + + LOG(3, s, t, " Remote requesting asyncmap. Rejecting.\n"); + q = ppp_conf_nak(s, b, sizeof(b), PPPLCP, response, q, p, o, asyncmap, sizeof(asyncmap)); + break; + + case 3: // Authentication-Protocol + { + int proto = ntohs(*(uint16_t *)(o + 2)); + char proto_name[] = "0x0000"; + int alen; + + if (proto == PPPPAP) + { + if (config->radius_authtypes & AUTHPAP) + { + sess_local[s].lcp_authtype = AUTHPAP; + break; + } + + strcpy(proto_name, "PAP"); + } + else if (proto == PPPCHAP) + { + if (config->radius_authtypes & AUTHCHAP + && *(o + 4) == 5) // MD5 + { + sess_local[s].lcp_authtype = AUTHCHAP; + break; + } + + strcpy(proto_name, "CHAP"); + } + else + sprintf(proto_name, "%#4.4x", proto); + + LOG(3, s, t, " Remote requesting %s authentication. Rejecting.\n", proto_name); + + alen = add_lcp_auth(authproto, sizeof(authproto), config->radius_authprefer); + if (alen < 2) break; // paranoia + + q = ppp_conf_nak(s, b, sizeof(b), PPPLCP, response, q, p, o, authproto + 2, alen - 2); + if (q && **response == ConfigNak && + config->radius_authtypes != config->radius_authprefer) + { + // alternate type + alen = add_lcp_auth(authproto, sizeof(authproto), config->radius_authtypes & ~config->radius_authprefer); + if (alen < 2) break; + q = ppp_conf_nak(s, b, sizeof(b), PPPLCP, response, q, p, o, authproto + 2, alen - 2); + } + + break; + } + break; + + case 4: // Quality-Protocol + case 5: // Magic-Number + case 7: // Protocol-Field-Compression + case 8: // Address-And-Control-Field-Compression + break; + + case 17: // Multilink Max-Receive-Reconstructed-Unit + { + uint16_t mrru = ntohs(*(uint16_t *)(o + 2)); + session[s].mrru = mrru; + (*changed)++; + LOG(3, s, t, " Received PPP LCP option MRRU: %d\n",mrru); + } + break; + + case 18: // Multilink Short Sequence Number Header Format + { + session[s].mssf = 1; + (*changed)++; + LOG(3, s, t, " Received PPP LCP option MSSN format\n"); + } + break; + + case 19: // Multilink Endpoint Discriminator + { + uint8_t epdis_class = o[2]; + int addr; + + session[s].epdis.addr_class = epdis_class; + session[s].epdis.length = length - 3; + if (session[s].epdis.length > 20) + { + LOG(1, s, t, "Error: received EndDis Address Length more than 20: %d\n", session[s].epdis.length); + session[s].epdis.length = 20; + } + + for (addr = 0; addr < session[s].epdis.length; addr++) + session[s].epdis.address[addr] = o[3+addr]; + + (*changed)++; + + switch (epdis_class) + { + case LOCALADDR: + LOG(3, s, t, " Received PPP LCP option Multilink EndDis Local Address Class: %d\n",epdis_class); + break; + case IPADDR: + LOG(3, s, t, " Received PPP LCP option Multilink EndDis IP Address Class: %d\n",epdis_class); + break; + case IEEEMACADDR: + LOG(3, s, t, " Received PPP LCP option Multilink EndDis IEEE MAC Address Class: %d\n",epdis_class); + break; + case PPPMAGIC: + LOG(3, s, t, " Received PPP LCP option Multilink EndDis PPP Magic No Class: %d\n",epdis_class); + break; + case PSNDN: + LOG(3, s, t, " Received PPP LCP option Multilink EndDis PSND No Class: %d\n",epdis_class); + break; + default: + LOG(3, s, t, " Received PPP LCP option Multilink EndDis NULL Class %d\n",epdis_class); + } + } + break; + + default: // Reject any unknown options + LOG(3, s, t, " Rejecting unknown PPP LCP option %d\n", type); + q = ppp_conf_rej(s, b, sizeof(b), PPPLCP, response, q, p, o); + } + x -= length; + o += length; + } +} + +// Process sent LCP options from o +// Set changed to 1 if we changed configuration that should be sent to cluster slaves +static int processsentlcpconfreq(sessionidt s, tunnelidt t, uint8_t *p, uint8_t *o, uint16_t x, int *changed) +{ + int auth = 0; + int ok = 1; + + while (x > 2) + { + int type = o[0]; + int length = o[1]; + + if (length == 0 || length == 1 || type == 0 || x < length) break; + switch (type) + { + case 1: // Maximum-Receive-Unit + { + uint16_t mru = ntohs(*(uint16_t *)(o + 2)); + if (mru >= MINMTU) + { + sess_local[s].ppp_mru = mru; + break; + } + + ok = 0; + break; + } + + case 2: // Async-Control-Character-Map + if (ntohl(*(uint32_t *)(o + 2))) + ok = 0; + break; + + case 3: // Authentication-Protocol + { + int proto = ntohs(*(uint16_t *)(o + 2)); + + if (proto == PPPPAP) + { + if (config->radius_authtypes & AUTHPAP) + { + auth = sess_local[s].lcp_authtype = AUTHPAP; + break; + } + ok = 0; + } + else if (proto == PPPCHAP) + { + if (config->radius_authtypes & AUTHCHAP + && *(o + 4) == 5) // MD5 + { + auth = sess_local[s].lcp_authtype = AUTHCHAP; + break; + } + ok = 0; + } + else + ok = 0; + } + break; + + case 4: // Quality-Protocol + break; + + case 5: // Magic-Number + if (length < 6) break; + session[s].magic = ntohl(*(uint32_t *)(o + 2)); + *changed = 1; + break; + + case 7: // Protocol-Field-Compression + session[s].flags |= SESSION_PFC; + *changed = 1; + break; + case 8: // Address-And-Control-Field-Compression + session[s].flags |= SESSION_ACFC; + *changed = 1; + break; + + case 17: // Multilink Max-Receive-Reconstructed-Unit + sess_local[s].mp_mrru = ntohs(*(uint16_t *)(o + 2)); + break; + + case 18: // Multilink Short Sequence Number Header Format + sess_local[s].mp_mssf = 1; + break; + + case 19: // Multilink Endpoint Discriminator + ok = 0; + break; + + default: // Reject any unknown options + ok = 0; + break; + } + x -= length; + o += length; + } + + if (!ok) + // Return after taking note of magic and flags + return 0; + + if (sess_local[s].lcp_authtype && !auth) + // We do want authentication, we have to check with client + return 0; + + if (sess_local[s].mp_epdis) + // We do want Endpoint Discriminator + return 0; + + return 1; +} + +// Try to use LCP proxy to avoid renegotiating it (in case the LAC doesn't support passing LCP through) +int processlcpproxy(sessionidt s, tunnelidt t, uint8_t *sent_lcp, uint16_t sent_lcp_n, uint8_t *received_lcp, uint16_t received_lcp_n) +{ + uint8_t *response = 0; + int changed = 0; + + if (!strcmp(config->lcp_renegotiation, "always")) + /* We always renegotiate */ + return 0; + + LOG(3, s, t, "Trying to reuse the LAC sent and received LCP configuration:\n"); + if (config->debug >= 3) + { + dumplcp(sent_lcp, sent_lcp_n); + dumplcp(received_lcp, received_lcp_n); + } + + /* Check what configuration the LAC sent */ + if (!processsentlcpconfreq(s, t, NULL, sent_lcp, sent_lcp_n, &changed)) + { + LOG(3, s, t, "Sent LCP conf does not match\n"); + return 0; + } + + /* Check what configuration the LAC received */ + processreceivedlcpconfreq(s, t, NULL, received_lcp, received_lcp_n, &changed, &response); + if (response) + { + LOG(3, s, t, "Received LCP conf does not match\n"); + /* Mismatch, renegotiate */ + return 0; + } + LOG(3, s, t, "LCP conf match\n"); + + if (changed) + cluster_send_session(s); + + // Ok! + return 1; +} + +// Try to use auth proxy to avoid renegotiating it (in case the LAC forces PAP) +int processauthproxy(sessionidt s, tunnelidt t, + uint16_t authtype, const char *authname, + size_t authchalln, const char authchall[authchalln], + size_t authrespn, const char authresp[authrespn]) +{ + uint16_t r; + + if ((sess_local[s].lcp_authtype == 0 && authtype != 0) + || (sess_local[s].lcp_authtype == AUTHPAP && authtype != 3) // PAP + || (sess_local[s].lcp_authtype == AUTHCHAP && authtype != 2)) // CHAP + { + LOG(3, s, t, "Authentication proxy mismatch: got %u (%s) while expecting %u\n", + authtype, ppp_auth_type(authtype), sess_local[s].lcp_authtype); + return 0; + } + + if (session[s].ppp.phase != Authenticate) + { + LOG(3, s, t, "Already authenticated\n"); + return 1; + } + + if (sess_local[s].lcp_authtype == 0) + { + LOG(4, s, t, "No auth needed\n"); + return 1; + } + + if ((!config->disable_lac_func) && lac_conf_forwardtoremotelns(s, authname)) + { + // Creating a tunnel/session has been started + return 1; + } + + if (!(r = radiusnew(s))) + { + LOG(1, s, t, "No RADIUS session available to authenticate session...\n"); + sessionshutdown(s, "No free RADIUS sessions.", CDN_UNAVAILABLE, TERM_SERVICE_UNAVAILABLE); + return 1; + } + + // Run PRE_AUTH plugins + struct param_pre_auth packet = { &tunnel[t], &session[s], strdup(authname), NULL, 0, 1 }; + + if (sess_local[s].lcp_authtype == AUTHPAP) + { + packet.password = strndup(authresp, authrespn); + packet.protocol = PPPPAP; + } + else if (sess_local[s].lcp_authtype == AUTHCHAP) + { + if (authchalln != 16) + { + LOG(1, s, t, "CHAP challenge size different from 16: %zu\n", authchalln); + return 0; + } + if (authrespn != 16) + { + LOG(1, s, t, "CHAP response size different from 16: %zu\n", authrespn); + return 0; + } + packet.password = calloc(17, 1); + memcpy(packet.password, authresp, 16); + packet.protocol = PPPCHAP; + } + else + // Not PAP or CHAP?? + return 0; + + run_plugins(PLUGIN_PRE_AUTH, &packet); + if (!packet.continue_auth) + { + LOG(3, s, t, "A plugin rejected PRE_AUTH\n"); + if (packet.username) free(packet.username); + if (packet.password) free(packet.password); + return 1; + } + + // Take all authentication information from proxy, and record for possibly proxying ourself + strncpy(session[s].user, packet.username, sizeof(session[s].user) - 1); + strncpy((char *) sess_local[s].auth_name, packet.username, sizeof(sess_local[s].auth_name) - 1); + + if (sess_local[s].lcp_authtype == AUTHPAP) + { + strncpy(radius[r].pass, packet.password, sizeof(radius[r].pass) - 1); + strncpy((char *) sess_local[s].auth_resp, packet.password, sizeof(sess_local[s].auth_resp) - 1); + } + else + { + memcpy(radius[r].auth, authchall, 16); + memcpy(sess_local[s].auth_chall, authchall, 16); + + memcpy(radius[r].pass, packet.password, 16); + memcpy(sess_local[s].auth_resp, packet.password, 16); + + radius[r].chap = 1; + } + radius[r].id = sess_local[s].auth_id; + + LOG(3, s, t, "Sending login for %s to RADIUS\n", packet.username); + + free(packet.username); + free(packet.password); + + if ((session[s].mrru) && (!first_session_in_bundle(s))) + radiussend(r, RADIUSJUSTAUTH); + else + radiussend(r, RADIUSAUTH); + + return 1; +} + // Process LCP messages void processlcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l) { @@ -648,165 +1079,10 @@ void processlcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l) } else if (*p == ConfigReq) { - int x = l - 4; - uint8_t *o = (p + 4); uint8_t *response = 0; - static uint8_t asyncmap[4] = { 0, 0, 0, 0 }; // all zero - static uint8_t authproto[5]; int changed = 0; - while (x > 2) - { - int type = o[0]; - int length = o[1]; - - if (length == 0 || length == 1 || type == 0 || x < length) break; - switch (type) - { - case 1: // Maximum-Receive-Unit - { - uint16_t mru = ntohs(*(uint16_t *)(o + 2)); - if (mru >= MINMTU) - { - session[s].mru = mru; - changed++; - break; - } - - LOG(3, s, t, " Remote requesting MRU of %u. Rejecting.\n", mru); - mru = htons(MRU); - q = ppp_conf_nak(s, b, sizeof(b), PPPLCP, &response, q, p, o, (uint8_t *) &mru, sizeof(mru)); - } - break; - - case 2: // Async-Control-Character-Map - if (!ntohl(*(uint32_t *)(o + 2))) // all bits zero is OK - break; - - LOG(3, s, t, " Remote requesting asyncmap. Rejecting.\n"); - q = ppp_conf_nak(s, b, sizeof(b), PPPLCP, &response, q, p, o, asyncmap, sizeof(asyncmap)); - break; - - case 3: // Authentication-Protocol - { - int proto = ntohs(*(uint16_t *)(o + 2)); - char proto_name[] = "0x0000"; - int alen; - - if (proto == PPPPAP) - { - if (config->radius_authtypes & AUTHPAP) - { - sess_local[s].lcp_authtype = AUTHPAP; - break; - } - - strcpy(proto_name, "PAP"); - } - else if (proto == PPPCHAP) - { - if (config->radius_authtypes & AUTHCHAP - && *(o + 4) == 5) // MD5 - { - sess_local[s].lcp_authtype = AUTHCHAP; - break; - } - - strcpy(proto_name, "CHAP"); - } - else - sprintf(proto_name, "%#4.4x", proto); - - LOG(3, s, t, " Remote requesting %s authentication. Rejecting.\n", proto_name); - - alen = add_lcp_auth(authproto, sizeof(authproto), config->radius_authprefer); - if (alen < 2) break; // paranoia - - q = ppp_conf_nak(s, b, sizeof(b), PPPLCP, &response, q, p, o, authproto + 2, alen - 2); - if (q && *response == ConfigNak && - config->radius_authtypes != config->radius_authprefer) - { - // alternate type - alen = add_lcp_auth(authproto, sizeof(authproto), config->radius_authtypes & ~config->radius_authprefer); - if (alen < 2) break; - q = ppp_conf_nak(s, b, sizeof(b), PPPLCP, &response, q, p, o, authproto + 2, alen - 2); - } - - break; - } - break; - - case 4: // Quality-Protocol - case 5: // Magic-Number - case 7: // Protocol-Field-Compression - case 8: // Address-And-Control-Field-Compression - break; - - case 17: // Multilink Max-Receive-Reconstructed-Unit - { - uint16_t mrru = ntohs(*(uint16_t *)(o + 2)); - session[s].mrru = mrru; - changed++; - LOG(3, s, t, " Received PPP LCP option MRRU: %d\n",mrru); - } - break; - - case 18: // Multilink Short Sequence Number Header Format - { - session[s].mssf = 1; - changed++; - LOG(3, s, t, " Received PPP LCP option MSSN format\n"); - } - break; - - case 19: // Multilink Endpoint Discriminator - { - uint8_t epdis_class = o[2]; - int addr; - - session[s].epdis.addr_class = epdis_class; - session[s].epdis.length = length - 3; - if (session[s].epdis.length > 20) - { - LOG(1, s, t, "Error: received EndDis Address Length more than 20: %d\n", session[s].epdis.length); - session[s].epdis.length = 20; - } - - for (addr = 0; addr < session[s].epdis.length; addr++) - session[s].epdis.address[addr] = o[3+addr]; - - changed++; - - switch (epdis_class) - { - case LOCALADDR: - LOG(3, s, t, " Received PPP LCP option Multilink EndDis Local Address Class: %d\n",epdis_class); - break; - case IPADDR: - LOG(3, s, t, " Received PPP LCP option Multilink EndDis IP Address Class: %d\n",epdis_class); - break; - case IEEEMACADDR: - LOG(3, s, t, " Received PPP LCP option Multilink EndDis IEEE MAC Address Class: %d\n",epdis_class); - break; - case PPPMAGIC: - LOG(3, s, t, " Received PPP LCP option Multilink EndDis PPP Magic No Class: %d\n",epdis_class); - break; - case PSNDN: - LOG(3, s, t, " Received PPP LCP option Multilink EndDis PSND No Class: %d\n",epdis_class); - break; - default: - LOG(3, s, t, " Received PPP LCP option Multilink EndDis NULL Class %d\n",epdis_class); - } - } - break; - - default: // Reject any unknown options - LOG(3, s, t, " Rejecting unknown PPP LCP option %d\n", type); - q = ppp_conf_rej(s, b, sizeof(b), PPPLCP, &response, q, p, o); - } - x -= length; - o += length; - } + processreceivedlcpconfreq(s, t, p, p + 4, l - 4, &changed, &response); if (changed) cluster_send_session(s);