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);