updated gamedata and updated extension to kick dead left over sessions that would be caused by being blocked by ISP on first connect to to server and then on second connect using a VPN instead. also changes how nosteamers attempting to spoof are handled so that a nosteamer could change IP address on a reconnect and still be allowed in

This commit is contained in:
jenz 2026-03-19 15:38:02 +00:00
parent 3a126db081
commit 86c714fb1b
2 changed files with 66 additions and 93 deletions

View File

@ -53,14 +53,6 @@
"windows64" "\x48\x89\x5C\x24\x2A\x44\x89\x4C\x24\x2A\x55\x56\x57\x41\x54\x41\x55\x41\x56\x41\x57\x48\x81\xEC\x80\x05\x00\x00" "windows64" "\x48\x89\x5C\x24\x2A\x44\x89\x4C\x24\x2A\x55\x56\x57\x41\x54\x41\x55\x41\x56\x41\x57\x48\x81\xEC\x80\x05\x00\x00"
} }
"CBaseServer__CheckChallengeType"
{
"library" "engine"
"linux" "@_ZN11CBaseServer18CheckChallengeTypeEP11CBaseClientiR8netadr_siPKcii"
"mac" "@_ZN11CBaseServer18CheckChallengeTypeEP11CBaseClientiR8netadr_siPKcii"
"windows" "\x55\x8B\xEC\x83\xEC\x14\x56\x57\x8B\x7D\x14\x8B\xF1"
}
"CBaseServer__RejectConnection" "CBaseServer__RejectConnection"
{ {
"library" "engine" "library" "engine"
@ -70,15 +62,6 @@
"windows64" "\x48\x89\x5C\x24\x2A\x48\x89\x6C\x24\x2A\x48\x89\x74\x24\x2A\x57\x48\x81\xEC\x50\x05\x00\x00" "windows64" "\x48\x89\x5C\x24\x2A\x48\x89\x6C\x24\x2A\x48\x89\x74\x24\x2A\x57\x48\x81\xEC\x50\x05\x00\x00"
} }
"CBaseClient__SetSteamID"
{
"library" "engine"
"linux" "@_ZN11CBaseClient10SetSteamIDERK8CSteamID"
"linux64" "@_ZN11CBaseClient10SetSteamIDERK8CSteamID"
"windows" "\x55\x8B\xEC\x56\x8B\xF1\x57\x8B\x7D\x08\x8D\x4E\x04"
"windows64" "\x48\x89\x5C\x24\x2A\x57\x48\x83\xEC\x20\x48\x8B\x02\x48\x8B\xD9\x48\x89\x41"
}
"CBaseServer__CheckMasterServerRequestRestart" "CBaseServer__CheckMasterServerRequestRestart"
{ {
"library" "engine" "library" "engine"
@ -86,62 +69,11 @@
"windows64" "\x4C\x8B\xDC\x49\x89\x5B\x2A\x49\x89\x6B\x2A\x56\x57\x41\x54\x41\x56\x41\x57\x48\x83\xEC\x60\x48\x8B\x05\x2A\x2A\x2A\x2A\x48\x8D\x1D" "windows64" "\x4C\x8B\xDC\x49\x89\x5B\x2A\x49\x89\x6B\x2A\x56\x57\x41\x54\x41\x56\x41\x57\x48\x83\xEC\x60\x48\x8B\x05\x2A\x2A\x2A\x2A\x48\x8D\x1D"
} }
"NET_SendPacket"
{
"library" "engine"
"linux" "@_Z14NET_SendPacketP11INetChanneliRK8netadr_sPKhiP8bf_writeb"
}
"NET_CheckCleanupFakeIPConnection"
{
"library" "engine"
"linux" "@_Z32NET_CheckCleanupFakeIPConnectioniRK8netadr_s"
}
"CSteam3Server__OnValidateAuthTicketResponse" "CSteam3Server__OnValidateAuthTicketResponse"
{ {
"library" "engine" "library" "engine"
"linux" "@_ZN13CSteam3Server28OnValidateAuthTicketResponseEP28ValidateAuthTicketResponse_t" "linux" "@_ZN13CSteam3Server28OnValidateAuthTicketResponseEP28ValidateAuthTicketResponse_t"
} }
"s_queryRateChecker"
{
"library" "engine"
"linux" "@_ZL18s_queryRateChecker"
}
"CIPRateLimit__CheckIP"
{
"library" "engine"
"linux" "@_ZN12CIPRateLimit7CheckIPE8netadr_s"
}
"CBaseServer__ValidChallenge"
{
"library" "engine"
"linux" "@_ZN11CBaseServer14ValidChallengeER8netadr_si"
}
"CBaseServer__InactivateClients"
{
"library" "engine"
"linux" "@_ZN11CBaseServer17InactivateClientsEv"
}
"net_sockets"
{
"library" "engine"
"linux" "@_ZL11net_sockets"
}
"hltv"
{
"library" "engine"
"linux" "@hltv"
}
"net_time"
{
"library" "engine"
"linux" "@net_time"
}
} }
} }
} }

View File

@ -23,6 +23,8 @@
#include "steam/steamclientpublic.h" #include "steam/steamclientpublic.h"
#include "steam/isteamclient.h" #include "steam/isteamclient.h"
#include <iclient.h> #include <iclient.h>
#include <ISDKTools.h>
#include <iserver.h>
#include <string> #include <string>
Connect g_connect; Connect g_connect;
@ -39,6 +41,8 @@ ConVar g_SvMapName("sv_mapname_override", "default", FCVAR_NOTIFY, "Overwrite th
IGameConfig *g_pGameConf = NULL; IGameConfig *g_pGameConf = NULL;
IForward *g_pConnectForward = NULL; IForward *g_pConnectForward = NULL;
IServer *iserver = NULL;
ISDKTools *g_pSDKTools = NULL;
class IClient; class IClient;
class CBaseServer; class CBaseServer;
@ -59,23 +63,6 @@ typedef enum EAuthProtocol
k_EBeginAuthSessionResultExpiredTicket = 5, // Ticket has expired k_EBeginAuthSessionResultExpiredTicket = 5, // Ticket has expired
*/ */
typedef struct netadr_s
{
private:
typedef enum
{
NA_NULL = 0,
NA_LOOPBACK,
NA_BROADCAST,
NA_IP,
} netadrtype_t;
public:
netadrtype_t type;
unsigned char ip[4];
unsigned short port;
} netadr_t;
const char *CSteamID::Render() const const char *CSteamID::Render() const
{ {
static char szSteamID[64]; static char szSteamID[64];
@ -239,6 +226,7 @@ public:
bool GotValidateAuthTicketResponse; bool GotValidateAuthTicketResponse;
bool SteamLegal; bool SteamLegal;
bool SteamAuthFailed; bool SteamAuthFailed;
bool ManualRetry;
void *pvTicket; void *pvTicket;
int cbTicket; int cbTicket;
@ -261,6 +249,7 @@ public:
this->GotValidateAuthTicketResponse = false; this->GotValidateAuthTicketResponse = false;
this->SteamLegal = false; this->SteamLegal = false;
this->SteamAuthFailed = false; this->SteamAuthFailed = false;
this->ManualRetry = false;
// Calculate and store the ticket pointer // Calculate and store the ticket pointer
this->pvTicket = (void *)((intptr_t)this->pCookie + sizeof(uint64)); this->pvTicket = (void *)((intptr_t)this->pCookie + sizeof(uint64));
@ -282,7 +271,7 @@ DETOUR_DECL_MEMBER1(CSteam3Server__OnValidateAuthTicketResponse, int, ValidateAu
} }
ConnectClientStorage Storage; ConnectClientStorage Storage;
if(g_ConnectClientStorage.retrieve(aSteamID, &Storage)) if (g_ConnectClientStorage.retrieve(aSteamID, &Storage))
{ {
if(!Storage.GotValidateAuthTicketResponse) if(!Storage.GotValidateAuthTicketResponse)
{ {
@ -291,8 +280,40 @@ DETOUR_DECL_MEMBER1(CSteam3Server__OnValidateAuthTicketResponse, int, ValidateAu
Storage.SteamLegal = SteamLegal; Storage.SteamLegal = SteamLegal;
g_ConnectClientStorage.replace(aSteamID, Storage); g_ConnectClientStorage.replace(aSteamID, Storage);
} }
//2026 march 17th: resolve (STEAM UserID [xxxxxx] is already in use on this server)
//we handle it here in the detour before CheckForDuplicateSteamID() is called.
//confirm that this client actually did a manual retry
if (Storage.ManualRetry)
{
if (!Storage.pClient || !Storage.pClient->IsConnected())
{
return DETOUR_MEMBER_CALL(CSteam3Server__OnValidateAuthTicketResponse)(pResponse);
} }
USERID_t clientID = Storage.pClient->GetNetworkID();
//two scenarios related to nosteam trying to spoof steam players.
//1: nosteamer trying to spoof active steam player on the server. should already be handled by MEMBER9 function comparing IP address and rejecting if nosteam
//2: nosteamer trying to spoof steam player not on the server right now. handled by PlayerManager_Connection kicking nosteamers with message "Trying to join with a legitimate steamid while not authenticated with steam."
for (int i = 0; i < iserver->GetClientCount(); i++)
{
IClient* pSlot = iserver->GetClient(i);
if (pSlot && pSlot->IsConnected() && pSlot != Storage.pClient)
{
USERID_t slotID = pSlot->GetNetworkID();
if (slotID.idtype == IDTYPE_STEAM && clientID.idtype == IDTYPE_STEAM)
{
if (slotID.steamid == clientID.steamid)
{
g_pSM->LogMessage(myself, "Disconnecting idle left over session for steamID: %s", aSteamID);
pSlot->Disconnect("Disconnecting dead left over session.");
break;
}
}
}
}
}
}
return DETOUR_MEMBER_CALL(CSteam3Server__OnValidateAuthTicketResponse)(pResponse); return DETOUR_MEMBER_CALL(CSteam3Server__OnValidateAuthTicketResponse)(pResponse);
} }
@ -461,16 +482,30 @@ DETOUR_DECL_MEMBER9(CBaseServer__ConnectClient, IClient*, netadr_t&, address, in
if(ExistingSteamid && !AsyncWaiting) if(ExistingSteamid && !AsyncWaiting)
{ {
Storage.ManualRetry = true;
// Another player trying to spoof a Steam ID or game crashed? // Another player trying to spoof a Steam ID or game crashed?
if(memcmp(address.ip, Storage.address.ip, sizeof(address.ip)) != 0) if(memcmp(address.ip, Storage.address.ip, sizeof(address.ip)) != 0)
{ {
// Reject NoSteam players // Is a nosteam player
if(SteamAuthFailed) if(SteamAuthFailed)
{
//if the nosteam player is trying to spoof a steam player reject the nosteamer.
if (!Storage.SteamAuthFailed)
{ {
g_pSM->LogMessage(myself, "about to do rejectconnection 1. %s", aSteamID); g_pSM->LogMessage(myself, "about to do rejectconnection 1. %s", aSteamID);
g_pRejectConnectionFunc((CBaseServer*)this, address, iClientChallenge, "Steam ID already in use."); g_pRejectConnectionFunc((CBaseServer*)this, address, iClientChallenge, "Steam ID already in use.");
return NULL; return NULL;
} }
//a nosteamer connecting the first time could be blocked by their ISP and then on the second connect be using a VPN
//so if the original nosteamer is not connected and ingame we allow the nosteamer to take over the spot
//a nosteamer spoofing another nosteamer that is not ingame is fine too.
if (Storage.pClient && Storage.pClient->IsConnected() && Storage.pClient->IsActive())
{
g_pSM->LogMessage(myself, "about to do rejectconnection 2. %s", aSteamID);
g_pRejectConnectionFunc((CBaseServer*)this, address, iClientChallenge, "Steam ID already in use.");
return NULL;
}
}
// Kick existing player // Kick existing player
if(Storage.pClient) if(Storage.pClient)
@ -480,7 +515,7 @@ DETOUR_DECL_MEMBER9(CBaseServer__ConnectClient, IClient*, netadr_t&, address, in
} }
else else
{ {
g_pSM->LogMessage(myself, "about to do rejectconnection 2. %s", aSteamID); g_pSM->LogMessage(myself, "about to do rejectconnection 3. %s", aSteamID);
g_pRejectConnectionFunc((CBaseServer*)this, address, iClientChallenge, "Please try again later."); g_pRejectConnectionFunc((CBaseServer*)this, address, iClientChallenge, "Please try again later.");
return NULL; return NULL;
} }
@ -545,7 +580,6 @@ DETOUR_DECL_MEMBER9(CBaseServer__ConnectClient, IClient*, netadr_t&, address, in
//auto client = DETOUR_MEMBER_MCALL_ORIGINAL(CBaseServer__ConnectClient, this)(address, nProtocol, iChallenge, iClientChallenge, nAuthProtocol, pchName, pchPassword, pCookie, cbCookie); //auto client = DETOUR_MEMBER_MCALL_ORIGINAL(CBaseServer__ConnectClient, this)(address, nProtocol, iChallenge, iClientChallenge, nAuthProtocol, pchName, pchPassword, pCookie, cbCookie);
g_bSuppressBeginAuthSession = false; g_bSuppressBeginAuthSession = false;
g_pSM->LogMessage(myself, "finished DETOUR_MEMBER_CALL. %s", aSteamID); g_pSM->LogMessage(myself, "finished DETOUR_MEMBER_CALL. %s", aSteamID);
Storage.pClient = client; Storage.pClient = client;
g_ConnectClientStorage.replace(aSteamID, Storage); g_ConnectClientStorage.replace(aSteamID, Storage);
@ -791,5 +825,12 @@ const sp_nativeinfo_t MyNatives[] =
void Connect::SDK_OnAllLoaded() void Connect::SDK_OnAllLoaded()
{ {
SM_GET_LATE_IFACE(SDKTOOLS, g_pSDKTools);
iserver = g_pSDKTools->GetIServer();
if (!iserver) {
smutils->LogError(myself, "Failed to get IServer interface from SDKTools!");
return;
}
sharesys->AddNatives(myself, MyNatives); sharesys->AddNatives(myself, MyNatives);
} }