327 lines
7.5 KiB
C++
327 lines
7.5 KiB
C++
#include "stdafx.h"
|
|
#include "rconsystem.h" // CRConSystem
|
|
#include "Network.h" // CNetwork
|
|
#include "CNP.h" // CQPRConCommand
|
|
#include "IConsole.h" // IConsole
|
|
//#if !defined(LINUX)
|
|
#include "IDataProbe.h" // IConsole
|
|
//#endif
|
|
|
|
|
|
// *****************************************************************
|
|
// *****************************************************************
|
|
class CRConConsoleSink :public IOutputPrintSink
|
|
{
|
|
public:
|
|
// constructor
|
|
CRConConsoleSink( CRConSystem &inRef, const CIPAddress &ip ) :m_Ref(inRef), m_ip(ip)
|
|
{
|
|
}
|
|
|
|
// interface IOutputPrintSink ------------------------------------
|
|
|
|
virtual void Print( const char *inszText )
|
|
{
|
|
CStream stmPacket;
|
|
CQPRConResponse RConResponse;
|
|
|
|
RConResponse.m_sText=inszText;
|
|
|
|
RConResponse.Save(stmPacket);
|
|
NRESULT hRes=m_Ref.m_sSocket.Send(stmPacket.GetPtr(), BITS2BYTES(stmPacket.GetSize()), &m_ip);
|
|
|
|
if(hRes==SOCKET_ERROR)
|
|
{
|
|
INetwork *pNetwork=m_Ref.m_pSystem->GetINetwork(); assert(pNetwork);
|
|
|
|
const char *szErrorRes=pNetwork->EnumerateError(hRes);
|
|
|
|
CryLogAlways("$4RConError: %s",szErrorRes);
|
|
}
|
|
}
|
|
|
|
CRConSystem & m_Ref; //!<
|
|
CIPAddress m_ip; //!<
|
|
};
|
|
// *****************************************************************
|
|
// *****************************************************************
|
|
|
|
CRConSystem::CRConSystem()
|
|
{
|
|
m_pSystem=0;
|
|
m_pIServer=0;
|
|
|
|
GetPassCode( "CNPNetworkKeyNode",m_nDevPassCode );
|
|
}
|
|
|
|
CRConSystem::~CRConSystem()
|
|
{
|
|
}
|
|
|
|
|
|
bool CRConSystem::Create( ISystem *pSystem )
|
|
{
|
|
assert(pSystem);
|
|
|
|
m_pSystem = pSystem;
|
|
|
|
if(NET_FAILED(m_sSocket.Create()))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void CRConSystem::Update( unsigned int dwTime,IClient *pClient )
|
|
{
|
|
static CStream stmBuffer;
|
|
static CIPAddress ipFrom;
|
|
|
|
int iReceived = 0;
|
|
|
|
if (pClient)
|
|
{
|
|
m_ipServer = pClient->GetServerIP();
|
|
}
|
|
|
|
do
|
|
{
|
|
stmBuffer.Reset();
|
|
|
|
m_sSocket.Receive(stmBuffer.GetPtr(), stmBuffer.GetAllocatedSize(), iReceived, ipFrom);
|
|
|
|
if(iReceived > 0)
|
|
{
|
|
stmBuffer.SetSize(BYTES2BITS(iReceived));
|
|
|
|
CNP cnpPacket;
|
|
cnpPacket.LoadAndSeekToZero(stmBuffer);
|
|
|
|
if(cnpPacket.m_cFrameType == FT_CQP_RCON_RESPONSE) // from Server back to Client
|
|
{
|
|
CQPRConResponse cqpRConResponse;
|
|
cqpRConResponse.Load(stmBuffer);
|
|
|
|
CryLogAlways("$5RCon Response: %s",cqpRConResponse.m_sText.c_str());
|
|
}
|
|
else
|
|
{
|
|
assert(0); // there should be no ther packets on this port
|
|
return;
|
|
}
|
|
}
|
|
} while(iReceived > 0);
|
|
|
|
|
|
while(!m_DeferredConsoleCommands.empty())
|
|
{
|
|
SDeferredCommand &defCmd( m_DeferredConsoleCommands.front() );
|
|
|
|
CRConConsoleSink sink( *this, defCmd.m_ip );
|
|
|
|
IConsole *pConsole( m_pSystem->GetIConsole() );
|
|
assert( pConsole );
|
|
|
|
pConsole->AddOutputPrintSink( &sink);
|
|
pConsole->ExecuteString( defCmd.m_sCommand.c_str() );
|
|
pConsole->RemoveOutputPrintSink( &sink );
|
|
|
|
m_DeferredConsoleCommands.pop_front();
|
|
}
|
|
}
|
|
|
|
|
|
void CRConSystem::OnServerCreated( IServer *inpServer )
|
|
{
|
|
assert(inpServer);
|
|
|
|
inpServer->RegisterPacketSink(FT_CQP_RCON_COMMAND,this);
|
|
m_pIServer = inpServer;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CRConSystem::GetPassCode( const char *szString,unsigned int *nOutCode )
|
|
{
|
|
//#if !defined(LINUX)
|
|
|
|
#ifdef _DATAPROBE
|
|
char md5[16];
|
|
GetISystem()->GetIDataProbe()->GetMD5( szString,strlen(szString),md5 );
|
|
memcpy( nOutCode,md5,16 ); // 16 byte.
|
|
#endif
|
|
|
|
//#endif
|
|
/*
|
|
#define POLY64REV 0xd800000000000000ULL
|
|
string sPass = szString;
|
|
// Duplicate pass 10 times.
|
|
for (int i = 0; i < 10; i++)
|
|
{
|
|
sPass += szString;
|
|
}
|
|
int len = sPass.size();
|
|
const unsigned char *buf = (const unsigned char*)sPass.c_str();
|
|
// calc CRC_64
|
|
static uint64 Table[256];
|
|
uint64 code = 0;
|
|
static int init = 0;
|
|
if (!init) {
|
|
int i;
|
|
init = 1;
|
|
for (i = 0; i <= 255; i++) {
|
|
int j;
|
|
uint64 part = i;
|
|
for (j = 0; j < 8; j++) {
|
|
if (part & 1)
|
|
part = (part >> 1) ^ POLY64REV;
|
|
else
|
|
part >>= 1;
|
|
}
|
|
Table[i] = part;
|
|
}
|
|
}
|
|
unsigned int key1[4] = { 123765122,1276327,13482722,29871129};
|
|
while (len--)
|
|
{
|
|
uint64 temp1 = code >> 8;
|
|
uint64 temp2 = Table[(code ^ (uint64)*buf) & 0xff];
|
|
code = temp1 ^ temp2;
|
|
buf += 1;
|
|
}
|
|
|
|
unsigned int key2[4] = { 53215122,278627227,1762561245,817671221};
|
|
|
|
// 8 bytes.
|
|
TEA_ENCODE( (unsigned int*)&code,nOutCode,8,key1 );
|
|
code = (~code);
|
|
TEA_ENCODE( (unsigned int*)&code,(nOutCode+2),8,key2 );
|
|
*/
|
|
}
|
|
|
|
void CRConSystem::OnReceivingPacket( const unsigned char inPacketID, CStream &stmPacket, CIPAddress &ip )
|
|
{
|
|
IConsole *pConsole=m_pSystem->GetIConsole(); assert(pConsole);
|
|
|
|
ICVar *pVar = pConsole->GetCVar("sv_rcon_password"); assert(pVar);
|
|
string sv_RConPassword = pVar->GetString();
|
|
|
|
if(sv_RConPassword=="")
|
|
return; // RCon is not activated
|
|
|
|
CQPRConCommand pccp;
|
|
|
|
pccp.Load(stmPacket);
|
|
|
|
|
|
// Get code for server password, must match code recieved from client.
|
|
unsigned int nServerPassCode[4];
|
|
GetPassCode( sv_RConPassword.c_str(),nServerPassCode );
|
|
|
|
if (memcmp(nServerPassCode,pccp.m_nRConPasswordCode,sizeof(nServerPassCode)) != 0
|
|
&& memcmp(m_nDevPassCode,pccp.m_nRConPasswordCode,sizeof(nServerPassCode)) != 0)
|
|
{
|
|
unsigned int dwIP = ip.GetAsUINT();
|
|
|
|
std::map<unsigned int, int>::iterator it = m_hmRconAttempts.find(dwIP);
|
|
|
|
if (it == m_hmRconAttempts.end())
|
|
{
|
|
int iTry = 1;
|
|
|
|
m_hmRconAttempts.insert(std::pair<unsigned int, int>(dwIP, iTry));
|
|
}
|
|
else
|
|
{
|
|
CryLogAlways( "$4%s used a bad rcon password!.", ip.GetAsString(0) );
|
|
|
|
int iTry = ++it->second;
|
|
|
|
// if 3 attempts failed, remove from the hash map and ban it!
|
|
if (iTry >= 3)
|
|
{
|
|
m_hmRconAttempts.erase(it);
|
|
m_pIServer->BanIP(dwIP);
|
|
|
|
|
|
CryLogAlways("$4Banned %s after 3 attempts with a bad rcon password.", ip.GetAsString(0));
|
|
}
|
|
}
|
|
|
|
// pLog->Log("DEBUG: Password does not match");
|
|
return; // rcon password does not match
|
|
}
|
|
else
|
|
{
|
|
// reset the number of tries if password successful
|
|
std::map<unsigned int, int>::iterator it = m_hmRconAttempts.find(ip.GetAsUINT());
|
|
|
|
if (it != m_hmRconAttempts.end())
|
|
{
|
|
m_hmRconAttempts.erase(it);
|
|
}
|
|
}
|
|
|
|
|
|
char tempCmd[512];
|
|
strncpy(tempCmd,pccp.m_sRConCommand.c_str(),sizeof(tempCmd)-1);
|
|
tempCmd[sizeof(tempCmd)-1] = 0;
|
|
|
|
char *szIP = ip.GetAsString();
|
|
|
|
CryLogAlways("$5Incoming RCon(%s): %s",szIP,tempCmd);
|
|
|
|
|
|
m_DeferredConsoleCommands.push_back(SDeferredCommand(tempCmd,ip));
|
|
|
|
/*
|
|
{
|
|
CRConConsoleSink sink(*this,ip);
|
|
|
|
pConsole->AddOutputPrintSink(&sink);
|
|
pConsole->ExecuteString(tempCmd);
|
|
pConsole->RemoveOutputPrintSink(&sink);
|
|
}
|
|
*/
|
|
}
|
|
|
|
void CRConSystem::ExecuteRConCommand( const char *inszCommand )
|
|
{
|
|
// get parameters
|
|
|
|
IConsole *pConsole=m_pSystem->GetIConsole(); assert(pConsole);
|
|
|
|
ICVar *pVar1 = pConsole->GetCVar("cl_rcon_serverip"); assert(pVar1);
|
|
string serverip = pVar1->GetString();
|
|
|
|
ICVar *pVar2 = pConsole->GetCVar("cl_rcon_port"); assert(pVar2);
|
|
WORD wPort = pVar2->GetIVal();
|
|
|
|
ICVar *pVar3 = pConsole->GetCVar("cl_rcon_password"); assert(pVar3);
|
|
string sPasswd = pVar3->GetString();
|
|
|
|
// send packet
|
|
CQPRConCommand cqpRConCommand;
|
|
CStream stmPacket;
|
|
CIPAddress ip(wPort,serverip.c_str());
|
|
|
|
// If server ip not specified use, current server.
|
|
if (serverip.empty())
|
|
{
|
|
ip.Set( m_ipServer );
|
|
}
|
|
|
|
unsigned int nClientCode[4];
|
|
GetPassCode( sPasswd.c_str(),nClientCode );
|
|
memcpy( cqpRConCommand.m_nRConPasswordCode,nClientCode,sizeof(nClientCode) );
|
|
|
|
char tempCmd[256];
|
|
strncpy(tempCmd,inszCommand,sizeof(tempCmd)-1);
|
|
tempCmd[sizeof(tempCmd)-1] = 0;
|
|
cqpRConCommand.m_sRConCommand = tempCmd;
|
|
|
|
cqpRConCommand.Save(stmPacket);
|
|
m_sSocket.Send(stmPacket.GetPtr(),BITS2BYTES(stmPacket.GetSize()),&ip);
|
|
|
|
// prinout
|
|
CryLogAlways("$5RCon (%s:%d)'%s'",serverip.c_str(),(int)wPort,tempCmd );
|
|
} |