2023-04-19 01:35:31 +02:00
//===========================================================================//
//
// Purpose: Shared rcon utilities.
//
//===========================================================================//
# include "core/stdafx.h"
# include "base_rcon.h"
# include "shared_rcon.h"
2024-06-01 11:24:47 +02:00
# 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 ;
}
2023-04-19 01:35:31 +02:00
//-----------------------------------------------------------------------------
// Purpose: serialize message to vector
// Input : *pBase -
// &vecBuf -
// *szReqBuf -
// *szReqVal -
// *requestType -
2024-06-01 11:24:47 +02:00
// bEncrypt -
// bDebug -
2023-04-19 01:35:31 +02:00
// Output : true on success, false otherwise
//-----------------------------------------------------------------------------
bool CL_NetConSerialize ( const CNetConBase * pBase , vector < char > & vecBuf , const char * szReqBuf ,
2024-06-01 11:24:47 +02:00
const char * szReqVal , const netcon : : request_e requestType , const bool bEncrypt , const bool bDebug )
2023-04-19 01:35:31 +02:00
{
2024-06-01 11:24:47 +02:00
netcon : : request request ;
2023-04-19 01:35:31 +02:00
request . set_messageid ( - 1 ) ;
request . set_requesttype ( requestType ) ;
request . set_requestmsg ( szReqBuf ) ;
request . set_requestval ( szReqVal ) ;
2024-06-01 11:24:47 +02:00
if ( ! SH_NetConPackEnvelope ( pBase , vecBuf , request . ByteSizeLong ( ) , & request , bEncrypt , bDebug ) )
2023-04-19 01:35:31 +02:00
{
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 ;
2023-04-19 01:52:05 +02:00
const bool bValidSocket = nHostPort ! = SOCKET_ERROR ;
2024-04-10 16:23:48 +02:00
if ( bValidSocket & & ( strcmp ( pHostAdr , " localhost " ) = = 0 ) )
2023-04-19 01:35:31 +02:00
{
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 ;
}
2023-04-19 01:52:05 +02:00
// Pass 'SOCKET_ERROR' if you want to set port from address string instead.
if ( bValidSocket )
{
pNetAdr - > SetPort ( htons ( u_short ( nHostPort ) ) ) ;
}
2023-04-19 01:35:31 +02:00
CSocketCreator * pCreator = pBase - > GetSocketCreator ( ) ;
if ( pCreator - > ConnectSocket ( * pNetAdr , true ) = = SOCKET_ERROR )
{
return false ;
}
2023-08-21 19:12:29 +02:00
Msg ( eDLL_T : : CLIENT , " Connected to: %s \n " , pNetAdr - > ToString ( ) ) ;
2023-04-19 01:35:31 +02:00
return true ;
}
2024-06-01 11:24:47 +02:00
//-----------------------------------------------------------------------------
// 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 ;
}
2023-04-19 01:35:31 +02:00
//-----------------------------------------------------------------------------
// Purpose: gets the netconsole data
// Input : *pBase -
// iSocket -
// Output : nullptr on failure
//-----------------------------------------------------------------------------
2023-04-22 16:02:54 +02:00
CConnectedNetConsoleData * SH_GetNetConData ( CNetConBase * pBase , const int iSocket )
2023-04-19 01:35:31 +02:00
{
2023-08-04 10:48:22 +02:00
CSocketCreator * pCreator = pBase - > GetSocketCreator ( ) ;
2023-04-22 21:46:05 +02:00
Assert ( iSocket > = 0 & & ( pCreator - > GetAcceptedSocketCount ( ) = = 0
| | iSocket < pCreator - > GetAcceptedSocketCount ( ) ) ) ;
2023-04-19 01:35:31 +02:00
if ( ! pCreator - > GetAcceptedSocketCount ( ) )
{
return nullptr ;
}
2023-08-04 10:48:22 +02:00
return & pCreator - > GetAcceptedSocketData ( iSocket ) ;
2023-04-19 01:35:31 +02:00
}
//-----------------------------------------------------------------------------
// Purpose: gets the netconsole socket
// Input : *pBase -
// iSocket -
// Output : SOCKET_ERROR (-1) on failure
//-----------------------------------------------------------------------------
2023-04-22 16:02:54 +02:00
SocketHandle_t SH_GetNetConSocketHandle ( CNetConBase * pBase , const int iSocket )
2023-04-19 01:35:31 +02:00
{
const CConnectedNetConsoleData * pData = SH_GetNetConData ( pBase , iSocket ) ;
if ( ! pData )
{
return SOCKET_ERROR ;
}
return pData - > m_hSocket ;
}
2024-06-01 11:24:47 +02:00
# 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
}
}
2024-04-10 15:15:27 +02:00
# ifndef CLIENT_DLL
void RCON_InitServerAndTrySyncKeys ( const char * pPassword )
2024-06-01 11:24:47 +02:00
{
2024-04-10 15:15:27 +02:00
# ifndef DEDICATED
RCONServer ( ) - > Init ( pPassword , rcon_key . GetString ( ) ) ;
2024-06-01 11:24:47 +02:00
2024-04-10 15:15:27 +02:00
if ( RCONServer ( ) - > IsInitialized ( ) )
{
// Sync server & client keys
RCONClient ( ) - > SetKey ( RCONServer ( ) - > GetKey ( ) ) ;
2024-06-01 11:24:47 +02:00
}
2024-04-10 15:15:27 +02:00
# else
RCONServer ( ) - > Init ( pPassword , rcon_key . GetString ( ) ) ;
# endif // !DEDICATED
2024-06-01 11:24:47 +02:00
}
2024-04-10 15:15:27 +02:00
# endif // !CLIENT_DLL
2024-06-01 11:24:47 +02:00
# 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