Make use of 'CConnectedNetConsoleData::m_bInputOnly' properly

This member was in the class when RCON was added to the r5sdk, but it was never utilized. Now, each netconsole can toggle whether they are input only or not, the server only sends logs to netconsoles that are not input only. This patch also contains a fix in which the listen server sends logs to the client of its own process, causing an infinite recursive call to DevMsg.
This commit is contained in:
Kawe Mazidjatari 2023-08-04 17:28:01 +02:00
parent 3a19ac0c24
commit f2783ae93f
9 changed files with 75 additions and 35 deletions

View File

@ -991,6 +991,18 @@ void RCON_Disconnect_f(const CCommand& args)
DevMsg(eDLL_T::CLIENT, "User closed RCON connection\n");
}
}
/*
=====================
RCON_SendLogs_f
request logs from RCON server
=====================
*/
void RCON_InputOnlyChanged_f(IConVar* pConVar, const char* pOldString, float flOldValue)
{
RCONClient()->RequestConsoleLog(RCONClient()->ShouldReceive());
}
#endif // !DEDICATED
#ifndef CLIENT_DLL

View File

@ -50,6 +50,7 @@ void CON_ClearHistory_f(const CCommand& args);
void RCON_CmdQuery_f(const CCommand& args);
void RCON_Disconnect_f(const CCommand& args);
void RCON_InputOnlyChanged_f(IConVar* pConVar, const char* pOldString, float flOldValue);
#endif // !DEDICATED
void RCON_PasswordChanged_f(IConVar* pConVar, const char* pOldString, float flOldValue);
#ifndef CLIENT_DLL

View File

@ -144,7 +144,7 @@ ConVar* bhit_abs_origin = nullptr;
//-----------------------------------------------------------------------------
// CLIENT |
#ifndef DEDICATED
ConVar* cl_rcon_request_sendlogs = nullptr;
ConVar* cl_rcon_inputonly = nullptr;
ConVar* cl_quota_stringCmdsPerSecond = nullptr;
ConVar* cl_cmdrate = nullptr;
@ -322,7 +322,7 @@ void ConVar_StaticInit(void)
sv_simulateBots = ConVar::StaticCreate("sv_simulateBots", "1", FCVAR_RELEASE, "Simulate user commands for bots on the server.", true, 0.f, false, 0.f, nullptr, nullptr);
sv_rcon_debug = ConVar::StaticCreate("sv_rcon_debug" , "0" , FCVAR_RELEASE, "Show rcon debug information ( !slower! ).", false, 0.f, false, 0.f, nullptr, nullptr);
sv_rcon_sendlogs = ConVar::StaticCreate("sv_rcon_sendlogs" , "0" , FCVAR_RELEASE, "Network console logs to connected and authenticated sockets.", false, 0.f, false, 0.f, nullptr, nullptr);
sv_rcon_sendlogs = ConVar::StaticCreate("sv_rcon_sendlogs" , "1" , FCVAR_RELEASE, "Network console logs to connected and authenticated sockets.", false, 0.f, false, 0.f, nullptr, nullptr);
sv_rcon_banpenalty = ConVar::StaticCreate("sv_rcon_banpenalty" , "10", FCVAR_RELEASE, "Number of minutes to ban users who fail rcon authentication.", false, 0.f, false, 0.f, nullptr, nullptr);
sv_rcon_maxfailures = ConVar::StaticCreate("sv_rcon_maxfailures", "10", FCVAR_RELEASE, "Max number of times a user can fail rcon authentication before being banned.", true, 1.f, false, 0.f, nullptr, nullptr);
sv_rcon_maxignores = ConVar::StaticCreate("sv_rcon_maxignores" , "15", FCVAR_RELEASE, "Max number of times a user can ignore the instruction message before being banned.", true, 1.f, false, 0.f, nullptr, nullptr);
@ -343,7 +343,7 @@ void ConVar_StaticInit(void)
//-------------------------------------------------------------------------
// CLIENT |
#ifndef DEDICATED
cl_rcon_request_sendlogs = ConVar::StaticCreate("cl_rcon_request_sendlogs", "1" , FCVAR_RELEASE, "Request the rcon server to send console logs on connect.", false, 0.f, false, 0.f, nullptr, nullptr);
cl_rcon_inputonly = ConVar::StaticCreate("cl_rcon_inputonly", "0" , FCVAR_RELEASE, "Tells the rcon server whether or not we are input only.", false, 0.f, false, 0.f, RCON_InputOnlyChanged_f, nullptr);
cl_quota_stringCmdsPerSecond = ConVar::StaticCreate("cl_quota_stringCmdsPerSecond", "16" , FCVAR_RELEASE, "How many string commands per second user is allowed to submit, 0 to allow all submissions.", true, 0.f, false, 0.f, nullptr, nullptr);
cl_notify_invert_x = ConVar::StaticCreate("cl_notify_invert_x", "0", FCVAR_DEVELOPMENTONLY, "Inverts the X offset for console notify debug overlay.", false, 0.f, false, 0.f, nullptr, nullptr);

View File

@ -133,7 +133,7 @@ extern ConVar* bhit_abs_origin;
//-------------------------------------------------------------------------
// CLIENT |
#ifndef DEDICATED
extern ConVar* cl_rcon_request_sendlogs;
extern ConVar* cl_rcon_inputonly;
extern ConVar* cl_quota_stringCmdsPerSecond;
extern ConVar* cl_cmdrate;

View File

@ -49,7 +49,7 @@ public:
m_nIgnoredMessage = 0;
m_bValidated = false;
m_bAuthorized = false;
m_bInputOnly = false;
m_bInputOnly = true;
m_RecvBuffer.resize(sizeof(u_long)); // Reserve enough for length-prefix.
}
};

View File

@ -103,33 +103,12 @@ bool CRConClient::ProcessMessage(const char* pMsgBuf, const int nMsgLen)
{
if (!response.responseval().empty())
{
const long i = strtol(response.responseval().c_str(), NULL, NULL);
const bool bLocalHost = (g_pNetAdr->ComparePort(m_Address) && g_pNetAdr->CompareAdr(m_Address));
const char* szEnable = nullptr;
const SocketHandle_t hSocket = GetSocket();
const int i = atoi(response.responseval().c_str());
if (!i) // sv_rcon_sendlogs is not set.
// '!i' means we are marked 'input only' on the rcon server.
if (!i && ShouldReceive())
{
if (!bLocalHost && cl_rcon_request_sendlogs->GetBool())
{
szEnable = "1";
}
}
else if (bLocalHost)
{
// Don't send logs to local host, it already gets logged to the same console.
szEnable = "0";
}
if (szEnable)
{
vector<char> vecMsg;
bool ret = Serialize(vecMsg, "", szEnable, cl_rcon::request_t::SERVERDATA_REQUEST_SEND_CONSOLE_LOG);
if (ret && !Send(hSocket, vecMsg.data(), int(vecMsg.size())))
{
Error(eDLL_T::CLIENT, NO_ERROR, "Failed to send RCON message: (%s)\n", "SOCKET_ERROR");
}
RequestConsoleLog(true);
}
}
@ -152,6 +131,31 @@ bool CRConClient::ProcessMessage(const char* pMsgBuf, const int nMsgLen)
return true;
}
//-----------------------------------------------------------------------------
// Purpose: request the rcon server to enable/disable sending logs to us
// Input : bWantLog -
//-----------------------------------------------------------------------------
void CRConClient::RequestConsoleLog(const bool bWantLog)
{
// If 'IsRemoteLocal()' returns true, and you called this with 'bWantLog'
// true, you caused a bug! It means the server address and port are equal
// to the global netadr singleton, which ultimately means we are running on
// a listen server. Listen server's already log to the same console,
// sending logs will cause the print func to get called recursively forever.
Assert(!(bWantLog && IsRemoteLocal()));
const char* szEnable = bWantLog ? "1" : "0";
const SocketHandle_t hSocket = GetSocket();
vector<char> vecMsg;
bool ret = Serialize(vecMsg, "", szEnable, cl_rcon::request_t::SERVERDATA_REQUEST_SEND_CONSOLE_LOG);
if (ret && !Send(hSocket, vecMsg.data(), int(vecMsg.size())))
{
Error(eDLL_T::CLIENT, NO_ERROR, "Failed to send RCON message: (%s)\n", "SOCKET_ERROR");
}
}
//-----------------------------------------------------------------------------
// Purpose: serializes input
// Input : *svReqBuf -
@ -183,6 +187,23 @@ SocketHandle_t CRConClient::GetSocket(void)
return SH_GetNetConSocketHandle(this, 0);
}
//-----------------------------------------------------------------------------
// Purpose: returns whether or not we should receive logs from the server
// Output : SOCKET_ERROR (-1) on failure
//-----------------------------------------------------------------------------
bool CRConClient::ShouldReceive(void)
{
return (!IsRemoteLocal() && !cl_rcon_inputonly->GetBool());
}
//-----------------------------------------------------------------------------
// Purpose: returns whether the rcon server is actually our own listen server
//-----------------------------------------------------------------------------
bool CRConClient::IsRemoteLocal(void)
{
return (g_pNetAdr->ComparePort(m_Address) && g_pNetAdr->CompareAdr(m_Address));
}
//-----------------------------------------------------------------------------
// Purpose: checks if client rcon is initialized
//-----------------------------------------------------------------------------

View File

@ -21,6 +21,10 @@ public:
bool Serialize(vector<char>& vecBuf, const char* szReqBuf,
const char* szReqVal, const cl_rcon::request_t requestType) const;
void RequestConsoleLog(const bool bWantLog);
bool ShouldReceive(void);
bool IsRemoteLocal(void);
bool IsInitialized(void) const;
bool IsConnected(void);

View File

@ -206,7 +206,7 @@ bool CRConServer::SendToAll(const char* pMsgBuf, const int nMsgLen) const
{
const CConnectedNetConsoleData& pData = m_Socket.GetAcceptedSocketData(i);
if (pData.m_bAuthorized)
if (pData.m_bAuthorized && !pData.m_bInputOnly)
{
int ret = ::send(pData.m_hSocket, sendbuf.str().data(),
int(sendbuf.str().size()), MSG_NOSIGNAL);
@ -334,7 +334,9 @@ void CRConServer::Authenticate(const cl_rcon::request& request, CConnectedNetCon
CloseNonAuthConnection();
}
SendEncode(pData.m_hSocket, s_AuthMessage, sv_rcon_sendlogs->GetString(),
const char* pSendLogs = (!sv_rcon_sendlogs->GetBool() || pData.m_bInputOnly) ? "0" : "1";
SendEncode(pData.m_hSocket, s_AuthMessage, pSendLogs,
sv_rcon::response_t::SERVERDATA_RESPONSE_AUTH, static_cast<int>(eDLL_T::NETCON));
}
else // Bad password.
@ -424,8 +426,8 @@ bool CRConServer::ProcessMessage(const char* pMsgBuf, const int nMsgLen)
{
if (pData.m_bAuthorized)
{
// !TODO[ AMOS ]: Each netcon its own var???
sv_rcon_sendlogs->SetValue(request.requestval().c_str());
// "0" means the netconsole is input only.
pData.m_bInputOnly = !atoi(request.requestval().c_str());
}
break;
}

View File

@ -283,7 +283,7 @@ bool CNetCon::ProcessMessage(const char* pMsgBuf, const int nMsgLen)
if (!response.responseval().empty())
{
const long i = strtol(response.responseval().c_str(), NULL, NULL);
if (!i) // sv_rcon_sendlogs is not set.
if (!i) // Means we are marked 'input only' on the rcon server.
{
vector<char> vecMsg;
bool ret = Serialize(vecMsg, "", "1", cl_rcon::request_t::SERVERDATA_REQUEST_SEND_CONSOLE_LOG);