diff --git a/connect2.games.txt b/connect2.games.txt index ae3485a..10e0e98 100644 --- a/connect2.games.txt +++ b/connect2.games.txt @@ -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" } - "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" { "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" } - "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" { "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" } - "NET_SendPacket" - { - "library" "engine" - "linux" "@_Z14NET_SendPacketP11INetChanneliRK8netadr_sPKhiP8bf_writeb" - } - - "NET_CheckCleanupFakeIPConnection" - { - "library" "engine" - "linux" "@_Z32NET_CheckCleanupFakeIPConnectioniRK8netadr_s" - } - "CSteam3Server__OnValidateAuthTicketResponse" { "library" "engine" "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" - } } } } diff --git a/extension/extension.cpp b/extension/extension.cpp index 57535d4..dbd645e 100644 --- a/extension/extension.cpp +++ b/extension/extension.cpp @@ -23,6 +23,8 @@ #include "steam/steamclientpublic.h" #include "steam/isteamclient.h" #include +#include +#include #include Connect g_connect; @@ -39,6 +41,8 @@ ConVar g_SvMapName("sv_mapname_override", "default", FCVAR_NOTIFY, "Overwrite th IGameConfig *g_pGameConf = NULL; IForward *g_pConnectForward = NULL; +IServer *iserver = NULL; +ISDKTools *g_pSDKTools = NULL; class IClient; class CBaseServer; @@ -59,23 +63,6 @@ typedef enum EAuthProtocol 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 { static char szSteamID[64]; @@ -239,6 +226,7 @@ public: bool GotValidateAuthTicketResponse; bool SteamLegal; bool SteamAuthFailed; + bool ManualRetry; void *pvTicket; int cbTicket; @@ -261,6 +249,7 @@ public: this->GotValidateAuthTicketResponse = false; this->SteamLegal = false; this->SteamAuthFailed = false; + this->ManualRetry = false; // Calculate and store the ticket pointer this->pvTicket = (void *)((intptr_t)this->pCookie + sizeof(uint64)); @@ -282,7 +271,7 @@ DETOUR_DECL_MEMBER1(CSteam3Server__OnValidateAuthTicketResponse, int, ValidateAu } ConnectClientStorage Storage; - if(g_ConnectClientStorage.retrieve(aSteamID, &Storage)) + if (g_ConnectClientStorage.retrieve(aSteamID, &Storage)) { if(!Storage.GotValidateAuthTicketResponse) { @@ -291,8 +280,40 @@ DETOUR_DECL_MEMBER1(CSteam3Server__OnValidateAuthTicketResponse, int, ValidateAu Storage.SteamLegal = SteamLegal; 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); } @@ -461,15 +482,29 @@ DETOUR_DECL_MEMBER9(CBaseServer__ConnectClient, IClient*, netadr_t&, address, in if(ExistingSteamid && !AsyncWaiting) { + Storage.ManualRetry = true; // Another player trying to spoof a Steam ID or game crashed? if(memcmp(address.ip, Storage.address.ip, sizeof(address.ip)) != 0) { - // Reject NoSteam players + // Is a nosteam player if(SteamAuthFailed) { - g_pSM->LogMessage(myself, "about to do rejectconnection 1. %s", aSteamID); - g_pRejectConnectionFunc((CBaseServer*)this, address, iClientChallenge, "Steam ID already in use."); - return NULL; + //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_pRejectConnectionFunc((CBaseServer*)this, address, iClientChallenge, "Steam ID already in use."); + 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 @@ -480,7 +515,7 @@ DETOUR_DECL_MEMBER9(CBaseServer__ConnectClient, IClient*, netadr_t&, address, in } 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."); 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); g_bSuppressBeginAuthSession = false; g_pSM->LogMessage(myself, "finished DETOUR_MEMBER_CALL. %s", aSteamID); - Storage.pClient = client; g_ConnectClientStorage.replace(aSteamID, Storage); @@ -791,5 +825,12 @@ const sp_nativeinfo_t MyNatives[] = 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); }