2022-02-06 16:48:52 +01:00
|
|
|
//=============================================================================//
|
|
|
|
//
|
|
|
|
// Purpose: Net system utilities
|
|
|
|
//
|
|
|
|
//=============================================================================//
|
|
|
|
|
|
|
|
#include "core/stdafx.h"
|
|
|
|
#include "engine/net.h"
|
2022-04-02 02:48:54 +02:00
|
|
|
#ifndef NETCONSOLE
|
|
|
|
#include "core/logdef.h"
|
2022-08-27 18:57:56 +02:00
|
|
|
#include "tier0/frametask.h"
|
2022-04-09 16:16:40 +02:00
|
|
|
#include "tier1/cvar.h"
|
2022-05-16 21:15:25 +02:00
|
|
|
#include "vstdlib/callback.h"
|
2022-04-02 02:48:54 +02:00
|
|
|
#include "mathlib/color.h"
|
|
|
|
#include "engine/net.h"
|
|
|
|
#include "engine/net_chan.h"
|
|
|
|
#ifndef CLIENT_DLL
|
2022-05-20 20:14:39 +02:00
|
|
|
#include "engine/server/server.h"
|
2022-05-20 11:52:19 +02:00
|
|
|
#include "engine/client/client.h"
|
2022-04-02 02:48:54 +02:00
|
|
|
#endif // !CLIENT_DLL
|
|
|
|
#endif // !NETCONSOLE
|
|
|
|
|
|
|
|
#ifndef NETCONSOLE
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose: hook and log the receive datagram
|
2022-04-24 19:32:47 +02:00
|
|
|
// Input : iSocket -
|
|
|
|
// *pInpacket -
|
|
|
|
// bEncrypted -
|
|
|
|
// Output : true on success, false otherwise
|
2022-04-02 02:48:54 +02:00
|
|
|
//-----------------------------------------------------------------------------
|
2022-04-24 19:32:47 +02:00
|
|
|
bool NET_ReceiveDatagram(int iSocket, netpacket_s* pInpacket, bool bEncrypted)
|
2022-04-02 02:48:54 +02:00
|
|
|
{
|
2022-04-27 18:22:08 +02:00
|
|
|
bool result = v_NET_ReceiveDatagram(iSocket, pInpacket, net_encryptionEnable->GetBool());
|
|
|
|
if (result && net_tracePayload->GetBool())
|
2022-04-02 02:48:54 +02:00
|
|
|
{
|
|
|
|
// Log received packet data.
|
2022-05-17 23:00:30 +02:00
|
|
|
HexDump("[+] NET_ReceiveDatagram", "net_trace", &pInpacket->pData[NULL], pInpacket->wiresize);
|
2022-04-02 02:48:54 +02:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose: hook and log the send datagram
|
2022-04-24 19:32:47 +02:00
|
|
|
// Input : s -
|
|
|
|
// *pPayload -
|
|
|
|
// iLenght -
|
|
|
|
// *pAdr -
|
2022-04-27 18:22:08 +02:00
|
|
|
// bEncrypt -
|
2022-04-24 19:32:47 +02:00
|
|
|
// Output : outgoing sequence number for this packet
|
2022-04-02 02:48:54 +02:00
|
|
|
//-----------------------------------------------------------------------------
|
2022-04-27 18:22:08 +02:00
|
|
|
int NET_SendDatagram(SOCKET s, void* pPayload, int iLenght, v_netadr_t* pAdr, bool bEncrypt)
|
2022-04-02 02:48:54 +02:00
|
|
|
{
|
2022-04-27 18:22:08 +02:00
|
|
|
int result = v_NET_SendDatagram(s, pPayload, iLenght, pAdr, net_encryptionEnable->GetBool());
|
|
|
|
if (result && net_tracePayload->GetBool())
|
2022-04-02 02:48:54 +02:00
|
|
|
{
|
|
|
|
// Log transmitted packet data.
|
2022-05-17 23:00:30 +02:00
|
|
|
HexDump("[+] NET_SendDatagram", "net_trace", pPayload, iLenght);
|
2022-04-02 02:48:54 +02:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose: sets the user specified encryption key
|
2022-08-30 20:04:59 +02:00
|
|
|
// Input : svNetKey -
|
2022-04-02 02:48:54 +02:00
|
|
|
//-----------------------------------------------------------------------------
|
2022-08-30 20:04:59 +02:00
|
|
|
void NET_SetKey(string svNetKey)
|
2022-04-02 02:48:54 +02:00
|
|
|
{
|
2022-08-30 01:22:53 +02:00
|
|
|
std::lock_guard<std::mutex> l(g_NetKeyMutex);
|
|
|
|
|
2022-08-30 20:04:59 +02:00
|
|
|
if (svNetKey.size() == AES_128_B64_ENCODED_SIZE &&
|
|
|
|
IsValidBase64(svNetKey))
|
|
|
|
{
|
|
|
|
g_svNetKey = svNetKey; // Results are tokenized by 'IsValidBase64()'.
|
|
|
|
v_NET_SetKey(g_pNetKey, g_svNetKey.c_str());
|
2022-08-30 01:22:53 +02:00
|
|
|
|
2022-08-30 20:04:59 +02:00
|
|
|
DevMsg(eDLL_T::ENGINE, "Installed NetKey: '%s%s%s'\n",
|
|
|
|
g_svGreyB.c_str(), g_svNetKey.c_str(), g_svReset.c_str());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-09-14 01:14:51 +02:00
|
|
|
Error(eDLL_T::ENGINE, NO_ERROR, "AES-128 key not encoded or invalid\n");
|
2022-08-30 20:04:59 +02:00
|
|
|
}
|
2022-04-02 02:48:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose: calculates and sets the encryption key
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void NET_GenerateKey()
|
|
|
|
{
|
2022-08-30 01:22:53 +02:00
|
|
|
if (!net_useRandomKey->GetBool())
|
2022-08-30 12:10:07 +02:00
|
|
|
{
|
2022-08-30 01:22:53 +02:00
|
|
|
net_useRandomKey->SetValue(1);
|
2022-08-30 12:10:07 +02:00
|
|
|
return; // Change callback will handle this.
|
|
|
|
}
|
2022-04-02 02:48:54 +02:00
|
|
|
|
|
|
|
BCRYPT_ALG_HANDLE hAlgorithm;
|
|
|
|
if (BCryptOpenAlgorithmProvider(&hAlgorithm, L"RNG", 0, 0) < 0)
|
|
|
|
{
|
2022-09-14 01:14:51 +02:00
|
|
|
Error(eDLL_T::ENGINE, NO_ERROR, "Failed to open rng algorithm\n");
|
2022-04-02 02:48:54 +02:00
|
|
|
return;
|
|
|
|
}
|
2022-08-30 01:22:53 +02:00
|
|
|
|
|
|
|
uint8_t pBuffer[AES_128_KEY_SIZE];
|
|
|
|
if (BCryptGenRandom(hAlgorithm, pBuffer, AES_128_KEY_SIZE, 0) < 0)
|
2022-04-02 02:48:54 +02:00
|
|
|
{
|
2022-09-14 01:14:51 +02:00
|
|
|
Error(eDLL_T::ENGINE, NO_ERROR, "Failed to generate random data\n");
|
2022-04-02 02:48:54 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-08-30 01:22:53 +02:00
|
|
|
NET_SetKey(Base64Encode(string(reinterpret_cast<char*>(&pBuffer), AES_128_KEY_SIZE)));
|
2022-04-02 02:48:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose: hook and log the client's signonstate to the console
|
2022-04-24 19:32:47 +02:00
|
|
|
// Input : *fmt -
|
|
|
|
// ... -
|
2022-04-02 02:48:54 +02:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void NET_PrintFunc(const char* fmt, ...)
|
|
|
|
{
|
|
|
|
static char buf[1024];
|
2022-09-11 23:45:06 +02:00
|
|
|
#ifndef DEDICATED
|
|
|
|
const static eDLL_T context = eDLL_T::CLIENT;
|
|
|
|
#else // !DEDICATED
|
|
|
|
const static eDLL_T context = eDLL_T::SERVER;
|
|
|
|
#endif
|
2022-04-02 02:48:54 +02:00
|
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
|
|
|
|
|
|
|
vsnprintf(buf, sizeof(buf), fmt, args);
|
|
|
|
|
2022-08-09 15:19:12 +02:00
|
|
|
buf[sizeof(buf) - 1] = '\0';
|
2022-04-02 02:48:54 +02:00
|
|
|
va_end(args);
|
|
|
|
|
2022-09-11 23:45:06 +02:00
|
|
|
DevMsg(context, "%s", buf);
|
2022-04-02 02:48:54 +02:00
|
|
|
}
|
|
|
|
|
2022-04-24 19:32:47 +02:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose: shutdown netchannel
|
|
|
|
// Input : *this -
|
|
|
|
// *szReason -
|
2022-05-12 01:20:19 +02:00
|
|
|
// bBadRep -
|
2022-04-24 19:32:47 +02:00
|
|
|
// bRemoveNow -
|
|
|
|
//-----------------------------------------------------------------------------
|
2022-05-12 01:20:19 +02:00
|
|
|
void NET_Shutdown(void* thisptr, const char* szReason, uint8_t bBadRep, bool bRemoveNow)
|
2022-04-24 19:32:47 +02:00
|
|
|
{
|
2022-08-27 18:57:56 +02:00
|
|
|
if (!ThreadInMainThread())
|
|
|
|
{
|
|
|
|
g_TaskScheduler->Dispatch([]()
|
|
|
|
{
|
|
|
|
// Re-load playlist from disk the next frame.
|
|
|
|
_DownloadPlaylists_f();
|
|
|
|
}, 0);
|
|
|
|
}
|
2022-05-12 01:20:19 +02:00
|
|
|
v_NET_Shutdown(thisptr, szReason, bBadRep, bRemoveNow);
|
2022-04-24 19:32:47 +02:00
|
|
|
}
|
|
|
|
|
2022-04-02 02:48:54 +02:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose: disconnect the client and shutdown netchannel
|
2022-04-24 19:32:47 +02:00
|
|
|
// Input : *pClient -
|
|
|
|
// nIndex -
|
|
|
|
// *szReason -
|
2022-05-12 01:20:19 +02:00
|
|
|
// bBadRep -
|
|
|
|
// bRemoveNow -
|
2022-04-02 02:48:54 +02:00
|
|
|
//-----------------------------------------------------------------------------
|
2022-05-20 11:52:19 +02:00
|
|
|
void NET_DisconnectClient(CClient* pClient, int nIndex, const char* szReason, uint8_t bBadRep, bool bRemoveNow)
|
2022-04-02 02:48:54 +02:00
|
|
|
{
|
|
|
|
#ifndef CLIENT_DLL
|
|
|
|
if (!pClient || std::strlen(szReason) == NULL || !pClient->GetNetChan())
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-05-12 01:20:19 +02:00
|
|
|
v_NET_Shutdown(pClient->GetNetChan(), szReason, bBadRep, bRemoveNow); // Shutdown netchan.
|
2022-05-21 18:56:56 +02:00
|
|
|
pClient->Clear(); // Reset CClient instance for client.
|
2022-05-13 11:26:44 +02:00
|
|
|
g_bIsPersistenceVarSet[nIndex] = false; // Reset Persistence var.
|
2022-04-02 02:48:54 +02:00
|
|
|
#endif // !CLIENT_DLL
|
|
|
|
}
|
|
|
|
#endif // !NETCONSOLE
|
2022-02-06 16:48:52 +01:00
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose: returns the WSA error code
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
const char* NET_ErrorString(int iCode)
|
|
|
|
{
|
|
|
|
switch (iCode)
|
|
|
|
{
|
2022-08-09 10:55:31 +02:00
|
|
|
case WSAEINTR : return "WSAEINTR";
|
|
|
|
case WSAEBADF : return "WSAEBADF";
|
|
|
|
case WSAEACCES : return "WSAEACCES";
|
|
|
|
case WSAEFAULT : return "WSAEFAULT";
|
|
|
|
case WSAEINVAL : return "WSAEINVAL";
|
|
|
|
case WSAEMFILE : return "WSAEMFILE";
|
|
|
|
case WSAEWOULDBLOCK : return "WSAEWOULDBLOCK";
|
|
|
|
case WSAEINPROGRESS : return "WSAEINPROGRESS";
|
|
|
|
case WSAEALREADY : return "WSAEALREADY";
|
|
|
|
case WSAENOTSOCK : return "WSAENOTSOCK";
|
|
|
|
case WSAEDESTADDRREQ : return "WSAEDESTADDRREQ";
|
|
|
|
case WSAEMSGSIZE : return "WSAEMSGSIZE";
|
|
|
|
case WSAEPROTOTYPE : return "WSAEPROTOTYPE";
|
|
|
|
case WSAENOPROTOOPT : return "WSAENOPROTOOPT";
|
|
|
|
case WSAEPROTONOSUPPORT : return "WSAEPROTONOSUPPORT";
|
|
|
|
case WSAESOCKTNOSUPPORT : return "WSAESOCKTNOSUPPORT";
|
|
|
|
case WSAEOPNOTSUPP : return "WSAEOPNOTSUPP";
|
|
|
|
case WSAEPFNOSUPPORT : return "WSAEPFNOSUPPORT";
|
|
|
|
case WSAEAFNOSUPPORT : return "WSAEAFNOSUPPORT";
|
|
|
|
case WSAEADDRINUSE : return "WSAEADDRINUSE";
|
|
|
|
case WSAEADDRNOTAVAIL : return "WSAEADDRNOTAVAIL";
|
|
|
|
case WSAENETDOWN : return "WSAENETDOWN";
|
|
|
|
case WSAENETUNREACH : return "WSAENETUNREACH";
|
|
|
|
case WSAENETRESET : return "WSAENETRESET";
|
|
|
|
case WSAECONNABORTED : return "WSWSAECONNABORTEDAEINTR";
|
|
|
|
case WSAECONNRESET : return "WSAECONNRESET";
|
|
|
|
case WSAENOBUFS : return "WSAENOBUFS";
|
|
|
|
case WSAEISCONN : return "WSAEISCONN";
|
|
|
|
case WSAENOTCONN : return "WSAENOTCONN";
|
|
|
|
case WSAESHUTDOWN : return "WSAESHUTDOWN";
|
|
|
|
case WSAETOOMANYREFS : return "WSAETOOMANYREFS";
|
|
|
|
case WSAETIMEDOUT : return "WSAETIMEDOUT";
|
|
|
|
case WSAECONNREFUSED : return "WSAECONNREFUSED";
|
|
|
|
case WSAELOOP : return "WSAELOOP";
|
|
|
|
case WSAENAMETOOLONG : return "WSAENAMETOOLONG";
|
|
|
|
case WSAEHOSTDOWN : return "WSAEHOSTDOWN";
|
|
|
|
case WSAEHOSTUNREACH : return "WSAEHOSTUNREACH";
|
|
|
|
case WSAENOTEMPTY : return "WSAENOTEMPTY";
|
|
|
|
case WSAEPROCLIM : return "WSAEPROCLIM";
|
|
|
|
case WSAEUSERS : return "WSAEUSERS";
|
|
|
|
case WSAEDQUOT : return "WSAEDQUOT";
|
|
|
|
case WSAESTALE : return "WSAESTALE";
|
|
|
|
case WSAEREMOTE : return "WSAEREMOTE";
|
|
|
|
case WSASYSNOTREADY : return "WSASYSNOTREADY";
|
|
|
|
case WSAVERNOTSUPPORTED : return "WSAVERNOTSUPPORTED";
|
|
|
|
case WSANOTINITIALISED : return "WSANOTINITIALISED";
|
|
|
|
case WSAEDISCON : return "WSAEDISCON";
|
|
|
|
case WSAENOMORE : return "WSAENOMORE";
|
|
|
|
case WSAECANCELLED : return "WSAECANCELLED";
|
|
|
|
case WSAEINVALIDPROCTABLE : return "WSAEINVALIDPROCTABLE";
|
|
|
|
case WSAEINVALIDPROVIDER : return "WSAEINVALIDPROVIDER";
|
|
|
|
case WSAEPROVIDERFAILEDINIT : return "WSAEPROVIDERFAILEDINIT";
|
|
|
|
case WSASYSCALLFAILURE : return "WSASYSCALLFAILURE";
|
|
|
|
case WSASERVICE_NOT_FOUND : return "WSASERVICE_NOT_FOUND";
|
|
|
|
case WSATYPE_NOT_FOUND : return "WSATYPE_NOT_FOUND";
|
|
|
|
case WSA_E_NO_MORE : return "WSA_E_NO_MORE";
|
|
|
|
case WSA_E_CANCELLED : return "WSA_E_CANCELLED";
|
|
|
|
case WSAEREFUSED : return "WSAEREFUSED";
|
|
|
|
case WSAHOST_NOT_FOUND : return "WSAHOST_NOT_FOUND";
|
|
|
|
case WSATRY_AGAIN : return "WSATRY_AGAIN";
|
|
|
|
case WSANO_RECOVERY : return "WSANO_RECOVERY";
|
|
|
|
case WSANO_DATA : return "WSANO_DATA";
|
|
|
|
case WSA_QOS_RECEIVERS : return "WSA_QOS_RECEIVERS";
|
|
|
|
case WSA_QOS_SENDERS : return "WSA_QOS_SENDERS";
|
|
|
|
case WSA_QOS_NO_SENDERS : return "WSA_QOS_NO_SENDERS";
|
|
|
|
case WSA_QOS_NO_RECEIVERS : return "WSA_QOS_NO_RECEIVERS";
|
|
|
|
case WSA_QOS_REQUEST_CONFIRMED : return "WSA_QOS_REQUEST_CONFIRMED";
|
|
|
|
case WSA_QOS_ADMISSION_FAILURE : return "WSA_QOS_ADMISSION_FAILURE";
|
|
|
|
case WSA_QOS_POLICY_FAILURE : return "WSA_QOS_POLICY_FAILURE";
|
|
|
|
case WSA_QOS_BAD_STYLE : return "WSA_QOS_BAD_STYLE";
|
|
|
|
case WSA_QOS_BAD_OBJECT : return "WSA_QOS_BAD_OBJECT";
|
|
|
|
case WSA_QOS_TRAFFIC_CTRL_ERROR : return "WSA_QOS_TRAFFIC_CTRL_ERROR";
|
|
|
|
case WSA_QOS_GENERIC_ERROR : return "WSA_QOS_GENERIC_ERROR";
|
|
|
|
case WSA_QOS_ESERVICETYPE : return "WSA_QOS_ESERVICETYPE";
|
|
|
|
case WSA_QOS_EFLOWSPEC : return "WSA_QOS_EFLOWSPEC";
|
|
|
|
case WSA_QOS_EPROVSPECBUF : return "WSA_QOS_EPROVSPECBUF";
|
|
|
|
case WSA_QOS_EFILTERSTYLE : return "WSA_QOS_EFILTERSTYLE";
|
|
|
|
case WSA_QOS_EFILTERTYPE : return "WSA_QOS_EFILTERTYPE";
|
|
|
|
case WSA_QOS_EFILTERCOUNT : return "WSA_QOS_EFILTERCOUNT";
|
|
|
|
case WSA_QOS_EOBJLENGTH : return "WSA_QOS_EOBJLENGTH";
|
|
|
|
case WSA_QOS_EFLOWCOUNT : return "WSA_QOS_EFLOWCOUNT";
|
|
|
|
case WSA_QOS_EUNKOWNPSOBJ : return "WSA_QOS_EUNKOWNPSOBJ";
|
|
|
|
case WSA_QOS_EPOLICYOBJ : return "WSA_QOS_EPOLICYOBJ";
|
|
|
|
case WSA_QOS_EFLOWDESC : return "WSA_QOS_EFLOWDESC";
|
|
|
|
case WSA_QOS_EPSFLOWSPEC : return "WSA_QOS_EPSFLOWSPEC";
|
|
|
|
case WSA_QOS_EPSFILTERSPEC : return "WSA_QOS_EPSFILTERSPEC";
|
|
|
|
case WSA_QOS_ESDMODEOBJ : return "WSA_QOS_ESDMODEOBJ";
|
|
|
|
case WSA_QOS_ESHAPERATEOBJ : return "WSA_QOS_ESHAPERATEOBJ";
|
|
|
|
case WSA_QOS_RESERVED_PETYPE : return "WSA_QOS_RESERVED_PETYPE";
|
|
|
|
case WSA_SECURE_HOST_NOT_FOUND : return "WSA_SECURE_HOST_NOT_FOUND";
|
|
|
|
case WSA_IPSEC_NAME_POLICY_ERROR: return "WSA_IPSEC_NAME_POLICY_ERROR";
|
2022-04-02 02:48:54 +02:00
|
|
|
default : return "UNKNOWN_ERROR";
|
2022-02-06 16:48:52 +01:00
|
|
|
}
|
|
|
|
}
|
2022-04-02 02:48:54 +02:00
|
|
|
|
|
|
|
#ifndef NETCONSOLE
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
void NET_Attach()
|
|
|
|
{
|
2022-04-27 18:22:08 +02:00
|
|
|
DetourAttach((LPVOID*)&v_NET_ReceiveDatagram, &NET_ReceiveDatagram);
|
|
|
|
DetourAttach((LPVOID*)&v_NET_SendDatagram, &NET_SendDatagram);
|
2022-04-02 02:48:54 +02:00
|
|
|
DetourAttach((LPVOID*)&v_NET_PrintFunc, &NET_PrintFunc);
|
|
|
|
#ifndef DEDICATED
|
2022-04-24 19:32:47 +02:00
|
|
|
DetourAttach((LPVOID*)&v_NET_Shutdown, &NET_Shutdown);
|
2022-04-02 02:48:54 +02:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void NET_Detach()
|
|
|
|
{
|
2022-04-27 18:22:08 +02:00
|
|
|
DetourDetach((LPVOID*)&v_NET_ReceiveDatagram, &NET_ReceiveDatagram);
|
|
|
|
DetourDetach((LPVOID*)&v_NET_SendDatagram, &NET_SendDatagram);
|
2022-04-02 02:48:54 +02:00
|
|
|
DetourDetach((LPVOID*)&v_NET_PrintFunc, &NET_PrintFunc);
|
|
|
|
#ifndef DEDICATED
|
2022-04-24 19:32:47 +02:00
|
|
|
DetourDetach((LPVOID*)&v_NET_Shutdown, &NET_Shutdown);
|
2022-04-02 02:48:54 +02:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
2022-08-30 12:10:07 +02:00
|
|
|
string g_svNetKey = DEFAULT_NET_ENCRYPTION_KEY;
|
2022-04-18 03:35:08 +02:00
|
|
|
uintptr_t g_pNetKey = NULL;
|
2022-04-02 02:48:54 +02:00
|
|
|
#endif // !NETCONSOLE
|