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
//
// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
//
2017-10-19 05:48:23 +03:00
// Copyright (c) Daiyuu Nobori.
2017-10-18 12:24:21 +03:00
// Copyright (c) SoftEther VPN Project, University of Tsukuba, Japan.
// Copyright (c) SoftEther Corporation.
2014-01-04 17:00:08 +04:00
//
// All Rights Reserved.
//
// http://www.softether.org/
//
2017-10-19 05:48:23 +03:00
// Author: Daiyuu Nobori, Ph.D.
2014-01-04 17:00:08 +04:00
// Comments: Tetsuo Sugiyama, Ph.D.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// version 2 as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License version 2
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
//
//
// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
//
2014-07-11 21:06:20 +04:00
// USE ONLY IN JAPAN. DO NOT USE THIS SOFTWARE IN ANOTHER COUNTRY UNLESS
// YOU HAVE A CONFIRMATION THAT THIS SOFTWARE DOES NOT VIOLATE ANY
// CRIMINAL LAWS OR CIVIL RIGHTS IN THAT PARTICULAR COUNTRY. USING THIS
// SOFTWARE IN OTHER COUNTRIES IS COMPLETELY AT YOUR OWN RISK. THE
// SOFTETHER VPN PROJECT HAS DEVELOPED AND DISTRIBUTED THIS SOFTWARE TO
// COMPLY ONLY WITH THE JAPANESE LAWS AND EXISTING CIVIL RIGHTS INCLUDING
// PATENTS WHICH ARE SUBJECTS APPLY IN JAPAN. OTHER COUNTRIES' LAWS OR
// CIVIL RIGHTS ARE NONE OF OUR CONCERNS NOR RESPONSIBILITIES. WE HAVE
// NEVER INVESTIGATED ANY CRIMINAL REGULATIONS, CIVIL LAWS OR
// INTELLECTUAL PROPERTY RIGHTS INCLUDING PATENTS IN ANY OF OTHER 200+
// COUNTRIES AND TERRITORIES. BY NATURE, THERE ARE 200+ REGIONS IN THE
// WORLD, WITH DIFFERENT LAWS. IT IS IMPOSSIBLE TO VERIFY EVERY
// COUNTRIES' LAWS, REGULATIONS AND CIVIL RIGHTS TO MAKE THE SOFTWARE
// COMPLY WITH ALL COUNTRIES' LAWS BY THE PROJECT. EVEN IF YOU WILL BE
// SUED BY A PRIVATE ENTITY OR BE DAMAGED BY A PUBLIC SERVANT IN YOUR
// COUNTRY, THE DEVELOPERS OF THIS SOFTWARE WILL NEVER BE LIABLE TO
// RECOVER OR COMPENSATE SUCH DAMAGES, CRIMINAL OR CIVIL
// RESPONSIBILITIES. NOTE THAT THIS LINE IS NOT LICENSE RESTRICTION BUT
// JUST A STATEMENT FOR WARNING AND DISCLAIMER.
2014-01-04 17:00:08 +04:00
//
//
2014-01-15 13:01:42 +04:00
// SOURCE CODE CONTRIBUTION
// ------------------------
//
// Your contribution to SoftEther VPN Project is much appreciated.
// Please send patches to us through GitHub.
// Read the SoftEther VPN Patch Acceptance Policy in advance:
// http://www.softether.org/5-download/src/9.patch
//
//
2014-01-04 17:00:08 +04:00
// DEAR SECURITY EXPERTS
// ---------------------
//
// If you find a bug or a security vulnerability please kindly inform us
// about the problem immediately so that we can fix the security problem
// to protect a lot of users around the world as soon as possible.
//
// Our e-mail address for security reports is:
// softether-vpn-security [at] softether.org
//
// Please note that the above e-mail address is not a technical support
// inquiry address. If you need technical assistance, please visit
// http://www.softether.org/ and ask your question on the users forum.
//
// Thank you for your cooperation.
2014-03-20 00:45:05 +04:00
//
//
2014-01-04 17:00:08 +04:00
// IPsec_PPP.c
// 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 ;
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
}
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
{
2018-03-13 17:10:22 +03:00
// MSCHAPv2 code
PPP_LCP * c = NewPPPLCP ( PPP_LCP_CODE_REQ , 0 ) ;
UCHAR ms_chap_v2_code [ 3 ] ;
WRITE_USHORT ( ms_chap_v2_code , PPP_LCP_AUTH_CHAP ) ;
ms_chap_v2_code [ 2 ] = PPP_CHAP_ALG_MS_CHAP_V2 ;
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 ;
}
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
{
2018-03-13 17:10:22 +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
{
WaitForTubes ( tubes , 1 , 100 ) ;
}
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
if ( ( p - > LastRecvTime + ( UINT64 ) PPP_DATA_TIMEOUT ) < = now )
{
// Communication time-out occurs
PPPLog ( p , " LP_DATA_TIMEOUT " ) ;
break ;
}
// 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
THREAD * NewPPPSession ( CEDAR * cedar , IP * client_ip , UINT client_port , IP * server_ip , UINT server_port , TUBE * send_tube , TUBE * recv_tube , char * postfix , char * client_software_name , char * client_hostname , char * crypt_name , UINT adjust_mss )
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 ;
p - > AuthProtocol = NULL ;
p - > MsChapV2_ErrorCode = 691 ;
p - > EapClient = NULL ;
2014-01-04 17:00:08 +04:00
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
2018-03-13 17:10:22 +03:00
return t ;
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
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 ;
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
}
2018-03-13 17:10:22 +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 )
{
p - > IPv4_State = = PPP_PROTO_STATUS_REJECTED ;
}
if ( * protocol = = PPP_PROTOCOL_IPV6CP | | * protocol = = PPP_PROTOCOL_IPV6 )
{
p - > IPv6_State = = PPP_PROTO_STATUS_REJECTED ;
}
}
}
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 ;
}
if ( opt - > DataSize = = sizeof ( ms_chap_v2_code ) & & Cmp ( opt - > Data , ms_chap_v2_code , opt - > DataSize ) = = 0 )
{
// Try to request PAP then
if ( ! isAccepted | | ! p - > EnableMSCHAPv2 )
{
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 ;
}
}
else if ( p - > AuthProtocol = = NULL )
{
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 ;
}
else if ( p - > AuthProtocol = = NULL )
{
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
bool PPPProcessCHAPResponsePacket ( PPP_SESSION * p , PPP_PACKET * pp , PPP_PACKET * req )
{
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
bool PPPProcessIPCPResponsePacket ( PPP_SESSION * p , PPP_PACKET * pp , PPP_PACKET * req )
{
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
}
2018-03-13 17:10:22 +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 ) ;
// Fallback mechanism - just request 1.0.0.1
if ( prevAddr = = Endian32 ( 0x01000001 ) )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
Debug ( " We already tried the fallback IP of 1.0.0.1, giving up \n " ) ;
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 ) ;
ui = Endian32 ( 0x01000001 ) ; // 1.0.0.1
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
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 ;
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
2018-03-13 17:10:22 +03:00
bool PPPProcessLCPRequestPacket ( PPP_SESSION * p , PPP_PACKET * pp )
{
bool result = true ;
UINT i = 0 ;
USHORT NegotiatedAuthProto = PPP_UNSPECIFIED ;
USHORT NegotiatedMRU = PPP_UNSPECIFIED ;
// 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 ;
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 ;
if ( t - > DataSize = = sizeof ( USHORT ) & & * ( ( USHORT * ) t - > Data ) = = Endian16 ( PPP_LCP_AUTH_PAP ) & & p - > AuthProtocol ! = PPP_PROTOCOL_CHAP )
{
t - > IsAccepted = true ;
NegotiatedAuthProto = PPP_PROTOCOL_PAP ;
}
else if ( t - > DataSize = = sizeof ( ms_chap_v2_code ) & & Cmp ( t - > Data , ms_chap_v2_code , t - > DataSize ) = = 0 )
{
t - > IsAccepted = true ;
NegotiatedAuthProto = PPP_PROTOCOL_CHAP ;
}
else
{
// We're recommending MSCHAPv2 by default as a more secure algo
t - > IsAccepted = false ;
t - > AltDataSize = sizeof ( ms_chap_v2_code ) ;
Copy ( t - > AltData , ms_chap_v2_code , sizeof ( ms_chap_v2_code ) ) ;
}
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 )
{
if ( p - > AuthProtocol = = NULL )
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 ,
2015-10-06 14:18:00 +03:00
p - > ClientHostname , p - > CryptName , false , p - > AdjustMss , NULL ) ;
2014-01-04 17:00:08 +04:00
if ( ipc ! = NULL )
{
p - > Ipc = ipc ;
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
}
2018-03-13 17:10:22 +03:00
}
bool PPPProcessIPCPRequestPacket ( PPP_SESSION * p , PPP_PACKET * pp )
{
PPP_IPOPTION o ;
PPP_IPOPTION res ;
DHCP_OPTION_LIST cao ;
IP client_ip ;
IP subnet ;
IP zero ;
IP gw ;
bool ok = true ;
bool processed = false ;
if ( p - > IPv4_State = = PPP_PROTO_STATUS_REJECTED )
2014-01-04 17:00:08 +04:00
{
2018-03-13 17:10:22 +03:00
Debug ( " We got an IPCP packet after we had it rejected " ) ;
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 ) )
{
Debug ( " Unsupported IPCP request! " ) ;
ok = false ;
}
// Process if not configured yet by server
if ( IsZero ( & p - > ClientAddressOption , sizeof ( DHCP_OPTION_LIST ) ) & & ok )
{
// 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
2018-03-13 17:10:22 +03:00
p - > DhcpRenewInterval = ( UINT64 ) ( t * 1000 ) ;
p - > DhcpNextRenewTime = Tick64 ( ) + p - > DhcpRenewInterval ;
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 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 ) ) ;
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)
if ( p - > IPv4_State = = PPP_PROTO_STATUS_CLOSED & & p - > ClientAddressOption . ServerAddress ! = NULL & & 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
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 ;
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
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 ;
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 ;
resend - > TimeoutTime = now + PPP_PACKET_RECV_TIMEOUT ;
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
{
2018-03-13 17:10:22 +03:00
d = TubeRecvSync ( p - > TubeRecv , PPP_PACKET_RECV_TIMEOUT ) ;
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 ;
2018-03-13 17:10:22 +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 - > 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 " ) ;
eap = HubNewEapClient ( p - > Cedar , hub , client_ip_tmp , id ) ;
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 ,
p - > ClientHostname , p - > CryptName , false , p - > AdjustMss , p - > EapClient ) ;
if ( ipc ! = NULL )
{
p - > Ipc = ipc ;
2014-01-04 17:00:08 +04:00
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 ;
}
}
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
}
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 ;
}
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
{
// Search for the last "@" in the string
len = StrLen ( src ) ;
last_at = INFINITE ;
for ( i = 0 ; i < len ; i + + )
{
char c = src [ i ] ;
2014-01-04 17:00:08 +04:00
2018-03-13 17:10:22 +03:00
if ( c = = ' @ ' )
{
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 )
{
// "@" is not specified
StrCpy ( token1 , sizeof ( token1 ) , src ) ;
}
else
{
// Split with last "@"
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 ) ) ;
}
HashSha1 ( hash , b - > Buf , b - > Size ) ;
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 ) ) ;
HashSha1 ( digest , b - > Buf , b - > Size ) ;
FreeBuf ( b ) ;
b = NewBuf ( ) ;
WriteBuf ( b , digest , sizeof ( digest ) ) ;
WriteBuf ( b , challenge8 , 8 ) ;
WriteBuf ( b , magic2 , StrLen ( magic2 ) ) ;
HashSha1 ( dst , b - > Buf , b - > Size ) ;
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 ;
}