This commit is contained in:
romkazvo
2023-08-07 19:29:24 +08:00
commit 34d6c5d489
4832 changed files with 1389451 additions and 0 deletions

961
CryNetwork/DefenceWall.cpp Normal file
View File

@@ -0,0 +1,961 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2001-2004.
// -------------------------------------------------------------------------
// File name: DefenceWall.cpp
// Version: v1.00
// Created: 25/1/2004 by Timur.
// Compilers: Visual Studio.NET 2003
// Description:
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "StdAfx.h"
#include "DefenceWall.h"
#include "Network.h"
#include "Client.h"
#include "Server.h"
#include "ServerSlot.h"
#include "ICryPak.h"
//#define LOGEVENTS // don't use in public release
enum CHEAT_PROTECTION_LEVEL {
CHEAT_LEVEL_DEFAULT = 1,
CHEAT_LEVEL_RANDOMCHECKS,
CHEAT_LEVEL_CODE,
};
// Max number of retried for single request.
#define MAX_CHECK_RETRIES 5
// Time in seconds during which client must return response to server.
#define WAIT_FOR_RESPONSE_TIME 20
// Check about every 5 mins.
#define RANDOM_CHECK_PERIOD 60*3
enum EDefenceWallRequestCode
{
DEFWALL_UNKNOWN = 0,
DEFWALL_CHECK_PAK = 1,
DEFWALL_CHECK_PROTECTED_FILE = 2,
DEFWALL_CHECK_DLL_CODE = 3,
};
//////////////////////////////////////////////////////////////////////////
CDefenceWall::CDefenceWall( CNetwork *pNetwork )
{
m_pNetwork = pNetwork;
m_pSystem = GetISystem();
m_nNextRequestId = 1;
m_pServer = 0;
m_bServer = false;
m_bLog = true;
m_nNumOpenedPacksOnServer = 0;
m_nEncryptKey[0] = 2962387638;
m_nEncryptKey[1] = 1782685322;
m_nEncryptKey[2] = 268651613;
m_nEncryptKey[3] = 156356231;
#if defined(WIN64) || defined(LINUX64)
m_b64bit = true;
#else
m_b64bit = false;
#endif
}
//////////////////////////////////////////////////////////////////////////
CDefenceWall::~CDefenceWall()
{
ClearAllPendingRequests();
m_protectedFiles.clear();
ClearClients();
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::SetServer( CServer *pServer )
{
m_pServer = pServer;
m_pClient = 0;
m_bServer = true;
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::SetClient( CClient *pClient )
{
m_pServer = 0;
m_pClient = pClient;
m_bServer = false;
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::ClearClients()
{
for (Clients::iterator it = m_clients.begin(); it != m_clients.end(); ++it)
{
delete *it;
}
m_clients.clear();
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::ClearAllPendingRequests()
{
for (PendingChecks::iterator it = m_pendingChecks.begin(); it != m_pendingChecks.end(); it++)
{
SClientCheckContext* pCtx = *it;
delete pCtx;
}
m_pendingChecks.clear();
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::FillStdServerProbes()
{
m_stdServerProbes.clear();
m_stdServerProbes.reserve(30);
IDataProbe *pProbe = GetISystem()->GetIDataProbe();
ICryPak::PakInfo* pPakInfo = m_pSystem->GetIPak()->GetPakInfo();
unsigned int i;
//////////////////////////////////////////////////////////////////////////
// Collect PAK files.
//////////////////////////////////////////////////////////////////////////
m_nNumOpenedPacksOnServer = pPakInfo->numOpenPaks;
for (i = 0; i < pPakInfo->numOpenPaks; i++)
{
SClientCheckContext ctx;
ctx.nNumOpenedPaks = pPakInfo->numOpenPaks;
if (ServerCreateFileProbe( pPakInfo->arrPaks[i].szFilePath,ctx,true ))
{
m_stdServerProbes.push_back(ctx);
}
}
m_pSystem->GetIPak()->FreePakInfo( pPakInfo );
// Do not compare user DLL`s.
/*
#if !defined(LINUX)
//////////////////////////////////////////////////////////////////////////
// Collect Modules Code probes.
//////////////////////////////////////////////////////////////////////////
// Create module probe for all DLL modules.
IDataProbe::SModuleInfo *pModules;
int numModules = pProbe->GetLoadedModules( &pModules );
for (int m = 0; m < numModules; m++)
{
SClientCheckContext ctx;
if (ServerCreateModuleProbe( pModules[m].filename.c_str(),ctx ))
m_stdServerProbes.push_back(ctx);
}
#endif
*/
}
//////////////////////////////////////////////////////////////////////////
bool CDefenceWall::ServerCreateModuleProbe( const char *sFilename,SClientCheckContext &ctx )
{
char sModule[_MAX_PATH];
char fname[_MAX_FNAME];
char ext[_MAX_EXT];
_splitpath( sFilename,0,0,fname,ext );
_makepath( sModule,0,0,fname,ext );
strlwr( sModule );
// Skip comparing render dll code. (Can be OGL,D3D or NULL)
if (strstr(sModule,"render"))
return false;
AddProtectedFile( (string("b")+"i"+"n"+"3"+"2"+"/"+sFilename).c_str() );
if (m_pNetwork->GetCheatProtectionLevel() >= CHEAT_LEVEL_CODE)
{
ctx.nRequestCode = DEFWALL_CHECK_DLL_CODE;
ctx.bExecutableCode = true;
ctx.probe.sFilename = sModule;
#if !defined(LINUX)
ctx.nFilenameHash = m_pSystem->GetIDataProbe()->GetHash( sModule );
ctx.probe.nCodeInfo = rand()%3;
if (!m_pSystem->GetIDataProbe()->GetRandomModuleProbe( ctx.probe ))
return false;
if (!m_pSystem->GetIDataProbe()->GetCode( ctx.probe ))
return false;
#endif
#ifdef LOGEVENTS
if (m_bLog) CryLog( "<DefenceWall> CreatedExeProbe[%d] %s %I64x",ctx.nRequestId,ctx.probe.sFilename.c_str(),ctx.probe.nCode );
#endif
}
else
{
return false;
}
return true;
}
//////////////////////////////////////////////////////////////////////////
bool CDefenceWall::ServerCreateFileProbe( const char *sFilename,SClientCheckContext &ctx,bool bRandomPart )
{
#if !defined(LINUX)
// Get current language.
ICVar *pLanguage=m_pSystem->GetIConsole()->GetCVar("g_language");
if (pLanguage && pLanguage->GetString())
{
// Skip validation of language specific paks.
char fname[_MAX_FNAME];
_splitpath( sFilename,NULL,NULL,fname,NULL );
if (strnicmp(fname,pLanguage->GetString(),strlen(pLanguage->GetString())) == 0)
{
// This is language pak... skip checking it.
return false;
}
}
string file = sFilename;
GetRelativeFilename(file);
ctx.nRequestCode = DEFWALL_CHECK_PAK;
ctx.bExecutableCode = false;
ctx.probe.sFilename = file;
ctx.nFilenameHash = m_pSystem->GetIDataProbe()->GetHash( file.c_str() );
if (bRandomPart)
{
ctx.probe.nCodeInfo = rand()%3;
if (!m_pSystem->GetIDataProbe()->GetRandomFileProbe( ctx.probe,true ))
return false;
if (!m_pSystem->GetIDataProbe()->GetCode( ctx.probe ))
return false;
}
else
{
ctx.probe.nCodeInfo = rand()%3;
ctx.probe.nSize = 0xFFFFFFFF;
if (!m_pSystem->GetIDataProbe()->GetCode( ctx.probe ))
return false;
}
#ifdef LOGEVENTS
if (m_bLog) CryLog( "<DefenceWall> CreatedFileProbe[%d] %s %I64x",ctx.nRequestId,ctx.probe.sFilename.c_str(),ctx.probe.nCode );
#endif
#endif
return true;
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::FirstTimeClientValidation( ClientInfo *pClientInfo )
{
CStream outstream;
for (unsigned int i = 0; i < m_stdServerProbes.size(); i++)
{
SClientCheckContext &ctx = m_stdServerProbes[i];
if (ctx.bExecutableCode && pClientInfo->b64bit != m_b64bit) // Cannot compare clients with 32/64bit difference.
continue;
IssueRequest( pClientInfo,outstream,ctx );
}
// Send network request to this client IP.
SendSecurityQueryToClient( pClientInfo->ip,outstream );
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::RandomClientValidation( ClientInfo *pClientInfo )
{
CStream outstream;
unsigned int n = 0;
// Ignore if no standart probes yet.
if (m_stdServerProbes.empty())
return;
bool bRepeat = false;
while (bRepeat) {
bRepeat = false;
n = rand() % m_stdServerProbes.size();
assert( n < m_stdServerProbes.size() );
if (n >= m_stdServerProbes.size())
bRepeat = true;
if (m_stdServerProbes[n].bExecutableCode && pClientInfo->b64bit != m_b64bit) // Cannot compare clients with 32/64bit difference.
bRepeat = true;
}
SClientCheckContext &ctx = m_stdServerProbes[n];
IssueRequest( pClientInfo,outstream,ctx );
// Send network request to this client IP.
SendSecurityQueryToClient( pClientInfo->ip,outstream );
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::IssueRequest( ClientInfo *pClientInfo,CStream &outstream,SClientCheckContext &ctx )
{
CTimeValue currTime = m_pNetwork->GetCurrentTime();
//////////////////////////////////////////////////////////////////////////
// Schedule new random check time for this client.
CTimeValue timediff;
timediff.SetSeconds( RANDOM_CHECK_PERIOD + (RANDOM_CHECK_PERIOD*rand())/RAND_MAX );
if (m_pNetwork->GetCheatProtectionLevel() == 5)
timediff.SetSeconds( 2 );
pClientInfo->nextRandomCheckTime = currTime + timediff;
//////////////////////////////////////////////////////////////////////////
ctx.clientIP = pClientInfo->ip;
if (ctx.nRetries == 0) // If repeating request do not assign new requestId.
{
ctx.nRequestId = m_nNextRequestId++;
}
ctx.requestTime = currTime;
pClientInfo->lastRequestTime = currTime;
SClientCheckContext *pCtx = new SClientCheckContext;
*pCtx = ctx;
if (ctx.nRetries == 0)
{
m_pendingChecks.push_back(pCtx);
}
#ifdef LOGEVENTS
if (m_bLog) CryLog( "<DefenceWall> IssueRequest[%d] %s %I64x (ofs=%d,size=%d)",pCtx->nRequestId,pCtx->probe.sFilename.c_str(),pCtx->probe.nCode,pCtx->probe.nOffset,pCtx->probe.nSize );
#endif
CStream stm;
WriteStreamRequest( *pCtx,stm );
outstream.Write( stm );
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::WriteStreamRequest( SClientCheckContext &ctx,CStream &stm )
{
stm.Write( ctx.nRequestCode );
stm.WritePacked( ctx.nRequestId );
stm.WritePacked( ctx.nFilenameHash );
stm.WritePacked( ctx.probe.nCodeInfo );
stm.WritePacked( ctx.probe.nOffset );
stm.WritePacked( ctx.probe.nSize );
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::ReadStreamRequest( SClientCheckContext &ctx,CStream &stm )
{
stm.Read( ctx.nRequestCode );
stm.ReadPacked( ctx.nRequestId );
stm.ReadPacked( ctx.nFilenameHash );
stm.ReadPacked( ctx.probe.nCodeInfo );
stm.ReadPacked( ctx.probe.nOffset );
stm.ReadPacked( ctx.probe.nSize );
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::WriteStreamResponse( SClientCheckContext &ctx,CStream &stm )
{
// Also crypt stream here.
stm.Write( ctx.nRequestCode );
stm.WritePacked( ctx.nRequestId );
stm.WritePacked( ctx.nNumOpenedPaks );
stm.WritePacked( ctx.nClientStatusFlags );
stm.WriteBits( (BYTE*)&ctx.probe.nCode,64 ); // write int64
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::ReadStreamResponse( SClientCheckContext &ctx,CStream &stm )
{
stm.Read( ctx.nRequestCode );
stm.ReadPacked( ctx.nRequestId );
stm.ReadPacked( ctx.nNumOpenedPaks );
stm.ReadPacked( ctx.nClientStatusFlags );
stm.ReadBits( (BYTE*)&ctx.probe.nCode,64 ); // read int64
}
//////////////////////////////////////////////////////////////////////////
SClientCheckContext* CDefenceWall::FindRequest( int nRequestId )
{
for (PendingChecks::iterator it = m_pendingChecks.begin(); it != m_pendingChecks.end(); it++)
{
SClientCheckContext* pCtx = *it;
if (pCtx->nRequestId == nRequestId)
{
return pCtx;
}
}
return 0;
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::RemoveRequest( SClientCheckContext* pCtx )
{
for (PendingChecks::iterator it = m_pendingChecks.begin(); it != m_pendingChecks.end(); it++)
{
if (pCtx == *it)
{
m_pendingChecks.erase(it);
return;
}
}
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::UnifyFilename( string &sFilename )
{
string file = sFilename;
std::replace( file.begin(),file.end(),'\\','/' );
strlwr( const_cast<char*>(file.c_str()) );
sFilename = file;
}
void CDefenceWall::GetRelativeFilename( string &sFilename )
{
UnifyFilename(sFilename);
// Get current folder.
char szCurrDir[_MAX_PATH];
GetCurrentDirectory( sizeof(szCurrDir),szCurrDir );
string sCurDir = szCurrDir;
UnifyFilename(sCurDir);
// Get relative path.
if (strncmp(sFilename.c_str(),sCurDir.c_str(),sCurDir.size()) == 0 && sFilename.size()+1 >= sCurDir.size())
{
// First part of file name is current dir.
sFilename = sFilename.substr(sCurDir.size()+1);
}
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::EncryptStream( CStream &stm )
{
unsigned int* pBuffer = (unsigned int*)stm.GetPtr();
int len = stm.GetSize()/8;
if (len >= 8)
{
TEA_ENCODE( pBuffer,pBuffer,TEA_GETSIZE(len),m_nEncryptKey );
}
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::DecryptStream( CStream &stm )
{
unsigned int* pBuffer = (unsigned int*)stm.GetPtr();
int len = stm.GetSize()/8;
if (len >= 8)
{
TEA_DECODE( pBuffer,pBuffer,TEA_GETSIZE(len),m_nEncryptKey );
}
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::SendSecurityQueryToClient( CIPAddress &clientIP,CStream &stm )
{
if (m_pServer)
{
CServerSlot *pSlot = m_pServer->GetPacketOwner( clientIP );
if (pSlot)
{
EncryptStream(stm);
#ifdef LOGEVENTS
if (m_bLog) CryLog( "<DefenceWall> Sending Stream to Client %d bytes",stm.GetSize()/8 );
#endif
pSlot->SendSecurityQuery(stm);
}
}
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::SendSecurityRespToServer( CStream &stm )
{
if (m_pClient)
{
EncryptStream(stm);
m_pClient->SendSecurityResponse(stm);
}
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::OnServerRequest( CStream &stm )
{
DecryptStream(stm);
m_clientOutputStream.Reset();
while (!stm.EOS())
{
// When client recieves server request.
SClientCheckContext ctx;
ReadStreamRequest( ctx,stm );
// Perform required check on client.
switch (ctx.nRequestCode)
{
case DEFWALL_CHECK_PAK:
case DEFWALL_CHECK_PROTECTED_FILE:
case DEFWALL_CHECK_DLL_CODE:
OnValidateClientContext( ctx );
break;
default:
// Unknown server request.
#ifdef LOGEVENTS
if (m_bLog) CryLog( "Unknown Server Request Code" );
#endif
break;
}
}
if (m_clientOutputStream.GetSize() > 0)
{
// Send client Outputstring back to server.
SendSecurityRespToServer( m_clientOutputStream );
}
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::OnClientResponse( CIPAddress &clientIP,CStream &stm )
{
// When server recieves client response.
DecryptStream(stm);
int nServerStatusFlags = GetSystemStatusFlags();
while (!stm.EOS())
{
SClientCheckContext clientResponse;
ReadStreamResponse( clientResponse,stm );
SClientCheckContext &ctx = clientResponse;
#ifdef LOGEVENTS
if (m_bLog) CryLog( "<DefenceWall> OnClientResponse[%d] %s %I64x",ctx.nRequestId,ctx.probe.sFilename.c_str(),ctx.probe.nCode );
#endif
if (clientResponse.nClientStatusFlags != nServerStatusFlags)
{
#ifdef LOGEVENTS
if (m_bLog) CryLog( "<DefenceWall> Wrong Vars! %d!=%d",clientResponse.nClientStatusFlags,nServerStatusFlags );
#endif
// Client have different vars set.
PunkDetected( clientIP,IServerSecuritySink::CHEAT_MODIFIED_VARS );
return;
}
// Server here checks that client response is valid and validation code match the one stored on server.
SClientCheckContext *pServerCtx = FindRequest( clientResponse.nRequestId );
if (pServerCtx)
{
// Compare client code.
if (pServerCtx->probe.nCode != clientResponse.probe.nCode)
{
#ifdef LOGEVENTS
if (m_bLog) CryLog( "<DefenceWall> Wrong Code! %d!=%d",clientResponse.probe.nCode,pServerCtx->probe.nCode );
#endif
// Wrong Code!
PunkDetected( clientIP,(pServerCtx->bExecutableCode)?IServerSecuritySink::CHEAT_MODIFIED_CODE:IServerSecuritySink::CHEAT_MODIFIED_FILE );
return;
}
else if (pServerCtx->nRequestCode == DEFWALL_CHECK_PAK && pServerCtx->nNumOpenedPaks != clientResponse.nNumOpenedPaks)
{
#ifdef LOGEVENTS
if (m_bLog) CryLog( "<DefenceWall> Wrong Num Paks! %d!=%d",clientResponse.nNumOpenedPaks,pServerCtx->nNumOpenedPaks );
#endif
// Client have different number of open packs then server!
PunkDetected( clientIP,IServerSecuritySink::CHEAT_MODIFIED_FILE );
return;
}
}
else
{
// Client send request code that server already doesnt have.
if (clientResponse.nRequestId >= m_nNextRequestId)
{
#ifdef LOGEVENTS
if (m_bLog) CryLog( "<DefenceWall> Too Big Request Id! %d!=%d",clientResponse.nClientStatusFlags,nServerStatusFlags );
#endif
// Possible cheating with the protocol... Client cannot recieve such a big request id before server issues it.
PunkDetected( clientIP,IServerSecuritySink::CHEAT_NET_PROTOCOL );
return;
}
else
{
// this request code was already checked.
}
}
// Remove request from list.
RemoveRequest( pServerCtx );
}
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::OnValidateClientContext( SClientCheckContext &ctx )
{
#if defined(LINUX)
return;
#else
bool bGotProbe = true;
// Perform required check on client.
switch (ctx.nRequestCode)
{
case DEFWALL_CHECK_PAK:
{
// Find out which filename to check.
ICryPak::PakInfo* pPakInfo = m_pSystem->GetIPak()->GetPakInfo();
ctx.nNumOpenedPaks = pPakInfo->numOpenPaks;
for (unsigned int i = 0; i < pPakInfo->numOpenPaks; i++)
{
#ifdef LOGEVENTS
if (m_bLog) CryLog( "<DefenceWall> PAK: %s",pPakInfo->arrPaks[i].szFilePath );
#endif
string file = pPakInfo->arrPaks[i].szFilePath;
GetRelativeFilename(file);
u32 nFilenameHash = m_pNetwork->GetStringHash(file.c_str());
if (nFilenameHash == ctx.nFilenameHash)
{
// Refering to the same file.
ctx.probe.sFilename = file;
break;
}
}
m_pSystem->GetIPak()->FreePakInfo( pPakInfo );
}
break;
case DEFWALL_CHECK_PROTECTED_FILE:
{
for (unsigned int i = 0; i < m_protectedFiles.size(); i++)
{
ProtectedFile &pf = m_protectedFiles[i];
if (pf.nFilenameHash == ctx.nFilenameHash)
{
// We are refering to the same file.
ctx.probe.sFilename = pf.filename;
break;
}
}
}
break;
case DEFWALL_CHECK_DLL_CODE:
{
// Create module probe for all DLL modules.
IDataProbe::SModuleInfo *pModules;
int numModules = m_pSystem->GetIDataProbe()->GetLoadedModules( &pModules );
for (int i = 0; i < numModules; i++)
{
char sModule[_MAX_PATH];
char fname[_MAX_FNAME];
char ext[_MAX_EXT];
_splitpath( pModules[i].filename.c_str(),0,0,fname,ext );
_makepath( sModule,0,0,fname,ext );
strlwr( sModule );
u32 nFilenameHash = m_pSystem->GetIDataProbe()->GetHash( sModule );
if (ctx.nFilenameHash == nFilenameHash)
{
ctx.probe.sFilename = sModule;
bGotProbe = m_pSystem->GetIDataProbe()->GetModuleProbe(ctx.probe);
}
}
}
break;
default:
// Unknown request...
#ifdef LOGEVENTS
if (m_bLog) CryLog( "Server Sent Unknown request" );
#endif
return;
}
// initialize code to be random.
ctx.probe.nCode = ((u64)rand()) | (((u64)rand())<<16) | (((u64)rand())<<32) | (((u64)rand())<<48);
// Calc hash code of this file.
if (bGotProbe && m_pSystem->GetIDataProbe()->GetCode( ctx.probe ))
{
// Code retrieved.
}
else
{
// Failed...
}
// Send code back to server.
#ifdef LOGEVENTS
if (m_bLog) CryLog( "<DefenceWall> OnServerRequest[%d] %s %I64x (ofs=%d,size=%d)",ctx.nRequestId,ctx.probe.sFilename.c_str(),ctx.probe.nCode,ctx.probe.nOffset,ctx.probe.nSize );
#endif
// Every response should contain these.
ctx.nClientStatusFlags = GetSystemStatusFlags();
WriteStreamResponse( ctx,m_clientOutputStream );
#endif //LINUX
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::ClearProtectedFiles()
{
//m_bLog = m_pNetwork->GetLogLevel() == 1024;
ClearAllPendingRequests();
m_protectedFiles.clear();
if (m_pNetwork->GetCheatProtectionLevel() > 0)
FillStdServerProbes();
//////////////////////////////////////////////////////////////////////////
// Add default protected files.
//////////////////////////////////////////////////////////////////////////
// Bin32\FarCry.exe
//AddProtectedFile( (string("b")+"i"+"n"+"3"+"2"+"/"+"f"+"a"+"r"+"c"+"r"+"y"+"."+"e"+"x"+"e").c_str() );
// Bin32\XRenderD3D9.exe
//AddProtectedFile( (string("b")+"i"+"n"+"3"+"2"+"/"+"x"+"r"+"e"+"n"+"d"+"e"+"r"+"d"+"3"+"d"+"9"+"."+"d"+"l"+"l").c_str() );
// Bin32\XRenderNULL.exe
//AddProtectedFile( (string("b")+"i"+"n"+"3"+"2"+"/"+"x"+"r"+"e"+"n"+"d"+"e"+"r"+"n"+"u"+"l"+"l"+"."+"d"+"l"+"l").c_str() );
// Bin32\XRenderOGL.exe
//AddProtectedFile( (string("b")+"i"+"n"+"3"+"2"+"/"+"x"+"r"+"e"+"n"+"d"+"e"+"r"+"o"+"g"+"l"+"."+"d"+"l"+"l").c_str() );
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::AddProtectedFile( const char *sFilename )
{
#if !defined(LINUX)
string file = sFilename;
UnifyFilename( file );
ProtectedFile pf;
pf.filename = file;
pf.nFilenameHash = m_pNetwork->GetStringHash(pf.filename.c_str());
// Create also STD server probe if on server.
if (m_bServer && m_pNetwork->GetCheatProtectionLevel() > 0)
{
// Calc hash code of this file.
SDataProbeContext probe;
probe.nCodeInfo = rand()%3;
probe.nOffset = 0;
probe.nSize = 0xFFFFFFFF; // all file.
probe.sFilename = file;
if (!m_pSystem->GetIDataProbe()->GetRandomFileProbe( probe,false ))
return;
if (!m_pSystem->GetIDataProbe()->GetCode( probe ))
return;
pf.nHashCode = probe.nCode;
SClientCheckContext ctx;
ctx.nRequestCode = DEFWALL_CHECK_PROTECTED_FILE;
ctx.bExecutableCode = false;
ctx.nFilenameHash = pf.nFilenameHash;
ctx.probe = probe;
m_stdServerProbes.push_back(ctx);
#ifdef LOGEVENTS
if (m_bLog) CryLog( "<DefenceWall> CreatedFileProbe[%d] %s %I64x",ctx.nRequestId,ctx.probe.sFilename.c_str(),ctx.probe.nCode );
#endif
}
m_protectedFiles.push_back(pf);
#endif
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::ServerUpdate()
{
if (!m_bServer)
return;
// m_bLog = m_pNetwork->GetLogLevel() == 1024;
// Ignore if no standart probes yet.
if (m_stdServerProbes.empty())
return;
CTimeValue currTime = m_pNetwork->GetCurrentTime();
float fCurrSeconds = currTime.GetSeconds();
std::vector<CIPAddress> notRespondingClients;
notRespondingClients.clear();
PendingChecks::iterator it,next;
// See if any requests expired and were not responded.
for (it = m_pendingChecks.begin(); it != m_pendingChecks.end(); it = next)
{
next = it; next++;
SClientCheckContext &ctx = *(*it);
// Check how long request is pending already.
float fRequestTime = ctx.requestTime.GetSeconds();
if (fCurrSeconds - fRequestTime > WAIT_FOR_RESPONSE_TIME)
{
// More then response seconds since request.
if (ctx.nRetries < MAX_CHECK_RETRIES)
{
#ifdef LOGEVENTS
if (m_bLog) CryLog( "<DefenceWall> Repeat Request[%d] (Retry:%d)",ctx.nRequestId,ctx.nRetries );
#endif
ctx.nRetries++;
ClientInfo *pClientInfo = FindClientInfo(ctx.clientIP);
if (pClientInfo)
{
// Try to issue the same request again.
CStream outstream;
IssueRequest( pClientInfo,outstream,ctx );
SendSecurityQueryToClient( ctx.clientIP,outstream );
}
else
{
#ifdef LOGEVENTS
if (m_bLog) CryLog( "<DefenceWall> Delete Request[%d] Unknown Client!",ctx.nRequestId );
#endif
m_pendingChecks.erase(it); // something wrong with this request, not client for this ip.
}
}
else
{
#ifdef LOGEVENTS
if (m_bLog) CryLog( "<DefenceWall> No Resonse from Client for Request(%d)",ctx.nRequestId);
#endif
// 3 Requests without an answer.... (assume cheating client).
notRespondingClients.push_back( ctx.clientIP );
m_pendingChecks.erase(it);
}
}
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
{
// If any client not responding.
for (unsigned int i = 0; i < notRespondingClients.size(); i++)
{
PunkDetected( notRespondingClients[i],IServerSecuritySink::CHEAT_NOT_RESPONDING );
}
}
if (m_pNetwork->GetCheatProtectionLevel() >= CHEAT_LEVEL_RANDOMCHECKS)
{
//////////////////////////////////////////////////////////////////////////
// Go over clients and check if they need random check yet.
for (Clients::const_iterator clit = m_clients.begin(); clit != m_clients.end(); ++clit)
{
ClientInfo *ci = *clit;
if (currTime > ci->nextRandomCheckTime)
{
// Make random request to this client.
RandomClientValidation( ci );
}
}
}
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::OnAddClient( CIPAddress &clientIP )
{
// Check if this client already added.
for (Clients::iterator it = m_clients.begin(); it != m_clients.end(); ++it)
{
// This client already added.
if ((*it)->ip == clientIP)
return;
}
bool b64bit = false;
CServerSlot *pSlot = m_pServer->GetPacketOwner( clientIP );
if (pSlot)
{
if (pSlot->IsLocalSlot())
return;
b64bit = pSlot->GetClientFlags() & CLIENT_FLAGS_64BIT;
}
ClientInfo *ci = new ClientInfo;
ci->lastRequestTime = 0;
ci->nextRandomCheckTime = 0;
ci->ip = clientIP;
ci->b64bit = b64bit;
m_clients.push_back( ci );
// Start Validation.
FirstTimeClientValidation( ci );
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::OnDisconnectClient( CIPAddress &clientIP )
{
// Remove all requests to this ip.
PendingChecks::iterator next;
for (PendingChecks::iterator it = m_pendingChecks.begin(); it != m_pendingChecks.end(); it = next)
{
next = it; next++;
SClientCheckContext* pCtx = *it;
if (pCtx->clientIP == clientIP)
{
// This ip should be removed.
delete pCtx;
next = m_pendingChecks.erase(it);
}
}
for (Clients::iterator clit = m_clients.begin(); clit != m_clients.end(); ++clit)
{
ClientInfo *ci = *clit;
if (ci->ip == clientIP)
{
m_clients.erase(clit);
delete ci;
break;
}
}
}
//////////////////////////////////////////////////////////////////////////
CDefenceWall::ClientInfo* CDefenceWall::FindClientInfo( CIPAddress &clientIP ) const
{
for (Clients::const_iterator clit = m_clients.begin(); clit != m_clients.end(); ++clit)
{
ClientInfo *ci = *clit;
if (ci->ip == clientIP)
{
return ci;
}
}
return 0;
}
//////////////////////////////////////////////////////////////////////////
void CDefenceWall::PunkDetected( CIPAddress &clientIP,int type )
{
ClientInfo *ci = FindClientInfo(clientIP);
if (ci)
{
ci->bSuspectedPunk = true;
}
m_pNetwork->PunkDetected( clientIP );
if (m_pServer)
{
if (m_pServer->GetSecuritySink())
{
m_pServer->GetSecuritySink()->CheaterFound( clientIP.GetAsUINT(),type,"" );
}
}
}
enum EDFSystemStatusFlags
{
SYS_STATUS_FORCE_NONDEVMODE = 0x0001,
SYS_STATUS_IN_DEVMODE = 0x0002,
SYS_STATUS_WAS_IN_DEVMODE = 0x0004,
SYS_STATUS_PAK_PRIORITY = 0x0008,
};
//////////////////////////////////////////////////////////////////////////
int CDefenceWall::GetSystemStatusFlags()
{
int flags = 0;
if (GetISystem()->GetForceNonDevMode())
flags |= SYS_STATUS_FORCE_NONDEVMODE;
// Check dev mode.
if (GetISystem()->IsDevMode())
flags |= SYS_STATUS_IN_DEVMODE;
// Check if was started in dev mode.
if (GetISystem()->WasInDevMode())
flags |= SYS_STATUS_WAS_IN_DEVMODE;
ICVar *pVar = GetISystem()->GetIConsole()->GetCVar("sys_PakPriority");
if (pVar && pVar->GetIVal() != 0)
flags |= SYS_STATUS_PAK_PRIORITY;
return flags;
}