2017-10-19 05:48:23 +03:00
// SoftEther VPN Source Code - Developer Edition Master Branch
2014-01-04 17:00:08 +04:00
// Cedar Communication Module
2018-09-10 01:46:29 +03:00
// Proto_PPP.c
2014-01-04 17:00:08 +04:00
// PPP protocol stack
# include "CedarPch.h"
2018-03-13 17:10:22 +03:00
// PPP main thread
2014-01-04 17:00:08 +04:00
void PPPThread ( THREAD * thread , void * param )
{
PPP_SESSION * p = ( PPP_SESSION * ) param ;
UINT i ;
PPP_LCP * c ;
USHORT us ;
UINT ui ;
USHORT next_protocol = 0 ;
bool ret = false ;
char ipstr1 [ 128 ] , ipstr2 [ 128 ] ;
2018-03-13 17:10:22 +03:00
bool authReqSent = false ;
UINT64 now = Tick64 ( ) ;
2014-01-04 17:00:08 +04:00
// Validate arguments
if ( thread = = NULL | | param = = NULL )
{
return ;
}
// Initialize
2018-03-13 17:10:22 +03:00
Debug ( " PPP Initialize " ) ;
PPPSetStatus ( p , PPP_STATUS_CONNECTED ) ;
p - > IPv4_State = PPP_PROTO_STATUS_CLOSED ;
p - > IPv6_State = PPP_PROTO_STATUS_CLOSED ;
2020-05-02 09:38:08 +03:00
p - > Eap_Protocol = PPP_UNSPECIFIED ;
2014-01-04 17:00:08 +04:00
p - > Mru1 = p - > Mru2 = PPP_MRU_DEFAULT ;
p - > RecvPacketList = NewList ( NULL ) ;
2018-03-13 17:10:22 +03:00
p - > SentReqPacketList = NewList ( NULL ) ;
p - > DelayedPackets = NewList ( PPPDelayedPacketsComparator ) ;
2014-01-04 17:00:08 +04:00
2015-10-06 14:18:00 +03:00
p - > MsChapV2_UseDoubleMsChapV2 = CedarIsThereAnyEapEnabledRadiusConfig ( p - > Cedar ) ;
2018-03-13 17:10:22 +03:00
Debug ( " MsChapV2_UseDoubleMsChapV2 = 0x%x \n " , p - > MsChapV2_UseDoubleMsChapV2 ) ;
2014-01-04 17:00:08 +04:00
//// Link establishment phase
2018-03-13 17:10:22 +03:00
Debug ( " PPP Link establishment phase \n " ) ;
2014-01-04 17:00:08 +04:00
IPToStr ( ipstr1 , sizeof ( ipstr1 ) , & p - > ClientIP ) ;
IPToStr ( ipstr2 , sizeof ( ipstr2 ) , & p - > ServerIP ) ;
PPPLog ( p , " LP_CONNECTED " , p - > Postfix , ipstr1 , p - > ClientHostname , p - > ClientPort , ipstr2 , p - > ServerPort ,
p - > ClientSoftwareName , p - > AdjustMss ) ;
2018-03-13 17:10:22 +03:00
// We need that so we don't time out on connection immediately
p - > LastRecvTime = Tick64 ( ) ;
Debug ( " PPP starting main dataloop \n " ) ;
// Dataloop active if the receiving tube is still connected
while ( true )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
PPP_LCP * lcp ;
bool receivedPacketProcessed = false ;
TUBE * tubes [ 2 ] ;
UINT r ;
PPPGetNextPacket ( p ) ;
if ( p - > CurrentPacket ! = NULL )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
// First we process any possible unsupported packets
receivedPacketProcessed = PPPRejectUnsupportedPacket ( p , p - > CurrentPacket ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
// Now do some basic processing
if ( ! receivedPacketProcessed & & p - > CurrentPacket - > IsControl & & p - > CurrentPacket - > Protocol = = PPP_PROTOCOL_LCP )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
if ( p - > CurrentPacket - > Lcp - > Code = = PPP_LCP_CODE_ECHO_REQUEST & & ! PPP_STATUS_IS_UNAVAILABLE ( p - > PPPStatus ) )
{
// Immediately return the echo response to the echo request
PPP_PACKET * pp2 = ZeroMalloc ( sizeof ( PPP_PACKET ) ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
pp2 - > IsControl = true ;
pp2 - > Protocol = PPP_PROTOCOL_LCP ;
pp2 - > Lcp = NewPPPLCP ( PPP_LCP_CODE_ECHO_RESPONSE , p - > CurrentPacket - > Lcp - > Id ) ;
pp2 - > Lcp - > Data = Clone ( p - > CurrentPacket - > Lcp - > Data , p - > CurrentPacket - > Lcp - > DataSize ) ;
pp2 - > Lcp - > DataSize = p - > CurrentPacket - > Lcp - > DataSize ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
if ( PPPSendPacketAndFree ( p , pp2 ) = = false )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
PPPSetStatus ( p , PPP_STATUS_FAIL ) ;
WHERE ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
receivedPacketProcessed = true ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
else if ( p - > CurrentPacket - > Lcp - > Code = = PPP_LCP_CODE_ECHO_RESPONSE & & ! PPP_STATUS_IS_UNAVAILABLE ( p - > PPPStatus ) )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
receivedPacketProcessed = true ;
// Ignore the Echo response packet
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
else if ( p - > CurrentPacket - > Lcp - > Code = = PPP_LCP_CODE_DROP & & ! PPP_STATUS_IS_UNAVAILABLE ( p - > PPPStatus ) )
{
receivedPacketProcessed = true ;
// Ignore the Drop packet
}
else if ( p - > CurrentPacket - > Lcp - > Code = = PPP_LCP_CODE_IDENTIFICATION & & ! PPP_STATUS_IS_UNAVAILABLE ( p - > PPPStatus ) )
{
receivedPacketProcessed = true ;
// Ignore the Identification packet
WHERE ;
}
else if ( p - > CurrentPacket - > Lcp - > Code = = PPP_LCP_CODE_TERMINATE_REQ )
{
PPP_PACKET * pp2 = ZeroMalloc ( sizeof ( PPP_PACKET ) ) ; ;
receivedPacketProcessed = true ;
// Return the Terminate ACK If a Terminate Request has been received
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
pp2 - > IsControl = true ;
pp2 - > Protocol = PPP_PROTOCOL_LCP ;
pp2 - > Lcp = NewPPPLCP ( PPP_LCP_CODE_TERMINATE_ACK , p - > CurrentPacket - > Lcp - > Id ) ;
pp2 - > Lcp - > Data = Clone ( p - > CurrentPacket - > Lcp - > Data , p - > CurrentPacket - > Lcp - > DataSize ) ;
pp2 - > Lcp - > DataSize = p - > CurrentPacket - > Lcp - > DataSize ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
p - > IsTerminateReceived = true ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
if ( PPPSendPacketAndFree ( p , pp2 ) = = false )
{
PPPSetStatus ( p , PPP_STATUS_FAIL ) ;
WHERE ;
}
else
{
SleepThread ( 100 ) ;
PPPSetStatus ( p , PPP_STATUS_CLOSED ) ;
}
}
else if ( p - > CurrentPacket - > Lcp - > Code = = PPP_LCP_CODE_TERMINATE_ACK )
{
PPPSetStatus ( p , PPP_STATUS_CLOSED ) ;
}
}
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
// 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 ;
// Removing from resend list
for ( i = 0 ; i < LIST_NUM ( p - > SentReqPacketList ) ; i + + )
{
PPP_REQUEST_RESEND * t = LIST_DATA ( p - > SentReqPacketList , i ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
if ( t - > Id = = p - > CurrentPacket - > Lcp - > Id )
{
request = t - > Packet ;
Delete ( p - > SentReqPacketList , t ) ;
Free ( t ) ;
break ;
}
}
PPPProcessResponsePacket ( p , p - > CurrentPacket , request ) ;
FreePPPPacket ( request ) ;
receivedPacketProcessed = true ;
}
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
// Process requests
if ( ! receivedPacketProcessed & & p - > CurrentPacket ! = NULL & & p - > CurrentPacket - > IsControl & & PPP_CODE_IS_REQUEST ( p - > CurrentPacket - > Protocol , p - > CurrentPacket - > Lcp - > Code ) & & ! PPP_STATUS_IS_UNAVAILABLE ( p - > PPPStatus ) )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
PPPProcessRequestPacket ( p , p - > CurrentPacket ) ;
receivedPacketProcessed = true ;
2014-01-04 17:00:08 +04:00
}
2015-10-06 14:18:00 +03:00
2018-03-13 17:10:22 +03:00
// Process data packets, discarded before we got any links up
if ( ! receivedPacketProcessed & & p - > CurrentPacket ! = NULL & & ! p - > CurrentPacket - > IsControl & & p - > PPPStatus = = PPP_STATUS_NETWORK_LAYER & & p - > Ipc ! = NULL )
2015-10-06 14:18:00 +03:00
{
2018-03-13 17:10:22 +03:00
UINT64 timeBeforeLoop = Tick64 ( ) ;
while ( true )
2015-10-06 14:18:00 +03:00
{
2018-03-13 17:10:22 +03:00
UINT64 nowL ;
// Here client to server
if ( p - > CurrentPacket - > Protocol = = PPP_PROTOCOL_IP & & p - > IPv4_State = = PPP_PROTO_STATUS_OPENED )
2015-10-06 14:18:00 +03:00
{
2018-03-13 17:10:22 +03:00
receivedPacketProcessed = true ;
IPCSendIPv4 ( p - > Ipc , p - > CurrentPacket - > Data , p - > CurrentPacket - > DataSize ) ;
}
else if ( p - > CurrentPacket - > Protocol = = PPP_PROTOCOL_IP )
{
Debug ( " Got IPv4 packet before IPv4 ready! \n " ) ;
}
else if ( p - > CurrentPacket - > Protocol = = PPP_PROTOCOL_IPV6 & & p - > IPv6_State = = PPP_PROTO_STATUS_OPENED )
{
receivedPacketProcessed = true ;
Debug ( " IPv6 to be implemented \n " ) ;
}
else if ( p - > CurrentPacket - > Protocol = = PPP_PROTOCOL_IPV6 )
{
Debug ( " Got IPv6 packet before IPv6 ready! \n " ) ;
}
2015-10-06 14:18:00 +03:00
2018-03-13 17:10:22 +03:00
// Let's break out of the loop once in a while so we don't get stuck here endlessly
nowL = Tick64 ( ) ;
if ( nowL > timeBeforeLoop + PPP_PACKET_RESEND_INTERVAL )
{
break ;
2015-10-06 14:18:00 +03:00
}
2018-03-13 17:10:22 +03:00
PPPGetNextPacket ( p ) ;
if ( p - > CurrentPacket = = NULL )
{
break ;
}
// Making sure we got a correctly parsed packet by rejecting all invalid ones
if ( PPPRejectUnsupportedPacket ( p , p - > CurrentPacket ) )
{
break ;
}
if ( p - > CurrentPacket - > IsControl | | p - > PPPStatus ! = PPP_STATUS_NETWORK_LAYER | | p - > Ipc = = NULL )
{
PPPAddNextPacket ( p , p - > CurrentPacket , 0 ) ;
p - > CurrentPacket = NULL ;
break ;
}
2015-10-06 14:18:00 +03:00
}
}
2018-03-13 17:10:22 +03:00
if ( ! receivedPacketProcessed & & p - > CurrentPacket ! = NULL )
{
Debug ( " Unprocessed and unrejected packet, protocol = 0x%x \n " , p - > CurrentPacket - > Protocol ) ;
}
2015-10-06 14:18:00 +03:00
}
2020-05-02 09:38:08 +03:00
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! " ;
2020-05-02 10:11:01 +03:00
UCHAR flags = PPP_EAP_TLS_FLAG_NONE ;
2020-05-02 09:38:08 +03:00
// 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...
2020-05-02 10:11:01 +03:00
flags | = PPP_EAP_TLS_FLAG_SSLSTARTED ;
2020-05-02 09:38:08 +03:00
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 ;
2020-05-02 14:40:46 +03:00
break ;
2020-05-02 09:38:08 +03:00
}
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 ;
2020-05-02 14:40:46 +03:00
break ;
2020-05-02 09:38:08 +03:00
}
break ;
}
}
2018-03-13 17:10:22 +03:00
else if ( p - > PPPStatus = = PPP_STATUS_BEFORE_AUTH & & p - > AuthProtocol = = PPP_PROTOCOL_CHAP )
2015-10-06 14:18:00 +03:00
{
2018-03-13 17:10:22 +03:00
// We got to start CHAP when we got no LCP packets from the client on previous iteration
// which means we parsed all the client requests and responses
Debug ( " Starting PPP Authentication phase MS-CHAP v2 \n " ) ;
lcp = BuildMSCHAP2ChallengePacket ( p ) ;
if ( ! PPPSendAndRetransmitRequest ( p , PPP_PROTOCOL_CHAP , lcp ) )
{
PPPSetStatus ( p , PPP_STATUS_FAIL ) ;
WHERE ;
}
PPPSetStatus ( p , PPP_STATUS_AUTHENTICATING ) ;
2015-10-06 14:18:00 +03:00
}
2018-03-13 17:10:22 +03:00
if ( p - > PPPStatus = = PPP_STATUS_CONNECTED & & ! authReqSent )
2015-10-06 14:18:00 +03:00
{
2020-05-02 09:38:08 +03:00
// EAP code
2018-03-13 17:10:22 +03:00
PPP_LCP * c = NewPPPLCP ( PPP_LCP_CODE_REQ , 0 ) ;
2020-05-02 10:11:01 +03:00
USHORT eap_code = Endian16 ( PPP_LCP_AUTH_EAP ) ;
2018-03-13 17:10:22 +03:00
2020-05-02 09:38:08 +03:00
Debug ( " Request EAP \n " ) ;
Add ( c - > OptionList , NewPPPOption ( PPP_LCP_OPTION_AUTH , & eap_code , sizeof ( eap_code ) ) ) ;
2018-03-13 17:10:22 +03:00
if ( ! PPPSendAndRetransmitRequest ( p , PPP_PROTOCOL_LCP , c ) )
{
PPPSetStatus ( p , PPP_STATUS_FAIL ) ;
WHERE ;
}
authReqSent = true ;
2015-10-06 14:18:00 +03:00
}
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
if ( p - > PPPStatus = = PPP_STATUS_AUTHENTICATING )
2014-01-04 17:00:08 +04:00
{
2020-05-02 10:11:01 +03:00
//Debug("Tick waiting for auth...\n");
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
if ( p - > PPPStatus = = PPP_STATUS_AUTH_FAIL )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
Debug ( " PPP auth failed, giving up \n " ) ;
p - > DisconnectCauseCode = 15 ;
p - > DisconnectCauseDirection = 1 ;
PPPSetStatus ( p , PPP_STATUS_CLOSING ) ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
if ( p - > PPPStatus = = PPP_STATUS_NETWORK_LAYER )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
UINT64 timeBeforeLoop ;
2014-01-04 17:00:08 +04:00
if ( p - > DhcpAllocated )
{
if ( now > = p - > DhcpNextRenewTime )
{
IP ip ;
// DHCP renewal procedure
p - > DhcpNextRenewTime = now + p - > DhcpRenewInterval ;
UINTToIP ( & ip , p - > ClientAddressOption . ServerAddress ) ;
IPCDhcpRenewIP ( p - > Ipc , & ip ) ;
}
}
IPCProcessL3Events ( p - > Ipc ) ;
2018-03-13 17:10:22 +03:00
timeBeforeLoop = Tick64 ( ) ;
2014-01-04 17:00:08 +04:00
while ( true )
{
2018-03-13 17:10:22 +03:00
UINT64 nowL ;
2014-01-04 17:00:08 +04:00
BLOCK * b = IPCRecvIPv4 ( p - > Ipc ) ;
PPP_PACKET * pp ;
PPP_PACKET tmp ;
if ( b = = NULL )
{
break ;
}
// Since receiving the IP packet, send it to the client by PPP
pp = & tmp ;
pp - > IsControl = false ;
pp - > Protocol = PPP_PROTOCOL_IP ;
pp - > Lcp = NULL ;
pp - > Data = b - > Buf ;
pp - > DataSize = b - > Size ;
PPPSendPacketEx ( p , pp , true ) ;
FreePPPPacketEx ( pp , true ) ;
Free ( b ) ;
2018-03-13 17:10:22 +03:00
// Let's break out of the loop once in a while so we don't get stuck here endlessly
nowL = Tick64 ( ) ;
if ( nowL > timeBeforeLoop + PPP_PACKET_RESEND_INTERVAL )
{
break ;
}
2014-01-04 17:00:08 +04:00
}
FlushTubeFlushList ( p - > FlushList ) ;
2018-03-13 17:10:22 +03:00
}
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
if ( p - > PPPStatus = = PPP_STATUS_AUTH_SUCCESS )
{
Debug ( " PPP auth success, ready for network layer on next tick \n " ) ;
p - > AuthOk = true ;
PPPSetStatus ( p , PPP_STATUS_NETWORK_LAYER ) ;
}
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
if ( ( p - > PPPStatus = = PPP_STATUS_CLOSING | | p - > PPPStatus = = PPP_STATUS_FAIL ) & & IsTubeConnected ( p - > TubeRecv ) & & IsTubeConnected ( p - > TubeSend ) )
{
Debug ( " Trying to cleanly close the connection, status = 0x%x \n " , p - > PPPStatus ) ;
PPPSetStatus ( p , PPP_STATUS_CLOSING_WAIT ) ;
lcp = NewPPPLCP ( PPP_LCP_CODE_TERMINATE_REQ , 0 ) ;
if ( ! PPPSendAndRetransmitRequest ( p , PPP_PROTOCOL_LCP , lcp ) )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
PPPSetStatus ( p , PPP_STATUS_FAIL ) ;
WHERE ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
}
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
if ( ! PPP_STATUS_IS_UNAVAILABLE ( p - > PPPStatus ) | | p - > PPPStatus = = PPP_STATUS_CLOSING_WAIT )
{
PPPProcessRetransmissions ( p ) ;
PPPSendEchoRequest ( p ) ;
}
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
tubes [ 0 ] = p - > TubeRecv ;
if ( p - > PPPStatus = = PPP_STATUS_NETWORK_LAYER & & p - > Ipc ! = NULL & & IsIPCConnected ( p - > Ipc ) )
{
r = GetNextIntervalForInterrupt ( p - > Ipc - > Interrupt ) ;
2014-01-04 17:00:08 +04:00
tubes [ 1 ] = p - > Ipc - > Sock - > RecvTube ;
2018-03-13 17:10:22 +03:00
WaitForTubes ( tubes , 2 , MIN ( r , PPP_PACKET_RESEND_INTERVAL ) ) ;
}
else
{
2020-05-02 14:40:46 +03:00
WaitForTubes ( tubes , 1 , 300 ) ; // Increasing timeout to make the ticks a bit slower
2018-03-13 17:10:22 +03:00
}
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
if ( IsTubeConnected ( p - > TubeRecv ) = = false | | IsTubeConnected ( p - > TubeSend ) = = false )
{
// Higher-level protocol is disconnected
PPPLog ( p , " LP_UPPER_PROTOCOL_DISCONNECTED " , p - > Postfix ) ;
break ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
if ( IsIPCConnected ( p - > Ipc ) = = false & & p - > PPPStatus = = PPP_STATUS_NETWORK_LAYER )
{
// IPC VPN session is disconnected
PPPLog ( p , " LP_VPN_SESSION_TERMINATED " ) ;
break ;
}
// Time-out inspection
2020-04-27 21:43:40 +03:00
if ( ( p - > LastRecvTime + ( UINT64 ) p - > DataTimeout ) < = now )
2018-03-13 17:10:22 +03:00
{
// Communication time-out occurs
PPPLog ( p , " LP_DATA_TIMEOUT " ) ;
break ;
}
2020-04-27 21:43:40 +03:00
// 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 ;
}
2018-03-13 17:10:22 +03:00
// Terminate if the PPP disconnected
if ( p - > IsTerminateReceived )
{
PPPLog ( p , " LP_NORMAL_TERMINATE " ) ;
break ;
}
if ( p - > PPPStatus = = PPP_STATUS_FAIL | | p - > PPPStatus = = PPP_STATUS_CLOSED )
{
Debug ( " Exiting main dataloop, status = 0x%x \n " , p - > PPPStatus ) ;
break ;
}
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
Debug ( " Exited main dataloop, status = 0x%x \n " , p - > PPPStatus ) ;
if ( p - > PPPStatus ! = PPP_STATUS_FAIL )
2014-01-04 17:00:08 +04:00
{
IP ip ;
char tmp [ MAX_SIZE ] ;
2018-03-13 17:10:22 +03:00
// Disconnected normally
PPPLog ( p , " LP_DISCONNECTED " ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
if ( p ! = NULL & & p - > DhcpAllocated & & IsIPCConnected ( p - > Ipc ) & & p - > ClientAddressOption . ServerAddress ! = 0 )
{
// If any address is assigned from the DHCP, release it
UINTToIP ( & ip , p - > ClientAddressOption . ServerAddress ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
IPToStr ( tmp , sizeof ( tmp ) , & ip ) ;
Debug ( " Releasing IP Address from DHCP Server %s... \n " , tmp ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
IPCDhcpFreeIP ( p - > Ipc , & ip ) ;
IPCProcessL3Events ( p - > Ipc ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
SleepThread ( 300 ) ;
}
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
else
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
PPPLog ( p , " LP_DISCONNECTED_ABNORMAL " ) ;
2014-01-04 17:00:08 +04:00
}
FreePPPSession ( p ) ;
2018-03-13 17:10:22 +03:00
Debug ( " PPP Session ended correctly \n " ) ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
// Entry point
// Create a new PPP session
2020-04-27 21:43:40 +03:00
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 )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
PPP_SESSION * p ;
THREAD * t ;
2014-01-04 17:00:08 +04:00
// Validate arguments
2018-03-13 17:10:22 +03:00
if ( cedar = = NULL | | client_ip = = NULL | | server_ip = = NULL | | send_tube = = NULL | | recv_tube = = NULL )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
return NULL ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
if ( IsEmptyStr ( postfix ) )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
postfix = " PPP " ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
if ( IsEmptyStr ( crypt_name ) )
{
crypt_name = " " ;
}
if ( IsEmptyStr ( client_software_name ) )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
client_software_name = " PPP VPN Client " ;
}
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
// Data structure initialization
p = ZeroMalloc ( sizeof ( PPP_SESSION ) ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
p - > EnableMSCHAPv2 = true ;
2020-05-02 09:38:08 +03:00
p - > AuthProtocol = PPP_UNSPECIFIED ;
2018-03-13 17:10:22 +03:00
p - > MsChapV2_ErrorCode = 691 ;
p - > EapClient = NULL ;
2014-01-04 17:00:08 +04:00
2020-04-27 21:43:40 +03:00
p - > DataTimeout = PPP_DATA_TIMEOUT ;
p - > PacketRecvTimeout = PPP_PACKET_RECV_TIMEOUT ;
p - > UserConnectionTimeout = 0 ;
2018-03-13 17:10:22 +03:00
p - > Cedar = cedar ;
AddRef ( cedar - > ref ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
p - > AdjustMss = adjust_mss ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
StrCpy ( p - > CryptName , sizeof ( p - > CryptName ) , crypt_name ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
Copy ( & p - > ClientIP , client_ip , sizeof ( IP ) ) ;
p - > ClientPort = client_port ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
Copy ( & p - > ServerIP , server_ip , sizeof ( IP ) ) ;
p - > ServerPort = server_port ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
p - > TubeRecv = recv_tube ;
p - > TubeSend = send_tube ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
AddRef ( p - > TubeRecv - > Ref ) ;
AddRef ( p - > TubeSend - > Ref ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
StrCpy ( p - > Postfix , sizeof ( p - > Postfix ) , postfix ) ;
StrCpy ( p - > ClientSoftwareName , sizeof ( p - > ClientSoftwareName ) , client_software_name ) ;
if ( IsEmptyStr ( client_hostname ) )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
IPToStr ( p - > ClientHostname , sizeof ( p - > ClientHostname ) , client_ip ) ;
}
else
{
StrCpy ( p - > ClientHostname , sizeof ( p - > ClientHostname ) , client_hostname ) ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
p - > FlushList = NewTubeFlushList ( ) ;
// Thread creation
t = NewThread ( PPPThread , p ) ;
2014-01-04 17:00:08 +04:00
2020-04-27 21:43:40 +03:00
p - > SessionThread = t ;
return p ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
// PPP processing functions
// Finds out if a packet is supported, if not - sends a notification to the peer
// result: false - supported, true - unsupported
bool PPPRejectUnsupportedPacket ( PPP_SESSION * p , PPP_PACKET * pp )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
return PPPRejectUnsupportedPacketEx ( p , pp , false ) ;
}
bool PPPRejectUnsupportedPacketEx ( PPP_SESSION * p , PPP_PACKET * pp , bool force )
{
bool result = false ;
if ( p = = NULL | | pp = = NULL )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
return false ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
if ( PPP_IS_SUPPORTED_PROTOCOL ( pp - > Protocol ) = = false | | force = = true )
{
// Unsupported algorithm
PPP_PACKET * pp2 = ZeroMalloc ( sizeof ( PPP_PACKET ) ) ;
BUF * buf ;
UCHAR c ;
USHORT us ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
Debug ( " Rejecting PPP protocol = 0x%x \n " , pp - > Protocol ) ;
result = true ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
pp2 - > Protocol = PPP_PROTOCOL_LCP ;
pp2 - > IsControl = false ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
buf = NewBuf ( ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
// Code
c = PPP_LCP_CODE_PROTOCOL_REJECT ;
WriteBuf ( buf , & c , 1 ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
// ID
c = p - > NextId + + ;
WriteBuf ( buf , & c , 1 ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
// Length
us = Endian16 ( pp - > DataSize + 6 ) ;
WriteBuf ( buf , & us , 2 ) ;
// Rejected Protocol
us = Endian16 ( pp - > Protocol ) ;
WriteBuf ( buf , & us , 2 ) ;
// Packet Data
WriteBuf ( buf , pp - > Data , pp - > DataSize ) ;
pp2 - > Data = Clone ( buf - > Buf , buf - > Size ) ;
pp2 - > DataSize = buf - > Size ;
FreeBuf ( buf ) ;
if ( ! PPPSendPacketAndFree ( p , pp2 ) )
{
PPPSetStatus ( p , PPP_STATUS_FAIL ) ;
WHERE ;
}
}
return result ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
// Do the retransmissions if needed
bool PPPProcessRetransmissions ( PPP_SESSION * p )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
INT64 i = 0 ;
UINT64 now = Tick64 ( ) ;
UINT64 count ;
if ( p - > SentReqPacketList = = NULL )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
Debug ( " Somehow SentReqPacketList is NULL! \n " ) ;
2014-01-04 17:00:08 +04:00
return false ;
}
2018-03-13 17:10:22 +03:00
// Making it signed but expanding to 64 bits
count = LIST_NUM ( p - > SentReqPacketList ) ;
if ( count = = 0 )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
return true ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
for ( i = count - 1 ; i > = 0 ; - - i )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
PPP_REQUEST_RESEND * t = LIST_DATA ( p - > SentReqPacketList , i ) ;
if ( t - > TimeoutTime < = now )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
Debug ( " Timing out on resending control packet protocol = 0x%x \n " , t - > Packet - > Protocol ) ;
Delete ( p - > SentReqPacketList , t ) ;
FreePPPPacket ( t - > Packet ) ;
Free ( t ) ;
}
else if ( t - > ResendTime < = now )
{
Debug ( " Resending control packet protocol = 0x%x \n " , t - > Packet - > Protocol ) ;
if ( ! PPPSendPacketEx ( p , t - > Packet , false ) )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
PPPSetStatus ( p , PPP_STATUS_FAIL ) ;
WHERE ;
return false ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
t - > ResendTime = now + PPP_PACKET_RESEND_INTERVAL ;
2014-01-04 17:00:08 +04:00
}
}
2018-03-13 17:10:22 +03:00
return true ;
}
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
// Send the PPP Echo Request
bool PPPSendEchoRequest ( PPP_SESSION * p )
{
UINT64 now = Tick64 ( ) ;
if ( p - > NextEchoSendTime = = 0 | | now > = p - > NextEchoSendTime )
{
PPP_PACKET * pp ;
char echo_data [ ] = " \0 \0 \0 \0 Aho Baka Manuke " ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
p - > NextEchoSendTime = now + ( UINT64 ) PPP_ECHO_SEND_INTERVAL ;
if ( IsIPCConnected ( p - > Ipc ) )
{
AddInterrupt ( p - > Ipc - > Interrupt , p - > NextEchoSendTime ) ;
}
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
// Validate arguments
if ( p = = NULL )
{
return false ;
}
pp = ZeroMalloc ( sizeof ( PPP_PACKET ) ) ;
pp - > Protocol = PPP_PROTOCOL_LCP ;
pp - > IsControl = true ;
pp - > Lcp = NewPPPLCP ( PPP_LCP_CODE_ECHO_REQUEST , 0 ) ;
pp - > Lcp - > Data = Clone ( echo_data , sizeof ( echo_data ) ) ;
pp - > Lcp - > DataSize = sizeof ( echo_data ) ;
if ( ! PPPSendPacketAndFree ( p , pp ) )
{
PPPSetStatus ( p , PPP_STATUS_FAIL ) ;
WHERE ;
return false ;
}
return true ;
}
2014-01-04 17:00:08 +04:00
return false ;
}
2018-03-13 17:10:22 +03:00
// Processes response packets
2020-02-06 10:49:09 +03:00
bool PPPProcessResponsePacket ( PPP_SESSION * p , PPP_PACKET * pp , PPP_PACKET * req )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
if ( req = = NULL )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
Debug ( " We received a response for... What? We never sent this request, protocol = 0x%x, code = 0x%x \n " , pp - > Protocol , pp - > Lcp - > Code ) ;
// Let's just discard this, as this was probably already parsed, and we just stumbled upon a resend
2014-01-04 17:00:08 +04:00
return false ;
}
2018-03-13 17:10:22 +03:00
switch ( pp - > Protocol )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
case PPP_PROTOCOL_LCP :
return PPPProcessLCPResponsePacket ( p , pp , req ) ;
break ;
case PPP_PROTOCOL_PAP :
Debug ( " Got a response PAP, which is invalid, we should get a request instead \n " ) ;
PPPSetStatus ( p , PPP_STATUS_FAIL ) ;
WHERE ;
return false ;
break ;
case PPP_PROTOCOL_CHAP :
return PPPProcessCHAPResponsePacket ( p , pp , req ) ;
break ;
case PPP_PROTOCOL_IPCP :
return PPPProcessIPCPResponsePacket ( p , pp , req ) ;
break ;
case PPP_PROTOCOL_IPV6CP :
Debug ( " IPv6CP to be implemented \n " ) ;
break ;
2020-05-02 01:54:03 +03:00
case PPP_PROTOCOL_EAP :
return PPPProcessEAPResponsePacket ( p , pp , req ) ;
break ;
2018-03-13 17:10:22 +03:00
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 ) ;
WHERE ;
return false ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
return false ;
2014-01-04 17:00:08 +04:00
}
2020-02-06 10:49:09 +03:00
bool PPPProcessLCPResponsePacket ( PPP_SESSION * p , PPP_PACKET * pp , PPP_PACKET * req )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
UINT i ;
bool isAccepted = ! PPP_LCP_CODE_IS_NEGATIVE ( pp - > Lcp - > Code ) ;
bool result = true ;
// MSCHAPv2 code
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 ;
// We got one of rejects here, not NACKs
if ( ! isAccepted & & pp - > Lcp - > Code = = PPP_LCP_CODE_PROTOCOL_REJECT )
{
// If we receive a protocol reject before we finished authenticating
// 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 ;
Debug ( " Protocol 0x%x rejected before auth, probably unsupported client, failing connection \n " , * protocol ) ;
PPPSetStatus ( p , PPP_STATUS_FAIL ) ;
WHERE ;
return false ;
}
else
{
USHORT * protocol = pp - > Lcp - > Data ;
if ( * protocol = = PPP_PROTOCOL_IPCP | | * protocol = = PPP_PROTOCOL_IP )
{
2020-04-27 22:18:57 +03:00
p - > IPv4_State = PPP_PROTO_STATUS_REJECTED ;
2018-03-13 17:10:22 +03:00
}
if ( * protocol = = PPP_PROTOCOL_IPV6CP | | * protocol = = PPP_PROTOCOL_IPV6 )
{
2020-04-27 22:18:57 +03:00
p - > IPv6_State = PPP_PROTO_STATUS_REJECTED ;
2018-03-13 17:10:22 +03:00
}
}
}
if ( ! isAccepted & & pp - > Lcp - > Code = = PPP_LCP_CODE_CODE_REJECT )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
PPPSetStatus ( p , PPP_STATUS_FAIL ) ;
WHERE ;
2014-01-04 17:00:08 +04:00
return false ;
}
2018-03-13 17:10:22 +03:00
for ( i = 0 ; i < LIST_NUM ( pp - > Lcp - > OptionList ) ; i + + )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
PPP_OPTION * t = LIST_DATA ( pp - > Lcp - > OptionList , i ) ;
PPP_OPTION * opt = NULL ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
switch ( t - > Type )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
case PPP_LCP_OPTION_MRU :
// MRU
if ( t - > DataSize = = sizeof ( USHORT ) )
{
USHORT value = READ_USHORT ( t - > Data ) ;
if ( ! isAccepted )
{
if ( pp - > Lcp - > Code ! = PPP_LCP_CODE_NAK )
{
Debug ( " MRU setup failed, rejected " ) ;
p - > Mru1 = p - > Mru2 = PPP_MRU_DEFAULT ;
}
if ( value < PPP_MRU_MIN | | value > PPP_MRU_MAX )
{
Debug ( " Couldn't agree on an MRU! Breaking link... MRU = 0x%x \n " , value ) ;
PPPSetStatus ( p , PPP_STATUS_FAIL ) ;
WHERE ;
return false ;
}
else
{
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 ) )
{
PPPSetStatus ( p , PPP_STATUS_FAIL ) ;
WHERE ;
return false ;
}
Debug ( " PPP: Server got %u as MRU from NACK, re-requesting \n " , p - > Mru2 ) ;
}
}
else if ( value < PPP_MRU_MIN | | value > PPP_MRU_MAX )
{
Debug ( " The client somehow ACKed an invalid MRU, breaking link... MRU = 0x%x \n " , value ) ;
PPPSetStatus ( p , PPP_STATUS_FAIL ) ;
WHERE ;
result = false ;
}
else
{
p - > Mru2 = value ;
Debug ( " PPP: Server set %u as MRU \n " , p - > Mru2 ) ;
}
}
break ;
case PPP_LCP_OPTION_AUTH :
opt = PPPGetOptionValue ( req - > Lcp , PPP_LCP_OPTION_AUTH ) ;
if ( opt = = NULL )
{
Debug ( " We got some weird response with option absent in request, wut? Disconnecting \n " ) ;
PPPSetStatus ( p , PPP_STATUS_FAIL ) ;
WHERE ;
return false ;
}
2020-05-02 09:38:08 +03:00
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 )
2018-03-13 17:10:22 +03:00
{
// Try to request PAP then
if ( ! isAccepted | | ! p - > EnableMSCHAPv2 )
{
UINT64 offer = 0 ;
PPP_LCP * c = NewPPPLCP ( PPP_LCP_CODE_REQ , 0 ) ;
USHORT proto = Endian16 ( PPP_LCP_AUTH_PAP ) ;
Copy ( & offer , t - > Data , t - > DataSize > sizeof ( UINT64 ) ? sizeof ( UINT64 ) : t - > DataSize ) ;
Debug ( " NACK proto with code = 0x%x, cypher = 0x%x, offered cypher = 0x%x \n " , pp - > Lcp - > Code , * ( ( USHORT * ) ( opt - > Data ) ) , offer ) ;
Debug ( " Request PAP \n " ) ;
Add ( c - > OptionList , NewPPPOption ( PPP_LCP_OPTION_AUTH , & proto , sizeof ( USHORT ) ) ) ;
if ( ! PPPSendAndRetransmitRequest ( p , PPP_PROTOCOL_LCP , c ) )
{
PPPSetStatus ( p , PPP_STATUS_FAIL ) ;
WHERE ;
return false ;
}
}
2020-05-02 09:38:08 +03:00
else if ( p - > AuthProtocol = = PPP_UNSPECIFIED )
2018-03-13 17:10:22 +03:00
{
p - > AuthProtocol = PPP_PROTOCOL_CHAP ;
Debug ( " Setting BEFORE_AUTH from ACK on LCP response parse on CHAP accept \n " ) ;
PPPSetStatus ( p , PPP_STATUS_BEFORE_AUTH ) ;
}
}
else if ( opt - > DataSize = = sizeof ( USHORT ) & & * ( ( USHORT * ) ( opt - > Data ) ) = = Endian16 ( PPP_LCP_AUTH_PAP ) )
{
// We couldn't agree on auth proto, failing connection
if ( ! isAccepted )
{
UINT64 offer = 0 ;
Copy ( & offer , t - > Data , t - > DataSize > sizeof ( UINT64 ) ? sizeof ( UINT64 ) : t - > DataSize ) ;
Debug ( " NACK proto with code = 0x%x, cypher = 0x%x, offered cypher = 0x%x \n " , pp - > Lcp - > Code , * ( ( USHORT * ) ( opt - > Data ) ) , offer ) ;
Debug ( " Couldn't agree on auth protocol! \n " ) ;
PPPLog ( p , " LP_PAP_MSCHAPV2_REJECTED " ) ;
PPPSetStatus ( p , PPP_STATUS_FAIL ) ;
WHERE ;
return false ;
}
2020-05-02 09:38:08 +03:00
else if ( p - > AuthProtocol = = PPP_UNSPECIFIED )
2018-03-13 17:10:22 +03:00
{
p - > AuthProtocol = PPP_PROTOCOL_PAP ;
Debug ( " Setting BEFORE_AUTH from ACK on LCP response parse on PAP accept \n " ) ;
PPPSetStatus ( p , PPP_STATUS_BEFORE_AUTH ) ;
}
}
break ;
2014-01-04 17:00:08 +04:00
}
}
2018-03-13 17:10:22 +03:00
return result ;
}
// Process CHAP responses
2020-02-06 10:49:09 +03:00
bool PPPProcessCHAPResponsePacket ( PPP_SESSION * p , PPP_PACKET * pp , PPP_PACKET * req )
2018-03-13 17:10:22 +03:00
{
PPP_LCP * lcp ;
if ( pp - > Lcp - > Code = = PPP_CHAP_CODE_RESPONSE )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
bool ok = false ;
if ( p - > PPPStatus ! = PPP_STATUS_AUTHENTICATING & & ! p - > AuthOk )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
Debug ( " Receiving CHAP response packets outside of auth status, some errors probably! " ) ;
PPPSetStatus ( p , PPP_STATUS_FAIL ) ;
WHERE ;
return false ;
}
if ( p - > AuthProtocol ! = PPP_PROTOCOL_CHAP )
{
Debug ( " Receiving CHAP packet when auth protocol set to 0x%x \n " , p - > AuthProtocol ) ;
PPPLog ( p , " LP_NEXT_PROTOCOL_IS_NOT_PAP " , pp - > Protocol ) ;
PPPRejectUnsupportedPacketEx ( p , pp , true ) ;
return false ;
}
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
ok = PPPParseMSCHAP2ResponsePacket ( p , pp ) ;
// If we got only first packet of double CHAP then send second challenge
if ( ok & & p - > MsChapV2_UseDoubleMsChapV2 & & p - > EapClient ! = NULL & & p - > Ipc = = NULL )
{
lcp = BuildMSCHAP2ChallengePacket ( p ) ;
if ( ! PPPSendAndRetransmitRequest ( p , PPP_PROTOCOL_CHAP , lcp ) )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
PPPSetStatus ( p , PPP_STATUS_FAIL ) ;
WHERE ;
return false ;
2014-01-04 17:00:08 +04:00
}
}
2018-03-13 17:10:22 +03:00
// We got a successful MSCHAPv2 response, so let's send a SUCCESS
else if ( ok )
{
char hex [ MAX_SIZE ] ;
char ret_str [ MAX_SIZE ] ;
BUF * lcp_ret_data = NewBuf ( ) ;
PPP_PACKET * res = ZeroMalloc ( sizeof ( PPP_PACKET ) ) ;
BinToStr ( hex , sizeof ( hex ) , p - > MsChapV2_ServerResponse , 20 ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
Format ( ret_str , sizeof ( ret_str ) ,
" S=%s " , hex ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
WriteBuf ( lcp_ret_data , ret_str , StrLen ( ret_str ) ) ;
lcp = NewPPPLCP ( PPP_CHAP_CODE_SUCCESS , p - > MsChapV2_PacketId ) ;
lcp - > Data = Clone ( lcp_ret_data - > Buf , lcp_ret_data - > Size ) ;
lcp - > DataSize = lcp_ret_data - > Size ;
if ( lcp_ret_data ! = NULL )
{
FreeBuf ( lcp_ret_data ) ;
}
res - > Lcp = lcp ;
res - > IsControl = true ;
res - > Protocol = PPP_PROTOCOL_CHAP ;
if ( ! PPPSendPacketAndFree ( p , res ) )
{
PPPSetStatus ( p , PPP_STATUS_FAIL ) ;
WHERE ;
return false ;
}
p - > AuthOk = true ;
PPPSetStatus ( p , PPP_STATUS_AUTH_SUCCESS ) ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
// We failed MSCHAPv2 auth
2014-01-04 17:00:08 +04:00
else
{
2018-03-13 17:10:22 +03:00
char hex [ MAX_SIZE ] ;
char ret_str [ MAX_SIZE ] ;
BUF * lcp_ret_data = NewBuf ( ) ;
PPP_PACKET * res = ZeroMalloc ( sizeof ( PPP_PACKET ) ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
BinToStr ( hex , sizeof ( hex ) , p - > MsChapV2_ServerChallenge , 16 ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
Format ( ret_str , sizeof ( ret_str ) ,
" E=%u R=0 C=%s V=3 " , p - > MsChapV2_ErrorCode , hex ) ;
WriteBuf ( lcp_ret_data , ret_str , StrLen ( ret_str ) ) ;
lcp = NewPPPLCP ( PPP_CHAP_CODE_FAILURE , p - > MsChapV2_PacketId ) ;
lcp - > Data = Clone ( lcp_ret_data - > Buf , lcp_ret_data - > Size ) ;
lcp - > DataSize = lcp_ret_data - > Size ;
if ( lcp_ret_data ! = NULL )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
FreeBuf ( lcp_ret_data ) ;
}
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
res - > Lcp = lcp ;
res - > IsControl = true ;
res - > Protocol = PPP_PROTOCOL_CHAP ;
if ( ! PPPSendPacketAndFree ( p , res ) )
{
PPPSetStatus ( p , PPP_STATUS_FAIL ) ;
WHERE ;
return false ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
PPPLog ( p , " LP_CHAP_FAILED " ) ;
PPPSetStatus ( p , PPP_STATUS_AUTH_FAIL ) ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
return ok ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
return false ;
}
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
// Process IPCP responses
2020-02-06 10:49:09 +03:00
bool PPPProcessIPCPResponsePacket ( PPP_SESSION * p , PPP_PACKET * pp , PPP_PACKET * req )
2018-03-13 17:10:22 +03:00
{
bool isAccepted = ! PPP_LCP_CODE_IS_NEGATIVE ( pp - > Lcp - > Code ) ;
IP addrStruct ;
char addrStr [ MAX_SIZE ] ;
UINT addr ;
IP prevAddrStruct ;
char prevAddrStr [ MAX_SIZE ] ;
UINT prevAddr ;
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 )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
Debug ( " Unsupported IPCP protocol " ) ;
p - > IPv4_State = PPP_PROTO_STATUS_REJECTED ;
PPPRejectUnsupportedPacketEx ( p , pp , true ) ;
return false ;
}
// We're dealing either with ACK or NACK
addr = IPToUINT ( & addrStruct ) ;
IPToStr ( addrStr , MAX_SIZE , & addrStruct ) ;
if ( isAccepted )
{
Debug ( " Accepted server IP address of %s \n " , addrStr ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
// We already configured client address, now server address is also confirmed, ready for IPv4 data flow
if ( p - > IPv4_State = = PPP_PROTO_STATUS_CONFIG )
{
p - > IPv4_State = PPP_PROTO_STATUS_CONFIG_WAIT ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
return true ;
2014-01-04 17:00:08 +04:00
}
2020-04-27 22:18:57 +03:00
p - > IPv4_State = PPP_PROTO_STATUS_CONFIG ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
PPPGetIPAddressValueFromLCP ( req - > Lcp , PPP_IPCP_OPTION_IP , & prevAddrStruct ) ;
prevAddr = IPToUINT ( & prevAddrStruct ) ;
IPToStr ( prevAddrStr , MAX_SIZE , & prevAddrStruct ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
Debug ( " Denied server IP address %s, proposed %s \n " , prevAddrStr , addrStr ) ;
2020-02-04 23:51:50 +03:00
// Fallback mechanism - just request 192.0.0.8
if ( prevAddr = = Endian32 ( 0xc0000008 ) )
2014-01-04 17:00:08 +04:00
{
2020-02-04 23:51:50 +03:00
Debug ( " We already tried the fallback IP of 192.0.0.8, giving up \n " ) ;
2018-03-13 17:10:22 +03:00
p - > IPv4_State = PPP_PROTO_STATUS_REJECTED ;
PPPRejectUnsupportedPacketEx ( p , pp , true ) ;
return false ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
c = NewPPPLCP ( PPP_LCP_CODE_REQ , 0 ) ;
2020-02-04 23:51:50 +03:00
ui = Endian32 ( 0xc0000008 ) ; // We always push 192.0.0.8, which is defined in RFC7600 as dummy IPv4 address.
2018-03-13 17:10:22 +03:00
Add ( c - > OptionList , NewPPPOption ( PPP_IPCP_OPTION_IP , & ui , sizeof ( UINT ) ) ) ;
if ( ! PPPSendAndRetransmitRequest ( p , PPP_PROTOCOL_IPCP , c ) )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
PPPSetStatus ( p , PPP_STATUS_FAIL ) ;
WHERE ;
return false ;
}
return false ;
}
2014-01-04 17:00:08 +04:00
2020-05-02 01:54:03 +03:00
// Process EAP responses
bool PPPProcessEAPResponsePacket ( PPP_SESSION * p , PPP_PACKET * pp , PPP_PACKET * req )
{
2020-05-02 09:38:08 +03:00
if ( pp - > Lcp - > DataSize > = 1 )
2020-05-02 01:54:03 +03:00
{
2020-05-02 09:38:08 +03:00
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
{
2020-05-02 19:15:30 +03:00
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 ;
}
}
2020-05-02 01:54:03 +03:00
}
return false ;
}
2018-03-13 17:10:22 +03:00
// Processes request packets
bool PPPProcessRequestPacket ( PPP_SESSION * p , PPP_PACKET * pp )
{
switch ( pp - > Protocol )
{
case PPP_PROTOCOL_LCP :
return PPPProcessLCPRequestPacket ( p , pp ) ;
break ;
case PPP_PROTOCOL_PAP :
return PPPProcessPAPRequestPacket ( p , pp ) ;
break ;
case PPP_PROTOCOL_CHAP :
Debug ( " Got a CHAP request, which is invalid, we should get CHAP response instead \n " ) ;
PPPSetStatus ( p , PPP_STATUS_FAIL ) ;
WHERE ;
return false ;
break ;
case PPP_PROTOCOL_IPCP :
return PPPProcessIPCPRequestPacket ( p , pp ) ;
break ;
case PPP_PROTOCOL_IPV6CP :
PPPRejectUnsupportedPacketEx ( p , pp , true ) ;
Debug ( " IPv6CP to be implemented \n " ) ;
break ;
2020-05-02 01:54:03 +03:00
case PPP_PROTOCOL_EAP :
return PPPProcessEAPRequestPacket ( p , pp ) ;
break ;
2018-03-13 17:10:22 +03:00
default :
Debug ( " Unsupported protocols should be already filtered out! protocol = 0x%x, code = 0x%x \n " , pp - > Protocol , pp - > Lcp - > Code ) ;
return false ;
break ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
return false ;
}
2014-01-04 17:00:08 +04:00
2020-02-06 10:49:09 +03:00
bool PPPProcessLCPRequestPacket ( PPP_SESSION * p , PPP_PACKET * pp )
2018-03-13 17:10:22 +03:00
{
bool result = true ;
UINT i = 0 ;
USHORT NegotiatedAuthProto = PPP_UNSPECIFIED ;
USHORT NegotiatedMRU = PPP_UNSPECIFIED ;
// MSCHAPv2 code
UCHAR ms_chap_v2_code [ 3 ] ;
2020-05-02 09:38:08 +03:00
USHORT eap_code = PPP_LCP_AUTH_EAP ;
2020-04-25 05:01:09 +03:00
2018-03-13 17:10:22 +03:00
WRITE_USHORT ( ms_chap_v2_code , PPP_LCP_AUTH_CHAP ) ;
ms_chap_v2_code [ 2 ] = PPP_CHAP_ALG_MS_CHAP_V2 ;
2020-04-25 05:01:09 +03:00
Debug ( " Got LCP packet request ID=%i OptionsListSize=%i \n " , pp - > Lcp - > Id , LIST_NUM ( pp - > Lcp - > OptionList ) ) ;
2018-03-13 17:10:22 +03:00
for ( i = 0 ; i < LIST_NUM ( pp - > Lcp - > OptionList ) ; i + + )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
PPP_OPTION * t = LIST_DATA ( pp - > Lcp - > OptionList , i ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
switch ( t - > Type )
{
case PPP_LCP_OPTION_AUTH :
t - > IsSupported = true ;
2020-05-02 10:11:01 +03:00
if ( t - > DataSize = = sizeof ( USHORT ) & & * ( ( USHORT * ) t - > Data ) = = PPP_LCP_AUTH_EAP & & p - > AuthProtocol = = PPP_UNSPECIFIED )
2020-05-02 09:38:08 +03:00
{
t - > IsAccepted = true ;
NegotiatedAuthProto = PPP_PROTOCOL_EAP ;
}
2020-05-02 10:11:01 +03:00
else if ( t - > DataSize = = sizeof ( USHORT ) & & * ( ( USHORT * ) t - > Data ) = = PPP_LCP_AUTH_PAP & & p - > AuthProtocol = = PPP_UNSPECIFIED )
2018-03-13 17:10:22 +03:00
{
t - > IsAccepted = true ;
NegotiatedAuthProto = PPP_PROTOCOL_PAP ;
}
2020-05-02 09:38:08 +03:00
else if ( t - > DataSize = = sizeof ( ms_chap_v2_code ) & & Cmp ( t - > Data , ms_chap_v2_code , t - > DataSize ) = = 0 & & p - > AuthProtocol = = PPP_UNSPECIFIED )
2018-03-13 17:10:22 +03:00
{
t - > IsAccepted = true ;
NegotiatedAuthProto = PPP_PROTOCOL_CHAP ;
}
else
{
2020-05-02 09:38:08 +03:00
// We're recommending EAP by default as a more secure algo
2018-03-13 17:10:22 +03:00
t - > IsAccepted = false ;
2020-05-02 09:38:08 +03:00
t - > AltDataSize = sizeof ( eap_code ) ;
Copy ( t - > AltData , & eap_code , sizeof ( eap_code ) ) ;
2018-03-13 17:10:22 +03:00
}
break ;
case PPP_LCP_OPTION_MRU :
t - > IsSupported = true ;
if ( t - > DataSize = = sizeof ( USHORT ) )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
USHORT value = READ_USHORT ( t - > Data ) ;
if ( value < PPP_MRU_MIN | | value > PPP_MRU_MAX )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
t - > IsAccepted = false ;
value = MAKESURE ( value , PPP_MRU_MIN , PPP_MRU_MAX ) ;
//Debug("MRU not accepted, sending NACK with value = 0x%x\n", value);
t - > AltDataSize = sizeof ( USHORT ) ;
WRITE_USHORT ( t - > AltData , value ) ;
}
else
{
t - > IsAccepted = true ;
NegotiatedMRU = value ;
//Debug("MRU accepted, value = 0x%x\n", value);
2014-01-04 17:00:08 +04:00
}
}
2018-03-13 17:10:22 +03:00
else
{
t - > IsAccepted = false ;
t - > AltDataSize = sizeof ( USHORT ) ;
WRITE_USHORT ( t - > AltData , PPP_MRU_DEFAULT ) ;
}
break ;
default :
t - > IsSupported = false ;
Debug ( " Unsupported LCP option = 0x%x \n " , t - > Type ) ;
break ;
2014-01-04 17:00:08 +04:00
}
}
2018-03-13 17:10:22 +03:00
if ( PPPRejectLCPOptions ( p , pp ) )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
Debug ( " Rejected LCP options... \n " ) ;
return false ;
}
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
if ( PPPNackLCPOptions ( p , pp ) )
{
Debug ( " NACKed LCP options... \n " ) ;
return false ;
}
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
if ( ! PPPAckLCPOptions ( p , pp ) )
{
return false ;
}
if ( NegotiatedAuthProto ! = PPP_UNSPECIFIED )
{
2020-05-02 09:38:08 +03:00
if ( p - > AuthProtocol = = PPP_UNSPECIFIED )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
p - > AuthProtocol = NegotiatedAuthProto ;
PPPSetStatus ( p , PPP_STATUS_BEFORE_AUTH ) ;
Debug ( " Setting BEFORE_AUTH from REQ on LCP request parse \n " ) ;
}
}
if ( NegotiatedMRU ! = PPP_UNSPECIFIED )
{
p - > Mru1 = NegotiatedMRU ;
}
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
return true ;
}
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
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 ) ) ;
Debug ( " Got a PAP request before we're ready for AUTH procedure! \n " ) ;
ret - > IsControl = true ;
ret - > Protocol = PPP_PROTOCOL_PAP ;
ret - > Lcp = lcp ;
if ( ! PPPSendPacketAndFree ( p , ret ) )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
PPPSetStatus ( p , PPP_STATUS_FAIL ) ;
WHERE ;
return false ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
return false ;
}
if ( p - > AuthProtocol ! = PPP_PROTOCOL_PAP )
{
Debug ( " Trying to auth with PAP when should be 0x%x \n " , p - > AuthProtocol ) ;
PPPLog ( p , " LP_NEXT_PROTOCOL_IS_NOT_CHAP " , pp - > Protocol ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
// Forcing rejection of PAP on configured MSCHAPv2
PPPRejectUnsupportedPacketEx ( p , pp , true ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
return false ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
if ( ! p - > AuthOk )
2014-01-04 17:00:08 +04:00
{
UCHAR * data ;
UINT size ;
2018-03-13 17:10:22 +03:00
PPPSetStatus ( p , PPP_STATUS_AUTHENTICATING ) ;
2014-01-04 17:00:08 +04:00
if ( p - > Ipc = = NULL )
{
// PAP
// Extract the ID and the password
2018-03-13 17:10:22 +03:00
data = pp - > Lcp - > Data ;
size = pp - > Lcp - > DataSize ;
2014-01-04 17:00:08 +04:00
if ( size > = 1 )
{
UCHAR len_id = data [ 0 ] ;
data + + ;
size - - ;
if ( size > = len_id )
{
char username [ 256 ] ;
char password [ 256 ] ;
Zero ( username , sizeof ( username ) ) ;
Zero ( password , sizeof ( password ) ) ;
Copy ( username , data , len_id ) ;
data + = len_id ;
size - = len_id ;
if ( size > = 1 )
{
UCHAR len_pass = data [ 0 ] ;
data + + ;
size - - ;
if ( size > = len_pass )
{
IPC * ipc ;
char id [ MAX_SIZE ] ;
char hub [ MAX_SIZE ] ;
ETHERIP_ID d ;
Zero ( id , sizeof ( id ) ) ;
Zero ( hub , sizeof ( hub ) ) ;
Copy ( password , data , len_pass ) ;
Debug ( " PPP: id=%s, pw=%s \n " , username , password ) ;
// The user name is divided into the ID and the virtual HUB name
Zero ( & d , sizeof ( d ) ) ;
PPPParseUsername ( p - > Cedar , username , & d ) ;
StrCpy ( id , sizeof ( id ) , d . UserName ) ;
StrCpy ( hub , sizeof ( hub ) , d . HubName ) ;
if ( IsEmptyStr ( id ) = = false )
{
// Attempt to connect with IPC
UINT error_code ;
ipc = NewIPC ( p - > Cedar , p - > ClientSoftwareName , p - > Postfix , hub , id , password ,
& error_code , & p - > ClientIP , p - > ClientPort , & p - > ServerIP , p - > ServerPort ,
2019-10-19 11:34:12 +03:00
p - > ClientHostname , p - > CryptName , false , p - > AdjustMss , NULL , NULL ,
IPC_LAYER_3 ) ;
2014-01-04 17:00:08 +04:00
if ( ipc ! = NULL )
{
p - > Ipc = ipc ;
2020-04-27 21:43:40 +03:00
// 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 ( ) ;
2018-03-13 17:10:22 +03:00
p - > AuthOk = true ;
}
else
{
PPPSetStatus ( p , PPP_STATUS_FAIL ) ;
WHERE ;
return false ;
2014-01-04 17:00:08 +04:00
}
}
}
}
}
}
}
else
{
// Return success for a request from the second time when it is successfully authenticated once
2018-03-13 17:10:22 +03:00
p - > AuthOk = true ;
}
}
if ( p - > AuthOk )
{
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 ;
if ( ! PPPSendPacketAndFree ( p , ret ) )
{
PPPSetStatus ( p , PPP_STATUS_FAIL ) ;
WHERE ;
return false ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
if ( p - > PPPStatus = = PPP_STATUS_AUTHENTICATING )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
PPPSetStatus ( p , PPP_STATUS_AUTH_SUCCESS ) ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
return true ;
}
if ( ! p - > AuthOk )
{
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 ;
if ( ! PPPSendPacketAndFree ( p , ret ) )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
PPPSetStatus ( p , PPP_STATUS_FAIL ) ;
WHERE ;
return false ;
}
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
if ( p - > PPPStatus = = PPP_STATUS_AUTHENTICATING )
{
PPPSetStatus ( p , PPP_STATUS_AUTH_FAIL ) ;
PPPLog ( p , " LP_PAP_FAILED " ) ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
return false ;
2014-01-04 17:00:08 +04:00
}
2020-05-02 09:38:08 +03:00
return p - > AuthOk ;
2018-03-13 17:10:22 +03:00
}
bool PPPProcessIPCPRequestPacket ( PPP_SESSION * p , PPP_PACKET * pp )
{
PPP_IPOPTION o ;
PPP_IPOPTION res ;
2020-04-25 18:02:02 +03:00
PPP_OPTION * dummyIpOption ;
UINT dummyIp = 0 ;
2018-03-13 17:10:22 +03:00
DHCP_OPTION_LIST cao ;
IP client_ip ;
IP subnet ;
IP zero ;
IP gw ;
bool ok = true ;
bool processed = false ;
2020-04-25 18:02:02 +03:00
bool isEmptyIpAddress = false ;
PPP_LCP * c ;
2018-03-13 17:10:22 +03:00
if ( p - > IPv4_State = = PPP_PROTO_STATUS_REJECTED )
2014-01-04 17:00:08 +04:00
{
2020-04-25 18:02:02 +03:00
Debug ( " We got an IPCP packet after we had it rejected \n " ) ;
2018-03-13 17:10:22 +03:00
return PPPRejectUnsupportedPacketEx ( p , pp , true ) ;
}
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
if ( ! PPPGetIPOptionFromLCP ( & o , pp - > Lcp ) )
{
2020-04-25 18:02:02 +03:00
Debug ( " IPCP request without client IP address received! Treating as zeroed out client IP... \n " ) ;
isEmptyIpAddress = true ;
dummyIpOption = NewPPPOption ( PPP_IPCP_OPTION_IP , & dummyIp , sizeof ( UINT ) ) ;
dummyIpOption - > IsSupported = true ;
dummyIpOption - > IsAccepted = false ;
Add ( pp - > Lcp - > OptionList , dummyIpOption ) ;
2018-03-13 17:10:22 +03:00
}
// Process if not configured yet by server
2020-04-25 18:02:02 +03:00
if ( ( IsZero ( & p - > ClientAddressOption , sizeof ( DHCP_OPTION_LIST ) ) | | isEmptyIpAddress ) & & ok )
2018-03-13 17:10:22 +03:00
{
// Decide if we received a static IP from client and it is allowed
if ( IsZeroIP ( & o . IpAddress ) = = false )
{
if ( p - > Ipc - > Policy - > DHCPForce = = false )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
if ( p - > DhcpAllocated = = false )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
if ( p - > UseStaticIPAddress = = false )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
DHCP_OPTION_LIST cao ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
// The client specify an IP address
Zero ( & cao , sizeof ( cao ) ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
cao . ClientAddress = IPToUINT ( & o . IpAddress ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
Copy ( & p - > ClientAddressOption , & cao , sizeof ( cao ) ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
p - > UseStaticIPAddress = true ;
2014-01-04 17:00:08 +04:00
}
}
}
2018-03-13 17:10:22 +03:00
}
else
{
p - > UseStaticIPAddress = false ;
}
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
// Get additional information for static clients
if ( p - > UseStaticIPAddress )
{
if ( p - > DhcpIpInformTried = = false )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
// Get additional information such as the subnet mask from the DHCP server
SetIP ( & subnet , 255 , 0 , 0 , 0 ) ;
Zero ( & zero , sizeof ( zero ) ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
UINTToIP ( & client_ip , p - > ClientAddressOption . ClientAddress ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
Zero ( & cao , sizeof ( cao ) ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
IPCSetIPv4Parameters ( p - > Ipc , & client_ip , & subnet , & zero , NULL ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
p - > DhcpIpInformTried = true ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
PPPLog ( p , " LP_DHCP_INFORM_TRYING " ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
if ( IPCDhcpRequestInformIP ( p - > Ipc , & cao , p - > TubeRecv , & client_ip ) )
{
Debug ( " IPCDhcpRequestInformIP ok. \n " ) ;
Copy ( & p - > ClientAddressOption , & cao , sizeof ( cao ) ) ;
p - > ClientAddressOption . ClientAddress = IPToUINT ( & client_ip ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
if ( true )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
char server_ip_str [ 64 ] ;
char subnet_str [ 64 ] , defgw_str [ 64 ] ;
char dns1_str [ 64 ] , dns2_str [ 64 ] ;
char wins1_str [ 64 ] , wins2_str [ 64 ] ;
IPToStr32 ( server_ip_str , sizeof ( server_ip_str ) , cao . ServerAddress ) ;
IPToStr32 ( subnet_str , sizeof ( subnet_str ) , cao . SubnetMask ) ;
IPToStr32 ( defgw_str , sizeof ( defgw_str ) , cao . Gateway ) ;
IPToStr32 ( dns1_str , sizeof ( dns1_str ) , cao . DnsServer ) ;
IPToStr32 ( dns2_str , sizeof ( dns2_str ) , cao . DnsServer2 ) ;
IPToStr32 ( wins1_str , sizeof ( wins1_str ) , cao . WinsServer ) ;
IPToStr32 ( wins2_str , sizeof ( wins2_str ) , cao . WinsServer2 ) ;
PPPLog ( p , " LP_DHCP_INFORM_OK " ,
subnet_str , defgw_str , cao . DomainName ,
dns1_str , dns2_str , wins1_str , wins2_str ,
server_ip_str ) ;
2014-01-04 17:00:08 +04:00
}
}
2018-03-13 17:10:22 +03:00
else
{
Debug ( " IPCDhcpRequestInformIP failed. \n " ) ;
ok = false ;
p - > DhcpIpInformTried = false ;
PPPLog ( p , " LP_DHCP_INFORM_NG " ) ;
}
IPCSetIPv4Parameters ( p - > Ipc , & zero , & zero , & zero , NULL ) ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
}
// Get IP address and additional information from DHCP
else
{
if ( p - > DhcpIpAllocTried = = false )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
DHCP_OPTION_LIST cao ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
Zero ( & cao , sizeof ( cao ) ) ;
p - > DhcpIpAllocTried = true ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
PPPLog ( p , " LP_DHCP_REQUEST_TRYING " ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
if ( IPCDhcpAllocateIP ( p - > Ipc , & cao , p - > TubeRecv ) )
{
UINT t ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
Debug ( " IPCDhcpAllocateIP ok. \n " ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
// IP address has been determined
Copy ( & p - > ClientAddressOption , & cao , sizeof ( cao ) ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
p - > DhcpAllocated = true ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
// Determine the DHCP update interval
t = cao . LeaseTime ;
if ( t = = 0 )
{
t = 600 ;
}
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
t = t / 3 ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
if ( t = = 0 )
{
t = 1 ;
}
2014-01-04 17:00:08 +04:00
2019-11-22 01:26:36 +03:00
p - > DhcpRenewInterval = ( UINT64 ) t * ( UINT64 ) 1000 ;
2014-01-04 17:00:08 +04:00
p - > DhcpNextRenewTime = Tick64 ( ) + p - > DhcpRenewInterval ;
2018-03-13 17:10:22 +03:00
if ( true )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
char client_ip_str [ 64 ] , server_ip_str [ 64 ] ;
char subnet_str [ 64 ] , defgw_str [ 64 ] ;
char dns1_str [ 64 ] , dns2_str [ 64 ] ;
char wins1_str [ 64 ] , wins2_str [ 64 ] ;
IPToStr32 ( client_ip_str , sizeof ( client_ip_str ) , cao . ClientAddress ) ;
IPToStr32 ( server_ip_str , sizeof ( server_ip_str ) , cao . ServerAddress ) ;
IPToStr32 ( subnet_str , sizeof ( subnet_str ) , cao . SubnetMask ) ;
IPToStr32 ( defgw_str , sizeof ( defgw_str ) , cao . Gateway ) ;
IPToStr32 ( dns1_str , sizeof ( dns1_str ) , cao . DnsServer ) ;
IPToStr32 ( dns2_str , sizeof ( dns2_str ) , cao . DnsServer2 ) ;
IPToStr32 ( wins1_str , sizeof ( wins1_str ) , cao . WinsServer ) ;
IPToStr32 ( wins2_str , sizeof ( wins2_str ) , cao . WinsServer2 ) ;
PPPLog ( p , " LP_DHCP_REQUEST_OK " ,
client_ip_str , subnet_str , defgw_str , cao . DomainName ,
dns1_str , dns2_str , wins1_str , wins2_str ,
server_ip_str , cao . LeaseTime ) ;
2014-01-04 17:00:08 +04:00
}
}
2018-03-13 17:10:22 +03:00
else
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
Debug ( " IPCDhcpAllocateIP failed. \n " ) ;
p - > DhcpIpAllocTried = false ;
ok = false ;
PPPLog ( p , " LP_DHCP_REQUEST_NG " ) ;
2014-01-04 17:00:08 +04:00
}
}
}
}
2018-03-13 17:10:22 +03:00
// If we already have a configured IP data - send it along
if ( IsValidUnicastIPAddressUINT4 ( p - > ClientAddressOption . ClientAddress ) & &
p - > ClientAddressOption . SubnetMask ! = 0 & & ok )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
// Success to determine the address
UINTToIP ( & subnet , p - > ClientAddressOption . SubnetMask ) ;
UINTToIP ( & gw , p - > ClientAddressOption . Gateway ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
Zero ( & res , sizeof ( res ) ) ;
UINTToIP ( & res . IpAddress , p - > ClientAddressOption . ClientAddress ) ;
UINTToIP ( & res . DnsServer1 , p - > ClientAddressOption . DnsServer ) ;
UINTToIP ( & res . DnsServer2 , p - > ClientAddressOption . DnsServer2 ) ;
UINTToIP ( & res . WinsServer1 , p - > ClientAddressOption . WinsServer ) ;
UINTToIP ( & res . WinsServer2 , p - > ClientAddressOption . WinsServer2 ) ;
if ( IPCSetIPv4Parameters ( p - > Ipc , & res . IpAddress , & subnet , & gw , & p - > ClientAddressOption . ClasslessRoute ) )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
char client_ip_str [ 64 ] ;
char subnet_str [ 64 ] , defgw_str [ 64 ] ;
char dns1_str [ 64 ] , dns2_str [ 64 ] ;
char wins1_str [ 64 ] , wins2_str [ 64 ] ;
// IPv4 parameters have been set for the first time
Debug ( " Param First Set. \n " ) ;
IPToStr ( client_ip_str , sizeof ( client_ip_str ) , & res . IpAddress ) ;
IPToStr ( subnet_str , sizeof ( subnet_str ) , & subnet ) ;
IPToStr ( defgw_str , sizeof ( defgw_str ) , & gw ) ;
IPToStr ( dns1_str , sizeof ( dns1_str ) , & res . DnsServer1 ) ;
IPToStr ( dns2_str , sizeof ( dns2_str ) , & res . DnsServer2 ) ;
IPToStr ( wins1_str , sizeof ( wins1_str ) , & res . WinsServer1 ) ;
IPToStr ( wins2_str , sizeof ( wins2_str ) , & res . WinsServer2 ) ;
PPPLog ( p , " LP_SET_IPV4_PARAM " , client_ip_str , subnet_str ,
defgw_str , dns1_str , dns2_str , wins1_str , wins2_str ) ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
/*// Backporting static configuration received from client - let him use whatever he wants,
// he won't accept anything else anyway (as per testing with Windows clients)
if ( ! IsZeroIP ( & o . DnsServer1 ) )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
CopyIP ( & res . DnsServer1 , & o . DnsServer1 ) ;
Debug ( " Setting DNS1 from client \n " ) ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
if ( ! IsZeroIP ( & o . DnsServer2 ) )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
CopyIP ( & res . DnsServer2 , & o . DnsServer2 ) ;
Debug ( " Setting DNS2 from client \n " ) ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
if ( ! IsZeroIP ( & o . WinsServer1 ) )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
CopyIP ( & res . WinsServer1 , & o . WinsServer1 ) ;
Debug ( " Setting WINS1 from client \n " ) ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
if ( ! IsZeroIP ( & o . WinsServer2 ) )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
CopyIP ( & res . WinsServer2 , & o . WinsServer2 ) ;
Debug ( " Setting WINS2 from client \n " ) ;
} */
/*if (!IsZeroIP(&res.DnsServer1) && IsZeroIP(&res.DnsServer2))
{
CopyIP ( & res . DnsServer2 , & res . DnsServer1 ) ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
if ( ! IsZeroIP ( & res . WinsServer1 ) & & IsZeroIP ( & res . WinsServer2 ) )
{
CopyIP ( & res . WinsServer2 , & res . WinsServer1 ) ;
} */
PPPSetIPOptionToLCP ( & res , pp - > Lcp , true ) ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
// We couldn't configure address for the client
2014-01-04 17:00:08 +04:00
else
{
2018-03-13 17:10:22 +03:00
// Failed to determine the address
Debug ( " IP Address Determination Failed. \n " ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
Zero ( & res , sizeof ( res ) ) ;
// We will try to reconfigure if we receive another request by wiping all data
Zero ( & p - > ClientAddressOption , sizeof ( DHCP_OPTION_LIST ) ) ;
2020-04-25 18:02:02 +03:00
p - > UseStaticIPAddress = false ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
PPPSetIPOptionToLCP ( & res , pp - > Lcp , true ) ;
}
if ( PPPRejectLCPOptionsEx ( p , pp , processed ) )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
Debug ( " Rejected IPCP options ID = 0x%x \n " , pp - > Lcp - > Id ) ;
processed = true ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
if ( ok & & PPPNackLCPOptionsEx ( p , pp , processed ) )
{
Debug ( " NACKed IPCP options ID = 0x%x \n " , pp - > Lcp - > Id ) ;
processed = true ;
}
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
// 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)
2020-05-02 09:38:08 +03:00
if ( p - > IPv4_State = = PPP_PROTO_STATUS_CLOSED & & p - > ClientAddressOption . ServerAddress ! = 0 & & ok )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
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 ) )
{
PPPSetStatus ( p , PPP_STATUS_FAIL ) ;
WHERE ;
return false ;
}
p - > IPv4_State = PPP_PROTO_STATUS_CONFIG ;
if ( ! processed )
{
PPPAddNextPacket ( p , pp , 1 ) ;
}
2014-01-04 17:00:08 +04:00
return false ;
}
2018-03-13 17:10:22 +03:00
// We still haven't received any answer from client about server IP, keep waiting...
if ( ( p - > IPv4_State = = PPP_PROTO_STATUS_CONFIG | | p - > IPv4_State = = PPP_PROTO_STATUS_CLOSED ) & & ! processed )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
PPPAddNextPacket ( p , pp , 1 ) ;
2014-01-04 17:00:08 +04:00
return false ;
}
2018-03-13 17:10:22 +03:00
//Debug("PPPAckLCPOptionsEx ok=%x, processed=%x", ok, processed);
if ( ! ok | | ! PPPAckLCPOptionsEx ( p , pp , processed ) )
2014-01-04 17:00:08 +04:00
{
return false ;
}
2018-03-13 17:10:22 +03:00
Debug ( " ACKed IPCP options ID = 0x%x \n " , pp - > Lcp - > Id ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
if ( ok & & p - > IPv4_State = = PPP_PROTO_STATUS_CONFIG_WAIT )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
p - > IPv4_State = PPP_PROTO_STATUS_OPENED ;
Debug ( " IPv4 OPENED \n " ) ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
return ok ;
}
2014-01-04 17:00:08 +04:00
2020-05-02 01:54:03 +03:00
// Process EAP request packets
bool PPPProcessEAPRequestPacket ( PPP_SESSION * p , PPP_PACKET * pp )
{
2020-05-02 09:38:08 +03:00
Debug ( " We got an EAP request, which is weird... \n " ) ;
2020-05-02 01:54:03 +03:00
return false ;
}
2018-03-13 17:10:22 +03:00
// LCP option based packets utility
bool PPPRejectLCPOptions ( PPP_SESSION * p , PPP_PACKET * pp )
{
return PPPRejectLCPOptionsEx ( p , pp , false ) ;
}
bool PPPRejectLCPOptionsEx ( PPP_SESSION * p , PPP_PACKET * pp , bool simulate )
{
UINT i = 0 ;
bool toBeRejected = false ;
PPP_PACKET * ret ;
for ( i = 0 ; i < LIST_NUM ( pp - > Lcp - > OptionList ) ; i + + )
{
PPP_OPTION * t = LIST_DATA ( pp - > Lcp - > OptionList , i ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
if ( t - > IsSupported = = false )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
toBeRejected = true ;
break ;
2014-01-04 17:00:08 +04:00
}
}
2018-03-13 17:10:22 +03:00
if ( toBeRejected = = false )
2014-01-04 17:00:08 +04:00
{
return false ;
}
2018-03-13 17:10:22 +03:00
ret = ZeroMalloc ( sizeof ( PPP_PACKET ) ) ;
ret - > IsControl = true ;
ret - > Protocol = pp - > Protocol ;
// Return a Reject if there are unsupported parameters
ret - > Lcp = NewPPPLCP ( PPP_LCP_CODE_REJECT , pp - > Lcp - > Id ) ;
for ( i = 0 ; i < LIST_NUM ( pp - > Lcp - > OptionList ) ; i + + )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
PPP_OPTION * t = LIST_DATA ( pp - > Lcp - > OptionList , i ) ;
if ( t - > IsSupported = = false )
{
// Attach the original option value as is
Add ( ret - > Lcp - > OptionList , NewPPPOption ( t - > Type , t - > Data , t - > DataSize ) ) ;
Debug ( " Rejected LCP option = 0x%x, proto = 0x%x \n " , t - > Type , pp - > Protocol ) ;
}
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
if ( LIST_NUM ( ret - > Lcp - > OptionList ) = = 0 | | simulate )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
FreePPPPacket ( ret ) ;
2014-01-04 17:00:08 +04:00
return false ;
}
2018-03-13 17:10:22 +03:00
PPPSendPacketAndFree ( p , ret ) ;
2014-01-04 17:00:08 +04:00
return true ;
}
2018-03-13 17:10:22 +03:00
bool PPPNackLCPOptions ( PPP_SESSION * p , PPP_PACKET * pp )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
return PPPNackLCPOptionsEx ( p , pp , false ) ;
}
bool PPPNackLCPOptionsEx ( PPP_SESSION * p , PPP_PACKET * pp , bool simulate )
{
UINT i = 0 ;
PPP_PACKET * ret ;
bool toBeNACKed = false ;
for ( i = 0 ; i < LIST_NUM ( pp - > Lcp - > OptionList ) ; i + + )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
PPP_OPTION * t = LIST_DATA ( pp - > Lcp - > OptionList , i ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
if ( t - > IsAccepted = = false & & t - > IsSupported = = true )
{
toBeNACKed = true ;
break ;
}
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
if ( toBeNACKed = = false )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
return false ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
ret = ZeroMalloc ( sizeof ( PPP_PACKET ) ) ;
ret - > IsControl = true ;
ret - > Protocol = pp - > Protocol ;
// Return a NAK if there are any unacceptable parameter
// even that all parameters are supported
ret - > Lcp = NewPPPLCP ( PPP_LCP_CODE_NAK , pp - > Lcp - > Id ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
for ( i = 0 ; i < LIST_NUM ( pp - > Lcp - > OptionList ) ; i + + )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
PPP_OPTION * t = LIST_DATA ( pp - > Lcp - > OptionList , i ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
if ( t - > IsAccepted = = false & & t - > IsSupported = = true )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
// Replace the original option value with an acceptable value
Add ( ret - > Lcp - > OptionList , NewPPPOption ( t - > Type , t - > AltData , t - > AltDataSize ) ) ;
Debug ( " NACKed LCP option = 0x%x, proto = 0x%x \n " , t - > Type , pp - > Protocol ) ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
}
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
if ( LIST_NUM ( ret - > Lcp - > OptionList ) = = 0 | | simulate )
{
FreePPPPacket ( ret ) ;
return false ;
}
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
PPPSendPacketAndFree ( p , ret ) ;
return true ;
}
bool PPPAckLCPOptions ( PPP_SESSION * p , PPP_PACKET * pp )
{
return PPPAckLCPOptionsEx ( p , pp , false ) ;
}
bool PPPAckLCPOptionsEx ( PPP_SESSION * p , PPP_PACKET * pp , bool simulate )
{
UINT i = 0 ;
PPP_PACKET * ret ;
bool toBeACKed = false ;
2020-04-25 05:01:09 +03:00
if ( LIST_NUM ( pp - > Lcp - > OptionList ) = = 0 )
{
// We acknoweldge an empty option list
toBeACKed = true ;
Debug ( " ACKing empty LCP options list, id=%i \n " , pp - > Lcp - > Id ) ;
}
2018-03-13 17:10:22 +03:00
for ( i = 0 ; i < LIST_NUM ( pp - > Lcp - > OptionList ) ; i + + )
{
PPP_OPTION * t = LIST_DATA ( pp - > Lcp - > OptionList , i ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
if ( t - > IsAccepted = = true & & t - > IsSupported = = true )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
toBeACKed = true ;
break ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
}
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
if ( toBeACKed = = false )
{
return false ;
}
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
ret = ZeroMalloc ( sizeof ( PPP_PACKET ) ) ;
ret - > IsControl = true ;
ret - > Protocol = pp - > Protocol ;
// Return an ACK if all parameters are accepted
ret - > Lcp = NewPPPLCP ( PPP_LCP_CODE_ACK , pp - > Lcp - > Id ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
for ( i = 0 ; i < LIST_NUM ( pp - > Lcp - > OptionList ) ; i + + )
{
PPP_OPTION * t = LIST_DATA ( pp - > Lcp - > OptionList , i ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
if ( t - > IsAccepted = = true & & t - > IsSupported = = true )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
// Attach the original option value as is
Add ( ret - > Lcp - > OptionList , NewPPPOption ( t - > Type , t - > Data , t - > DataSize ) ) ;
Debug ( " ACKed LCP option = 0x%x, proto = 0x%x \n " , t - > Type , pp - > Protocol ) ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
}
2014-01-04 17:00:08 +04:00
2020-04-25 05:01:09 +03:00
if ( simulate )
2018-03-13 17:10:22 +03:00
{
FreePPPPacket ( ret ) ;
return false ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
PPPSendPacketAndFree ( p , ret ) ;
return true ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
// PPP networking functions
// Send a request packet in the PPP
bool PPPSendAndRetransmitRequest ( PPP_SESSION * p , USHORT protocol , PPP_LCP * c )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
PPP_PACKET * pp ;
UINT64 now = Tick64 ( ) ;
PPP_REQUEST_RESEND * resend ;
2014-01-04 17:00:08 +04:00
// Validate arguments
2018-03-13 17:10:22 +03:00
if ( p = = NULL | | c = = NULL )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
return false ;
}
pp = ZeroMalloc ( sizeof ( PPP_PACKET ) ) ;
pp - > Protocol = protocol ;
pp - > IsControl = true ;
pp - > Lcp = c ;
if ( pp - > Lcp - > Id = = 0 )
{
pp - > Lcp - > Id = p - > NextId + + ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
// Send the PPP packet
if ( ! PPPSendPacketEx ( p , pp , false ) )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
PPPSetStatus ( p , PPP_STATUS_FAIL ) ;
WHERE ;
return false ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
resend = ZeroMalloc ( sizeof ( PPP_REQUEST_RESEND ) ) ;
resend - > Id = pp - > Lcp - > Id ;
resend - > Packet = pp ;
resend - > ResendTime = now + PPP_PACKET_RESEND_INTERVAL ;
2020-04-27 21:43:40 +03:00
resend - > TimeoutTime = now + p - > PacketRecvTimeout ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
Add ( p - > SentReqPacketList , resend ) ;
return true ;
}
// Send the PPP packet and frees the sent packet
bool PPPSendPacketAndFree ( PPP_SESSION * p , PPP_PACKET * pp )
{
bool result = PPPSendPacketEx ( p , pp , false ) ;
FreePPPPacket ( pp ) ;
return result ;
}
// Send the PPP packet
bool PPPSendPacketEx ( PPP_SESSION * p , PPP_PACKET * pp , bool no_flush )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
bool ret = false ;
BUF * b ;
2014-01-04 17:00:08 +04:00
// Validate arguments
2018-03-13 17:10:22 +03:00
if ( p = = NULL | | pp = = NULL )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
return false ;
}
b = BuildPPPPacketData ( pp ) ;
if ( b = = NULL )
{
return false ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
ret = TubeSendEx ( p - > TubeSend , b - > Buf , b - > Size , NULL , no_flush ) ;
if ( no_flush )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
AddTubeToFlushList ( p - > FlushList , p - > TubeSend ) ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
FreeBuf ( b ) ;
return ret ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
// Receive a PPP packet
PPP_PACKET * PPPRecvPacket ( PPP_SESSION * p , bool async )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
TUBEDATA * d ;
PPP_PACKET * pp ;
2014-01-04 17:00:08 +04:00
// Validate arguments
if ( p = = NULL )
{
return NULL ;
}
LABEL_LOOP :
2018-03-13 17:10:22 +03:00
if ( async = = false )
2014-01-04 17:00:08 +04:00
{
2020-04-27 21:43:40 +03:00
d = TubeRecvSync ( p - > TubeRecv , p - > PacketRecvTimeout ) ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
else
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
d = TubeRecvAsync ( p - > TubeRecv ) ;
}
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
if ( d = = NULL )
{
return NULL ;
}
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
pp = ParsePPPPacket ( d - > Data , d - > DataSize ) ;
FreeTubeData ( d ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
if ( pp = = NULL )
{
// A broken packet is received
2014-01-04 17:00:08 +04:00
goto LABEL_LOOP ;
}
2018-03-13 17:10:22 +03:00
p - > LastRecvTime = Tick64 ( ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
return pp ;
}
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
PPP_PACKET * PPPGetNextPacket ( PPP_SESSION * p )
{
PPP_PACKET * ret = NULL ;
UINT i = 0 ;
if ( p - > CurrentPacket ! = NULL )
{
FreePPPPacket ( p - > CurrentPacket ) ;
p - > CurrentPacket = NULL ;
}
for ( i = 0 ; i < LIST_NUM ( p - > DelayedPackets ) ; i + + )
{
PPP_DELAYED_PACKET * t = LIST_DATA ( p - > DelayedPackets , i ) ;
if ( t - > DelayTicks > 0 )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
t - > DelayTicks - - ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
else
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
ret = t - > Packet ;
Delete ( p - > DelayedPackets , t ) ;
Free ( t ) ;
break ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
}
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
if ( ret ! = NULL )
{
p - > CurrentPacket = ret ;
return ret ;
}
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
ret = PPPRecvPacket ( p , true ) ;
if ( ret ! = NULL & & ret - > IsControl & & ret - > Lcp ! = NULL )
{
PPP_DELAYED_PACKET * firstRelated = NULL ;
for ( i = 0 ; i < LIST_NUM ( p - > DelayedPackets ) ; i + + )
{
PPP_DELAYED_PACKET * t = LIST_DATA ( p - > DelayedPackets , i ) ;
char related = PPPRelatedPacketComparator ( ret , t - > Packet ) ;
if ( related ! = 0xF & & related ! = 0xE )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
if ( related = = 0 )
{
// It's the same packet, just remove it and wait for it's delays
FreePPPPacket ( ret ) ;
firstRelated = NULL ;
ret = NULL ;
break ;
}
if ( related = = 1 )
{
// We got a packet which should come later than any of delayed ones
PPPAddNextPacket ( p , ret , t - > DelayTicks ) ;
firstRelated = NULL ;
ret = NULL ;
break ;
}
if ( related = = - 1 )
{
char prevFoundRelated = - 1 ;
if ( firstRelated ! = NULL )
{
prevFoundRelated = PPPRelatedPacketComparator ( t - > Packet , firstRelated - > Packet ) ;
}
if ( prevFoundRelated = = - 1 )
{
firstRelated = t ;
}
}
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
}
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
if ( firstRelated ! = NULL )
{
PPPAddNextPacket ( p , ret , firstRelated - > DelayTicks ) ;
ret = NULL ;
2014-01-04 17:00:08 +04:00
}
}
2018-03-13 17:10:22 +03:00
p - > CurrentPacket = ret ;
return ret ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
void PPPAddNextPacket ( PPP_SESSION * p , PPP_PACKET * pp , UINT delay )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
PPP_DELAYED_PACKET * t = ZeroMalloc ( sizeof ( PPP_DELAYED_PACKET ) ) ;
UINT i ;
if ( p - > CurrentPacket = = pp )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
p - > CurrentPacket = NULL ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
t - > Packet = pp ;
t - > DelayTicks = delay ;
Add ( p - > DelayedPackets , t ) ;
Sort ( p - > DelayedPackets ) ;
/*Debug("after sorting delayeds\n");
for ( i = 0 ; i < LIST_NUM ( p - > DelayedPackets ) ; i + + )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
t = LIST_DATA ( p - > DelayedPackets , i ) ;
if ( t - > Packet - > Lcp ! = NULL )
{
Debug ( " > Packet proto = 0x%x, id = 0x%x, code = 0x%x, delay = 0x%x \n " , t - > Packet - > Protocol , t - > Packet - > Lcp - > Id , t - > Packet - > Lcp - > Code , t - > DelayTicks ) ;
}
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
Debug ( " after sorting delayeds end \n " ) ; */
}
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
int PPPDelayedPacketsComparator ( const void * a , const void * b )
{
PPP_DELAYED_PACKET * first = a ;
PPP_DELAYED_PACKET * second = b ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
char related = PPPRelatedPacketComparator ( first - > Packet , second - > Packet ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
if ( related = = 0xF | | related = = 0xE )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
if ( first - > DelayTicks < second - > DelayTicks )
{
return - 1 ;
}
if ( first - > DelayTicks > second - > DelayTicks )
{
return 1 ;
}
return 0 ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
// We make all delay ticks to be accounted with the sorting
if ( related < = 1 & & related > = - 1 )
{
if ( related = = - 1 & & first - > DelayTicks > = second - > DelayTicks )
{
second - > DelayTicks = first - > DelayTicks ;
second - > DelayTicks + + ;
}
else if ( related = = 1 & & first - > DelayTicks < = second - > DelayTicks )
{
first - > DelayTicks = second - > DelayTicks ;
first - > DelayTicks + + ;
}
return related ;
}
return 0 ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
// -1 - packet a comes before packet b
// 0 - this is the same packet
// 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 )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
if ( a - > IsControl & & b - > IsControl & &
a - > Lcp ! = NULL & & b - > Lcp ! = NULL & &
a - > Protocol = = b - > Protocol & &
PPP_CODE_IS_REQUEST ( a - > Protocol , a - > Lcp - > Code ) = = PPP_CODE_IS_REQUEST ( b - > Protocol , b - > Lcp - > Code ) & &
PPP_CODE_IS_RESPONSE ( a - > Protocol , a - > Lcp - > Code ) = = PPP_CODE_IS_RESPONSE ( b - > Protocol , b - > Lcp - > Code ) )
{
// The packet is related!
if ( a - > Lcp - > Id < b - > Lcp - > Id )
{
return - 1 ;
}
else if ( a - > Lcp - > Id = = b - > Lcp - > Id )
{
if ( a - > Lcp - > Code = = b - > Lcp - > Code )
{
return 0 ;
}
else
{
return 0xE ;
}
}
else if ( a - > Lcp - > Id > b - > Lcp - > Id )
{
return 1 ;
}
else
{
return 0xE ;
}
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
else
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
// The packet is not related!
return 0xF ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
}
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
// PPP utility functions
// Packet structure creation utilities
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
// Create the LCP
PPP_LCP * NewPPPLCP ( UCHAR code , UCHAR id )
{
PPP_LCP * c = ZeroMalloc ( sizeof ( PPP_LCP ) ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
c - > Code = code ;
c - > Id = id ;
c - > OptionList = NewListFast ( NULL ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
return c ;
2014-01-04 17:00:08 +04:00
}
// Create a new PPP options
PPP_OPTION * NewPPPOption ( UCHAR type , void * data , UINT size )
{
PPP_OPTION * o ;
// Validate arguments
if ( size ! = 0 & & data = = NULL )
{
return NULL ;
}
o = ZeroMalloc ( sizeof ( PPP_OPTION ) ) ;
o - > Type = type ;
Copy ( o - > Data , data , size ) ;
o - > DataSize = size ;
return o ;
}
2018-03-13 17:10:22 +03:00
// Packet parse utilities
2014-01-04 17:00:08 +04:00
// Analyse the PPP packet
PPP_PACKET * ParsePPPPacket ( void * data , UINT size )
{
PPP_PACKET * pp ;
UCHAR * buf ;
// Validate arguments
if ( data = = NULL | | size = = 0 )
{
return NULL ;
}
pp = ZeroMalloc ( sizeof ( PPP_PACKET ) ) ;
buf = ( UCHAR * ) data ;
// Address
if ( size < 1 )
{
goto LABEL_ERROR ;
}
if ( buf [ 0 ] ! = 0xff )
{
goto LABEL_ERROR ;
}
size - - ;
buf + + ;
// Control
if ( size < 1 )
{
goto LABEL_ERROR ;
}
if ( buf [ 0 ] ! = 0x03 )
{
goto LABEL_ERROR ;
}
size - - ;
buf + + ;
// Protocol
if ( size < 2 )
{
goto LABEL_ERROR ;
}
pp - > Protocol = READ_USHORT ( buf ) ;
2018-03-13 17:10:22 +03:00
2014-01-04 17:00:08 +04:00
size - = 2 ;
buf + = 2 ;
2020-05-02 01:54:03 +03:00
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 )
2018-03-13 17:10:22 +03:00
{
pp - > IsControl = true ;
}
pp - > Data = Clone ( buf , size ) ;
pp - > DataSize = size ;
if ( pp - > IsControl )
{
pp - > Lcp = PPPParseLCP ( pp - > Protocol , pp - > Data , pp - > DataSize ) ;
if ( pp - > Lcp = = NULL )
{
goto LABEL_ERROR ;
}
}
return pp ;
LABEL_ERROR :
FreePPPPacket ( pp ) ;
return NULL ;
}
// Analyse the LCP data
PPP_LCP * PPPParseLCP ( USHORT protocol , void * data , UINT size )
{
UCHAR * buf ;
PPP_LCP * c ;
USHORT len ;
bool has_option_list = false ;
// Validate arguments
if ( data = = NULL | | size = = 0 )
{
return NULL ;
}
buf = ( UCHAR * ) data ;
c = ZeroMalloc ( sizeof ( PPP_LCP ) ) ;
c - > OptionList = NewListFast ( NULL ) ;
// Code
if ( size < 1 )
{
goto LABEL_ERROR ;
}
c - > Code = buf [ 0 ] ;
buf + + ;
size - - ;
// ID
if ( size < 1 )
{
goto LABEL_ERROR ;
}
c - > Id = buf [ 0 ] ;
buf + + ;
size - - ;
// Length
if ( size < 2 )
{
goto LABEL_ERROR ;
}
len = READ_USHORT ( buf ) ;
if ( len < 4 )
{
goto LABEL_ERROR ;
}
len - = 4 ;
buf + = 2 ;
size - = 2 ;
// Options or Data
if ( size < len )
{
goto LABEL_ERROR ;
}
has_option_list = PPP_CODE_IS_WITH_OPTION_LIST ( protocol , c - > Code ) ;
if ( has_option_list = = false )
{
c - > Data = Clone ( buf , size ) ;
c - > DataSize = size ;
}
else
{
// Option List
while ( len > = 1 )
{
PPP_OPTION o ;
Zero ( & o , sizeof ( o ) ) ;
// Type
if ( len < 1 )
{
goto LABEL_ERROR ;
}
o . Type = buf [ 0 ] ;
buf + + ;
len - - ;
// Length
if ( len < 1 )
{
goto LABEL_ERROR ;
}
o . DataSize = buf [ 0 ] ;
if ( o . DataSize < 2 )
{
goto LABEL_ERROR ;
}
o . DataSize - = 2 ;
buf + + ;
len - - ;
// Data
if ( len < o . DataSize )
{
goto LABEL_ERROR ;
}
Copy ( o . Data , buf , o . DataSize ) ;
buf + = o . DataSize ;
len - = o . DataSize ;
Add ( c - > OptionList , Clone ( & o , sizeof ( o ) ) ) ;
}
}
return c ;
LABEL_ERROR :
FreePPPLCP ( c ) ;
return NULL ;
}
// Analyse MS CHAP v2 Response packet
bool PPPParseMSCHAP2ResponsePacket ( PPP_SESSION * p , PPP_PACKET * pp )
{
bool ok = false ;
char client_ip_tmp [ 256 ] ;
EAP_CLIENT * eap ;
UCHAR client_response_buffer [ 49 ] ;
UCHAR * client_challenge_16 ;
UCHAR * client_response_24 ;
char username_tmp [ MAX_SIZE ] ;
IPC * ipc = NULL ;
char id [ MAX_SIZE ] ;
char hub [ MAX_SIZE ] ;
char password [ MAX_SIZE ] ;
char server_challenge_hex [ MAX_SIZE ] ;
char client_challenge_hex [ MAX_SIZE ] ;
char client_response_hex [ MAX_SIZE ] ;
char eap_client_hex [ 64 ] ;
ETHERIP_ID d ;
UINT error_code ;
UINT64 eap_client_ptr = ( UINT64 ) p - > EapClient ;
if ( pp - > Lcp ! = NULL & & pp - > Lcp - > DataSize > = 51 )
{
BUF * b ;
if ( pp - > Lcp - > Id ! = p - > MsChapV2_PacketId )
{
Debug ( " Got incorrect LCP PacketId! Should be 0x%x, got 0x%x \n " , p - > MsChapV2_PacketId , pp - > Lcp - > Id ) ;
p - > MsChapV2_PacketId = pp - > Lcp - > Id ;
}
b = NewBuf ( ) ;
WriteBuf ( b , pp - > Lcp - > Data , pp - > Lcp - > DataSize ) ;
SeekBuf ( b , 0 , 0 ) ;
if ( ReadBufChar ( b ) = = 49 )
{
ReadBuf ( b , client_response_buffer , 49 ) ;
Zero ( username_tmp , sizeof ( username_tmp ) ) ;
ReadBuf ( b , username_tmp , sizeof ( username_tmp ) - 1 ) ;
Debug ( " MS-CHAPv2: id=%s \n " , username_tmp ) ;
client_challenge_16 = client_response_buffer + 0 ;
client_response_24 = client_response_buffer + 16 + 8 ;
Copy ( p - > MsChapV2_ClientChallenge , client_challenge_16 , 16 ) ;
Copy ( p - > MsChapV2_ClientResponse , client_response_24 , 24 ) ;
Zero ( id , sizeof ( id ) ) ;
Zero ( hub , sizeof ( hub ) ) ;
// The user name is divided into the ID and the virtual HUB name
Zero ( & d , sizeof ( d ) ) ;
PPPParseUsername ( p - > Cedar , username_tmp , & d ) ;
StrCpy ( id , sizeof ( id ) , d . UserName ) ;
StrCpy ( hub , sizeof ( hub ) , d . HubName ) ;
Debug ( " MS-CHAPv2: username=%s, hubname=%s \n " , id , hub ) ;
IPToStr ( client_ip_tmp , sizeof ( client_ip_tmp ) , & p - > ClientIP ) ;
// Convert the MS-CHAPv2 data to a password string
BinToStr ( server_challenge_hex , sizeof ( server_challenge_hex ) ,
p - > MsChapV2_ServerChallenge , sizeof ( p - > MsChapV2_ServerChallenge ) ) ;
BinToStr ( client_challenge_hex , sizeof ( client_challenge_hex ) ,
p - > MsChapV2_ClientChallenge , sizeof ( p - > MsChapV2_ClientChallenge ) ) ;
BinToStr ( client_response_hex , sizeof ( client_response_hex ) ,
p - > MsChapV2_ClientResponse , sizeof ( p - > MsChapV2_ClientResponse ) ) ;
BinToStr ( eap_client_hex , sizeof ( eap_client_hex ) ,
& eap_client_ptr , 8 ) ;
Format ( password , sizeof ( password ) , " %s%s:%s:%s:%s:%s " ,
IPC_PASSWORD_MSCHAPV2_TAG ,
username_tmp ,
server_challenge_hex ,
client_challenge_hex ,
client_response_hex ,
eap_client_hex ) ;
if ( p - > MsChapV2_UseDoubleMsChapV2 & & p - > EapClient = = NULL )
{
Debug ( " Double MSCHAPv2 creating EAP client \n " ) ;
2020-02-04 23:51:50 +03:00
eap = HubNewEapClient ( p - > Cedar , hub , client_ip_tmp , id , " L3:PPP " ) ;
2018-03-13 17:10:22 +03:00
if ( eap )
{
ok = true ;
p - > EapClient = eap ;
}
else
{
PPPSetStatus ( p , PPP_STATUS_FAIL ) ;
WHERE ;
return false ;
}
}
else if ( p - > Ipc = = NULL )
{
Debug ( " MSCHAPv2 creating IPC \n " ) ;
ipc = NewIPC ( p - > Cedar , p - > ClientSoftwareName , p - > Postfix , hub , id , password ,
& error_code , & p - > ClientIP , p - > ClientPort , & p - > ServerIP , p - > ServerPort ,
2020-02-04 23:51:50 +03:00
p - > ClientHostname , p - > CryptName , false , p - > AdjustMss , p - > EapClient , NULL ,
+ IPC_LAYER_3 ) ;
2018-03-13 17:10:22 +03:00
if ( ipc ! = NULL )
{
p - > Ipc = ipc ;
2014-01-04 17:00:08 +04:00
2020-04-27 21:43:40 +03:00
// 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 ( ) ;
2018-03-13 17:10:22 +03:00
Copy ( p - > MsChapV2_ServerResponse , ipc - > MsChapV2_ServerResponse , 20 ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
ok = true ;
2020-04-27 21:43:40 +03:00
p - > AuthOk = true ;
2018-03-13 17:10:22 +03:00
}
}
else
{
Debug ( " Got weird packet when we already have an active IPC! Ipc = 0x%x, AuthOk = 0x%x, Status = 0x%x \n " , p - > Ipc , p - > AuthOk , p - > PPPStatus ) ;
ok = p - > AuthOk ;
}
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
FreeBuf ( b ) ;
}
else
{
Debug ( " Got invalid MSCHAPv2 packet \n " ) ;
}
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
return ok ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
// Packet building utilities
2014-01-04 17:00:08 +04:00
// Build a PPP packet data
BUF * BuildPPPPacketData ( PPP_PACKET * pp )
{
BUF * ret ;
UCHAR c ;
USHORT us ;
// Validate arguments
if ( pp = = NULL )
{
return NULL ;
}
ret = NewBuf ( ) ;
// Address
c = 0xff ;
WriteBuf ( ret , & c , 1 ) ;
// Control
c = 0x03 ;
WriteBuf ( ret , & c , 1 ) ;
// Protocol
us = Endian16 ( pp - > Protocol ) ;
WriteBuf ( ret , & us , 2 ) ;
if ( pp - > IsControl )
{
// LCP
BUF * b = BuildLCPData ( pp - > Lcp ) ;
WriteBufBuf ( ret , b ) ;
FreeBuf ( b ) ;
}
else
{
// Data
WriteBuf ( ret , pp - > Data , pp - > DataSize ) ;
}
SeekBuf ( ret , 0 , 0 ) ;
return ret ;
}
// Build the LCP packet data
BUF * BuildLCPData ( PPP_LCP * c )
{
BUF * b ;
UCHAR zero = 0 ;
UINT i ;
// Validate arguments
if ( c = = NULL )
{
return NULL ;
}
b = NewBuf ( ) ;
// Code
WriteBuf ( b , & c - > Code , 1 ) ;
// ID
WriteBuf ( b , & c - > Id , 1 ) ;
// Length (to be updated later)
zero = 0 ;
WriteBuf ( b , & zero , 1 ) ;
WriteBuf ( b , & zero , 1 ) ;
if ( c - > Data = = NULL )
{
// Option List
2018-03-13 17:10:22 +03:00
for ( i = 0 ; i < LIST_NUM ( c - > OptionList ) ; i + + )
2014-01-04 17:00:08 +04:00
{
PPP_OPTION * o = LIST_DATA ( c - > OptionList , i ) ;
UCHAR sz = o - > DataSize + 2 ;
WriteBuf ( b , & o - > Type , 1 ) ;
WriteBuf ( b , & sz , 1 ) ;
WriteBuf ( b , o - > Data , o - > DataSize ) ;
}
}
else
{
// Data
WriteBuf ( b , c - > Data , c - > DataSize ) ;
}
SeekBuf ( b , 0 , 0 ) ;
// Update Length
WRITE_USHORT ( ( ( UCHAR * ) b - > Buf ) + 2 , b - > Size ) ;
return b ;
}
2018-03-13 17:10:22 +03:00
// Build the MS CHAP v2 challenge packet
PPP_LCP * BuildMSCHAP2ChallengePacket ( PPP_SESSION * p )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
PPP_LCP * lcp ;
BUF * b ;
char machine_name [ MAX_SIZE ] ;
UINT64 now = Tick64 ( ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
// Generate a Server Challenge packet of MS-CHAP v2
GetMachineHostName ( machine_name , sizeof ( machine_name ) ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
if ( p - > EapClient = = NULL )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
MsChapV2Server_GenerateChallenge ( p - > MsChapV2_ServerChallenge ) ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
else
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
Copy ( p - > MsChapV2_ServerChallenge , p - > EapClient - > MsChapV2Challenge . Chap_ChallengeValue , 16 ) ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
p - > MsChapV2_PacketId = p - > NextId + + ;
lcp = NewPPPLCP ( PPP_CHAP_CODE_CHALLENGE , p - > MsChapV2_PacketId ) ;
b = NewBuf ( ) ;
WriteBufChar ( b , 16 ) ;
WriteBuf ( b , p - > MsChapV2_ServerChallenge , sizeof ( p - > MsChapV2_ServerChallenge ) ) ;
WriteBuf ( b , machine_name , StrLen ( machine_name ) ) ;
lcp - > Data = Clone ( b - > Buf , b - > Size ) ;
lcp - > DataSize = b - > Size ;
FreeBuf ( b ) ;
Debug ( " Building MS-CHAP v2 Challenge \n " ) ;
return lcp ;
}
// IPCP packet utilities
// Set the IP options of PPP to LCP
bool PPPSetIPOptionToLCP ( PPP_IPOPTION * o , PPP_LCP * c , bool only_modify )
{
bool ret = false ;
// Validate arguments
if ( c = = NULL | | o = = NULL )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
return false ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
ret = PPPSetIPAddressValueToLCP ( c , PPP_IPCP_OPTION_IP , & o - > IpAddress , only_modify ) ;
PPPSetIPAddressValueToLCP ( c , PPP_IPCP_OPTION_DNS1 , & o - > DnsServer1 , only_modify ) ;
PPPSetIPAddressValueToLCP ( c , PPP_IPCP_OPTION_DNS2 , & o - > DnsServer2 , only_modify ) ;
PPPSetIPAddressValueToLCP ( c , PPP_IPCP_OPTION_WINS1 , & o - > WinsServer1 , only_modify ) ;
PPPSetIPAddressValueToLCP ( c , PPP_IPCP_OPTION_WINS2 , & o - > WinsServer2 , only_modify ) ;
return ret ;
}
// Get the IP options of PPP from LCP
bool PPPGetIPOptionFromLCP ( PPP_IPOPTION * o , PPP_LCP * c )
{
bool ret ;
// Validate arguments
if ( c = = NULL | | o = = NULL )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
return false ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
Zero ( o , sizeof ( PPP_IPOPTION ) ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
ret = PPPGetIPAddressValueFromLCP ( c , PPP_IPCP_OPTION_IP , & o - > IpAddress ) ;
PPPGetIPAddressValueFromLCP ( c , PPP_IPCP_OPTION_DNS1 , & o - > DnsServer1 ) ;
PPPGetIPAddressValueFromLCP ( c , PPP_IPCP_OPTION_DNS2 , & o - > DnsServer2 ) ;
PPPGetIPAddressValueFromLCP ( c , PPP_IPCP_OPTION_WINS1 , & o - > WinsServer1 ) ;
PPPGetIPAddressValueFromLCP ( c , PPP_IPCP_OPTION_WINS2 , & o - > WinsServer2 ) ;
return ret ;
}
// Set the IP address data to the option list of the LCP
bool PPPSetIPAddressValueToLCP ( PPP_LCP * c , UINT type , IP * ip , bool only_modify )
{
IP ip2 ;
UINT ui ;
// Validate arguments
if ( c = = NULL | | ip = = NULL )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
return false ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
ui = IPToUINT ( ip ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
if ( PPPGetIPAddressValueFromLCP ( c , type , & ip2 ) )
{
PPP_OPTION * opt ;
opt = PPPGetOptionValue ( c , type ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
if ( opt ! = NULL )
{
if ( IsZeroIP ( ip ) = = false )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
if ( CmpIpAddr ( & ip2 , ip ) = = 0 )
{
// No change
opt - > IsAccepted = true ;
opt - > IsSupported = true ;
}
else
{
// Changed
opt - > IsAccepted = false ;
opt - > IsSupported = true ;
opt - > AltDataSize = 4 ;
Copy ( opt - > AltData , & ui , 4 ) ;
}
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
else
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
// The parameter itself is not supported
// (if the IP address is 0.0.0.0)
opt - > IsSupported = false ;
opt - > IsAccepted = false ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
}
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
return true ;
}
else
{
if ( IsZeroIP ( ip ) = = false )
{
// Add as a new item
if ( only_modify ! = false )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
return false ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
else
{
PPP_OPTION * opt2 = NewPPPOption ( type , & ui , 4 ) ;
UCHAR ipstr [ MAX_SIZE ] ;
opt2 - > IsAccepted = true ;
opt2 - > IsSupported = true ;
Copy ( opt2 - > AltData , opt2 - > Data , opt2 - > DataSize ) ;
opt2 - > AltDataSize = opt2 - > DataSize ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
Add ( c - > OptionList , opt2 ) ;
IPToStr ( ipstr , MAX_SIZE , ip ) ;
return true ;
}
}
else
{
return false ;
2014-01-04 17:00:08 +04:00
}
}
2018-03-13 17:10:22 +03:00
}
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
// Get the IP address data from the option list of the LCP
bool PPPGetIPAddressValueFromLCP ( PPP_LCP * c , UINT type , IP * ip )
{
PPP_OPTION * opt ;
UINT ui ;
// Validate arguments
if ( c = = NULL | | ip = = NULL )
{
return false ;
}
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
opt = PPPGetOptionValue ( c , type ) ;
if ( opt = = NULL )
{
return false ;
}
if ( opt - > DataSize ! = 4 )
{
return false ;
}
opt - > IsSupported = true ;
ui = * ( ( UINT * ) opt - > Data ) ;
UINTToIP ( ip , ui ) ;
return true ;
2014-01-04 17:00:08 +04:00
}
2020-05-02 01:54:03 +03:00
// EAP packet utilities
2020-05-02 09:38:08 +03:00
bool PPPProcessEAPTlsResponse ( PPP_SESSION * p , PPP_EAP * eap_packet , UINT eapTlsSize )
2020-05-02 01:54:03 +03:00
{
2020-05-02 09:38:08 +03:00
UCHAR * dataBuffer ;
UINT dataSize ;
UINT tlsLength = 0 ;
2020-05-02 19:15:30 +03:00
UINT i ;
2020-05-02 09:38:08 +03:00
bool isFragmented = false ;
PPP_LCP * lcp ;
PPP_EAP * eap ;
UCHAR flags ;
UINT64 sizeLeft = 0 ;
2020-05-02 10:11:01 +03:00
Debug ( " Got EAP-TLS size=%i \n " , eapTlsSize ) ;
if ( eapTlsSize = = 1 )
2020-05-02 09:38:08 +03:00
{
// This is an EAP-TLS message ACK
2020-05-02 10:11:01 +03:00
if ( p - > Eap_TlsCtx . cachedBufferSend ! = NULL )
2020-05-02 09:38:08 +03:00
{
// We got an ACK to transmit the next fragmented message
dataSize = p - > Mru1 - 8 - 1 - 1 ; // Calculating the maximum payload size (without TlsLength)
2020-05-02 10:11:01 +03:00
sizeLeft = GetMemSize ( p - > Eap_TlsCtx . cachedBufferSend ) ;
sizeLeft - = p - > Eap_TlsCtx . cachedBufferSendPntr - p - > Eap_TlsCtx . cachedBufferSend ;
2020-05-02 09:38:08 +03:00
2020-05-02 10:11:01 +03:00
flags = PPP_EAP_TLS_FLAG_FRAGMENTED ; // M flag
2020-05-02 09:38:08 +03:00
if ( dataSize > sizeLeft )
{
dataSize = sizeLeft ;
2020-05-02 10:11:01 +03:00
flags = PPP_EAP_TLS_FLAG_NONE ; // Clearing the M flag because it is the last packet
2020-05-02 09:38:08 +03:00
}
lcp = BuildEAPTlsRequest ( p - > Eap_PacketId + + , dataSize , flags ) ;
eap = lcp - > Data ;
2020-05-02 10:11:01 +03:00
Copy ( eap - > Tls . TlsDataWithoutLength , p - > Eap_TlsCtx . cachedBufferSendPntr , dataSize ) ;
p - > Eap_TlsCtx . cachedBufferSendPntr + = dataSize ;
2020-05-02 09:38:08 +03:00
if ( ! PPPSendAndRetransmitRequest ( p , PPP_PROTOCOL_EAP , lcp ) )
{
PPPSetStatus ( p , PPP_STATUS_FAIL ) ;
WHERE ;
return false ;
}
2020-05-02 10:11:01 +03:00
Debug ( " Sent EAP-TLS size=%i type=%i flag=%i \n " , lcp - > DataSize , eap - > Type , eap - > Tls . Flags ) ;
2020-05-02 09:38:08 +03:00
2020-05-02 10:11:01 +03:00
if ( flags = = PPP_EAP_TLS_FLAG_NONE )
2020-05-02 09:38:08 +03:00
{
// As it is the latest message, we need to cleanup
2020-05-02 10:11:01 +03:00
Free ( p - > Eap_TlsCtx . cachedBufferSend ) ;
p - > Eap_TlsCtx . cachedBufferSend = NULL ;
p - > Eap_TlsCtx . cachedBufferSendPntr = NULL ;
2020-05-02 09:38:08 +03:00
}
}
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 ;
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 ,
2020-05-02 14:40:46 +03:00
p - > ClientHostname , p - > CryptName , false , p - > AdjustMss , NULL , p - > Eap_TlsCtx . clientCert . X ,
2020-05-02 09:38:08 +03:00
IPC_LAYER_3 ) ;
if ( ipc ! = NULL )
{
2020-05-02 19:15:30 +03:00
PPP_PACKET * pack ;
2020-05-02 09:38:08 +03:00
p - > Ipc = ipc ;
PPPSetStatus ( p , PPP_STATUS_AUTH_SUCCESS ) ;
// Just send an EAP-Success
2020-05-02 19:15:30 +03:00
pack = ZeroMalloc ( sizeof ( PPP_PACKET ) ) ;
pack - > IsControl = true ;
pack - > Protocol = PPP_PROTOCOL_EAP ;
2020-05-02 09:38:08 +03:00
lcp = NewPPPLCP ( PPP_EAP_CODE_SUCCESS , p - > Eap_PacketId + + ) ;
2020-05-02 19:15:30 +03:00
pack - > Lcp = lcp ;
Debug ( " Sent EAP-TLS size=%i SUCCESS \n " , lcp - > DataSize ) ;
if ( ! PPPSendPacketAndFree ( p , pack ) )
2020-05-02 09:38:08 +03:00
{
PPPSetStatus ( p , PPP_STATUS_FAIL ) ;
WHERE ;
return false ;
}
return true ;
}
else
{
2020-05-02 19:15:30 +03:00
PPP_PACKET * pack ;
2020-05-02 09:38:08 +03:00
PPPSetStatus ( p , PPP_STATUS_AUTH_FAIL ) ;
2020-05-02 19:15:30 +03:00
pack = ZeroMalloc ( sizeof ( PPP_PACKET ) ) ;
pack - > IsControl = true ;
pack - > Protocol = PPP_PROTOCOL_EAP ;
2020-05-02 09:38:08 +03:00
lcp = NewPPPLCP ( PPP_EAP_CODE_FAILURE , p - > Eap_PacketId + + ) ;
2020-05-02 19:15:30 +03:00
pack - > Lcp = lcp ;
Debug ( " Sent EAP-TLS size=%i FAILURE \n " , lcp - > DataSize ) ;
if ( ! PPPSendPacketAndFree ( p , pack ) )
2020-05-02 09:38:08 +03:00
{
PPPSetStatus ( p , PPP_STATUS_FAIL ) ;
WHERE ;
return false ;
}
return false ;
}
}
else
{
Debug ( " Weird ACK for no reason at all... \n " ) ;
return false ;
}
}
return true ;
}
dataBuffer = eap_packet - > Tls . TlsDataWithoutLength ;
dataSize = eapTlsSize - 1 ;
2020-05-02 10:11:01 +03:00
if ( eap_packet - > Tls . Flags & PPP_EAP_TLS_FLAG_TLS_LENGTH )
2020-05-02 09:38:08 +03:00
{
dataBuffer = eap_packet - > Tls . TlsDataWithLength . Data ;
dataSize - = 4 ;
2020-05-02 10:11:01 +03:00
tlsLength = Endian32 ( eap_packet - > Tls . TlsDataWithLength . TlsLength ) ;
2020-05-02 09:38:08 +03:00
}
2020-05-02 19:15:30 +03:00
/*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 " ) ; */
2020-05-02 10:11:01 +03:00
if ( eap_packet - > Tls . Flags & PPP_EAP_TLS_FLAG_FRAGMENTED )
2020-05-02 09:38:08 +03:00
{
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
2020-05-02 10:11:01 +03:00
if ( isFragmented | | p - > Eap_TlsCtx . cachedBufferRecv ! = NULL )
2020-05-02 09:38:08 +03:00
{
2020-05-02 10:11:01 +03:00
if ( p - > Eap_TlsCtx . cachedBufferRecv = = NULL & & tlsLength > 0 )
2020-05-02 09:38:08 +03:00
{
2020-05-02 10:11:01 +03:00
p - > Eap_TlsCtx . cachedBufferRecv = ZeroMalloc ( MAX ( dataSize , tlsLength ) ) ;
p - > Eap_TlsCtx . cachedBufferRecvPntr = p - > Eap_TlsCtx . cachedBufferRecv ;
2020-05-02 09:38:08 +03:00
}
2020-05-02 19:15:30 +03:00
else if ( p - > Eap_TlsCtx . cachedBufferRecv = = NULL )
2020-05-02 09:38:08 +03:00
{
2020-05-02 19:15:30 +03:00
p - > Eap_TlsCtx . cachedBufferRecv = ZeroMalloc ( MAX ( dataSize , PPP_MRU_MAX * 10 ) ) ; // 10 MRUs should be enough
p - > Eap_TlsCtx . cachedBufferRecvPntr = p - > Eap_TlsCtx . cachedBufferRecv ;
2020-05-02 09:38:08 +03:00
}
2020-05-02 10:11:01 +03:00
sizeLeft = GetMemSize ( p - > Eap_TlsCtx . cachedBufferRecv ) ;
sizeLeft - = p - > Eap_TlsCtx . cachedBufferRecvPntr - p - > Eap_TlsCtx . cachedBufferRecv ;
2020-05-02 09:38:08 +03:00
2020-05-02 19:15:30 +03:00
Copy ( p - > Eap_TlsCtx . cachedBufferRecvPntr , dataBuffer , MIN ( sizeLeft , dataSize ) ) ;
2020-05-02 09:38:08 +03:00
2020-05-02 19:15:30 +03:00
p - > Eap_TlsCtx . cachedBufferRecvPntr + = MIN ( sizeLeft , dataSize ) ;
2020-05-02 09:38:08 +03:00
}
// If we got a cached buffer, we should feed the FIFOs via it
2020-05-02 10:11:01 +03:00
if ( p - > Eap_TlsCtx . cachedBufferRecv ! = NULL )
2020-05-02 09:38:08 +03:00
{
2020-05-02 10:11:01 +03:00
dataBuffer = p - > Eap_TlsCtx . cachedBufferRecv ;
dataSize = GetMemSize ( p - > Eap_TlsCtx . cachedBufferRecv ) ;
2020-05-02 19:15:30 +03:00
if ( dataSize = = MAX_BUFFERING_PACKET_SIZE )
{
dataSize = p - > Eap_TlsCtx . cachedBufferRecvPntr - p - > Eap_TlsCtx . cachedBufferRecv ;
}
2020-05-02 09:38:08 +03:00
}
// 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 ;
}
2020-05-02 10:11:01 +03:00
Debug ( " Sent EAP-TLS size=%i \n " , lcp - > DataSize ) ;
2020-05-02 09:38:08 +03:00
}
else
{
2020-05-02 19:15:30 +03:00
/*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 " ) ; */
2020-05-02 09:38:08 +03:00
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
2020-05-02 10:11:01 +03:00
if ( p - > Eap_TlsCtx . cachedBufferRecv ! = NULL )
2020-05-02 09:38:08 +03:00
{
2020-05-02 10:11:01 +03:00
Free ( p - > Eap_TlsCtx . cachedBufferRecv ) ;
p - > Eap_TlsCtx . cachedBufferRecv = NULL ;
p - > Eap_TlsCtx . cachedBufferRecvPntr = NULL ;
2020-05-02 09:38:08 +03:00
}
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 )
{
2020-05-02 10:11:01 +03:00
if ( p - > Eap_TlsCtx . cachedBufferSend = = NULL )
2020-05-02 09:38:08 +03:00
{
2020-05-02 10:11:01 +03:00
p - > Eap_TlsCtx . cachedBufferSend = ZeroMalloc ( dataSize ) ;
p - > Eap_TlsCtx . cachedBufferSendPntr = p - > Eap_TlsCtx . cachedBufferSend ;
2020-05-02 09:38:08 +03:00
}
2020-05-02 10:11:01 +03:00
ReadFifo ( p - > Eap_TlsCtx . SslPipe - > RawOut - > RecvFifo , p - > Eap_TlsCtx . cachedBufferSend , dataSize ) ;
2020-05-02 09:38:08 +03:00
// 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)
2020-05-02 10:11:01 +03:00
flags = PPP_EAP_TLS_FLAG_TLS_LENGTH ; // L flag
flags | = PPP_EAP_TLS_FLAG_FRAGMENTED ; // M flag
2020-05-02 09:38:08 +03:00
lcp = BuildEAPTlsRequest ( p - > Eap_PacketId + + , dataSize , flags ) ;
eap = lcp - > Data ;
2020-05-02 10:11:01 +03:00
eap - > Tls . TlsDataWithLength . TlsLength = Endian32 ( tlsLength ) ;
Copy ( eap - > Tls . TlsDataWithLength . Data , p - > Eap_TlsCtx . cachedBufferSend , dataSize ) ;
p - > Eap_TlsCtx . cachedBufferSendPntr + = dataSize ;
2020-05-02 09:38:08 +03:00
if ( ! PPPSendAndRetransmitRequest ( p , PPP_PROTOCOL_EAP , lcp ) )
{
PPPSetStatus ( p , PPP_STATUS_FAIL ) ;
WHERE ;
return false ;
}
2020-05-02 10:11:01 +03:00
Debug ( " Sent EAP-TLS size=%i type=%i flag=%i \n " , lcp - > DataSize , eap - > Type , eap - > Tls . Flags ) ;
2020-05-02 09:38:08 +03:00
}
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 ;
}
2020-05-02 10:11:01 +03:00
Debug ( " Sent EAP-TLS size=%i type=%i flag=%i \n " , lcp - > DataSize , eap - > Type , eap - > Tls . Flags ) ;
2020-05-02 09:38:08 +03:00
}
}
}
}
else
{
Debug ( " Got an EAP_TLS packet when not authenticating, ignoring... \n " ) ;
}
2020-05-02 01:54:03 +03:00
return false ;
}
2020-05-02 09:38:08 +03:00
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 ) ;
2020-05-02 10:11:01 +03:00
if ( flags & PPP_EAP_TLS_FLAG_TLS_LENGTH )
2020-05-02 09:38:08 +03:00
{
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 ) ;
}
2018-03-13 17:10:22 +03:00
// Other packet utilities
// Get the option value
PPP_OPTION * PPPGetOptionValue ( PPP_LCP * c , UCHAR type )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
UINT i ;
// Validate arguments
if ( c = = NULL )
{
return NULL ;
}
for ( i = 0 ; i < LIST_NUM ( c - > OptionList ) ; i + + )
{
PPP_OPTION * t = LIST_DATA ( c - > OptionList , i ) ;
if ( t - > Type = = type )
{
return t ;
}
}
return NULL ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
// Check whether the Virtual HUB with the specified name exist?
bool IsHubExistsWithLock ( CEDAR * cedar , char * hubname )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
bool ret = false ;
2014-01-04 17:00:08 +04:00
// Validate arguments
2018-03-13 17:10:22 +03:00
if ( cedar = = NULL | | hubname = = NULL )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
return false ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
LockList ( cedar - > HubList ) ;
{
ret = IsHub ( cedar , hubname ) ;
}
UnlockList ( cedar - > HubList ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
return ret ;
}
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
// Sets the PPP status without overwriting the FAIL status
void PPPSetStatus ( PPP_SESSION * p , UINT status )
{
if ( status = = PPP_STATUS_FAIL )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
Debug ( " SETTING PPP_STATUS_FAIL!!! \n " ) ;
}
if ( ! PPP_STATUS_IS_UNAVAILABLE ( p - > PPPStatus ) | | PPP_STATUS_IS_UNAVAILABLE ( status ) )
{
p - > PPPStatus = status ;
2014-01-04 17:00:08 +04:00
}
}
2018-03-13 17:10:22 +03:00
// Memory freeing functions
2014-01-04 17:00:08 +04:00
// Release the PPP session
void FreePPPSession ( PPP_SESSION * p )
{
2018-03-13 17:10:22 +03:00
UINT i ;
2014-01-04 17:00:08 +04:00
// Validate arguments
if ( p = = NULL )
{
return ;
}
2018-03-13 17:10:22 +03:00
// Release the memory
for ( i = 0 ; i < LIST_NUM ( p - > RecvPacketList ) ; i + + )
{
PPP_PACKET * pp = LIST_DATA ( p - > RecvPacketList , i ) ;
FreePPPPacket ( pp ) ;
}
ReleaseList ( p - > RecvPacketList ) ;
for ( i = 0 ; i < LIST_NUM ( p - > SentReqPacketList ) ; i + + )
{
PPP_REQUEST_RESEND * t = LIST_DATA ( p - > SentReqPacketList , i ) ;
FreePPPPacket ( t - > Packet ) ;
Free ( t ) ;
}
ReleaseList ( p - > SentReqPacketList ) ;
for ( i = 0 ; i < LIST_NUM ( p - > DelayedPackets ) ; i + + )
{
PPP_DELAYED_PACKET * t = LIST_DATA ( p - > DelayedPackets , i ) ;
FreePPPPacket ( t - > Packet ) ;
Free ( t ) ;
}
ReleaseList ( p - > DelayedPackets ) ;
if ( p - > CurrentPacket ! = NULL )
{
FreePPPPacket ( p - > CurrentPacket ) ;
}
2014-01-04 17:00:08 +04:00
if ( p - > TubeRecv ! = NULL )
{
// Record the PPP disconnect reason code for L2TP
p - > TubeRecv - > IntParam1 = p - > DisconnectCauseCode ;
p - > TubeRecv - > IntParam2 = p - > DisconnectCauseDirection ;
}
2020-05-02 09:38:08 +03:00
// Freeing EAP-TLS context
2020-05-02 10:11:01 +03:00
if ( p - > Eap_TlsCtx . cachedBufferRecv ! = NULL )
{
Free ( p - > Eap_TlsCtx . cachedBufferRecv ) ;
}
if ( p - > Eap_TlsCtx . cachedBufferSend ! = NULL )
2020-05-02 09:38:08 +03:00
{
2020-05-02 10:11:01 +03:00
Free ( p - > Eap_TlsCtx . cachedBufferRecv ) ;
2020-05-02 09:38:08 +03:00
}
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 ) ;
}
2014-01-04 17:00:08 +04:00
FreeTubeFlushList ( p - > FlushList ) ;
TubeDisconnect ( p - > TubeRecv ) ;
TubeDisconnect ( p - > TubeSend ) ;
ReleaseCedar ( p - > Cedar ) ;
ReleaseTube ( p - > TubeRecv ) ;
ReleaseTube ( p - > TubeSend ) ;
if ( p - > Ipc ! = NULL )
{
FreeIPC ( p - > Ipc ) ;
}
2015-10-06 14:18:00 +03:00
PPPFreeEapClient ( p ) ;
2014-01-04 17:00:08 +04:00
Free ( p ) ;
}
// Release the LCP
void FreePPPLCP ( PPP_LCP * c )
{
// Validate arguments
if ( c = = NULL )
{
return ;
}
FreePPPOptionList ( c - > OptionList ) ;
Free ( c - > Data ) ;
Free ( c ) ;
}
// Release the PPP options list
void FreePPPOptionList ( LIST * o )
{
UINT i ;
// Validate arguments
if ( o = = NULL )
{
return ;
}
2018-03-13 17:10:22 +03:00
for ( i = 0 ; i < LIST_NUM ( o ) ; i + + )
2014-01-04 17:00:08 +04:00
{
PPP_OPTION * t = LIST_DATA ( o , i ) ;
Free ( t ) ;
}
ReleaseList ( o ) ;
}
2018-03-13 17:10:22 +03:00
// Release the PPP packet
void FreePPPPacket ( PPP_PACKET * pp )
{
FreePPPPacketEx ( pp , false ) ;
}
void FreePPPPacketEx ( PPP_PACKET * pp , bool no_free_struct )
2014-01-04 17:00:08 +04:00
{
// Validate arguments
2018-03-13 17:10:22 +03:00
if ( pp = = NULL )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
return ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
FreePPPLCP ( pp - > Lcp ) ;
Free ( pp - > Data ) ;
if ( no_free_struct = = false )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
Free ( pp ) ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
}
// Free the associated EAP client
void PPPFreeEapClient ( PPP_SESSION * p )
{
if ( p = = NULL )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
return ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
if ( p - > EapClient ! = NULL )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
ReleaseEapClient ( p - > EapClient ) ;
p - > EapClient = NULL ;
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
}
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
// Utility functions used not only in PPP stack
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
// Separate into the user name and the Virtual HUB name by analyzing the string
bool PPPParseUsername ( CEDAR * cedar , char * src_username , ETHERIP_ID * dst )
{
UINT i , len , last_at , first_en ;
char token1 [ MAX_SIZE ] ; // username
char token2 [ MAX_SIZE ] ; // hub_name
char src [ MAX_SIZE ] ;
// Validate arguments
Zero ( dst , sizeof ( ETHERIP_ID ) ) ;
if ( cedar = = NULL | | src = = NULL | | dst = = NULL )
{
return false ;
}
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
StrCpy ( src , sizeof ( src ) , src_username ) ;
Trim ( src ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
// Search for the first "\\" in the string
len = StrLen ( src ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
first_en = SearchStrEx ( src , " \\ " , 0 , true ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
if ( first_en ! = INFINITE & & first_en > = 1 & & ( first_en < ( len - 1 ) ) )
{
StrCpy ( token1 , sizeof ( token1 ) , src + first_en + 1 ) ;
StrCpy ( token2 , sizeof ( token2 ) , src ) ;
token2 [ first_en ] = 0 ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
// Confirm whether the hubname exists if the virtual HUB name is
// specified like as hubname\username
if ( IsHubExistsWithLock ( cedar , token2 ) = = false )
{
// If the hubname does not exist, restore to the original name
StrCpy ( token1 , sizeof ( token1 ) , src ) ;
ClearStr ( token2 , sizeof ( token2 ) ) ;
}
}
else
{
2020-02-04 23:51:50 +03:00
// Search for the separator character's last position in the string
2018-03-13 17:10:22 +03:00
len = StrLen ( src ) ;
last_at = INFINITE ;
for ( i = 0 ; i < len ; i + + )
{
char c = src [ i ] ;
2014-01-04 17:00:08 +04:00
2020-02-04 23:51:50 +03:00
if ( c = = cedar - > UsernameHubSeparator )
2018-03-13 17:10:22 +03:00
{
last_at = i ;
}
}
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
Zero ( token1 , sizeof ( token1 ) ) ;
Zero ( token2 , sizeof ( token2 ) ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
if ( last_at = = INFINITE )
{
2020-02-04 23:51:50 +03:00
// The separator character is not specifiedd
2018-03-13 17:10:22 +03:00
StrCpy ( token1 , sizeof ( token1 ) , src ) ;
}
else
{
StrCpy ( token1 , sizeof ( token1 ) , src ) ;
token1 [ last_at ] = 0 ;
StrCpy ( token2 , sizeof ( token2 ) , src + last_at + 1 ) ;
}
// Check whether such Virtual HUB exists If the virtual HUB name is specified
if ( IsEmptyStr ( token2 ) = = false )
{
if ( IsHubExistsWithLock ( cedar , token2 ) = = false )
{
// Because the specified virtual HUB name doesn't exist, it's considered to be a part of the user name
StrCpy ( token1 , sizeof ( token1 ) , src ) ;
ClearStr ( token2 , sizeof ( token2 ) ) ;
}
}
2014-01-04 17:00:08 +04:00
}
2018-03-13 17:10:22 +03:00
if ( IsEmptyStr ( token2 ) )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
// Select the default Virtual HUB if the Virtual HUB name is not specified
StrCpy ( token2 , sizeof ( token2 ) , SERVER_DEFAULT_HUB_NAME ) ;
if ( cedar - > Server ! = NULL & & cedar - > Server - > IPsecServer ! = NULL )
{
Lock ( cedar - > Server - > IPsecServer - > LockSettings ) ;
{
IPsecNormalizeServiceSetting ( cedar - > Server - > IPsecServer ) ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
StrCpy ( token2 , sizeof ( token2 ) , cedar - > Server - > IPsecServer - > Services . L2TP_DefaultHub ) ;
}
Unlock ( cedar - > Server - > IPsecServer - > LockSettings ) ;
}
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
}
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
// Return the results
StrCpy ( dst - > HubName , sizeof ( dst - > HubName ) , token2 ) ;
StrCpy ( dst - > UserName , sizeof ( dst - > UserName ) , token1 ) ;
return true ;
2014-01-04 17:00:08 +04:00
}
// Generate the NT hash of the password
void GenerateNtPasswordHash ( UCHAR * dst , char * password )
{
UCHAR * tmp ;
UINT tmp_size ;
UINT i , len ;
// Validate arguments
if ( dst = = NULL | | password = = NULL )
{
return ;
}
// Generate a Unicode password
len = StrLen ( password ) ;
tmp_size = len * 2 ;
tmp = ZeroMalloc ( tmp_size ) ;
for ( i = 0 ; i < len ; i + + )
{
tmp [ i * 2 ] = password [ i ] ;
}
// Hashing
HashMd4 ( dst , tmp , tmp_size ) ;
Free ( tmp ) ;
}
// Generate the MS-CHAPv2 server-side challenge
void MsChapV2Server_GenerateChallenge ( UCHAR * dst )
{
// Validate arguments
if ( dst = = NULL )
{
return ;
}
Rand ( dst , 16 ) ;
}
// Generate the MS-CHAPv2 client-side challenge
void MsChapV2Client_GenerateChallenge ( UCHAR * dst )
{
// Validate arguments
if ( dst = = NULL )
{
return ;
}
Rand ( dst , 16 ) ;
}
// Generate a 8 bytes challenge
void MsChapV2_GenerateChallenge8 ( UCHAR * dst , UCHAR * client_challenge , UCHAR * server_challenge , char * username )
{
BUF * b ;
UCHAR hash [ SHA1_SIZE ] ;
char username2 [ MAX_SIZE ] ;
char domainname2 [ MAX_SIZE ] ;
// Validate arguments
if ( dst = = NULL | | client_challenge = = NULL | | server_challenge = = NULL )
{
return ;
}
b = NewBuf ( ) ;
WriteBuf ( b , client_challenge , 16 ) ;
WriteBuf ( b , server_challenge , 16 ) ;
ParseNtUsername ( username , username2 , sizeof ( username2 ) , domainname2 , sizeof ( domainname2 ) , true ) ;
if ( IsEmptyStr ( username2 ) = = false )
{
WriteBuf ( b , username2 , StrLen ( username2 ) ) ;
}
2018-09-22 07:35:30 +03:00
Sha1 ( hash , b - > Buf , b - > Size ) ;
2014-01-04 17:00:08 +04:00
FreeBuf ( b ) ;
Copy ( dst , hash , 8 ) ;
}
// Generate the MS-CHAPv2 client response
void MsChapV2Client_GenerateResponse ( UCHAR * dst , UCHAR * challenge8 , UCHAR * nt_password_hash )
{
UCHAR password_hash_2 [ 21 ] ;
UCHAR key1 [ 8 ] , key2 [ 8 ] , key3 [ 8 ] ;
// Validate arguments
if ( dst = = NULL | | challenge8 = = NULL | | nt_password_hash = = NULL )
{
return ;
}
Zero ( password_hash_2 , sizeof ( password_hash_2 ) ) ;
Copy ( password_hash_2 , nt_password_hash , 16 ) ;
Zero ( key1 , sizeof ( key1 ) ) ;
Zero ( key2 , sizeof ( key2 ) ) ;
Zero ( key3 , sizeof ( key3 ) ) ;
Copy ( key1 , password_hash_2 + 0 , 7 ) ;
Copy ( key2 , password_hash_2 + 7 , 7 ) ;
Copy ( key3 , password_hash_2 + 14 , 7 ) ;
DesEcbEncrypt ( dst + 0 , challenge8 , key1 ) ;
DesEcbEncrypt ( dst + 8 , challenge8 , key2 ) ;
DesEcbEncrypt ( dst + 16 , challenge8 , key3 ) ;
}
// Generate a hash of the hash of the NT password
void GenerateNtPasswordHashHash ( UCHAR * dst_hash , UCHAR * src_hash )
{
// Validate arguments
if ( dst_hash = = NULL | | src_hash = = NULL )
{
return ;
}
HashMd4 ( dst_hash , src_hash , 16 ) ;
}
// Generate the MS-CHAPv2 server response
void MsChapV2Server_GenerateResponse ( UCHAR * dst , UCHAR * nt_password_hash_hash , UCHAR * client_response , UCHAR * challenge8 )
{
UCHAR digest [ SHA1_SIZE ] ;
BUF * b ;
char * magic1 = " Magic server to client signing constant " ;
char * magic2 = " Pad to make it do more than one iteration " ;
// Validate arguments
if ( dst = = NULL | | nt_password_hash_hash = = NULL | | client_response = = NULL | | challenge8 = = NULL )
{
return ;
}
b = NewBuf ( ) ;
WriteBuf ( b , nt_password_hash_hash , 16 ) ;
WriteBuf ( b , client_response , 24 ) ;
WriteBuf ( b , magic1 , StrLen ( magic1 ) ) ;
2018-09-22 07:35:30 +03:00
Sha1 ( digest , b - > Buf , b - > Size ) ;
2014-01-04 17:00:08 +04:00
FreeBuf ( b ) ;
b = NewBuf ( ) ;
WriteBuf ( b , digest , sizeof ( digest ) ) ;
WriteBuf ( b , challenge8 , 8 ) ;
WriteBuf ( b , magic2 , StrLen ( magic2 ) ) ;
2018-09-22 07:35:30 +03:00
Sha1 ( dst , b - > Buf , b - > Size ) ;
2014-01-04 17:00:08 +04:00
FreeBuf ( b ) ;
}
// Verify whether the password matches one that is specified by the user in the MS-CHAPv2
bool MsChapV2VerityPassword ( IPC_MSCHAP_V2_AUTHINFO * d , char * password )
{
UCHAR ntlm_hash [ MD5_SIZE ] ;
UCHAR challenge8 [ 8 ] ;
UCHAR client_response [ 24 ] ;
// Validate arguments
if ( d = = NULL | | password = = NULL )
{
return false ;
}
GenerateNtPasswordHash ( ntlm_hash , password ) ;
MsChapV2_GenerateChallenge8 ( challenge8 , d - > MsChapV2_ClientChallenge , d - > MsChapV2_ServerChallenge , d - > MsChapV2_PPPUsername ) ;
MsChapV2Client_GenerateResponse ( client_response , challenge8 , ntlm_hash ) ;
if ( Cmp ( client_response , d - > MsChapV2_ClientResponse , 24 ) ! = 0 )
{
return false ;
}
return true ;
}
// Estimate the password in the brute force for the request packet of MS-CHAPv2
char * MsChapV2DoBruteForce ( IPC_MSCHAP_V2_AUTHINFO * d , LIST * password_list )
{
UINT i ;
// Validate arguments
if ( d = = NULL | | password_list = = NULL )
{
return NULL ;
}
for ( i = 0 ; i < LIST_NUM ( password_list ) ; i + + )
{
char * s = LIST_DATA ( password_list , i ) ;
char tmp [ MAX_SIZE ] ;
UINT j , max ;
UINT len ;
StrCpy ( tmp , sizeof ( tmp ) , s ) ;
len = StrLen ( tmp ) ;
max = Power ( 2 , MIN ( len , 9 ) ) ;
for ( j = 0 ; j < max ; j + + )
{
SetStrCaseAccordingToBits ( tmp , j ) ;
if ( MsChapV2VerityPassword ( d , tmp ) )
{
return CopyStr ( tmp ) ;
}
}
}
return NULL ;
}
2020-05-02 01:54:03 +03:00