diff --git a/src/Cedar/CedarType.h b/src/Cedar/CedarType.h index 27762cbb..e3124a8c 100644 --- a/src/Cedar/CedarType.h +++ b/src/Cedar/CedarType.h @@ -500,6 +500,8 @@ typedef struct PPP_IPOPTION PPP_IPOPTION; typedef struct PPP_IPV6OPTION PPP_IPV6OPTION; typedef struct PPP_REQUEST_RESEND PPP_REQUEST_RESEND; typedef struct PPP_DELAYED_PACKET PPP_DELAYED_PACKET; +typedef struct PPP_EAP PPP_EAP; +typedef struct PPP_EAP_TLS_CONTEXT PPP_EAP_TLS_CONTEXT; // ============================================================== diff --git a/src/Cedar/IPC.c b/src/Cedar/IPC.c index ffa9baaa..96de8962 100644 --- a/src/Cedar/IPC.c +++ b/src/Cedar/IPC.c @@ -948,7 +948,7 @@ DHCPV4_DATA *IPCSendDhcpRequest(IPC *ipc, IP *dest_ip, UINT tran_id, DHCP_OPTION BUF *IPCBuildDhcpRequest(IPC *ipc, IP *dest_ip, UINT tran_id, DHCP_OPTION_LIST *opt) { IPV4_HEADER ip; - UDP_HEADER* udp; + UDP_HEADER *udp; DHCPV4_HEADER dhcp; UINT blank_size = 128 + 64; BUF *ret; diff --git a/src/Cedar/Proto_L2TP.c b/src/Cedar/Proto_L2TP.c index 960103ca..edf1b94f 100644 --- a/src/Cedar/Proto_L2TP.c +++ b/src/Cedar/Proto_L2TP.c @@ -1995,6 +1995,7 @@ UINT CalcL2TPMss(L2TP_SERVER *l2tp, L2TP_TUNNEL *t, L2TP_SESSION *s) // Start the L2TP thread void StartL2TPThread(L2TP_SERVER *l2tp, L2TP_TUNNEL *t, L2TP_SESSION *s) { + PPP_SESSION* underlyingSession; // Validate arguments if (l2tp == NULL || t == NULL || s == NULL) { @@ -2023,9 +2024,11 @@ void StartL2TPThread(L2TP_SERVER *l2tp, L2TP_TUNNEL *t, L2TP_SESSION *s) } // Create a PPP thread - s->Thread = NewPPPSession(l2tp->Cedar, &t->ClientIp, t->ClientPort, &t->ServerIp, t->ServerPort, + underlyingSession = NewPPPSession(l2tp->Cedar, &t->ClientIp, t->ClientPort, &t->ServerIp, t->ServerPort, s->TubeSend, s->TubeRecv, L2TP_IPC_POSTFIX, tmp, t->HostName, l2tp->CryptName, CalcL2TPMss(l2tp, t, s)); + s->Thread = underlyingSession->SessionThread; + s->PPPSession = underlyingSession; } } @@ -2122,8 +2125,21 @@ void L2TPProcessInterrupts(L2TP_SERVER *l2tp) { L2TP_TUNNEL *t = LIST_DATA(l2tp->TunnelList, i); LIST *delete_session_list = NULL; + UINT64 l2tpTimeout = L2TP_TUNNEL_TIMEOUT; - if ((l2tp->Now >= (t->LastRecvTick + (UINT64)L2TP_TUNNEL_TIMEOUT)) && t->Timedout == false) + // If we got on ANY session a higher timeout than the default L2TP tunnel timeout, increase it + for (i = 0; i < LIST_NUM(t->SessionList); i++) + { + L2TP_SESSION* s = LIST_DATA(t->SessionList, i); + + if (s->PPPSession != NULL && s->PPPSession->DataTimeout > l2tpTimeout) + { + l2tpTimeout = s->PPPSession->DataTimeout; + } + } + + + if ((l2tp->Now >= (t->LastRecvTick + (UINT64)l2tpTimeout)) && t->Timedout == false) { // Disconnect the tunnel forcibly if data can not be received for a certain period of time t->Timedout = true; diff --git a/src/Cedar/Proto_L2TP.h b/src/Cedar/Proto_L2TP.h index 1cd9767b..9d83f66b 100644 --- a/src/Cedar/Proto_L2TP.h +++ b/src/Cedar/Proto_L2TP.h @@ -169,6 +169,7 @@ struct L2TP_SESSION UINT64 DisconnectTimeout; // Disconnection completion time-out bool HasThread; // Whether have a thread THREAD *Thread; // Thread + PPP_SESSION* PPPSession; // Underlying PPP session TUBE *TubeSend; // Tube of PPP to L2TP direction TUBE *TubeRecv; // Tube of L2TP to PPP direction UINT PseudowireType; // Type of L2TPv3 virtual line diff --git a/src/Cedar/Proto_PPP.c b/src/Cedar/Proto_PPP.c index 1bf4528f..811cad74 100644 --- a/src/Cedar/Proto_PPP.c +++ b/src/Cedar/Proto_PPP.c @@ -35,6 +35,8 @@ void PPPThread(THREAD *thread, void *param) p->IPv4_State = PPP_PROTO_STATUS_CLOSED; p->IPv6_State = PPP_PROTO_STATUS_CLOSED; + p->Eap_Protocol = PPP_UNSPECIFIED; + p->Mru1 = p->Mru2 = PPP_MRU_DEFAULT; p->RecvPacketList = NewList(NULL); p->SentReqPacketList = NewList(NULL); @@ -145,7 +147,7 @@ void PPPThread(THREAD *thread, void *param) // Process responses if (!receivedPacketProcessed && p->CurrentPacket != NULL && p->CurrentPacket->IsControl && PPP_CODE_IS_RESPONSE(p->CurrentPacket->Protocol, p->CurrentPacket->Lcp->Code) && !PPP_STATUS_IS_UNAVAILABLE(p->PPPStatus)) { - PPP_PACKET* request = NULL; + PPP_PACKET *request = NULL; // Removing from resend list for (i = 0; i < LIST_NUM(p->SentReqPacketList); i++) { @@ -229,6 +231,45 @@ void PPPThread(THREAD *thread, void *param) Debug("Unprocessed and unrejected packet, protocol = 0x%x\n", p->CurrentPacket->Protocol); } } + else if (p->PPPStatus == PPP_STATUS_BEFORE_AUTH && p->AuthProtocol == PPP_PROTOCOL_EAP) + { + PPP_LCP *lcpEap; + PPP_EAP *eapPacket; + UCHAR *welcomeMessage = "Welcome to the SoftEther VPN server!"; + UCHAR flags = PPP_EAP_TLS_FLAG_NONE; + // We got to start EAP when we got no LCP packets from the client on previous iteration + // which means we parsed all the client requests and responses + + switch (p->Eap_Protocol) + { + case PPP_EAP_TYPE_TLS: + // Sending TLS Start... + flags |= PPP_EAP_TLS_FLAG_SSLSTARTED; + lcpEap = BuildEAPTlsRequest(p->Eap_PacketId++, 0, flags); + PPPSetStatus(p, PPP_STATUS_AUTHENTICATING); + if (!PPPSendAndRetransmitRequest(p, PPP_PROTOCOL_EAP, lcpEap)) + { + PPPSetStatus(p, PPP_STATUS_FAIL); + WHERE; + break; + } + break; + case PPP_EAP_TYPE_IDENTITY: + default: // We treat the unspecified protocol as the IDENTITY protocol + p->Eap_Protocol = PPP_EAP_TYPE_IDENTITY; + lcpEap = BuildEAPPacketEx(PPP_EAP_CODE_REQUEST, p->Eap_PacketId++, PPP_EAP_TYPE_IDENTITY, sizeof(welcomeMessage)); + eapPacket = lcpEap->Data; + Copy(eapPacket->Data, welcomeMessage, sizeof(welcomeMessage)); + PPPSetStatus(p, PPP_STATUS_AUTHENTICATING); + if (!PPPSendAndRetransmitRequest(p, PPP_PROTOCOL_EAP, lcpEap)) + { + PPPSetStatus(p, PPP_STATUS_FAIL); + WHERE; + break; + } + break; + } + } else if (p->PPPStatus == PPP_STATUS_BEFORE_AUTH && p->AuthProtocol == PPP_PROTOCOL_CHAP) { // We got to start CHAP when we got no LCP packets from the client on previous iteration @@ -247,14 +288,12 @@ void PPPThread(THREAD *thread, void *param) if (p->PPPStatus == PPP_STATUS_CONNECTED && !authReqSent) { - // MSCHAPv2 code + // EAP code PPP_LCP *c = NewPPPLCP(PPP_LCP_CODE_REQ, 0); - UCHAR ms_chap_v2_code[3]; - WRITE_USHORT(ms_chap_v2_code, PPP_LCP_AUTH_CHAP); - ms_chap_v2_code[2] = PPP_CHAP_ALG_MS_CHAP_V2; + USHORT eap_code = Endian16(PPP_LCP_AUTH_EAP); - Debug("Request MSCHAPv2\n"); - Add(c->OptionList, NewPPPOption(PPP_LCP_OPTION_AUTH, ms_chap_v2_code, sizeof(ms_chap_v2_code))); + Debug("Request EAP\n"); + Add(c->OptionList, NewPPPOption(PPP_LCP_OPTION_AUTH, &eap_code, sizeof(eap_code))); if (!PPPSendAndRetransmitRequest(p, PPP_PROTOCOL_LCP, c)) { PPPSetStatus(p, PPP_STATUS_FAIL); @@ -265,7 +304,7 @@ void PPPThread(THREAD *thread, void *param) if (p->PPPStatus == PPP_STATUS_AUTHENTICATING) { - Debug("Tick waiting for auth...\n"); + //Debug("Tick waiting for auth...\n"); } if (p->PPPStatus == PPP_STATUS_AUTH_FAIL) @@ -368,7 +407,7 @@ void PPPThread(THREAD *thread, void *param) } else { - WaitForTubes(tubes, 1, 100); + WaitForTubes(tubes, 1, 300); // Increasing timeout to make the ticks a bit slower } if (IsTubeConnected(p->TubeRecv) == false || IsTubeConnected(p->TubeSend) == false) @@ -386,13 +425,22 @@ void PPPThread(THREAD *thread, void *param) } // Time-out inspection - if ((p->LastRecvTime + (UINT64)PPP_DATA_TIMEOUT) <= now) + if ((p->LastRecvTime + (UINT64)p->DataTimeout) <= now) { // Communication time-out occurs PPPLog(p, "LP_DATA_TIMEOUT"); break; } + // Maximum PPP session time of the user reached inspection + if (p->UserConnectionTick != 0 && p->UserConnectionTimeout != 0 && + p->UserConnectionTick + p->UserConnectionTimeout <= now) + { + // User connection time-out occurs + PPPLog(p, "LP_USER_TIMEOUT"); + break; + } + // Terminate if the PPP disconnected if (p->IsTerminateReceived) { @@ -444,7 +492,7 @@ void PPPThread(THREAD *thread, void *param) // Entry point // Create a new PPP session -THREAD *NewPPPSession(CEDAR *cedar, IP *client_ip, UINT client_port, IP *server_ip, UINT server_port, TUBE *send_tube, TUBE *recv_tube, char *postfix, char *client_software_name, char *client_hostname, char *crypt_name, UINT adjust_mss) +PPP_SESSION *NewPPPSession(CEDAR *cedar, IP *client_ip, UINT client_port, IP *server_ip, UINT server_port, TUBE *send_tube, TUBE *recv_tube, char *postfix, char *client_software_name, char *client_hostname, char *crypt_name, UINT adjust_mss) { PPP_SESSION *p; THREAD *t; @@ -470,10 +518,14 @@ THREAD *NewPPPSession(CEDAR *cedar, IP *client_ip, UINT client_port, IP *server_ p = ZeroMalloc(sizeof(PPP_SESSION)); p->EnableMSCHAPv2 = true; - p->AuthProtocol = NULL; + p->AuthProtocol = PPP_UNSPECIFIED; p->MsChapV2_ErrorCode = 691; p->EapClient = NULL; + p->DataTimeout = PPP_DATA_TIMEOUT; + p->PacketRecvTimeout = PPP_PACKET_RECV_TIMEOUT; + p->UserConnectionTimeout = 0; + p->Cedar = cedar; AddRef(cedar->ref); @@ -510,7 +562,9 @@ THREAD *NewPPPSession(CEDAR *cedar, IP *client_ip, UINT client_port, IP *server_ // Thread creation t = NewThread(PPPThread, p); - return t; + p->SessionThread = t; + + return p; } // PPP processing functions @@ -691,6 +745,9 @@ bool PPPProcessResponsePacket(PPP_SESSION *p, PPP_PACKET *pp, PPP_PACKET *req) case PPP_PROTOCOL_IPV6CP: Debug("IPv6CP to be implemented\n"); break; + case PPP_PROTOCOL_EAP: + return PPPProcessEAPResponsePacket(p, pp, req); + break; default: Debug("We received a response for an unsupported protocol??? Should be filtered out already! protocol = 0x%x, code = 0x%x\n", pp->Protocol, pp->Lcp->Code); PPPSetStatus(p, PPP_STATUS_FAIL); @@ -718,7 +775,7 @@ bool PPPProcessLCPResponsePacket(PPP_SESSION *p, PPP_PACKET *pp, PPP_PACKET *req // probably means the PPP client is not compatible anyway so we fail the connection if (p->PPPStatus != PPP_STATUS_NETWORK_LAYER) { - USHORT* protocol = pp->Lcp->Data; + USHORT *protocol = pp->Lcp->Data; Debug("Protocol 0x%x rejected before auth, probably unsupported client, failing connection\n", *protocol); PPPSetStatus(p, PPP_STATUS_FAIL); WHERE; @@ -726,14 +783,14 @@ bool PPPProcessLCPResponsePacket(PPP_SESSION *p, PPP_PACKET *pp, PPP_PACKET *req } else { - USHORT* protocol = pp->Lcp->Data; + USHORT *protocol = pp->Lcp->Data; if (*protocol == PPP_PROTOCOL_IPCP || *protocol == PPP_PROTOCOL_IP) { - p->IPv4_State == PPP_PROTO_STATUS_REJECTED; + p->IPv4_State = PPP_PROTO_STATUS_REJECTED; } if (*protocol == PPP_PROTOCOL_IPV6CP || *protocol == PPP_PROTOCOL_IPV6) { - p->IPv6_State == PPP_PROTO_STATUS_REJECTED; + p->IPv6_State = PPP_PROTO_STATUS_REJECTED; } } } @@ -773,7 +830,7 @@ bool PPPProcessLCPResponsePacket(PPP_SESSION *p, PPP_PACKET *pp, PPP_PACKET *req } else { - PPP_LCP* lcp = NewPPPLCP(PPP_LCP_CODE_REQ, 0); + PPP_LCP *lcp = NewPPPLCP(PPP_LCP_CODE_REQ, 0); Add(lcp->OptionList, NewPPPOption(PPP_LCP_OPTION_AUTH, &value, sizeof(USHORT))); if (!PPPSendAndRetransmitRequest(p, PPP_PROTOCOL_LCP, lcp)) { @@ -807,7 +864,37 @@ bool PPPProcessLCPResponsePacket(PPP_SESSION *p, PPP_PACKET *pp, PPP_PACKET *req WHERE; return false; } - if (opt->DataSize == sizeof(ms_chap_v2_code) && Cmp(opt->Data, ms_chap_v2_code, opt->DataSize) == 0) + if (opt->DataSize == sizeof(USHORT) && *((USHORT*)(opt->Data)) == Endian16(PPP_LCP_AUTH_EAP)) + { + // Try to request MS-CHAPv2 then + if (!isAccepted) + { + UINT64 offer = 0; + PPP_LCP *c = NewPPPLCP(PPP_LCP_CODE_REQ, 0); + UCHAR ms_chap_v2_code[3]; + + WRITE_USHORT(ms_chap_v2_code, PPP_LCP_AUTH_CHAP); + ms_chap_v2_code[2] = PPP_CHAP_ALG_MS_CHAP_V2; + + Copy(&offer, ms_chap_v2_code, sizeof(ms_chap_v2_code)); + Debug("NACK proto with code = 0x%x, cypher = 0x%x, offered cypher = 0x%x\n", pp->Lcp->Code, *((USHORT*)(opt->Data)), offer); + Debug("Request MSCHAPv2\n"); + Add(c->OptionList, NewPPPOption(PPP_LCP_OPTION_AUTH, &ms_chap_v2_code, sizeof(ms_chap_v2_code))); + if (!PPPSendAndRetransmitRequest(p, PPP_PROTOCOL_LCP, c)) + { + PPPSetStatus(p, PPP_STATUS_FAIL); + WHERE; + return false; + } + } + else + { + p->AuthProtocol = PPP_PROTOCOL_EAP; + Debug("Setting BEFORE_AUTH from ACK on LCP response parse on EAP accept\n"); + PPPSetStatus(p, PPP_STATUS_BEFORE_AUTH); + } + } + else if (opt->DataSize == sizeof(ms_chap_v2_code) && Cmp(opt->Data, ms_chap_v2_code, opt->DataSize) == 0) { // Try to request PAP then if (!isAccepted || !p->EnableMSCHAPv2) @@ -826,7 +913,7 @@ bool PPPProcessLCPResponsePacket(PPP_SESSION *p, PPP_PACKET *pp, PPP_PACKET *req return false; } } - else if (p->AuthProtocol == NULL) + else if (p->AuthProtocol == PPP_UNSPECIFIED) { p->AuthProtocol = PPP_PROTOCOL_CHAP; Debug("Setting BEFORE_AUTH from ACK on LCP response parse on CHAP accept\n"); @@ -848,7 +935,7 @@ bool PPPProcessLCPResponsePacket(PPP_SESSION *p, PPP_PACKET *pp, PPP_PACKET *req WHERE; return false; } - else if (p->AuthProtocol == NULL) + else if (p->AuthProtocol == PPP_UNSPECIFIED) { p->AuthProtocol = PPP_PROTOCOL_PAP; Debug("Setting BEFORE_AUTH from ACK on LCP response parse on PAP accept\n"); @@ -865,7 +952,7 @@ bool PPPProcessLCPResponsePacket(PPP_SESSION *p, PPP_PACKET *pp, PPP_PACKET *req // Process CHAP responses bool PPPProcessCHAPResponsePacket(PPP_SESSION *p, PPP_PACKET *pp, PPP_PACKET *req) { - PPP_LCP* lcp; + PPP_LCP *lcp; if (pp->Lcp->Code == PPP_CHAP_CODE_RESPONSE) { bool ok = false; @@ -902,8 +989,8 @@ bool PPPProcessCHAPResponsePacket(PPP_SESSION *p, PPP_PACKET *pp, PPP_PACKET *re { char hex[MAX_SIZE]; char ret_str[MAX_SIZE]; - BUF* lcp_ret_data = NewBuf(); - PPP_PACKET* res = ZeroMalloc(sizeof(PPP_PACKET)); + BUF *lcp_ret_data = NewBuf(); + PPP_PACKET *res = ZeroMalloc(sizeof(PPP_PACKET)); BinToStr(hex, sizeof(hex), p->MsChapV2_ServerResponse, 20); Format(ret_str, sizeof(ret_str), @@ -939,8 +1026,8 @@ bool PPPProcessCHAPResponsePacket(PPP_SESSION *p, PPP_PACKET *pp, PPP_PACKET *re { char hex[MAX_SIZE]; char ret_str[MAX_SIZE]; - BUF* lcp_ret_data = NewBuf(); - PPP_PACKET* res = ZeroMalloc(sizeof(PPP_PACKET)); + BUF *lcp_ret_data = NewBuf(); + PPP_PACKET *res = ZeroMalloc(sizeof(PPP_PACKET)); BinToStr(hex, sizeof(hex), p->MsChapV2_ServerChallenge, 16); @@ -989,7 +1076,7 @@ bool PPPProcessIPCPResponsePacket(PPP_SESSION *p, PPP_PACKET *pp, PPP_PACKET *re IP prevAddrStruct; char prevAddrStr[MAX_SIZE]; UINT prevAddr; - PPP_LCP* c; + PPP_LCP *c; UINT ui; if (!PPPGetIPAddressValueFromLCP(pp->Lcp, PPP_IPCP_OPTION_IP, &addrStruct) || pp->Lcp->Code == PPP_LCP_CODE_REJECT || pp->Lcp->Code == PPP_LCP_CODE_CODE_REJECT) @@ -1016,7 +1103,7 @@ bool PPPProcessIPCPResponsePacket(PPP_SESSION *p, PPP_PACKET *pp, PPP_PACKET *re return true; } - p->IPv4_State == PPP_PROTO_STATUS_CONFIG; + p->IPv4_State = PPP_PROTO_STATUS_CONFIG; PPPGetIPAddressValueFromLCP(req->Lcp, PPP_IPCP_OPTION_IP, &prevAddrStruct); prevAddr = IPToUINT(&prevAddrStruct); @@ -1046,6 +1133,78 @@ bool PPPProcessIPCPResponsePacket(PPP_SESSION *p, PPP_PACKET *pp, PPP_PACKET *re return false; } +// Process EAP responses +bool PPPProcessEAPResponsePacket(PPP_SESSION *p, PPP_PACKET *pp, PPP_PACKET *req) +{ + if (pp->Lcp->DataSize >= 1) + { + PPP_EAP *eap_packet = pp->Lcp->Data; + UINT eap_datasize = pp->Lcp->DataSize - 1; + UINT64 offer = 0; + PPP_LCP *c; + UCHAR ms_chap_v2_code[3]; + + WRITE_USHORT(ms_chap_v2_code, PPP_LCP_AUTH_CHAP); + ms_chap_v2_code[2] = PPP_CHAP_ALG_MS_CHAP_V2; + + switch (eap_packet->Type) + { + case PPP_EAP_TYPE_IDENTITY: + Copy(p->Eap_Identity, eap_packet->Data, MIN(MAX_SIZE, eap_datasize)); + // As we received the identity packet, we switch back to BEFORE_AUTH and switch to the EAP_TLS proto to send the TlsStart packet on the next tick + p->Eap_Protocol = PPP_EAP_TYPE_TLS; + PPPSetStatus(p, PPP_STATUS_BEFORE_AUTH); + break; + case PPP_EAP_TYPE_NOTIFICATION: + // Basically this is just an acknoweldgment that the notification was accepted by the client. Nothing to do here... + break; + case PPP_EAP_TYPE_NAK: + /// TODO: implement alternative EAP protocol selection based on received NAK + // For now just fallback to auth protocol selection to try to select MSCHAP or PAP + Debug("Got a EAP_NAK, abandoning EAP protocol\n"); + PPPRejectUnsupportedPacketEx(p, pp, true); + PPPSetStatus(p, PPP_STATUS_CONNECTED); + + c = NewPPPLCP(PPP_LCP_CODE_REQ, 0); + Copy(&offer, ms_chap_v2_code, sizeof(ms_chap_v2_code)); + Debug("Request MSCHAPv2 from EAP NAK\n"); + Add(c->OptionList, NewPPPOption(PPP_LCP_OPTION_AUTH, &ms_chap_v2_code, sizeof(ms_chap_v2_code))); + if (!PPPSendAndRetransmitRequest(p, PPP_PROTOCOL_LCP, c)) + { + PPPSetStatus(p, PPP_STATUS_FAIL); + WHERE; + return false; + } + break; + case PPP_EAP_TYPE_TLS: + PPPProcessEAPTlsResponse(p, eap_packet, eap_datasize); + break; + default: + Debug("We got an unexpected EAP response packet! Ignoring...\n"); + break; + } + } + else + { + PPP_EAP *eap; + + Debug("We got a CODE=%i ID=%i from client with zero size EAP structure, that shouldn't be happening!\n", pp->Lcp->Code, pp->Lcp->Id); + + eap = req->Lcp->Data; + if (eap->Type == PPP_EAP_TYPE_TLS) + { + PPP_LCP *lcp = BuildEAPTlsRequest(p->Eap_PacketId++, 0, PPP_EAP_TLS_FLAG_NONE); + if (!PPPSendAndRetransmitRequest(p, PPP_PROTOCOL_EAP, lcp)) + { + PPPSetStatus(p, PPP_STATUS_FAIL); + WHERE; + return false; + } + } + } + return false; +} + // Processes request packets bool PPPProcessRequestPacket(PPP_SESSION *p, PPP_PACKET *pp) @@ -1071,6 +1230,9 @@ bool PPPProcessRequestPacket(PPP_SESSION *p, PPP_PACKET *pp) PPPRejectUnsupportedPacketEx(p, pp, true); Debug("IPv6CP to be implemented\n"); break; + case PPP_PROTOCOL_EAP: + return PPPProcessEAPRequestPacket(p, pp); + break; default: Debug("Unsupported protocols should be already filtered out! protocol = 0x%x, code = 0x%x\n", pp->Protocol, pp->Lcp->Code); return false; @@ -1088,6 +1250,7 @@ bool PPPProcessLCPRequestPacket(PPP_SESSION *p, PPP_PACKET *pp) USHORT NegotiatedMRU = PPP_UNSPECIFIED; // MSCHAPv2 code UCHAR ms_chap_v2_code[3]; + USHORT eap_code = PPP_LCP_AUTH_EAP; WRITE_USHORT(ms_chap_v2_code, PPP_LCP_AUTH_CHAP); ms_chap_v2_code[2] = PPP_CHAP_ALG_MS_CHAP_V2; @@ -1102,22 +1265,27 @@ bool PPPProcessLCPRequestPacket(PPP_SESSION *p, PPP_PACKET *pp) { case PPP_LCP_OPTION_AUTH: t->IsSupported = true; - if (t->DataSize == sizeof(USHORT) && *((USHORT*)t->Data) == Endian16(PPP_LCP_AUTH_PAP) && p->AuthProtocol != PPP_PROTOCOL_CHAP) + if (t->DataSize == sizeof(USHORT) && *((USHORT*)t->Data) == PPP_LCP_AUTH_EAP && p->AuthProtocol == PPP_UNSPECIFIED) + { + t->IsAccepted = true; + NegotiatedAuthProto = PPP_PROTOCOL_EAP; + } + else if (t->DataSize == sizeof(USHORT) && *((USHORT*)t->Data) == PPP_LCP_AUTH_PAP && p->AuthProtocol == PPP_UNSPECIFIED) { t->IsAccepted = true; NegotiatedAuthProto = PPP_PROTOCOL_PAP; } - else if (t->DataSize == sizeof(ms_chap_v2_code) && Cmp(t->Data, ms_chap_v2_code, t->DataSize) == 0) + else if (t->DataSize == sizeof(ms_chap_v2_code) && Cmp(t->Data, ms_chap_v2_code, t->DataSize) == 0 && p->AuthProtocol == PPP_UNSPECIFIED) { t->IsAccepted = true; NegotiatedAuthProto = PPP_PROTOCOL_CHAP; } else { - // We're recommending MSCHAPv2 by default as a more secure algo + // We're recommending EAP by default as a more secure algo t->IsAccepted = false; - t->AltDataSize = sizeof(ms_chap_v2_code); - Copy(t->AltData, ms_chap_v2_code, sizeof(ms_chap_v2_code)); + t->AltDataSize = sizeof(eap_code); + Copy(t->AltData, &eap_code, sizeof(eap_code)); } break; case PPP_LCP_OPTION_MRU: @@ -1173,7 +1341,7 @@ bool PPPProcessLCPRequestPacket(PPP_SESSION *p, PPP_PACKET *pp) if (NegotiatedAuthProto != PPP_UNSPECIFIED) { - if (p->AuthProtocol == NULL) + if (p->AuthProtocol == PPP_UNSPECIFIED) { p->AuthProtocol = NegotiatedAuthProto; PPPSetStatus(p, PPP_STATUS_BEFORE_AUTH); @@ -1188,12 +1356,12 @@ bool PPPProcessLCPRequestPacket(PPP_SESSION *p, PPP_PACKET *pp) return true; } -bool PPPProcessPAPRequestPacket(PPP_SESSION *p, PPP_PACKET* pp) +bool PPPProcessPAPRequestPacket(PPP_SESSION *p, PPP_PACKET *pp) { if (p->PPPStatus != PPP_STATUS_BEFORE_AUTH && !p->AuthOk) { - PPP_LCP* lcp = NewPPPLCP(PPP_PAP_CODE_NAK, pp->Lcp->Id); - PPP_PACKET* ret = ZeroMalloc(sizeof(PPP_PACKET)); + PPP_LCP *lcp = NewPPPLCP(PPP_PAP_CODE_NAK, pp->Lcp->Id); + PPP_PACKET *ret = ZeroMalloc(sizeof(PPP_PACKET)); Debug("Got a PAP request before we're ready for AUTH procedure!\n"); @@ -1292,6 +1460,13 @@ bool PPPProcessPAPRequestPacket(PPP_SESSION *p, PPP_PACKET* pp) if (ipc != NULL) { p->Ipc = ipc; + + // Setting user timeouts + p->PacketRecvTimeout = (UINT64)p->Ipc->Policy->TimeOut * 1000 * 3 / 4; // setting to 3/4 of the user timeout + p->DataTimeout = (UINT64)p->Ipc->Policy->TimeOut * 1000; + p->UserConnectionTimeout = (UINT64)p->Ipc->Policy->AutoDisconnect * 1000; + p->UserConnectionTick = Tick64(); + p->AuthOk = true; } else @@ -1314,8 +1489,8 @@ bool PPPProcessPAPRequestPacket(PPP_SESSION *p, PPP_PACKET* pp) } if (p->AuthOk) { - PPP_LCP* lcp = NewPPPLCP(PPP_PAP_CODE_ACK, pp->Lcp->Id); - PPP_PACKET* ret = ZeroMalloc(sizeof(PPP_PACKET)); + PPP_LCP *lcp = NewPPPLCP(PPP_PAP_CODE_ACK, pp->Lcp->Id); + PPP_PACKET *ret = ZeroMalloc(sizeof(PPP_PACKET)); ret->IsControl = true; ret->Protocol = PPP_PROTOCOL_PAP; ret->Lcp = lcp; @@ -1334,8 +1509,8 @@ bool PPPProcessPAPRequestPacket(PPP_SESSION *p, PPP_PACKET* pp) } if (!p->AuthOk) { - PPP_LCP* lcp = NewPPPLCP(PPP_PAP_CODE_NAK, pp->Lcp->Id); - PPP_PACKET* ret = ZeroMalloc(sizeof(PPP_PACKET)); + PPP_LCP *lcp = NewPPPLCP(PPP_PAP_CODE_NAK, pp->Lcp->Id); + PPP_PACKET *ret = ZeroMalloc(sizeof(PPP_PACKET)); ret->IsControl = true; ret->Protocol = PPP_PROTOCOL_PAP; ret->Lcp = lcp; @@ -1354,11 +1529,11 @@ bool PPPProcessPAPRequestPacket(PPP_SESSION *p, PPP_PACKET* pp) return false; } - + return p->AuthOk; } -bool PPPProcessIPCPRequestPacket(PPP_SESSION *p, PPP_PACKET* pp) +bool PPPProcessIPCPRequestPacket(PPP_SESSION *p, PPP_PACKET *pp) { PPP_IPOPTION o; PPP_IPOPTION res; @@ -1372,7 +1547,7 @@ bool PPPProcessIPCPRequestPacket(PPP_SESSION *p, PPP_PACKET* pp) bool ok = true; bool processed = false; bool isEmptyIpAddress = false; - PPP_LCP* c; + PPP_LCP *c; if (p->IPv4_State == PPP_PROTO_STATUS_REJECTED) { @@ -1648,9 +1823,9 @@ bool PPPProcessIPCPRequestPacket(PPP_SESSION *p, PPP_PACKET* pp) // We will delay this packet ACK and send the server IP first, then wait for a reparse // it is kind of dirty but fixes issues on some clients (namely VPN Client Pro on Android) - if (p->IPv4_State == PPP_PROTO_STATUS_CLOSED && p->ClientAddressOption.ServerAddress != NULL && ok) + if (p->IPv4_State == PPP_PROTO_STATUS_CLOSED && p->ClientAddressOption.ServerAddress != 0 && ok) { - PPP_LCP* c = NewPPPLCP(PPP_LCP_CODE_REQ, 0); + PPP_LCP *c = NewPPPLCP(PPP_LCP_CODE_REQ, 0); UINT ui = p->ClientAddressOption.ServerAddress; Add(c->OptionList, NewPPPOption(PPP_IPCP_OPTION_IP, &ui, sizeof(UINT))); if (!PPPSendAndRetransmitRequest(p, PPP_PROTOCOL_IPCP, c)) @@ -1689,16 +1864,23 @@ bool PPPProcessIPCPRequestPacket(PPP_SESSION *p, PPP_PACKET* pp) return ok; } +// Process EAP request packets +bool PPPProcessEAPRequestPacket(PPP_SESSION *p, PPP_PACKET *pp) +{ + Debug("We got an EAP request, which is weird...\n"); + return false; +} + // LCP option based packets utility -bool PPPRejectLCPOptions(PPP_SESSION *p, PPP_PACKET* pp) +bool PPPRejectLCPOptions(PPP_SESSION *p, PPP_PACKET *pp) { return PPPRejectLCPOptionsEx(p, pp, false); } -bool PPPRejectLCPOptionsEx(PPP_SESSION *p, PPP_PACKET* pp, bool simulate) +bool PPPRejectLCPOptionsEx(PPP_SESSION *p, PPP_PACKET *pp, bool simulate) { UINT i = 0; bool toBeRejected = false; - PPP_PACKET* ret; + PPP_PACKET *ret; for (i = 0; i < LIST_NUM(pp->Lcp->OptionList); i++) { PPP_OPTION *t = LIST_DATA(pp->Lcp->OptionList, i); @@ -1742,14 +1924,14 @@ bool PPPRejectLCPOptionsEx(PPP_SESSION *p, PPP_PACKET* pp, bool simulate) PPPSendPacketAndFree(p, ret); return true; } -bool PPPNackLCPOptions(PPP_SESSION *p, PPP_PACKET* pp) +bool PPPNackLCPOptions(PPP_SESSION *p, PPP_PACKET *pp) { return PPPNackLCPOptionsEx(p, pp, false); } -bool PPPNackLCPOptionsEx(PPP_SESSION *p, PPP_PACKET* pp, bool simulate) +bool PPPNackLCPOptionsEx(PPP_SESSION *p, PPP_PACKET *pp, bool simulate) { UINT i = 0; - PPP_PACKET* ret; + PPP_PACKET *ret; bool toBeNACKed = false; for (i = 0; i < LIST_NUM(pp->Lcp->OptionList); i++) { @@ -1795,14 +1977,14 @@ bool PPPNackLCPOptionsEx(PPP_SESSION *p, PPP_PACKET* pp, bool simulate) PPPSendPacketAndFree(p, ret); return true; } -bool PPPAckLCPOptions(PPP_SESSION *p, PPP_PACKET* pp) +bool PPPAckLCPOptions(PPP_SESSION *p, PPP_PACKET *pp) { return PPPAckLCPOptionsEx(p, pp, false); } -bool PPPAckLCPOptionsEx(PPP_SESSION *p, PPP_PACKET* pp, bool simulate) +bool PPPAckLCPOptionsEx(PPP_SESSION *p, PPP_PACKET *pp, bool simulate) { UINT i = 0; - PPP_PACKET* ret; + PPP_PACKET *ret; bool toBeACKed = false; if (LIST_NUM(pp->Lcp->OptionList) == 0) { @@ -1860,7 +2042,7 @@ bool PPPSendAndRetransmitRequest(PPP_SESSION *p, USHORT protocol, PPP_LCP *c) { PPP_PACKET *pp; UINT64 now = Tick64(); - PPP_REQUEST_RESEND* resend; + PPP_REQUEST_RESEND *resend; // Validate arguments if (p == NULL || c == NULL) @@ -1889,7 +2071,7 @@ bool PPPSendAndRetransmitRequest(PPP_SESSION *p, USHORT protocol, PPP_LCP *c) resend->Id = pp->Lcp->Id; resend->Packet = pp; resend->ResendTime = now + PPP_PACKET_RESEND_INTERVAL; - resend->TimeoutTime = now + PPP_PACKET_RECV_TIMEOUT; + resend->TimeoutTime = now + p->PacketRecvTimeout; Add(p->SentReqPacketList, resend); @@ -1946,7 +2128,7 @@ LABEL_LOOP: if (async == false) { - d = TubeRecvSync(p->TubeRecv, PPP_PACKET_RECV_TIMEOUT); + d = TubeRecvSync(p->TubeRecv, p->PacketRecvTimeout); } else { @@ -1974,7 +2156,7 @@ LABEL_LOOP: PPP_PACKET *PPPGetNextPacket(PPP_SESSION *p) { - PPP_PACKET* ret = NULL; + PPP_PACKET *ret = NULL; UINT i = 0; if (p->CurrentPacket != NULL) { @@ -1983,7 +2165,7 @@ PPP_PACKET *PPPGetNextPacket(PPP_SESSION *p) } for (i = 0; i < LIST_NUM(p->DelayedPackets); i++) { - PPP_DELAYED_PACKET* t = LIST_DATA(p->DelayedPackets, i); + PPP_DELAYED_PACKET *t = LIST_DATA(p->DelayedPackets, i); if (t->DelayTicks > 0) { t->DelayTicks--; @@ -2007,10 +2189,10 @@ PPP_PACKET *PPPGetNextPacket(PPP_SESSION *p) if (ret != NULL && ret->IsControl && ret->Lcp != NULL) { - PPP_DELAYED_PACKET* firstRelated = NULL; + PPP_DELAYED_PACKET *firstRelated = NULL; for (i = 0; i < LIST_NUM(p->DelayedPackets); i++) { - PPP_DELAYED_PACKET* t = LIST_DATA(p->DelayedPackets, i); + PPP_DELAYED_PACKET *t = LIST_DATA(p->DelayedPackets, i); char related = PPPRelatedPacketComparator(ret, t->Packet); if (related != 0xF && related != 0xE) { @@ -2058,7 +2240,7 @@ PPP_PACKET *PPPGetNextPacket(PPP_SESSION *p) void PPPAddNextPacket(PPP_SESSION *p, PPP_PACKET *pp, UINT delay) { - PPP_DELAYED_PACKET* t = ZeroMalloc(sizeof(PPP_DELAYED_PACKET)); + PPP_DELAYED_PACKET *t = ZeroMalloc(sizeof(PPP_DELAYED_PACKET)); UINT i; if (p->CurrentPacket == pp) { @@ -2080,10 +2262,10 @@ void PPPAddNextPacket(PPP_SESSION *p, PPP_PACKET *pp, UINT delay) Debug("after sorting delayeds end\n");*/ } -int PPPDelayedPacketsComparator(const void* a, const void* b) +int PPPDelayedPacketsComparator(const void *a, const void *b) { - PPP_DELAYED_PACKET* first = a; - PPP_DELAYED_PACKET* second = b; + PPP_DELAYED_PACKET *first = a; + PPP_DELAYED_PACKET *second = b; char related = PPPRelatedPacketComparator(first->Packet, second->Packet); @@ -2123,7 +2305,7 @@ int PPPDelayedPacketsComparator(const void* a, const void* b) // 1 - packet a comes after packet b // 0xF - packet is not related // 0xE - we got an error while comparing, treating as not related would be the most correct -char PPPRelatedPacketComparator(PPP_PACKET* a, PPP_PACKET* b) +char PPPRelatedPacketComparator(PPP_PACKET *a, PPP_PACKET *b) { if (a->IsControl && b->IsControl && a->Lcp != NULL && b->Lcp != NULL && @@ -2248,7 +2430,7 @@ PPP_PACKET *ParsePPPPacket(void *data, UINT size) size -= 2; buf += 2; - if (pp->Protocol == PPP_PROTOCOL_LCP || pp->Protocol == PPP_PROTOCOL_PAP || pp->Protocol == PPP_PROTOCOL_CHAP || pp->Protocol == PPP_PROTOCOL_IPCP || pp->Protocol == PPP_PROTOCOL_IPV6CP) + if (pp->Protocol == PPP_PROTOCOL_LCP || pp->Protocol == PPP_PROTOCOL_PAP || pp->Protocol == PPP_PROTOCOL_CHAP || pp->Protocol == PPP_PROTOCOL_IPCP || pp->Protocol == PPP_PROTOCOL_IPV6CP || pp->Protocol == PPP_PROTOCOL_EAP) { pp->IsControl = true; } @@ -2388,7 +2570,7 @@ LABEL_ERROR: } // Analyse MS CHAP v2 Response packet -bool PPPParseMSCHAP2ResponsePacket(PPP_SESSION* p, PPP_PACKET* pp) +bool PPPParseMSCHAP2ResponsePacket(PPP_SESSION *p, PPP_PACKET *pp) { bool ok = false; @@ -2499,9 +2681,17 @@ bool PPPParseMSCHAP2ResponsePacket(PPP_SESSION* p, PPP_PACKET* pp) { p->Ipc = ipc; + // Setting user timeouts + p->PacketRecvTimeout = (UINT64)p->Ipc->Policy->TimeOut * 1000 * 3 / 4; // setting to 3/4 of the user timeout + p->DataTimeout = (UINT64)p->Ipc->Policy->TimeOut * 1000; + p->UserConnectionTimeout = (UINT64)p->Ipc->Policy->AutoDisconnect * 1000; + p->UserConnectionTick = Tick64(); + Copy(p->MsChapV2_ServerResponse, ipc->MsChapV2_ServerResponse, 20); ok = true; + + p->AuthOk = true; } } else @@ -2623,7 +2813,7 @@ BUF *BuildLCPData(PPP_LCP *c) } // Build the MS CHAP v2 challenge packet -PPP_LCP *BuildMSCHAP2ChallengePacket(PPP_SESSION* p) +PPP_LCP *BuildMSCHAP2ChallengePacket(PPP_SESSION *p) { PPP_LCP *lcp; BUF *b; @@ -2813,6 +3003,332 @@ bool PPPGetIPAddressValueFromLCP(PPP_LCP *c, UINT type, IP *ip) return true; } +// EAP packet utilities +bool PPPProcessEAPTlsResponse(PPP_SESSION *p, PPP_EAP *eap_packet, UINT eapTlsSize) +{ + UCHAR *dataBuffer; + UINT dataSize; + UINT tlsLength = 0; + UINT i; + bool isFragmented = false; + PPP_LCP *lcp; + PPP_EAP *eap; + UCHAR flags = PPP_EAP_TLS_FLAG_NONE; + UINT64 sizeLeft = 0; + Debug("Got EAP-TLS size=%i\n", eapTlsSize); + if (eapTlsSize == 1) + { + // This is an EAP-TLS message ACK + if (p->Eap_TlsCtx.CachedBufferSend != NULL) + { + // We got an ACK to transmit the next fragmented message + dataSize = p->Mru1 - 8 - 1 - 1; // Calculating the maximum payload size (without TlsLength) + sizeLeft = GetMemSize(p->Eap_TlsCtx.CachedBufferSend); + sizeLeft -= p->Eap_TlsCtx.CachedBufferSendPntr - p->Eap_TlsCtx.CachedBufferSend; + + flags = PPP_EAP_TLS_FLAG_FRAGMENTED; // M flag + if (dataSize > sizeLeft) + { + dataSize = sizeLeft; + flags = PPP_EAP_TLS_FLAG_NONE; // Clearing the M flag because it is the last packet + } + lcp = BuildEAPTlsRequest(p->Eap_PacketId++, dataSize, flags); + eap = lcp->Data; + Copy(eap->Tls.TlsDataWithoutLength, p->Eap_TlsCtx.CachedBufferSendPntr, dataSize); + p->Eap_TlsCtx.CachedBufferSendPntr += dataSize; + + if (!PPPSendAndRetransmitRequest(p, PPP_PROTOCOL_EAP, lcp)) + { + PPPSetStatus(p, PPP_STATUS_FAIL); + WHERE; + return false; + } + Debug("Sent EAP-TLS size=%i type=%i flag=%i\n", lcp->DataSize, eap->Type, eap->Tls.Flags); + + if (flags == PPP_EAP_TLS_FLAG_NONE) + { + // As it is the latest message, we need to cleanup + Free(p->Eap_TlsCtx.CachedBufferSend); + p->Eap_TlsCtx.CachedBufferSend = NULL; + p->Eap_TlsCtx.CachedBufferSendPntr = NULL; + } + } + else + { + // It probably should be the final ACK on closed SSL pipe + SyncSslPipe(p->Eap_TlsCtx.SslPipe); + if (p->Eap_TlsCtx.ClientCert.X != NULL) + { + IPC *ipc; + ETHERIP_ID d; + UINT error_code; + + /*if (!p->Eap_TlsCtx.SslPipe->IsDisconnected) + { + dataSize = FifoSize(p->Eap_TlsCtx.SslPipe->RawOut->RecvFifo); + lcp = BuildEAPTlsRequest(p->Eap_PacketId++, dataSize, 0); + eap = lcp->Data; + ReadFifo(p->Eap_TlsCtx.SslPipe->RawOut->RecvFifo, &(eap->Tls.TlsDataWithoutLength), dataSize); + if (!PPPSendAndRetransmitRequest(p, PPP_PROTOCOL_EAP, lcp)) + { + PPPSetStatus(p, PPP_STATUS_FAIL); + WHERE; + return false; + } + Debug("Sent EAP-TLS size=%i type=%i flag=%i\n", lcp->DataSize, eap->Type, eap->Tls.Flags); + return true; + }*/ + + PPPParseUsername(p->Cedar, p->Eap_Identity, &d); + + ipc = NewIPC(p->Cedar, p->ClientSoftwareName, p->Postfix, d.HubName, d.UserName, "", + &error_code, &p->ClientIP, p->ClientPort, &p->ServerIP, p->ServerPort, + p->ClientHostname, p->CryptName, false, p->AdjustMss, NULL, p->Eap_TlsCtx.ClientCert.X, + IPC_LAYER_3); + + if (ipc != NULL) + { + PPP_PACKET *pack; + UINT identificator = p->Eap_PacketId - 1; // THIS IS A HACK TO SUPPORT VPN Client Pro on Android!!! + + p->Ipc = ipc; + PPPSetStatus(p, PPP_STATUS_AUTH_SUCCESS); + + // Just send an EAP-Success + pack = ZeroMalloc(sizeof(PPP_PACKET)); + pack->IsControl = true; + pack->Protocol = PPP_PROTOCOL_EAP; + lcp = NewPPPLCP(PPP_EAP_CODE_SUCCESS, identificator); + pack->Lcp = lcp; + Debug("Sent EAP-TLS size=%i SUCCESS\n", lcp->DataSize); + if (!PPPSendPacketAndFree(p, pack)) + { + PPPSetStatus(p, PPP_STATUS_FAIL); + WHERE; + return false; + } + return true; + } + else + { + PPP_PACKET *pack; + UINT identificator = p->Eap_PacketId - 1; // THIS IS A HACK TO SUPPORT VPN Client Pro on Android!!! + + PPPSetStatus(p, PPP_STATUS_AUTH_FAIL); + + pack = ZeroMalloc(sizeof(PPP_PACKET)); + pack->IsControl = true; + pack->Protocol = PPP_PROTOCOL_EAP; + lcp = NewPPPLCP(PPP_EAP_CODE_FAILURE, identificator); + pack->Lcp = lcp; + Debug("Sent EAP-TLS size=%i FAILURE\n", lcp->DataSize); + if (!PPPSendPacketAndFree(p, pack)) + { + PPPSetStatus(p, PPP_STATUS_FAIL); + WHERE; + return false; + } + return false; + } + } + else + { + // Some clients needs a little help it seems - namely VPN Client Pro on Android + flags |= PPP_EAP_TLS_FLAG_SSLSTARTED; + lcp = BuildEAPTlsRequest(p->Eap_PacketId++, 0, flags); + PPPSetStatus(p, PPP_STATUS_AUTHENTICATING); + if (!PPPSendAndRetransmitRequest(p, PPP_PROTOCOL_EAP, lcp)) + { + PPPSetStatus(p, PPP_STATUS_FAIL); + WHERE; + return false; + } + Debug("Sent EAP-TLS size=%i\n", lcp->DataSize); + return true; + } + } + return true; + } + dataBuffer = eap_packet->Tls.TlsDataWithoutLength; + dataSize = eapTlsSize - 1; + if (eap_packet->Tls.Flags & PPP_EAP_TLS_FLAG_TLS_LENGTH) + { + dataBuffer = eap_packet->Tls.TlsDataWithLength.Data; + dataSize -= 4; + tlsLength = Endian32(eap_packet->Tls.TlsDataWithLength.TlsLength); + } + /*Debug("=======RECV EAP-TLS PACKET DUMP=======\n"); + for (i = 0; i < dataSize; i++) + { + if (i > 0) printf(" "); + Debug("%02X", dataBuffer[i]); + } + Debug("\n=======RECV EAP-TLS PACKET DUMP END=======\n");*/ + if (eap_packet->Tls.Flags & PPP_EAP_TLS_FLAG_FRAGMENTED) + { + isFragmented = true; + } + + if (p->PPPStatus == PPP_STATUS_AUTHENTICATING) + { + // First we initialize the SslPipe if it is not already inited + if (p->Eap_TlsCtx.SslPipe == NULL) + { + p->Eap_TlsCtx.Dh = DhNewFromBits(DH_PARAM_BITS_DEFAULT); + p->Eap_TlsCtx.SslPipe = NewSslPipeEx(true, p->Cedar->ServerX, p->Cedar->ServerK, p->Eap_TlsCtx.Dh, true, &(p->Eap_TlsCtx.ClientCert)); + } + + // If the current frame is fragmented, or it is a possible last of a fragmented series, bufferize it + if (isFragmented || p->Eap_TlsCtx.CachedBufferRecv != NULL) + { + if (p->Eap_TlsCtx.CachedBufferRecv == NULL && tlsLength > 0) + { + p->Eap_TlsCtx.CachedBufferRecv = ZeroMalloc(MAX(dataSize, tlsLength)); + p->Eap_TlsCtx.CachedBufferRecvPntr = p->Eap_TlsCtx.CachedBufferRecv; + } + else if (p->Eap_TlsCtx.CachedBufferRecv == NULL) + { + p->Eap_TlsCtx.CachedBufferRecv = ZeroMalloc(MAX(dataSize, PPP_MRU_MAX * 10)); // 10 MRUs should be enough + p->Eap_TlsCtx.CachedBufferRecvPntr = p->Eap_TlsCtx.CachedBufferRecv; + } + sizeLeft = GetMemSize(p->Eap_TlsCtx.CachedBufferRecv); + sizeLeft -= p->Eap_TlsCtx.CachedBufferRecvPntr - p->Eap_TlsCtx.CachedBufferRecv; + + Copy(p->Eap_TlsCtx.CachedBufferRecvPntr, dataBuffer, MIN(sizeLeft, dataSize)); + + p->Eap_TlsCtx.CachedBufferRecvPntr += MIN(sizeLeft, dataSize); + } + + // If we got a cached buffer, we should feed the FIFOs via it + if (p->Eap_TlsCtx.CachedBufferRecv != NULL) + { + dataBuffer = p->Eap_TlsCtx.CachedBufferRecv; + dataSize = GetMemSize(p->Eap_TlsCtx.CachedBufferRecv); + if (dataSize == MAX_BUFFERING_PACKET_SIZE) + { + dataSize = p->Eap_TlsCtx.CachedBufferRecvPntr - p->Eap_TlsCtx.CachedBufferRecv; + } + } + + // Just acknoweldge that we buffered the fragmented data + if (isFragmented) + { + PPP_LCP *lcp = BuildEAPPacketEx(PPP_EAP_CODE_REQUEST, p->Eap_PacketId++, PPP_EAP_TYPE_TLS, 0); + if (!PPPSendAndRetransmitRequest(p, PPP_PROTOCOL_EAP, lcp)) + { + PPPSetStatus(p, PPP_STATUS_FAIL); + WHERE; + return false; + } + Debug("Sent EAP-TLS size=%i\n", lcp->DataSize); + } + else + { + /*Debug("=======RECV EAP-TLS FIFO DUMP=======\n"); + for (i = 0; i < dataSize; i++) + { + if (i > 0) printf(" "); + Debug("%02X", dataBuffer[i]); + } + Debug("\n=======RECV EAP-TLS PACKET FIFO END=======\n");*/ + WriteFifo(p->Eap_TlsCtx.SslPipe->RawIn->SendFifo, dataBuffer, dataSize); + SyncSslPipe(p->Eap_TlsCtx.SslPipe); + // Delete the cached buffer after we fed it into the pipe + if (p->Eap_TlsCtx.CachedBufferRecv != NULL) + { + Free(p->Eap_TlsCtx.CachedBufferRecv); + p->Eap_TlsCtx.CachedBufferRecv = NULL; + p->Eap_TlsCtx.CachedBufferRecvPntr = NULL; + } + + if (p->Eap_TlsCtx.SslPipe->IsDisconnected == false) + { + dataSize = FifoSize(p->Eap_TlsCtx.SslPipe->RawOut->RecvFifo); + // Do we need to send a fragmented packet? + if (dataSize > p->Mru1 - 8 - 1 - 1) + { + if (p->Eap_TlsCtx.CachedBufferSend == NULL) + { + p->Eap_TlsCtx.CachedBufferSend = ZeroMalloc(dataSize); + p->Eap_TlsCtx.CachedBufferSendPntr = p->Eap_TlsCtx.CachedBufferSend; + } + ReadFifo(p->Eap_TlsCtx.SslPipe->RawOut->RecvFifo, p->Eap_TlsCtx.CachedBufferSend, dataSize); + + // Now send data from the cached buffer with set fragmentation flag and also total TLS Size + tlsLength = dataSize; + dataSize = p->Mru1 - 8 - 1 - 1 - 4; // Calculating the maximum payload size (adjusting for including TlsLength) + flags = PPP_EAP_TLS_FLAG_TLS_LENGTH; // L flag + flags |= PPP_EAP_TLS_FLAG_FRAGMENTED; // M flag + lcp = BuildEAPTlsRequest(p->Eap_PacketId++, dataSize, flags); + eap = lcp->Data; + eap->Tls.TlsDataWithLength.TlsLength = Endian32(tlsLength); + Copy(eap->Tls.TlsDataWithLength.Data, p->Eap_TlsCtx.CachedBufferSend, dataSize); + p->Eap_TlsCtx.CachedBufferSendPntr += dataSize; + if (!PPPSendAndRetransmitRequest(p, PPP_PROTOCOL_EAP, lcp)) + { + PPPSetStatus(p, PPP_STATUS_FAIL); + WHERE; + return false; + } + Debug("Sent EAP-TLS size=%i type=%i flag=%i\n", lcp->DataSize, eap->Type, eap->Tls.Flags); + } + else + { + lcp = BuildEAPTlsRequest(p->Eap_PacketId++, dataSize, 0); + eap = lcp->Data; + ReadFifo(p->Eap_TlsCtx.SslPipe->RawOut->RecvFifo, &(eap->Tls.TlsDataWithoutLength), dataSize); + if (!PPPSendAndRetransmitRequest(p, PPP_PROTOCOL_EAP, lcp)) + { + PPPSetStatus(p, PPP_STATUS_FAIL); + WHERE; + return false; + } + Debug("Sent EAP-TLS size=%i type=%i flag=%i\n", lcp->DataSize, eap->Type, eap->Tls.Flags); + } + } + } + } + else + { + Debug("Got an EAP_TLS packet when not authenticating, ignoring...\n"); + } + return false; +} + +PPP_LCP *BuildEAPPacketEx(UCHAR code, UCHAR id, UCHAR type, UINT datasize) +{ + PPP_EAP *eap_packet; + PPP_LCP *lcp_packet; + UINT lcpDatasize; + lcpDatasize = datasize + sizeof(UCHAR); + eap_packet = ZeroMalloc(lcpDatasize); + eap_packet->Type = type; + lcp_packet = NewPPPLCP(code, id); + lcp_packet->Data = eap_packet; + lcp_packet->DataSize = lcpDatasize; + return lcp_packet; +} + +PPP_LCP *BuildEAPTlsPacketEx(UCHAR code, UCHAR id, UCHAR type, UINT datasize, UCHAR flags) +{ + PPP_LCP *lcp_packet; + PPP_EAP *eap_packet; + UINT tls_datasize = datasize + sizeof(UCHAR); + if (flags & PPP_EAP_TLS_FLAG_TLS_LENGTH) + { + tls_datasize += sizeof(UINT32); + } + lcp_packet = BuildEAPPacketEx(code, id, type, tls_datasize); + eap_packet = lcp_packet->Data; + eap_packet->Tls.Flags = flags; + return lcp_packet; +} + +PPP_LCP *BuildEAPTlsRequest(UCHAR id, UINT datasize, UCHAR flags) +{ + return BuildEAPTlsPacketEx(PPP_EAP_CODE_REQUEST, id, PPP_EAP_TYPE_TLS, datasize, flags); +} + // Other packet utilities // Get the option value @@ -2924,6 +3440,29 @@ void FreePPPSession(PPP_SESSION *p) p->TubeRecv->IntParam2 = p->DisconnectCauseDirection; } + // Freeing EAP-TLS context + if (p->Eap_TlsCtx.CachedBufferRecv != NULL) + { + Free(p->Eap_TlsCtx.CachedBufferRecv); + } + if (p->Eap_TlsCtx.CachedBufferSend != NULL) + { + Free(p->Eap_TlsCtx.CachedBufferRecv); + } + if (p->Eap_TlsCtx.SslPipe != NULL) + { + FreeSslPipe(p->Eap_TlsCtx.SslPipe); + } + if (p->Eap_TlsCtx.ClientCert.X != NULL) + { + FreeX(p->Eap_TlsCtx.ClientCert.X); + } + if (p->Eap_TlsCtx.Dh != NULL) + { + DhFree(p->Eap_TlsCtx.Dh); + } + + FreeTubeFlushList(p->FlushList); TubeDisconnect(p->TubeRecv); @@ -3337,3 +3876,5 @@ char *MsChapV2DoBruteForce(IPC_MSCHAP_V2_AUTHINFO *d, LIST *password_list) return NULL; } + + diff --git a/src/Cedar/Proto_PPP.h b/src/Cedar/Proto_PPP.h index afd9bfd8..311617ba 100644 --- a/src/Cedar/Proto_PPP.h +++ b/src/Cedar/Proto_PPP.h @@ -18,25 +18,28 @@ #define PPP_PAP_CODE_IS_REQUEST(c) ((c) == PPP_PAP_CODE_REQ) #define PPP_PAP_CODE_IS_RESPONSE(c) ((c) == PPP_PAP_CODE_ACK || (c) == PPP_PAP_CODE_NAK) -#define PPP_CHAP_CODE_IS_REQUEST(c) ((c) == PPP_CHAP_CODE_CHALLENGE || (c) == PPP_CHAP_CODE_SUCCESS || (c) == PPP_CHAP_CODE_FAILURE) -#define PPP_CHAP_CODE_IS_RESPONSE(c) ((c) == PPP_CHAP_CODE_RESPONSE) +#define PPP_CHAP_CODE_IS_REQUEST(c) ((c) == PPP_CHAP_CODE_CHALLENGE || (c) == PPP_CHAP_CODE_SUCCESS || (c) == PPP_CHAP_CODE_FAILURE) +#define PPP_CHAP_CODE_IS_RESPONSE(c) ((c) == PPP_CHAP_CODE_RESPONSE) -#define PPP_CODE_IS_RESPONSE(protocol, c) ((((protocol) == PPP_PROTOCOL_LCP || (protocol) == PPP_PROTOCOL_IPCP || (protocol) == PPP_PROTOCOL_IPV6CP) && PPP_LCP_CODE_IS_RESPONSE(c)) || (((protocol) == PPP_PROTOCOL_PAP) && PPP_PAP_CODE_IS_RESPONSE(c)) || (((protocol) == PPP_PROTOCOL_CHAP) && PPP_CHAP_CODE_IS_RESPONSE(c))) -#define PPP_CODE_IS_REQUEST(protocol, c) ((((protocol) == PPP_PROTOCOL_LCP || (protocol) == PPP_PROTOCOL_IPCP || (protocol) == PPP_PROTOCOL_IPV6CP) && PPP_LCP_CODE_IS_REQUEST(c)) || (((protocol) == PPP_PROTOCOL_PAP) && PPP_PAP_CODE_IS_REQUEST(c)) || (((protocol) == PPP_PROTOCOL_CHAP) && PPP_CHAP_CODE_IS_REQUEST(c))) +#define PPP_EAP_CODE_IS_REQUEST(c) ((c) == PPP_EAP_CODE_REQUEST) +#define PPP_EAP_CODE_IS_RESPONSE(c) ((c) == PPP_EAP_CODE_RESPONSE || (c) == PPP_EAP_CODE_SUCCESS || (c) == PPP_EAP_CODE_FAILURE) + +#define PPP_CODE_IS_RESPONSE(protocol, c) ((((protocol) == PPP_PROTOCOL_LCP || (protocol) == PPP_PROTOCOL_IPCP || (protocol) == PPP_PROTOCOL_IPV6CP) && PPP_LCP_CODE_IS_RESPONSE(c)) || (((protocol) == PPP_PROTOCOL_PAP) && PPP_PAP_CODE_IS_RESPONSE(c)) || (((protocol) == PPP_PROTOCOL_CHAP) && PPP_CHAP_CODE_IS_RESPONSE(c)) || (((protocol) == PPP_PROTOCOL_EAP) && PPP_EAP_CODE_IS_RESPONSE(c))) +#define PPP_CODE_IS_REQUEST(protocol, c) ((((protocol) == PPP_PROTOCOL_LCP || (protocol) == PPP_PROTOCOL_IPCP || (protocol) == PPP_PROTOCOL_IPV6CP) && PPP_LCP_CODE_IS_REQUEST(c)) || (((protocol) == PPP_PROTOCOL_PAP) && PPP_PAP_CODE_IS_REQUEST(c)) || (((protocol) == PPP_PROTOCOL_CHAP) && PPP_CHAP_CODE_IS_REQUEST(c)) || (((protocol) == PPP_PROTOCOL_EAP) && PPP_EAP_CODE_IS_REQUEST(c))) #define PPP_CODE_IS_WITH_OPTION_LIST(protocol, c) ((((protocol) == PPP_PROTOCOL_LCP || (protocol) == PPP_PROTOCOL_IPCP || (protocol) == PPP_PROTOCOL_IPV6CP) && PPP_LCP_CODE_IS_WITH_OPTION_LIST(c)) || false) -#define PPP_IS_SUPPORTED_PROTOCOL(p) ((p) == PPP_PROTOCOL_LCP || (p) == PPP_PROTOCOL_PAP || (p) == PPP_PROTOCOL_CHAP || (p) == PPP_PROTOCOL_IPCP || (p) == PPP_PROTOCOL_IPV6CP || (p) == PPP_PROTOCOL_IP || (p) == PPP_PROTOCOL_IPV6) +#define PPP_IS_SUPPORTED_PROTOCOL(p) ((p) == PPP_PROTOCOL_LCP || (p) == PPP_PROTOCOL_PAP || (p) == PPP_PROTOCOL_CHAP || (p) == PPP_PROTOCOL_IPCP || (p) == PPP_PROTOCOL_IPV6CP || (p) == PPP_PROTOCOL_IP || (p) == PPP_PROTOCOL_IPV6 || (p) == PPP_PROTOCOL_EAP ) #define PPP_STATUS_IS_UNAVAILABLE(c) ((c) == PPP_STATUS_FAIL || (c) == PPP_STATUS_AUTH_FAIL || (c) == PPP_STATUS_CLOSING || (c) == PPP_STATUS_CLOSING_WAIT || (c) == PPP_STATUS_CLOSED) //// Constants // Time-out value -#define PPP_PACKET_RECV_TIMEOUT (30 * 1000) // Timeout until the next packet is received -#define PPP_PACKET_RESEND_INTERVAL (5 * 1000) // Retransmission interval of the last packet +#define PPP_PACKET_RECV_TIMEOUT (15 * 1000) // Timeout until the next packet is received (3/4 of default policy) +#define PPP_PACKET_RESEND_INTERVAL (3 * 1000) // Retransmission interval of the last packet #define PPP_TERMINATE_TIMEOUT 2000 // Timeout value to complete disconnection after requesting to disconnect in the PPP #define PPP_ECHO_SEND_INTERVAL 4792 // Transmission interval of PPP Echo Request -#define PPP_DATA_TIMEOUT (60 * 1000) // Communication time-out +#define PPP_DATA_TIMEOUT (20 * 1000) // Communication time-out (from default policy) // MRU #define PPP_MRU_DEFAULT 1500 // Default value @@ -48,7 +51,8 @@ #define PPP_PROTOCOL_PAP 0xc023 #define PPP_PROTOCOL_IPCP 0x8021 #define PPP_PROTOCOL_CHAP 0xc223 -#define PPP_PROTOCOL_IPV6CP 0x8057 +#define PPP_PROTOCOL_EAP 0xc227 +#define PPP_PROTOCOL_IPV6CP 0x8057 // PPP protocol (for transfer) #define PPP_PROTOCOL_IP 0x0021 @@ -91,35 +95,54 @@ #define PPP_IPCP_OPTION_WINS2 132 // IPV6CP option type -#define PPP_IPV6CP_OPTION_IID 1 +#define PPP_IPV6CP_OPTION_IID 1 + +// EAP codes +#define PPP_EAP_CODE_REQUEST 1 +#define PPP_EAP_CODE_RESPONSE 2 +#define PPP_EAP_CODE_SUCCESS 3 +#define PPP_EAP_CODE_FAILURE 4 + +// EAP types +#define PPP_EAP_TYPE_IDENTITY 1 +#define PPP_EAP_TYPE_NOTIFICATION 2 +#define PPP_EAP_TYPE_NAK 3 +#define PPP_EAP_TYPE_TLS 13 + +// EAP-TLS Flags +#define PPP_EAP_TLS_FLAG_NONE 0 +#define PPP_EAP_TLS_FLAG_TLS_LENGTH 1 << 7 +#define PPP_EAP_TLS_FLAG_FRAGMENTED 1 << 6 +#define PPP_EAP_TLS_FLAG_SSLSTARTED 1 << 5 // Authentication protocol #define PPP_LCP_AUTH_PAP PPP_PROTOCOL_PAP #define PPP_LCP_AUTH_CHAP PPP_PROTOCOL_CHAP +#define PPP_LCP_AUTH_EAP PPP_PROTOCOL_EAP // Algorithm of CHAP #define PPP_CHAP_ALG_MS_CHAP_V2 0x81 // Link status -#define PPP_STATUS_CONNECTED 0x1 -#define PPP_STATUS_BEFORE_AUTH 0x10 -#define PPP_STATUS_AUTHENTICATING 0x11 -#define PPP_STATUS_AUTH_SUCCESS 0x19 -#define PPP_STATUS_NETWORK_LAYER 0x20 -#define PPP_STATUS_CLOSING 0x100 -#define PPP_STATUS_CLOSING_WAIT 0x101 -#define PPP_STATUS_CLOSED 0x110 -#define PPP_STATUS_FAIL 0x1000 -#define PPP_STATUS_AUTH_FAIL 0x1010 +#define PPP_STATUS_CONNECTED 0x1 +#define PPP_STATUS_BEFORE_AUTH 0x10 +#define PPP_STATUS_AUTHENTICATING 0x11 +#define PPP_STATUS_AUTH_SUCCESS 0x19 +#define PPP_STATUS_NETWORK_LAYER 0x20 +#define PPP_STATUS_CLOSING 0x100 +#define PPP_STATUS_CLOSING_WAIT 0x101 +#define PPP_STATUS_CLOSED 0x110 +#define PPP_STATUS_FAIL 0x1000 +#define PPP_STATUS_AUTH_FAIL 0x1010 // Protocol status -#define PPP_PROTO_STATUS_CLOSED 0x0 -#define PPP_PROTO_STATUS_CONFIG 0x1 -#define PPP_PROTO_STATUS_CONFIG_WAIT 0x2 -#define PPP_PROTO_STATUS_OPENED 0x10 -#define PPP_PROTO_STATUS_REJECTED 0x100 +#define PPP_PROTO_STATUS_CLOSED 0x0 +#define PPP_PROTO_STATUS_CONFIG 0x1 +#define PPP_PROTO_STATUS_CONFIG_WAIT 0x2 +#define PPP_PROTO_STATUS_OPENED 0x10 +#define PPP_PROTO_STATUS_REJECTED 0x100 -#define PPP_UNSPECIFIED 0xFFFF +#define PPP_UNSPECIFIED 0xFFFF //// Type @@ -164,6 +187,53 @@ struct PPP_OPTION UINT AltDataSize; // Alternate data size }; +#ifdef OS_WIN32 +#pragma pack(push, 1) +#else // OS_WIN32 +#pragma pack(1) +#endif + + +// PPP EAP packet +// EAP is a subset of LCP, sharing Code and Id. The Data field is then mapped to this structure +// We got 8 bytes of size before this structure +struct PPP_EAP +{ + UCHAR Type; + union { + UCHAR Data[0]; + struct PPP_EAP_TLS + { + UCHAR Flags; + union { + UCHAR TlsDataWithoutLength[0]; + struct + { + UINT32 TlsLength; + UCHAR Data[0]; + } TlsDataWithLength; + }; + } Tls; + }; +} GCC_PACKED; + +#ifdef OS_WIN32 +#pragma pack(pop) +#else // OS_WIN32 +#pragma pack() +#endif + +struct PPP_EAP_TLS_CONTEXT +{ + SSL_PIPE *SslPipe; + DH_CTX *Dh; + struct SslClientCertInfo ClientCert; + UCHAR *CachedBufferRecv; + UCHAR *CachedBufferRecvPntr; + UCHAR *CachedBufferSend; + UCHAR *CachedBufferSendPntr; +}; + // PPP request resend struct PPP_REQUEST_RESEND { @@ -234,10 +304,23 @@ struct PPP_SESSION UINT IPv4_State; UINT IPv6_State; + // EAP contexts + UINT Eap_Protocol; // Current EAP Protocol used + UINT Eap_PacketId; // EAP Packet ID; + UCHAR Eap_Identity[MAX_SIZE]; // Received from client identity + PPP_EAP_TLS_CONTEXT Eap_TlsCtx; // Context information for EAP TLS. May be possibly reused for EAP TTLS? + LIST *SentReqPacketList; // Sent requests list PPP_PACKET *CurrentPacket; LIST *DelayedPackets; + + UINT64 PacketRecvTimeout; + UINT64 DataTimeout; + UINT64 UserConnectionTimeout; + UINT64 UserConnectionTick; + + THREAD *SessionThread; // Thread of the PPP session }; @@ -248,7 +331,7 @@ struct PPP_SESSION void PPPThread(THREAD *thread, void *param); // Entry point -THREAD *NewPPPSession(CEDAR *cedar, IP *client_ip, UINT client_port, IP *server_ip, UINT server_port, TUBE *send_tube, TUBE *recv_tube, char *postfix, char *client_software_name, char *client_hostname, char *crypt_name, UINT adjust_mss); +PPP_SESSION *NewPPPSession(CEDAR *cedar, IP *client_ip, UINT client_port, IP *server_ip, UINT server_port, TUBE *send_tube, TUBE *recv_tube, char *postfix, char *client_software_name, char *client_hostname, char *crypt_name, UINT adjust_mss); // PPP processing functions bool PPPRejectUnsupportedPacket(PPP_SESSION *p, PPP_PACKET *pp); @@ -260,21 +343,22 @@ bool PPPProcessResponsePacket(PPP_SESSION *p, PPP_PACKET *pp, PPP_PACKET *req); bool PPPProcessLCPResponsePacket(PPP_SESSION *p, PPP_PACKET *pp, PPP_PACKET *req); bool PPPProcessCHAPResponsePacket(PPP_SESSION *p, PPP_PACKET *pp, PPP_PACKET *req); bool PPPProcessIPCPResponsePacket(PPP_SESSION *p, PPP_PACKET *pp, PPP_PACKET *req); +bool PPPProcessEAPResponsePacket(PPP_SESSION *p, PPP_PACKET *pp, PPP_PACKET *req); // Request packets bool PPPProcessRequestPacket(PPP_SESSION *p, PPP_PACKET *pp); bool PPPProcessLCPRequestPacket(PPP_SESSION *p, PPP_PACKET *pp); bool PPPProcessPAPRequestPacket(PPP_SESSION *p, PPP_PACKET *pp); bool PPPProcessIPCPRequestPacket(PPP_SESSION *p, PPP_PACKET *pp); +bool PPPProcessEAPRequestPacket(PPP_SESSION *p, PPP_PACKET *pp); // LCP option based packets utility bool PPPRejectLCPOptions(PPP_SESSION *p, PPP_PACKET *pp); bool PPPRejectLCPOptionsEx(PPP_SESSION *p, PPP_PACKET *pp, bool simulate); bool PPPNackLCPOptions(PPP_SESSION *p, PPP_PACKET *pp); -bool PPPNackLCPOptionsEx(PPP_SESSION *p, PPP_PACKET* pp, bool simulate); +bool PPPNackLCPOptionsEx(PPP_SESSION *p, PPP_PACKET *pp, bool simulate); bool PPPAckLCPOptions(PPP_SESSION *p, PPP_PACKET *pp); bool PPPAckLCPOptionsEx(PPP_SESSION *p, PPP_PACKET *pp, bool simulate); - // PPP networking functions // Send packets bool PPPSendAndRetransmitRequest(PPP_SESSION *p, USHORT protocol, PPP_LCP *c); @@ -305,6 +389,11 @@ bool PPPGetIPOptionFromLCP(PPP_IPOPTION *o, PPP_LCP *c); bool PPPSetIPOptionToLCP(PPP_IPOPTION *o, PPP_LCP *c, bool only_modify); bool PPPGetIPAddressValueFromLCP(PPP_LCP *c, UINT type, IP *ip); bool PPPSetIPAddressValueToLCP(PPP_LCP *c, UINT type, IP *ip, bool only_modify); +// EAP packet utilities +bool PPPProcessEAPTlsResponse(PPP_SESSION *p, PPP_EAP *eap_packet, UINT eapTlsSize); +PPP_LCP *BuildEAPPacketEx(UCHAR code, UCHAR id, UCHAR type, UINT datasize); +PPP_LCP *BuildEAPTlsPacketEx(UCHAR code, UCHAR id, UCHAR type, UINT datasize, UCHAR flags); +PPP_LCP *BuildEAPTlsRequest(UCHAR id, UINT datasize, UCHAR flags); // Other packet utilities PPP_OPTION *PPPGetOptionValue(PPP_LCP *c, UCHAR type); bool IsHubExistsWithLock(CEDAR *cedar, char *hubname); diff --git a/src/Cedar/Proto_SSTP.c b/src/Cedar/Proto_SSTP.c index cd9c7e86..63c2666c 100644 --- a/src/Cedar/Proto_SSTP.c +++ b/src/Cedar/Proto_SSTP.c @@ -97,6 +97,8 @@ void SstpProcessControlPacket(SSTP_SERVER *s, SSTP_PACKET *p) // Process the SSTP received data packet void SstpProcessDataPacket(SSTP_SERVER *s, SSTP_PACKET *p) { + PPP_SESSION *underlyingSession; + // Validate arguments if (s == NULL || p == NULL || p->IsControl) { @@ -108,9 +110,11 @@ void SstpProcessDataPacket(SSTP_SERVER *s, SSTP_PACKET *p) if (s->PPPThread == NULL) { // Create a thread to initialize the new PPP module - s->PPPThread = NewPPPSession(s->Cedar, &s->ClientIp, s->ClientPort, &s->ServerIp, s->ServerPort, + underlyingSession = NewPPPSession(s->Cedar, &s->ClientIp, s->ClientPort, &s->ServerIp, s->ServerPort, s->TubeSend, s->TubeRecv, SSTP_IPC_POSTFIX, SSTP_IPC_CLIENT_NAME, s->ClientHostName, s->ClientCipherName, 0); + s->PPPSession = underlyingSession; + s->PPPThread = underlyingSession->SessionThread; } // Pass the received data to the PPP module @@ -177,6 +181,7 @@ void SstpSendPacket(SSTP_SERVER *s, SSTP_PACKET *p) // Process the timer interrupt void SstpProcessInterrupt(SSTP_SERVER *s) { + UINT64 sstpTimeout = SSTP_TIMEOUT; // Validate arguments if (s == NULL) { @@ -261,7 +266,12 @@ void SstpProcessInterrupt(SSTP_SERVER *s) } } - if ((s->LastRecvTick + (UINT64)SSTP_TIMEOUT) <= s->Now) + if (s->PPPSession != NULL && s->PPPSession->DataTimeout > sstpTimeout) + { + sstpTimeout = s->PPPSession->DataTimeout; + } + + if ((s->LastRecvTick + sstpTimeout) <= s->Now) { // Disconnect the SSTP because a timeout occurred SstpAbort(s); diff --git a/src/Cedar/Proto_SSTP.h b/src/Cedar/Proto_SSTP.h index ed722734..8ef8e424 100644 --- a/src/Cedar/Proto_SSTP.h +++ b/src/Cedar/Proto_SSTP.h @@ -16,7 +16,7 @@ #define SSTP_IPC_POSTFIX "SSTP" #define SSTP_ECHO_SEND_INTERVAL_MIN 2500 // Transmission interval of Echo Request (minimum) #define SSTP_ECHO_SEND_INTERVAL_MAX 4792 // Transmission interval of Echo Request (maximum) -#define SSTP_TIMEOUT 10000 // Communication time-out of SSTP +#define SSTP_TIMEOUT 20 * 1000 // Communication time-out of SSTP (from default policy) // SSTP Message Type #define SSTP_MSG_CALL_CONNECT_REQUEST 0x0001 @@ -116,6 +116,7 @@ struct SSTP_SERVER UINT64 LastRecvTick; // Tick when some data has received at the end bool FlushRecvTube; // Flag whether to flush the reception tube UINT EstablishedCount; // Number of session establishment + PPP_SESSION *PPPSession; // Underlying PPP Session }; diff --git a/src/Mayaqua/Network.c b/src/Mayaqua/Network.c index 682214cd..717d0f9d 100644 --- a/src/Mayaqua/Network.c +++ b/src/Mayaqua/Network.c @@ -5701,10 +5701,17 @@ int SslCertVerifyCallback(int preverify_ok, X509_STORE_CTX *ctx) if (cert != NULL) { X *tmpX = X509ToX(cert); // this only wraps cert, but we need to make a copy - X *copyX = CloneX(tmpX); + if (!CompareX(tmpX, clientcert->X)) + { + X* copyX = CloneX(tmpX); + if (clientcert->X != NULL) + { + FreeX(clientcert->X); + } + clientcert->X = copyX; + } tmpX->do_not_free = true; // do not release inner X509 object FreeX(tmpX); - clientcert->X = copyX; } } } @@ -5729,9 +5736,13 @@ SSL_PIPE *NewSslPipeEx(bool server_mode, X *x, K *k, DH_CTX *dh, bool verify_pee { if (server_mode) { - SSL_CTX_set_ssl_version(ssl_ctx, SSLv23_method()); + SSL_CTX_set_ssl_version(ssl_ctx, SSLv23_server_method()); SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_SSLv2); +#ifdef SSL_OP_NO_TLSv1_3 + SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TLSv1_3); // For some reason pppd under linux doesn't like it +#endif + AddChainSslCertOnDirectory(ssl_ctx); if (dh != NULL) @@ -11785,7 +11796,16 @@ bool AddChainSslCert(struct ssl_ctx_st *ctx, X *x) if (x_copy != NULL) { - SSL_CTX_add_extra_chain_cert(ctx, x_copy->x509); + if (x_copy->root_cert) + { + X509_STORE* store = SSL_CTX_get_cert_store(ctx); + X509_STORE_add_cert(store, x_copy->x509); + X509_free(x_copy->x509); + } + else + { + SSL_CTX_add_extra_chain_cert(ctx, x_copy->x509); + } x_copy->do_not_free = true; ret = true;