Compare commits

..

3 commits

Author SHA1 Message Date
54d36d7512 Merge remote-tracking branch 'upstream/master' 2025-05-03 10:55:58 +02:00
Samuel Thibault
e7db528544 Add lcp_renegotiation option
To support proxy LCP negotiation.

Note: we *have* to take the auth id from the proxy answer, otherwise we would
replay previous ids, for which the client might cache the answer and thus
ignore our new challenge and just repeat their outdated answer.
2025-04-18 14:41:36 -04:00
Samuel Thibault
817ce35748 ppp: Move LCP received configuration parsing to a separate function
So it can be reused for proxy LCP negotiation.
2025-04-18 14:41:36 -04:00
5 changed files with 548 additions and 187 deletions

View file

@ -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 : PPP counter and timer values, as described in §4.1 of
[RFC1661](ftp://ftp.rfc-editor.org/in-notes/rfc1661.txt). [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) `primary_dns` (ip address); `econdary_dns` (ip address)
: Whenever a PPP connection is established, DNS servers will be sent : Whenever a PPP connection is established, DNS servers will be sent

View file

@ -60,9 +60,9 @@
* LNS1 --------------------> LNS2 (Session Open) * LNS1 --------------------> LNS2 (Session Open)
* ZLB * ZLB
* LNS1 <-------------------- LNS2 (Session Open) * LNS1 <-------------------- LNS2 (Session Open)
* LCP Negotiation * LCP Renegotiation (unless proxied)
* Client <------------------------------------------------------------------------> LNS2 * Client <------------------------------------------------------------------------> LNS2
* PAP/CHAP Authentification * PAP (Ack only if proxied) / CHAP Authentification
* Client <------------------------------------------------------------------------> LNS2 * Client <------------------------------------------------------------------------> LNS2
* DATA (ppp) * DATA (ppp)
* Client <------------------------------------------------------------------------> LNS2 * Client <------------------------------------------------------------------------> LNS2

116
l2tpns.c
View file

@ -159,6 +159,7 @@ config_descriptt config_values[] = {
CONFIG("ppp_max_configure", ppp_max_configure, INT), CONFIG("ppp_max_configure", ppp_max_configure, INT),
CONFIG("ppp_max_failure", ppp_max_failure, INT), CONFIG("ppp_max_failure", ppp_max_failure, INT),
CONFIG("ppp_keepalive", ppp_keepalive, BOOL), CONFIG("ppp_keepalive", ppp_keepalive, BOOL),
CONFIG("lcp_renegotiation", lcp_renegotiation, STRING),
CONFIG("primary_dns", default_dns1, IPv4), CONFIG("primary_dns", default_dns1, IPv4),
CONFIG("secondary_dns", default_dns2, IPv4), CONFIG("secondary_dns", default_dns2, IPv4),
CONFIG("primary_radius", radiusserver[0], 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 uint16_t message = 0xFFFF; // message type
uint8_t fatal = 0; uint8_t fatal = 0;
uint8_t mandatory = 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 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) 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 called[MAXTEL] = ""; // called number
char calling[MAXTEL] = ""; // calling 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 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)); LOG(4, s, t, " Proxy Auth Type %u (%s)\n", atype, ppp_auth_type(atype));
break; break;
} }
case 30: // Proxy Authentication Name case 30: // Proxy Authentication Name
{ {
char authname[64];
memset(authname, 0, sizeof(authname)); memset(authname, 0, sizeof(authname));
memcpy(authname, b, (n < sizeof(authname)) ? n : sizeof(authname) - 1); memcpy(authname, b, (n < sizeof(authname)) ? n : sizeof(authname) - 1);
LOG(4, s, t, " Proxy Auth Name (%s)\n", if (n < sizeof(authname))
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; break;
} }
case 31: // Proxy Authentication Challenge case 31: // Proxy Authentication Challenge
{ {
if (n <= sizeof(authchall))
{
memcpy(authchall, b, n);
authchalln = n;
LOG(4, s, t, " Proxy Auth Challenge\n"); LOG(4, s, t, " Proxy Auth Challenge\n");
}
else
{
LOG(2, s, t, " Proxy Auth Challenge too long\n");
}
break; break;
} }
case 32: // Proxy Authentication ID 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); LOG(4, s, t, " Proxy Auth ID (%u)\n", authid);
break; break;
} }
case 33: // Proxy Authentication Response 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 (*p == 5 && p[1] == 6) // Magic-Number if (n <= sizeof(authresp))
amagic = ntohl(*(uint32_t *) (p + 2)); {
else if (*p == 7) // Protocol-Field-Compression memcpy(authresp, b, n);
aflags |= SESSION_PFC; authrespn = n;
else if (*p == 8) // Address-and-Control-Field-Compression LOG(4, s, t, " Proxy Auth Response\n");
aflags |= SESSION_ACFC;
p += p[1];
} }
else
{
LOG(2, s, t, " Proxy Auth Response too long\n");
} }
break; break;
}
case 27: // last sent lcp
{
last_sent_lcp_confreq = b;
last_sent_lcp_confreq_n = n;
break;
}
case 28: // last recv lcp confreq 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 case 26: // Initial Received LCP CONFREQ
break; break;
case 39: // seq required - we control it as an LNS anyway... 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; break;
case 12: // ICCN case 12: // ICCN
LOG(3, s, t, "Received ICCN\n"); LOG(3, s, t, "Received ICCN\n");
if (amagic == 0) amagic = time_now;
session[s].magic = amagic; // set magic number session[s].magic = time_now; // set magic number
session[s].flags = aflags; // set flags received
session[s].mru = PPPoE_MRU; // default session[s].mru = PPPoE_MRU; // default
controlnull(t); // ack controlnull(t); // ack
@ -5034,8 +5063,39 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr, uint16_t indexu
else else
sess_local[s].mp_epdis = 0; 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); sendlcp(s, t);
change_state(s, lcp, RequestSent); change_state(s, lcp, RequestSent);
}
break; break;
case 14: // CDN case 14: // CDN
@ -7446,6 +7506,16 @@ static void update_config()
MSS = MRU - TCP_HDRS; MSS = MRU - TCP_HDRS;
MSS6 = MRU - TCP6_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 // Update radius
config->numradiusservers = 0; config->numradiusservers = 0;
for (i = 0; i < MAXRADSERVER; i++) for (i = 0; i < MAXRADSERVER; i++)

View file

@ -756,6 +756,7 @@ typedef struct
int ppp_max_configure; // max lcp configure requests to send int ppp_max_configure; // max lcp configure requests to send
int ppp_max_failure; // max lcp configure naks to send int ppp_max_failure; // max lcp configure naks to send
int ppp_keepalive; // send echoes regardless int ppp_keepalive; // send echoes regardless
char lcp_renegotiation[12]; // LCP renegotiation (always or on-mismatch)
char radiussecret[64]; char radiussecret[64];
char radius_require_message_authenticator[5]; 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_open(sessionidt s, tunnelidt t);
void lcp_restart(sessionidt s); void lcp_restart(sessionidt s);
void processlcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l); 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 processipcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l);
void processipv6cp(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); void processipin(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l);

588
ppp.c
View file

@ -556,6 +556,437 @@ static void ppp_code_rej(sessionidt s, tunnelidt t, uint16_t proto,
tunnelsend(buf, l + (q - buf), t); 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 // Process LCP messages
void processlcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l) 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) else if (*p == ConfigReq)
{ {
int x = l - 4;
uint8_t *o = (p + 4);
uint8_t *response = 0; uint8_t *response = 0;
static uint8_t asyncmap[4] = { 0, 0, 0, 0 }; // all zero
static uint8_t authproto[5];
int changed = 0; int changed = 0;
while (x > 2) processreceivedlcpconfreq(s, t, p, p + 4, l - 4, &changed, &response);
{
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) if (changed)
cluster_send_session(s); cluster_send_session(s);