diff --git a/docs/src/html/manual.md b/docs/src/html/manual.md index 6fbccf7..cff4b6a 100644 --- a/docs/src/html/manual.md +++ b/docs/src/html/manual.md @@ -159,18 +159,6 @@ 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 8347d55..2af1570 100644 --- a/l2tplac.c +++ b/l2tplac.c @@ -60,11 +60,11 @@ * LNS1 --------------------> LNS2 (Session Open) * ZLB * LNS1 <-------------------- LNS2 (Session Open) - * LCP Renegotiation (unless proxied) + * LCP Negotiation * Client <------------------------------------------------------------------------> LNS2 - * PAP (Ack only if proxied) / CHAP Authentification + * PAP/CHAP Authentification * Client <------------------------------------------------------------------------> LNS2 - * DATA (ppp) + * DATA (ppp) * Client <------------------------------------------------------------------------> LNS2 * */ diff --git a/l2tpns.c b/l2tpns.c index 4423df8..203fc40 100644 --- a/l2tpns.c +++ b/l2tpns.c @@ -159,7 +159,6 @@ 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), @@ -4185,18 +4184,9 @@ 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 @@ -4673,70 +4663,50 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr, uint16_t indexu } case 29: // Proxy Authentication Type { - atype = ntohs(*(uint16_t *)b); + uint16_t 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); - 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); - } + LOG(4, s, t, " Proxy Auth Name (%s)\n", + authname); break; } case 31: // Proxy Authentication Challenge { - 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"); - } + LOG(4, s, t, " Proxy Auth Challenge\n"); break; } case 32: // Proxy Authentication ID { - authid = ntohs(*(uint16_t *)(b)); + uint16_t authid = ntohs(*(uint16_t *)(b)); LOG(4, s, t, " Proxy Auth ID (%u)\n", authid); break; } case 33: // Proxy Authentication Response - { - if (n <= sizeof(authresp)) - { - 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; - } + LOG(4, s, t, " Proxy Auth Response\n"); + break; case 27: // last sent lcp - { - last_sent_lcp_confreq = b; - last_sent_lcp_confreq_n = n; - break; + { // find magic number + uint8_t *p = b, *e = p + n; + while (p + 1 < e && p[1] && p + p[1] <= e) + { + 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]; + } } + break; case 28: // last recv lcp confreq - { - last_received_lcp_confreq = b; - last_received_lcp_confreq_n = n; - break; - } + break; case 26: // Initial Received LCP CONFREQ break; case 39: // seq required - we control it as an LNS anyway... @@ -5047,8 +5017,9 @@ 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"); - - session[s].magic = time_now; // set magic number + if (amagic == 0) amagic = time_now; + session[s].magic = amagic; // set magic number + session[s].flags = aflags; // set flags received session[s].mru = PPPoE_MRU; // default controlnull(t); // ack @@ -5063,39 +5034,8 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr, uint16_t indexu else sess_local[s].mp_epdis = 0; - 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); - } - + sendlcp(s, t); + change_state(s, lcp, RequestSent); break; case 14: // CDN @@ -7506,16 +7446,6 @@ 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 04a6f11..39cdb3c 100644 --- a/l2tpns.h +++ b/l2tpns.h @@ -756,7 +756,6 @@ 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]; @@ -993,8 +992,6 @@ 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 eed07b6..a7d8a2b 100644 --- a/ppp.c +++ b/ppp.c @@ -556,437 +556,6 @@ 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) { @@ -1079,10 +648,165 @@ 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; - processreceivedlcpconfreq(s, t, p, p + 4, l - 4, &changed, &response); + 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; + } if (changed) cluster_send_session(s);