Compare commits
3 commits
57004c5744
...
54d36d7512
| Author | SHA1 | Date | |
|---|---|---|---|
| 54d36d7512 | |||
|
|
e7db528544 | ||
|
|
817ce35748 |
5 changed files with 548 additions and 187 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -60,9 +60,9 @@
|
|||
* 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)
|
||||
* Client <------------------------------------------------------------------------> LNS2
|
||||
|
|
|
|||
116
l2tpns.c
116
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
|
||||
{
|
||||
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 (*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];
|
||||
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;
|
||||
}
|
||||
case 27: // last sent lcp
|
||||
{
|
||||
last_sent_lcp_confreq = b;
|
||||
last_sent_lcp_confreq_n = n;
|
||||
break;
|
||||
}
|
||||
case 28: // last recv lcp confreq
|
||||
{
|
||||
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;
|
||||
|
||||
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++)
|
||||
|
|
|
|||
3
l2tpns.h
3
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);
|
||||
|
|
|
|||
588
ppp.c
588
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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue