mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
401 lines
10 KiB
C++
401 lines
10 KiB
C++
//===========================================================================//
|
|
//
|
|
// Purpose: Shared rcon utilities.
|
|
//
|
|
//===========================================================================//
|
|
#include "core/stdafx.h"
|
|
#include "base_rcon.h"
|
|
#include "shared_rcon.h"
|
|
#include "protoc/netcon.pb.h"
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: serialize message to vector
|
|
// Input : *pBase -
|
|
// &vecBuf -
|
|
// *pResponseMsg -
|
|
// *pResponseVal -
|
|
// responseType -
|
|
// nMessageId -
|
|
// nMessageType -
|
|
// bEncrypt -
|
|
// bDebug -
|
|
// Output : true on success, false otherwise
|
|
//-----------------------------------------------------------------------------
|
|
bool SV_NetConSerialize(const CNetConBase* pBase, vector<char>& vecBuf, const char* pResponseMsg, const char* pResponseVal,
|
|
const netcon::response_e responseType, const int nMessageId, const int nMessageType, const bool bEncrypt, const bool bDebug)
|
|
{
|
|
netcon::response response;
|
|
|
|
response.set_messageid(nMessageId);
|
|
response.set_messagetype(nMessageType);
|
|
response.set_responsetype(responseType);
|
|
response.set_responsemsg(pResponseMsg);
|
|
response.set_responseval(pResponseVal);
|
|
|
|
if (!SH_NetConPackEnvelope(pBase, vecBuf, response.ByteSizeLong(), &response, bEncrypt, bDebug))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: serialize message to vector
|
|
// Input : *pBase -
|
|
// &vecBuf -
|
|
// *szReqBuf -
|
|
// *szReqVal -
|
|
// *requestType -
|
|
// bEncrypt -
|
|
// bDebug -
|
|
// Output : true on success, false otherwise
|
|
//-----------------------------------------------------------------------------
|
|
bool CL_NetConSerialize(const CNetConBase* pBase, vector<char>& vecBuf, const char* szReqBuf,
|
|
const char* szReqVal, const netcon::request_e requestType, const bool bEncrypt, const bool bDebug)
|
|
{
|
|
netcon::request request;
|
|
|
|
request.set_messageid(-1);
|
|
request.set_requesttype(requestType);
|
|
request.set_requestmsg(szReqBuf);
|
|
request.set_requestval(szReqVal);
|
|
|
|
if (!SH_NetConPackEnvelope(pBase, vecBuf, request.ByteSizeLong(), &request, bEncrypt, bDebug))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: attempt to connect to remote
|
|
// Input : *pBase -
|
|
// *pHostAdr -
|
|
// nHostPort -
|
|
// Output : true on success, false otherwise
|
|
//-----------------------------------------------------------------------------
|
|
bool CL_NetConConnect(CNetConBase* pBase, const char* pHostAdr, const int nHostPort)
|
|
{
|
|
string svLocalHost;
|
|
const bool bValidSocket = nHostPort != SOCKET_ERROR;
|
|
|
|
if (bValidSocket && (strcmp(pHostAdr, "localhost") == 0))
|
|
{
|
|
char szHostName[512];
|
|
if (!gethostname(szHostName, sizeof(szHostName)))
|
|
{
|
|
svLocalHost = Format("[%s]:%i", szHostName, nHostPort);
|
|
pHostAdr = svLocalHost.c_str();
|
|
}
|
|
}
|
|
|
|
CNetAdr* pNetAdr = pBase->GetNetAddress();
|
|
if (!pNetAdr->SetFromString(pHostAdr, true))
|
|
{
|
|
Error(eDLL_T::CLIENT, NO_ERROR, "Failed to set RCON address: %s\n", pHostAdr);
|
|
return false;
|
|
}
|
|
|
|
// Pass 'SOCKET_ERROR' if you want to set port from address string instead.
|
|
if (bValidSocket)
|
|
{
|
|
pNetAdr->SetPort(htons(u_short(nHostPort)));
|
|
}
|
|
|
|
CSocketCreator* pCreator = pBase->GetSocketCreator();
|
|
if (pCreator->ConnectSocket(*pNetAdr, true) == SOCKET_ERROR)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
Msg(eDLL_T::CLIENT, "Connected to: %s\n", pNetAdr->ToString());
|
|
return true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: packs a message envelope
|
|
// Input : *pBase -
|
|
// &outMsgBuf -
|
|
// nMsgLen -
|
|
// *inMsg -
|
|
// bEncrypt -
|
|
// bDebug -
|
|
// Output : true on success, false otherwise
|
|
//-----------------------------------------------------------------------------
|
|
bool SH_NetConPackEnvelope(const CNetConBase* pBase, vector<char>& outMsgBuf, const size_t nMsgLen,
|
|
google::protobuf::MessageLite* inMsg, const bool bEncrypt, const bool bDebug)
|
|
{
|
|
char* encodeBuf = new char[nMsgLen];
|
|
std::unique_ptr<char[]> encodedContainer(encodeBuf);
|
|
|
|
if (!pBase->Encode(inMsg, encodeBuf, nMsgLen))
|
|
{
|
|
if (bDebug)
|
|
{
|
|
Error(eDLL_T::ENGINE, NO_ERROR, "Failed to encode RCON message data\n");
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
netcon::envelope envelope;
|
|
envelope.set_encrypted(bEncrypt);
|
|
|
|
const char* dataBuf = encodeBuf;
|
|
std::unique_ptr<char[]> container;
|
|
|
|
if (bEncrypt)
|
|
{
|
|
char* encryptBuf = new char[nMsgLen];
|
|
container.reset(encryptBuf);
|
|
|
|
CryptoContext_s ctx;
|
|
if (!pBase->Encrypt(ctx, encodeBuf, encryptBuf, nMsgLen))
|
|
{
|
|
if (bDebug)
|
|
{
|
|
Error(eDLL_T::ENGINE, NO_ERROR, "Failed to encrypt RCON message data\n");
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
envelope.set_nonce(ctx.ivData, sizeof(ctx.ivData));
|
|
dataBuf = encryptBuf;
|
|
}
|
|
|
|
envelope.set_data(dataBuf, nMsgLen);
|
|
const size_t envelopeSize = envelope.ByteSizeLong();
|
|
|
|
outMsgBuf.resize(envelopeSize);
|
|
|
|
if (!pBase->Encode(&envelope, &outMsgBuf[0], envelopeSize))
|
|
{
|
|
if (bDebug)
|
|
{
|
|
Error(eDLL_T::ENGINE, NO_ERROR, "Failed to encode RCON message envelope\n");
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: unpacks a message envelope
|
|
// Input : *pBase -
|
|
// *pMsgBuf -
|
|
// nMsgLen -
|
|
// *outMsg -
|
|
// bEncrypt -
|
|
// bDebug -
|
|
// Output : true on success, false otherwise
|
|
//-----------------------------------------------------------------------------
|
|
bool SH_NetConUnpackEnvelope(const CNetConBase* pBase, const char* pMsgBuf, const size_t nMsgLen,
|
|
google::protobuf::MessageLite* outMsg, const bool bDebug)
|
|
{
|
|
netcon::envelope envelope;
|
|
|
|
if (!pBase->Decode(&envelope, pMsgBuf, nMsgLen))
|
|
{
|
|
if (bDebug)
|
|
{
|
|
Error(eDLL_T::ENGINE, NO_ERROR, "Failed to decode RCON message envelope\n");
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
const size_t msgLen = envelope.data().size();
|
|
|
|
if (msgLen > RCON_MAX_PAYLOAD_SIZE)
|
|
{
|
|
Error(eDLL_T::ENGINE, NO_ERROR, "Data in RCON message envelope is too large (%zu > %zu)\n",
|
|
msgLen, RCON_MAX_PAYLOAD_SIZE);
|
|
|
|
return false;
|
|
}
|
|
|
|
const char* netMsg = envelope.data().c_str();
|
|
const char* dataBuf = netMsg;
|
|
|
|
std::unique_ptr<char[]> container;
|
|
|
|
if (envelope.encrypted())
|
|
{
|
|
char* decryptBuf = new char[msgLen];
|
|
container.reset(decryptBuf);
|
|
|
|
const size_t ivLen = envelope.nonce().size();
|
|
|
|
if (ivLen != sizeof(CryptoIV_t))
|
|
{
|
|
if (bDebug)
|
|
{
|
|
Error(eDLL_T::ENGINE, NO_ERROR, "Nonce in RCON message envelope is invalid (%zu != %zu)\n",
|
|
ivLen, sizeof(CryptoIV_t));
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
CryptoContext_s ctx;
|
|
memcpy(ctx.ivData, envelope.nonce().data(), ivLen);
|
|
|
|
if (!pBase->Decrypt(ctx, netMsg, decryptBuf, msgLen))
|
|
{
|
|
if (bDebug)
|
|
{
|
|
Error(eDLL_T::ENGINE, NO_ERROR, "Failed to decrypt RCON message data\n");
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
dataBuf = decryptBuf;
|
|
}
|
|
|
|
Assert(dataBuf);
|
|
|
|
if (!pBase->Decode(outMsg, dataBuf, msgLen))
|
|
{
|
|
if (bDebug)
|
|
{
|
|
Error(eDLL_T::ENGINE, NO_ERROR, "Failed to decode RCON message data\n");
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: gets the netconsole data
|
|
// Input : *pBase -
|
|
// iSocket -
|
|
// Output : nullptr on failure
|
|
//-----------------------------------------------------------------------------
|
|
CConnectedNetConsoleData* SH_GetNetConData(CNetConBase* pBase, const int iSocket)
|
|
{
|
|
CSocketCreator* pCreator = pBase->GetSocketCreator();
|
|
Assert(iSocket >= 0 && (pCreator->GetAcceptedSocketCount() == 0
|
|
|| iSocket < pCreator->GetAcceptedSocketCount()));
|
|
|
|
if (!pCreator->GetAcceptedSocketCount())
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
return &pCreator->GetAcceptedSocketData(iSocket);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: gets the netconsole socket
|
|
// Input : *pBase -
|
|
// iSocket -
|
|
// Output : SOCKET_ERROR (-1) on failure
|
|
//-----------------------------------------------------------------------------
|
|
SocketHandle_t SH_GetNetConSocketHandle(CNetConBase* pBase, const int iSocket)
|
|
{
|
|
const CConnectedNetConsoleData* pData = SH_GetNetConData(pBase, iSocket);
|
|
if (!pData)
|
|
{
|
|
return SOCKET_ERROR;
|
|
}
|
|
|
|
return pData->m_hSocket;
|
|
}
|
|
|
|
#ifndef _TOOLS
|
|
|
|
#ifndef CLIENT_DLL
|
|
#include "engine/server/sv_rcon.h"
|
|
#endif // !CLIENT_DLL
|
|
#ifndef DEDICATED
|
|
#include "engine/client/cl_rcon.h"
|
|
#endif // !DEDICATED
|
|
|
|
void RCON_KeyChanged_f(IConVar* pConVar, const char* pOldString);
|
|
void RCON_PasswordChanged_f(IConVar* pConVar, const char* pOldString);
|
|
|
|
ConVar rcon_debug("rcon_debug", "0", FCVAR_RELEASE, "Show rcon debug information ( !slower! )");
|
|
ConVar rcon_encryptframes("rcon_encryptframes", "1", FCVAR_RELEASE, "Whether to encrypt RCON messages");
|
|
ConVar rcon_key("rcon_key", "", FCVAR_SERVER_CANNOT_QUERY | FCVAR_DONTRECORD | FCVAR_RELEASE, "Base64 remote server access encryption key (random if empty or invalid)", &RCON_KeyChanged_f);
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: change RCON key on server and client
|
|
//-----------------------------------------------------------------------------
|
|
void RCON_KeyChanged_f(IConVar* pConVar, const char* pOldString)
|
|
{
|
|
if (ConVar* pConVarRef = g_pCVar->FindVar(pConVar->GetName()))
|
|
{
|
|
const char* pNewString = pConVarRef->GetString();
|
|
|
|
if (strcmp(pOldString, pNewString) == NULL)
|
|
return; // Same key.
|
|
|
|
|
|
#if !defined(DEDICATED) && !defined(CLIENT_DLL)
|
|
RCONServer()->SetKey(pNewString);
|
|
RCONClient()->SetKey(RCONServer()->GetKey()); // Sync server & client keys
|
|
|
|
Msg(eDLL_T::ENGINE, "Installed RCON Key: %s'%s%s%s'\n",
|
|
g_svReset, g_svGreyB, RCONClient()->GetKey(), g_svReset);
|
|
#else
|
|
#ifdef DEDICATED
|
|
RCONServer()->SetKey(pNewString);
|
|
|
|
Msg(eDLL_T::SERVER, "Installed RCON Key: %s'%s%s%s'\n",
|
|
g_svReset, g_svGreyB, RCONServer()->GetKey(), g_svReset);
|
|
#endif // DEDICATED
|
|
#ifdef CLIENT_DLL
|
|
RCONClient()->SetKey(pNewString);
|
|
|
|
Msg(eDLL_T::CLIENT, "Installed RCON Key: %s'%s%s%s'\n",
|
|
g_svReset, g_svGreyB, RCONClient()->GetKey(), g_svReset);
|
|
#endif // CLIENT_DLL
|
|
|
|
#endif // !DEDICATED && !CLIENT_DLL
|
|
}
|
|
}
|
|
|
|
#ifndef CLIENT_DLL
|
|
void RCON_InitServerAndTrySyncKeys(const char* pPassword)
|
|
{
|
|
#ifndef DEDICATED
|
|
RCONServer()->Init(pPassword, rcon_key.GetString());
|
|
|
|
if (RCONServer()->IsInitialized())
|
|
{
|
|
// Sync server & client keys
|
|
RCONClient()->SetKey(RCONServer()->GetKey());
|
|
}
|
|
#else
|
|
RCONServer()->Init(pPassword, rcon_key.GetString());
|
|
#endif // !DEDICATED
|
|
}
|
|
#endif // !CLIENT_DLL
|
|
|
|
#ifndef DEDICATED
|
|
void RCON_InitClientAndTrySyncKeys()
|
|
{
|
|
#ifndef CLIENT_DLL
|
|
if (RCONServer()->IsInitialized())
|
|
{
|
|
// Sync server & client keys
|
|
RCONClient()->Init(RCONServer()->GetKey());
|
|
}
|
|
else
|
|
#endif // !CLIENT_DLL
|
|
{
|
|
RCONClient()->Init(rcon_key.GetString());
|
|
}
|
|
}
|
|
#endif // !DEDICATED
|
|
|
|
#endif // !_TOOLS
|