2022-02-06 16:48:52 +01:00
|
|
|
//===========================================================================//
|
2022-02-13 15:10:38 +01:00
|
|
|
//
|
|
|
|
// Purpose: Implementation of the rcon server.
|
|
|
|
//
|
2022-02-06 16:48:52 +01:00
|
|
|
//===========================================================================//
|
|
|
|
|
|
|
|
#include "core/stdafx.h"
|
2022-04-09 16:16:40 +02:00
|
|
|
#include "tier1/cmd.h"
|
|
|
|
#include "tier1/cvar.h"
|
|
|
|
#include "tier1/IConVar.h"
|
2022-02-06 16:48:52 +01:00
|
|
|
#include "tier1/NetAdr2.h"
|
|
|
|
#include "tier2/socketcreator.h"
|
2022-08-02 23:58:43 +02:00
|
|
|
#include "engine/net.h"
|
2022-05-20 11:52:19 +02:00
|
|
|
#include "engine/server/sv_rcon.h"
|
2022-02-13 15:10:38 +01:00
|
|
|
#include "protoc/sv_rcon.pb.h"
|
|
|
|
#include "protoc/cl_rcon.pb.h"
|
2022-02-06 16:48:52 +01:00
|
|
|
#include "mathlib/sha256.h"
|
|
|
|
#include "common/igameserverdata.h"
|
|
|
|
|
2022-08-02 23:58:43 +02:00
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2022-08-03 09:32:48 +02:00
|
|
|
// Purpose:
|
2022-08-02 23:58:43 +02:00
|
|
|
//-----------------------------------------------------------------------------
|
2022-08-03 09:32:48 +02:00
|
|
|
CRConServer::CRConServer(void)
|
2022-08-02 23:58:43 +02:00
|
|
|
: m_bInitialized(false)
|
|
|
|
, m_nConnIndex(0)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2022-08-03 09:32:48 +02:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose:
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
CRConServer::~CRConServer(void)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2022-02-06 16:48:52 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
2022-02-14 23:16:24 +01:00
|
|
|
// Purpose: NETCON systems init
|
2022-02-06 16:48:52 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void CRConServer::Init(void)
|
|
|
|
{
|
2022-07-25 19:35:08 +02:00
|
|
|
if (!m_bInitialized)
|
2022-02-06 16:48:52 +01:00
|
|
|
{
|
2022-07-25 19:35:08 +02:00
|
|
|
if (!this->SetPassword(rcon_password->GetString()))
|
2022-02-08 16:32:00 +01:00
|
|
|
{
|
2022-07-25 19:35:08 +02:00
|
|
|
return;
|
2022-02-08 16:32:00 +01:00
|
|
|
}
|
2022-02-06 16:48:52 +01:00
|
|
|
}
|
|
|
|
|
2022-11-14 21:00:41 +01:00
|
|
|
m_Adr2.SetIPAndPort(rcon_address->GetString(), hostport->GetString());
|
|
|
|
m_Socket.CreateListenSocket(m_Adr2, false);
|
2022-02-06 16:48:52 +01:00
|
|
|
|
2022-02-08 16:32:00 +01:00
|
|
|
DevMsg(eDLL_T::SERVER, "Remote server access initialized\n");
|
2022-02-06 16:48:52 +01:00
|
|
|
m_bInitialized = true;
|
|
|
|
}
|
|
|
|
|
2022-02-14 23:16:24 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose: NETCON systems shutdown
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void CRConServer::Shutdown(void)
|
|
|
|
{
|
2022-11-14 21:00:41 +01:00
|
|
|
if (m_Socket.IsListening())
|
2022-02-14 23:16:24 +01:00
|
|
|
{
|
2022-11-14 21:00:41 +01:00
|
|
|
m_Socket.CloseListenSocket();
|
2022-02-14 23:16:24 +01:00
|
|
|
}
|
|
|
|
m_bInitialized = false;
|
|
|
|
}
|
|
|
|
|
2022-02-06 16:48:52 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
2022-02-08 16:32:00 +01:00
|
|
|
// Purpose: run tasks for the RCON server
|
2022-02-06 16:48:52 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void CRConServer::Think(void)
|
|
|
|
{
|
2022-11-14 21:00:41 +01:00
|
|
|
const int nCount = m_Socket.GetAcceptedSocketCount();
|
2022-02-08 16:32:00 +01:00
|
|
|
|
|
|
|
// Close redundant sockets if there are too many except for whitelisted and authenticated.
|
|
|
|
if (nCount >= sv_rcon_maxsockets->GetInt())
|
|
|
|
{
|
|
|
|
for (m_nConnIndex = nCount - 1; m_nConnIndex >= 0; m_nConnIndex--)
|
|
|
|
{
|
2022-11-14 21:00:41 +01:00
|
|
|
const CNetAdr2 netAdr2 = m_Socket.GetAcceptedSocketAddress(m_nConnIndex);
|
2022-08-03 09:32:48 +02:00
|
|
|
if (netAdr2.GetIP(true).compare(sv_rcon_whitelist_address->GetString()) != 0)
|
2022-02-08 16:32:00 +01:00
|
|
|
{
|
2022-11-14 21:00:41 +01:00
|
|
|
const CConnectedNetConsoleData* pData = m_Socket.GetAcceptedSocketData(m_nConnIndex);
|
2022-02-08 16:32:00 +01:00
|
|
|
if (!pData->m_bAuthorized)
|
|
|
|
{
|
2022-02-14 23:16:24 +01:00
|
|
|
this->CloseConnection();
|
2022-02-08 16:32:00 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-13 15:10:38 +01:00
|
|
|
// Create a new listen socket if authenticated connection is closed.
|
2022-02-08 16:32:00 +01:00
|
|
|
if (nCount == 0)
|
|
|
|
{
|
2022-11-14 21:00:41 +01:00
|
|
|
if (!m_Socket.IsListening())
|
2022-02-08 16:32:00 +01:00
|
|
|
{
|
2022-11-14 21:00:41 +01:00
|
|
|
m_Socket.CreateListenSocket(m_Adr2, false);
|
2022-02-08 16:32:00 +01:00
|
|
|
}
|
|
|
|
}
|
2022-02-06 16:48:52 +01:00
|
|
|
}
|
|
|
|
|
2022-07-25 19:35:08 +02:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose: changes the password
|
|
|
|
// Input : *pszPassword -
|
|
|
|
// Output : true on success, false otherwise
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
bool CRConServer::SetPassword(const char* pszPassword)
|
|
|
|
{
|
|
|
|
m_bInitialized = false;
|
2022-11-14 21:00:41 +01:00
|
|
|
m_Socket.CloseAllAcceptedSockets();
|
2022-07-25 19:35:08 +02:00
|
|
|
|
2022-11-14 21:00:41 +01:00
|
|
|
const size_t nLen = std::strlen(pszPassword);
|
2022-08-11 11:07:45 +02:00
|
|
|
if (nLen < 8)
|
2022-07-25 19:35:08 +02:00
|
|
|
{
|
2022-08-11 11:07:45 +02:00
|
|
|
if (nLen > 0)
|
2022-07-25 19:35:08 +02:00
|
|
|
{
|
|
|
|
Warning(eDLL_T::SERVER, "Remote server access requires a password of at least 8 characters\n");
|
|
|
|
}
|
2022-08-11 11:07:45 +02:00
|
|
|
|
2022-07-25 19:35:08 +02:00
|
|
|
this->Shutdown();
|
|
|
|
return false;
|
|
|
|
}
|
2022-08-11 11:07:45 +02:00
|
|
|
|
2022-07-25 19:35:08 +02:00
|
|
|
m_svPasswordHash = sha256(pszPassword);
|
|
|
|
DevMsg(eDLL_T::SERVER, "Password hash ('%s')\n", m_svPasswordHash.c_str());
|
|
|
|
|
|
|
|
m_bInitialized = true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-02-06 16:48:52 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose: server RCON main loop (run this every frame)
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void CRConServer::RunFrame(void)
|
|
|
|
{
|
|
|
|
if (m_bInitialized)
|
|
|
|
{
|
2022-11-14 21:00:41 +01:00
|
|
|
m_Socket.RunFrame();
|
2022-02-08 16:32:00 +01:00
|
|
|
this->Think();
|
|
|
|
this->Recv();
|
2022-02-06 16:48:52 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2022-08-02 23:58:43 +02:00
|
|
|
// Purpose: send message to all connected sockets
|
2022-02-13 15:16:09 +01:00
|
|
|
// Input : *svMessage -
|
2022-02-06 16:48:52 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
2022-02-13 15:10:38 +01:00
|
|
|
void CRConServer::Send(const std::string& svMessage) const
|
2022-02-06 16:48:52 +01:00
|
|
|
{
|
2022-11-14 21:00:41 +01:00
|
|
|
if (const int nCount = m_Socket.GetAcceptedSocketCount())
|
2022-02-06 16:48:52 +01:00
|
|
|
{
|
2022-08-02 23:58:43 +02:00
|
|
|
std::ostringstream ssSendBuf;
|
2022-11-14 21:00:41 +01:00
|
|
|
const u_long nLen = htonl(svMessage.size());
|
2022-02-06 16:48:52 +01:00
|
|
|
|
2022-11-14 21:00:41 +01:00
|
|
|
ssSendBuf.write(reinterpret_cast<const char*>(&nLen), sizeof(u_long));
|
|
|
|
ssSendBuf.write(svMessage.data(), svMessage.size());
|
2022-08-02 23:58:43 +02:00
|
|
|
|
|
|
|
for (int i = nCount - 1; i >= 0; i--)
|
2022-02-08 16:32:00 +01:00
|
|
|
{
|
2022-11-14 21:00:41 +01:00
|
|
|
CConnectedNetConsoleData* pData = m_Socket.GetAcceptedSocketData(i);
|
2022-08-02 23:58:43 +02:00
|
|
|
|
|
|
|
if (pData->m_bAuthorized)
|
|
|
|
{
|
2022-08-03 09:32:48 +02:00
|
|
|
::send(pData->m_hSocket, ssSendBuf.str().data(), static_cast<int>(ssSendBuf.str().size()), MSG_NOSIGNAL);
|
2022-08-02 23:58:43 +02:00
|
|
|
}
|
2022-02-08 16:32:00 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-02 23:58:43 +02:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose: send message to specific connected socket
|
|
|
|
// Input : hSocket -
|
|
|
|
// *svMessage -
|
|
|
|
//-----------------------------------------------------------------------------
|
2022-11-14 21:00:41 +01:00
|
|
|
void CRConServer::Send(const SocketHandle_t hSocket, const std::string& svMessage) const
|
2022-08-02 23:58:43 +02:00
|
|
|
{
|
|
|
|
std::ostringstream ssSendBuf;
|
2022-11-14 21:00:41 +01:00
|
|
|
const u_long nLen = htonl(svMessage.size());
|
2022-08-02 23:58:43 +02:00
|
|
|
|
2022-11-14 21:00:41 +01:00
|
|
|
ssSendBuf.write(reinterpret_cast<const char*>(&nLen), sizeof(u_long));
|
|
|
|
ssSendBuf.write(svMessage.data(), svMessage.size());
|
2022-08-02 23:58:43 +02:00
|
|
|
|
|
|
|
::send(hSocket, ssSendBuf.str().data(), static_cast<int>(ssSendBuf.str().size()), MSG_NOSIGNAL);
|
|
|
|
}
|
|
|
|
|
2022-08-17 02:20:04 +02:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose: send serialized message to all connected sockets
|
|
|
|
// Input : *svRspBuf -
|
|
|
|
// *svRspVal -
|
|
|
|
// responseType -
|
|
|
|
// nResponseId -
|
|
|
|
//-----------------------------------------------------------------------------
|
2022-11-14 21:00:41 +01:00
|
|
|
void CRConServer::Send(const std::string& svRspBuf, const std::string& svRspVal, const sv_rcon::response_t responseType, const int nResponseId)
|
2022-08-17 02:20:04 +02:00
|
|
|
{
|
|
|
|
if (responseType == sv_rcon::response_t::SERVERDATA_RESPONSE_CONSOLE_LOG)
|
|
|
|
{
|
|
|
|
if (!sv_rcon_sendlogs->GetBool())
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this->Send(this->Serialize(svRspBuf, svRspVal, responseType, nResponseId));
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose: send serialized message to specific connected socket
|
|
|
|
// Input : hSocket -
|
|
|
|
// *svRspBuf -
|
|
|
|
// *svRspVal -
|
|
|
|
// responseType -
|
|
|
|
// nResponseId -
|
|
|
|
//-----------------------------------------------------------------------------
|
2022-11-14 21:00:41 +01:00
|
|
|
void CRConServer::Send(const SocketHandle_t hSocket, const std::string& svRspBuf, const std::string& svRspVal, const sv_rcon::response_t responseType, const int nResponseId)
|
2022-08-17 02:20:04 +02:00
|
|
|
{
|
|
|
|
if (responseType == sv_rcon::response_t::SERVERDATA_RESPONSE_CONSOLE_LOG)
|
|
|
|
{
|
|
|
|
if (!sv_rcon_sendlogs->GetBool())
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this->Send(hSocket, this->Serialize(svRspBuf, svRspVal, responseType, nResponseId));
|
|
|
|
}
|
|
|
|
|
2022-02-08 16:32:00 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
2022-02-13 15:10:38 +01:00
|
|
|
// Purpose: receive message
|
2022-02-08 16:32:00 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void CRConServer::Recv(void)
|
|
|
|
{
|
2022-11-14 21:00:41 +01:00
|
|
|
const int nCount = m_Socket.GetAcceptedSocketCount();
|
2022-08-03 18:34:44 +02:00
|
|
|
static char szRecvBuf[1024];
|
2022-02-08 16:32:00 +01:00
|
|
|
|
|
|
|
for (m_nConnIndex = nCount - 1; m_nConnIndex >= 0; m_nConnIndex--)
|
|
|
|
{
|
2022-11-14 21:00:41 +01:00
|
|
|
CConnectedNetConsoleData* pData = m_Socket.GetAcceptedSocketData(m_nConnIndex);
|
2022-02-06 16:48:52 +01:00
|
|
|
{//////////////////////////////////////////////
|
2022-02-14 23:16:24 +01:00
|
|
|
if (this->CheckForBan(pData))
|
2022-02-06 16:48:52 +01:00
|
|
|
{
|
2022-08-17 12:28:52 +02:00
|
|
|
this->Send(pData->m_hSocket, this->Serialize(s_pszBannedMessage, "", sv_rcon::response_t::SERVERDATA_RESPONSE_AUTH, static_cast<int>(EGlobalContext_t::NETCON_S)));
|
2022-02-13 15:10:38 +01:00
|
|
|
this->CloseConnection();
|
2022-02-06 16:48:52 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2022-11-14 21:00:41 +01:00
|
|
|
const int nPendingLen = ::recv(pData->m_hSocket, szRecvBuf, sizeof(char), MSG_PEEK);
|
|
|
|
if (nPendingLen == SOCKET_ERROR && m_Socket.IsSocketBlocking())
|
2022-02-06 16:48:52 +01:00
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (nPendingLen <= 0) // EOF or error.
|
|
|
|
{
|
2022-02-13 15:10:38 +01:00
|
|
|
this->CloseConnection();
|
2022-02-06 16:48:52 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}//////////////////////////////////////////////
|
|
|
|
|
|
|
|
u_long nReadLen; // Find out how much we have to read.
|
2022-02-08 16:32:00 +01:00
|
|
|
::ioctlsocket(pData->m_hSocket, FIONREAD, &nReadLen);
|
2022-02-06 16:48:52 +01:00
|
|
|
|
2022-02-13 15:10:38 +01:00
|
|
|
while (nReadLen > 0)
|
2022-02-06 16:48:52 +01:00
|
|
|
{
|
2022-11-14 21:00:41 +01:00
|
|
|
const int nRecvLen = ::recv(pData->m_hSocket, szRecvBuf, MIN(sizeof(szRecvBuf), nReadLen), MSG_NOSIGNAL);
|
2022-02-06 16:48:52 +01:00
|
|
|
if (nRecvLen == 0) // Socket was closed.
|
|
|
|
{
|
2022-02-13 15:10:38 +01:00
|
|
|
this->CloseConnection();
|
2022-02-06 16:48:52 +01:00
|
|
|
break;
|
|
|
|
}
|
2022-11-14 21:00:41 +01:00
|
|
|
if (nRecvLen < 0 && !m_Socket.IsSocketBlocking())
|
2022-02-06 16:48:52 +01:00
|
|
|
{
|
2022-09-14 01:14:51 +02:00
|
|
|
Error(eDLL_T::SERVER, NO_ERROR, "RCON Cmd: recv error (%s)\n", NET_ErrorString(WSAGetLastError()));
|
2022-02-06 16:48:52 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2022-02-13 15:10:38 +01:00
|
|
|
nReadLen -= nRecvLen; // Process what we've got.
|
|
|
|
this->ProcessBuffer(szRecvBuf, nRecvLen, pData);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose: serializes input
|
2022-02-13 15:16:09 +01:00
|
|
|
// Input : *svRspBuf -
|
|
|
|
// *svRspVal -
|
2022-08-17 02:20:04 +02:00
|
|
|
// responseType -
|
2022-02-13 15:10:38 +01:00
|
|
|
// Output : serialized results as string
|
|
|
|
//-----------------------------------------------------------------------------
|
2022-11-14 21:00:41 +01:00
|
|
|
std::string CRConServer::Serialize(const std::string& svRspBuf, const std::string& svRspVal, const sv_rcon::response_t responseType, const int nResponseId) const
|
2022-02-13 15:10:38 +01:00
|
|
|
{
|
|
|
|
sv_rcon::response sv_response;
|
2022-02-06 16:48:52 +01:00
|
|
|
|
2022-08-03 18:34:44 +02:00
|
|
|
sv_response.set_responseid(nResponseId);
|
2022-08-17 02:20:04 +02:00
|
|
|
sv_response.set_responsetype(responseType);
|
2022-02-13 15:10:38 +01:00
|
|
|
|
2022-08-17 02:20:04 +02:00
|
|
|
switch (responseType)
|
2022-02-13 15:10:38 +01:00
|
|
|
{
|
|
|
|
case sv_rcon::response_t::SERVERDATA_RESPONSE_AUTH:
|
|
|
|
{
|
|
|
|
sv_response.set_responsebuf(svRspBuf);
|
2022-08-17 11:50:40 +02:00
|
|
|
sv_response.set_responseval(svRspVal);
|
2022-02-13 15:10:38 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case sv_rcon::response_t::SERVERDATA_RESPONSE_CONSOLE_LOG:
|
|
|
|
{
|
|
|
|
sv_response.set_responsebuf(svRspBuf);
|
2022-08-17 11:50:40 +02:00
|
|
|
sv_response.set_responseval(svRspVal);
|
2022-02-13 15:10:38 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
break;
|
2022-02-06 16:48:52 +01:00
|
|
|
}
|
|
|
|
}
|
2022-08-02 23:58:43 +02:00
|
|
|
return sv_response.SerializeAsString();
|
2022-02-13 15:10:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose: de-serializes input
|
2022-02-13 15:16:09 +01:00
|
|
|
// Input : *svBuf -
|
2022-02-13 15:10:38 +01:00
|
|
|
// Output : de-serialized object
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
cl_rcon::request CRConServer::Deserialize(const std::string& svBuf) const
|
|
|
|
{
|
|
|
|
cl_rcon::request cl_request;
|
2022-08-02 23:58:43 +02:00
|
|
|
cl_request.ParseFromArray(svBuf.data(), static_cast<int>(svBuf.size()));
|
2022-02-13 15:10:38 +01:00
|
|
|
|
|
|
|
return cl_request;
|
2022-02-06 16:48:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose: authenticate new connections
|
2022-02-13 15:16:09 +01:00
|
|
|
// Input : *cl_request -
|
|
|
|
// *pData -
|
2022-02-06 16:48:52 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
2022-02-13 15:10:38 +01:00
|
|
|
void CRConServer::Authenticate(const cl_rcon::request& cl_request, CConnectedNetConsoleData* pData)
|
2022-02-06 16:48:52 +01:00
|
|
|
{
|
|
|
|
if (pData->m_bAuthorized)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2022-08-02 23:58:43 +02:00
|
|
|
else // Authorize.
|
2022-02-06 16:48:52 +01:00
|
|
|
{
|
2022-05-07 03:06:19 +02:00
|
|
|
if (this->Comparator(cl_request.requestbuf()))
|
2022-02-14 03:02:38 +01:00
|
|
|
{
|
2022-02-06 16:48:52 +01:00
|
|
|
pData->m_bAuthorized = true;
|
2022-11-14 21:00:41 +01:00
|
|
|
m_Socket.CloseListenSocket();
|
2022-02-24 16:44:33 +01:00
|
|
|
|
2022-08-02 23:58:43 +02:00
|
|
|
this->CloseNonAuthConnection();
|
2022-08-17 12:28:52 +02:00
|
|
|
this->Send(pData->m_hSocket, this->Serialize(s_pszAuthMessage, sv_rcon_sendlogs->GetString(), sv_rcon::response_t::SERVERDATA_RESPONSE_AUTH, static_cast<int>(EGlobalContext_t::NETCON_S)));
|
2022-02-06 16:48:52 +01:00
|
|
|
}
|
|
|
|
else // Bad password.
|
|
|
|
{
|
2022-11-14 21:00:41 +01:00
|
|
|
const CNetAdr2 netAdr2 = m_Socket.GetAcceptedSocketAddress(m_nConnIndex);
|
2022-02-14 03:02:38 +01:00
|
|
|
if (sv_rcon_debug->GetBool())
|
|
|
|
{
|
|
|
|
DevMsg(eDLL_T::SERVER, "Bad RCON password attempt from '%s'\n", netAdr2.GetIPAndPort().c_str());
|
|
|
|
}
|
2022-02-13 15:10:38 +01:00
|
|
|
|
2022-08-17 12:28:52 +02:00
|
|
|
this->Send(pData->m_hSocket, this->Serialize(s_pszWrongPwMessage, "", sv_rcon::response_t::SERVERDATA_RESPONSE_AUTH, static_cast<int>(EGlobalContext_t::NETCON_S)));
|
2022-02-06 16:48:52 +01:00
|
|
|
|
|
|
|
pData->m_bAuthorized = false;
|
2022-05-13 21:41:03 +02:00
|
|
|
pData->m_bValidated = false;
|
2022-02-06 16:48:52 +01:00
|
|
|
pData->m_nFailedAttempts++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-14 03:02:38 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose: sha256 hashed password comparison
|
2022-08-17 02:20:04 +02:00
|
|
|
// Input : svCompare -
|
2022-02-14 03:02:38 +01:00
|
|
|
// Output : true if matches, false otherwise
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
bool CRConServer::Comparator(std::string svPassword) const
|
|
|
|
{
|
|
|
|
svPassword = sha256(svPassword);
|
|
|
|
if (sv_rcon_debug->GetBool())
|
|
|
|
{
|
|
|
|
DevMsg(eDLL_T::SERVER, "+---------------------------------------------------------------------------+\n");
|
|
|
|
DevMsg(eDLL_T::SERVER, "] Server: '%s'[\n", m_svPasswordHash.c_str());
|
|
|
|
DevMsg(eDLL_T::SERVER, "] Client: '%s'[\n", svPassword.c_str());
|
|
|
|
DevMsg(eDLL_T::SERVER, "+---------------------------------------------------------------------------+\n");
|
|
|
|
}
|
2022-08-17 02:20:04 +02:00
|
|
|
if (std::memcmp(svPassword.data(), m_svPasswordHash.data(), SHA256::DIGEST_SIZE) == 0)
|
2022-02-14 03:02:38 +01:00
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-02-06 16:48:52 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
2022-08-02 23:58:43 +02:00
|
|
|
// Purpose: parses input response buffer using length-prefix framing
|
|
|
|
// Input : *pRecvBuf -
|
2022-02-08 16:32:00 +01:00
|
|
|
// nRecvLen -
|
|
|
|
// *pData -
|
2022-02-06 16:48:52 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
2022-08-02 23:58:43 +02:00
|
|
|
void CRConServer::ProcessBuffer(const char* pRecvBuf, int nRecvLen, CConnectedNetConsoleData* pData)
|
2022-02-06 16:48:52 +01:00
|
|
|
{
|
2022-08-02 23:58:43 +02:00
|
|
|
while (nRecvLen > 0)
|
2022-02-06 16:48:52 +01:00
|
|
|
{
|
2022-08-02 23:58:43 +02:00
|
|
|
if (pData->m_nPayloadLen)
|
2022-02-06 16:48:52 +01:00
|
|
|
{
|
2022-08-02 23:58:43 +02:00
|
|
|
if (pData->m_nPayloadRead < pData->m_nPayloadLen)
|
2022-02-06 16:48:52 +01:00
|
|
|
{
|
2022-08-02 23:58:43 +02:00
|
|
|
pData->m_RecvBuffer[pData->m_nPayloadRead++] = *pRecvBuf;
|
|
|
|
|
|
|
|
pRecvBuf++;
|
|
|
|
nRecvLen--;
|
|
|
|
}
|
|
|
|
if (pData->m_nPayloadRead == pData->m_nPayloadLen)
|
|
|
|
{
|
|
|
|
this->ProcessMessage(this->Deserialize(std::string(
|
|
|
|
reinterpret_cast<char*>(pData->m_RecvBuffer.data()), pData->m_nPayloadLen)));
|
|
|
|
|
|
|
|
pData->m_nPayloadLen = 0;
|
|
|
|
pData->m_nPayloadRead = 0;
|
2022-02-06 16:48:52 +01:00
|
|
|
}
|
|
|
|
}
|
2022-11-14 21:00:41 +01:00
|
|
|
else if (pData->m_nPayloadRead < sizeof(u_long)) // Read size field.
|
2022-08-02 23:58:43 +02:00
|
|
|
{
|
|
|
|
pData->m_RecvBuffer[pData->m_nPayloadRead++] = *pRecvBuf;
|
|
|
|
|
|
|
|
pRecvBuf++;
|
|
|
|
nRecvLen--;
|
|
|
|
}
|
|
|
|
else // Build prefix.
|
2022-02-06 16:48:52 +01:00
|
|
|
{
|
2022-11-14 21:00:41 +01:00
|
|
|
pData->m_nPayloadLen = ntohl(*reinterpret_cast<u_long*>(&pData->m_RecvBuffer[0]));
|
2022-08-02 23:58:43 +02:00
|
|
|
pData->m_nPayloadRead = 0;
|
|
|
|
|
|
|
|
if (!pData->m_bAuthorized)
|
2022-02-06 16:48:52 +01:00
|
|
|
{
|
2022-08-02 23:58:43 +02:00
|
|
|
if (pData->m_nPayloadLen > MAX_NETCONSOLE_INPUT_LEN)
|
|
|
|
{
|
|
|
|
this->CloseConnection(); // Sending large messages while not authenticated.
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-03 18:41:25 +02:00
|
|
|
if (pData->m_nPayloadLen < 0 ||
|
|
|
|
pData->m_nPayloadLen > pData->m_RecvBuffer.max_size())
|
2022-08-02 23:58:43 +02:00
|
|
|
{
|
2022-09-14 01:14:51 +02:00
|
|
|
Error(eDLL_T::SERVER, NO_ERROR, "RCON Cmd: sync error (%d)\n", pData->m_nPayloadLen);
|
2022-08-02 23:58:43 +02:00
|
|
|
this->CloseConnection(); // Out of sync (irrecoverable).
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pData->m_RecvBuffer.resize(pData->m_nPayloadLen);
|
2022-02-06 16:48:52 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-13 15:10:38 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose: processes received message
|
|
|
|
// Input : *cl_request -
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void CRConServer::ProcessMessage(const cl_rcon::request& cl_request)
|
|
|
|
{
|
2022-11-14 21:00:41 +01:00
|
|
|
CConnectedNetConsoleData* pData = m_Socket.GetAcceptedSocketData(m_nConnIndex);
|
2022-02-13 15:10:38 +01:00
|
|
|
|
|
|
|
if (!pData->m_bAuthorized
|
|
|
|
&& cl_request.requesttype() != cl_rcon::request_t::SERVERDATA_REQUEST_AUTH)
|
|
|
|
{
|
|
|
|
// Notify net console that authentication is required.
|
2022-08-17 12:28:52 +02:00
|
|
|
this->Send(pData->m_hSocket, this->Serialize(s_pszNoAuthMessage, "", sv_rcon::response_t::SERVERDATA_RESPONSE_AUTH, static_cast<int>(EGlobalContext_t::NETCON_S)));
|
2022-02-13 15:10:38 +01:00
|
|
|
|
2022-05-13 21:41:03 +02:00
|
|
|
pData->m_bValidated = false;
|
2022-02-13 15:10:38 +01:00
|
|
|
pData->m_nIgnoredMessage++;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
switch (cl_request.requesttype())
|
|
|
|
{
|
|
|
|
case cl_rcon::request_t::SERVERDATA_REQUEST_AUTH:
|
|
|
|
{
|
|
|
|
this->Authenticate(cl_request, pData);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case cl_rcon::request_t::SERVERDATA_REQUEST_EXECCOMMAND:
|
2022-08-02 23:58:43 +02:00
|
|
|
{
|
2022-09-09 19:47:31 +02:00
|
|
|
if (pData->m_bAuthorized) // Only execute if auth was successful.
|
2022-08-02 23:58:43 +02:00
|
|
|
{
|
|
|
|
this->Execute(cl_request, false);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2022-02-13 15:10:38 +01:00
|
|
|
case cl_rcon::request_t::SERVERDATA_REQUEST_SETVALUE:
|
|
|
|
{
|
|
|
|
if (pData->m_bAuthorized)
|
|
|
|
{
|
2022-08-02 23:58:43 +02:00
|
|
|
this->Execute(cl_request, true);
|
2022-02-13 15:10:38 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case cl_rcon::request_t::SERVERDATA_REQUEST_SEND_CONSOLE_LOG:
|
|
|
|
{
|
|
|
|
if (pData->m_bAuthorized)
|
|
|
|
{
|
2022-08-17 02:20:04 +02:00
|
|
|
sv_rcon_sendlogs->SetValue(true);
|
2022-02-13 15:10:38 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-06 16:48:52 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
2022-02-08 16:32:00 +01:00
|
|
|
// Purpose: execute commands issued from net console
|
2022-02-13 15:10:38 +01:00
|
|
|
// Input : *cl_request -
|
2022-08-02 23:58:43 +02:00
|
|
|
// bConVar -
|
2022-02-06 16:48:52 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
2022-11-14 21:00:41 +01:00
|
|
|
void CRConServer::Execute(const cl_rcon::request& cl_request, const bool bConVar) const
|
2022-02-06 16:48:52 +01:00
|
|
|
{
|
2022-08-04 00:21:48 +02:00
|
|
|
if (bConVar)
|
2022-02-13 15:10:38 +01:00
|
|
|
{
|
2022-08-04 00:21:48 +02:00
|
|
|
ConVar* pConVar = g_pCVar->FindVar(cl_request.requestbuf().c_str());
|
2022-08-04 11:06:56 +02:00
|
|
|
if (pConVar) // Only run if this is a ConVar.
|
2022-08-04 00:21:48 +02:00
|
|
|
{
|
|
|
|
pConVar->SetValue(cl_request.requestval().c_str());
|
|
|
|
}
|
2022-02-13 15:10:38 +01:00
|
|
|
}
|
2022-08-04 00:21:48 +02:00
|
|
|
else // Execute command with "<val>".
|
2022-02-13 15:10:38 +01:00
|
|
|
{
|
2022-05-07 03:06:19 +02:00
|
|
|
Cbuf_AddText(Cbuf_GetCurrentPlayer(), cl_request.requestbuf().c_str(), cmd_source_t::kCommandSrcCode);
|
2022-02-13 15:10:38 +01:00
|
|
|
}
|
2022-02-06 16:48:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2022-02-08 16:32:00 +01:00
|
|
|
// Purpose: checks for amount of failed attempts and bans net console accordingly
|
|
|
|
// Input : *pData -
|
2022-02-06 16:48:52 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
2022-02-08 16:32:00 +01:00
|
|
|
bool CRConServer::CheckForBan(CConnectedNetConsoleData* pData)
|
2022-02-06 16:48:52 +01:00
|
|
|
{
|
2022-05-13 21:41:03 +02:00
|
|
|
if (pData->m_bValidated)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
pData->m_bValidated = true;
|
2022-11-14 21:00:41 +01:00
|
|
|
CNetAdr2 netAdr2 = m_Socket.GetAcceptedSocketAddress(m_nConnIndex);
|
2022-02-06 16:48:52 +01:00
|
|
|
|
2022-11-14 21:00:41 +01:00
|
|
|
// Check if IP is in the banned list.
|
|
|
|
if (std::find(m_vBannedList.begin(), m_vBannedList.end(),
|
|
|
|
netAdr2.GetIP(true)) != m_vBannedList.end())
|
2022-02-06 16:48:52 +01:00
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-11-14 21:00:41 +01:00
|
|
|
// Check if net console has reached maximum number of attempts > add to banned list.
|
2022-02-08 16:32:00 +01:00
|
|
|
if (pData->m_nFailedAttempts >= sv_rcon_maxfailures->GetInt()
|
|
|
|
|| pData->m_nIgnoredMessage >= sv_rcon_maxignores->GetInt())
|
2022-02-06 16:48:52 +01:00
|
|
|
{
|
2022-11-14 21:00:41 +01:00
|
|
|
// Don't add white listed address to banned list.
|
2022-08-03 09:32:48 +02:00
|
|
|
if (netAdr2.GetIP(true).compare(sv_rcon_whitelist_address->GetString()) == 0)
|
2022-02-08 16:32:00 +01:00
|
|
|
{
|
|
|
|
pData->m_nFailedAttempts = 0;
|
|
|
|
pData->m_nIgnoredMessage = 0;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
DevMsg(eDLL_T::SERVER, "Banned '%s' for RCON hacking attempts\n", netAdr2.GetIPAndPort().c_str());
|
2022-11-14 21:00:41 +01:00
|
|
|
m_vBannedList.push_back(netAdr2.GetIP(true));
|
2022-02-06 16:48:52 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2022-02-08 16:32:00 +01:00
|
|
|
// Purpose: close specific connection
|
2022-02-06 16:48:52 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
2022-02-08 16:32:00 +01:00
|
|
|
void CRConServer::CloseConnection(void) // NETMGR
|
2022-02-06 16:48:52 +01:00
|
|
|
{
|
2022-11-14 21:00:41 +01:00
|
|
|
CConnectedNetConsoleData* pData = m_Socket.GetAcceptedSocketData(m_nConnIndex);
|
2022-02-24 16:44:33 +01:00
|
|
|
if (pData->m_bAuthorized)
|
|
|
|
{
|
|
|
|
// Inform server owner when authenticated connection has been closed.
|
2022-11-14 21:00:41 +01:00
|
|
|
CNetAdr2 netAdr2 = m_Socket.GetAcceptedSocketAddress(m_nConnIndex);
|
2022-02-24 16:44:33 +01:00
|
|
|
DevMsg(eDLL_T::SERVER, "Net console '%s' closed RCON connection\n", netAdr2.GetIPAndPort().c_str());
|
|
|
|
}
|
2022-11-14 21:00:41 +01:00
|
|
|
m_Socket.CloseAcceptedSocket(m_nConnIndex);
|
2022-02-06 16:48:52 +01:00
|
|
|
}
|
|
|
|
|
2022-02-08 16:32:00 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose: close all connections except for authenticated
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void CRConServer::CloseNonAuthConnection(void)
|
|
|
|
{
|
2022-11-14 21:00:41 +01:00
|
|
|
int nCount = m_Socket.GetAcceptedSocketCount();
|
2022-02-08 16:32:00 +01:00
|
|
|
for (int i = nCount - 1; i >= 0; i--)
|
|
|
|
{
|
2022-11-14 21:00:41 +01:00
|
|
|
CConnectedNetConsoleData* pData = m_Socket.GetAcceptedSocketData(i);
|
2022-02-08 16:32:00 +01:00
|
|
|
|
|
|
|
if (!pData->m_bAuthorized)
|
|
|
|
{
|
2022-11-14 21:00:41 +01:00
|
|
|
m_Socket.CloseAcceptedSocket(i);
|
2022-02-08 16:32:00 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-08-11 11:07:45 +02:00
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose: checks if server rcon is initialized
|
|
|
|
// Output : true if initialized, false otherwise
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
bool CRConServer::IsInitialized(void) const
|
|
|
|
{
|
|
|
|
return m_bInitialized;
|
|
|
|
}
|
|
|
|
|
2022-02-08 16:32:00 +01:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
2022-11-14 21:00:41 +01:00
|
|
|
CRConServer g_RCONServer;
|
|
|
|
CRConServer* RCONServer() // Singleton RCON Server.
|
2022-07-25 19:35:08 +02:00
|
|
|
{
|
2022-11-14 21:00:41 +01:00
|
|
|
return &g_RCONServer;
|
2022-07-25 19:35:08 +02:00
|
|
|
}
|