diff --git a/extension.cpp b/extension.cpp index a1be2cf..8055aff 100644 --- a/extension.cpp +++ b/extension.cpp @@ -49,26 +49,26 @@ size_t strlcpy(char *dst, const char *src, size_t dsize) { - const char *osrc = src; - size_t nleft = dsize; + const char *osrc = src; + size_t nleft = dsize; - /* Copy as many bytes as will fit. */ - if (nleft != 0) { - while (--nleft != 0) { - if ((*dst++ = *src++) == '\0') - break; - } - } + /* Copy as many bytes as will fit. */ + if (nleft != 0) { + while (--nleft != 0) { + if ((*dst++ = *src++) == '\0') + break; + } + } - /* Not enough room in dst, add NUL and traverse rest of src. */ - if (nleft == 0) { - if (dsize != 0) - *dst = '\0'; /* NUL-terminate dst */ - while (*src++) - ; - } + /* Not enough room in dst, add NUL and traverse rest of src. */ + if (nleft == 0) { + if (dsize != 0) + *dst = '\0'; /* NUL-terminate dst */ + while (*src++) + ; + } - return(src - osrc - 1); /* count does not include NUL */ + return(src - osrc - 1); /* count does not include NUL */ } /** @@ -76,7 +76,7 @@ strlcpy(char *dst, const char *src, size_t dsize) * @brief Implement extension code here. */ -Connect g_Connect; /**< Global singleton for extension's main interface */ +Connect g_Connect; /**< Global singleton for extension's main interface */ ConnectEvents g_ConnectEvents; ConnectTimer g_ConnectTimer; @@ -93,6 +93,7 @@ ConVar *g_pSvTags; IGameConfig *g_pGameConf = NULL; IForward *g_pConnectForward = NULL; +IForward *g_pOnBeginAuthSessionResult = NULL; IGameEventManager2 *g_pGameEvents = NULL; ITimer *g_pConnectTimer = NULL; ISDKTools *g_pSDKTools = NULL; @@ -107,23 +108,23 @@ char g_ClientSteamIDMap[SM_MAXPLAYERS + 1][32]; typedef struct netpacket_s { - netadr_t from; // sender IP - int source; // received source - double received; // received time - unsigned char *data; // pointer to raw packet data - bf_read message; // easy bitbuf data access - int size; // size in bytes - int wiresize; // size in bytes before decompression - bool stream; // was send as stream - struct netpacket_s *pNext; // for internal use, should be NULL in public + netadr_t from; // sender IP + int source; // received source + double received; // received time + unsigned char *data; // pointer to raw packet data + bf_read message; // easy bitbuf data access + int size; // size in bytes + int wiresize; // size in bytes before decompression + bool stream; // was send as stream + struct netpacket_s *pNext; // for internal use, should be NULL in public } netpacket_t; typedef struct { - int nPort; // UDP/TCP use same port number - bool bListening; // true if TCP port is listening - int hUDP; // handle to UDP socket from socket() - int hTCP; // handle to TCP socket from socket() + int nPort; // UDP/TCP use same port number + bool bListening; // true if TCP port is listening + int hUDP; // handle to UDP socket from socket() + int hTCP; // handle to TCP socket from socket() } netsocket_t; CUtlVector *net_sockets; @@ -137,52 +138,52 @@ bool (*CBaseServer__ValidChallenge)(void *pThis, netadr_t adr, int challengeNr); struct CQueryCache { - struct CPlayer - { - bool active; - bool fake; - int userid; - IClient *pClient; - char name[MAX_PLAYER_NAME_LENGTH]; - unsigned nameLen; - int32_t score; - double time; - } players[SM_MAXPLAYERS + 1]; + struct CPlayer + { + bool active; + bool fake; + int userid; + IClient *pClient; + char name[MAX_PLAYER_NAME_LENGTH]; + unsigned nameLen; + int32_t score; + double time; + } players[SM_MAXPLAYERS + 1]; - struct CInfo - { - uint8_t nProtocol = 17; // Protocol | byte | Protocol version used by the server. - char aHostName[255]; // Name | string | Name of the server. - uint8_t aHostNameLen; - char aMapName[255]; // Map | string | Map the server has currently loaded. - uint8_t aMapNameLen; - char aGameDir[255]; // Folder | string | Name of the folder containing the game files. - uint8_t aGameDirLen; - char aGameDescription[255]; // Game | string | Full name of the game. - uint8_t aGameDescriptionLen; - uint16_t iSteamAppID; // ID | short | Steam Application ID of game. - uint8_t nNumClients = 0; // Players | byte | Number of players on the server. - uint8_t nMaxClients; // Max. Players | byte | Maximum number of players the server reports it can hold. - uint8_t nFakeClients = 0; // Bots | byte | Number of bots on the server. - uint8_t nServerType = 'd'; // Server type | byte | Indicates the type of server: 'd' for a dedicated server, 'l' for a non-dedicated server, 'p' for a SourceTV relay (proxy) - uint8_t nEnvironment = 'l'; // Environment | byte | Indicates the operating system of the server: 'l' for Linux, 'w' for Windows, 'm' or 'o' for Mac (the code changed after L4D1) - uint8_t nPassword; // Visibility | byte | Indicates whether the server requires a password: 0 for public, 1 for private - uint8_t bIsSecure; // VAC | byte | Specifies whether the server uses VAC: 0 for unsecured, 1 for secured - char aVersion[40]; // Version | string | Version of the game installed on the server. - uint8_t aVersionLen; - uint8_t nNewFlags = 0; // Extra Data Flag (EDF) | byte | If present, this specifies which additional data fields will be included. - uint16_t iUDPPort; // EDF & 0x80 -> Port | short | The server's game port number. - uint64_t iSteamID; // EDF & 0x10 -> SteamID | long long | Server's SteamID. - uint16_t iHLTVUDPPort; // EDF & 0x40 -> Port | short | Spectator port number for SourceTV. - char aHLTVName[255]; // EDF & 0x40 -> Name | string | Name of the spectator server for SourceTV. - uint8_t aHLTVNameLen; - char aKeywords[255]; // EDF & 0x20 -> Keywords | string | Tags that describe the game according to the server (for future use.) (sv_tags) - uint8_t aKeywordsLen; - uint64_t iGameID; // EDF & 0x01 -> GameID | long long | The server's 64-bit GameID. If this is present, a more accurate AppID is present in the low 24 bits. The earlier AppID could have been truncated as it was forced into 16-bit storage. - } info; + struct CInfo + { + uint8_t nProtocol = 17; // Protocol | byte | Protocol version used by the server. + char aHostName[255]; // Name | string | Name of the server. + uint8_t aHostNameLen; + char aMapName[255]; // Map | string | Map the server has currently loaded. + uint8_t aMapNameLen; + char aGameDir[255]; // Folder | string | Name of the folder containing the game files. + uint8_t aGameDirLen; + char aGameDescription[255]; // Game | string | Full name of the game. + uint8_t aGameDescriptionLen; + uint16_t iSteamAppID; // ID | short | Steam Application ID of game. + uint8_t nNumClients = 0; // Players | byte | Number of players on the server. + uint8_t nMaxClients; // Max. Players | byte | Maximum number of players the server reports it can hold. + uint8_t nFakeClients = 0; // Bots | byte | Number of bots on the server. + uint8_t nServerType = 'd'; // Server type | byte | Indicates the type of server: 'd' for a dedicated server, 'l' for a non-dedicated server, 'p' for a SourceTV relay (proxy) + uint8_t nEnvironment = 'l'; // Environment | byte | Indicates the operating system of the server: 'l' for Linux, 'w' for Windows, 'm' or 'o' for Mac (the code changed after L4D1) + uint8_t nPassword; // Visibility | byte | Indicates whether the server requires a password: 0 for public, 1 for private + uint8_t bIsSecure; // VAC | byte | Specifies whether the server uses VAC: 0 for unsecured, 1 for secured + char aVersion[40]; // Version | string | Version of the game installed on the server. + uint8_t aVersionLen; + uint8_t nNewFlags = 0; // Extra Data Flag (EDF) | byte | If present, this specifies which additional data fields will be included. + uint16_t iUDPPort; // EDF & 0x80 -> Port | short | The server's game port number. + uint64_t iSteamID; // EDF & 0x10 -> SteamID | long long | Server's SteamID. + uint16_t iHLTVUDPPort; // EDF & 0x40 -> Port | short | Spectator port number for SourceTV. + char aHLTVName[255]; // EDF & 0x40 -> Name | string | Name of the spectator server for SourceTV. + uint8_t aHLTVNameLen; + char aKeywords[255]; // EDF & 0x20 -> Keywords | string | Tags that describe the game according to the server (for future use.) (sv_tags) + uint8_t aKeywordsLen; + uint64_t iGameID; // EDF & 0x01 -> GameID | long long | The server's 64-bit GameID. If this is present, a more accurate AppID is present in the low 24 bits. The earlier AppID could have been truncated as it was forced into 16-bit storage. + } info; - uint8_t info_cache[sizeof(CInfo)] = {0xFF, 0xFF, 0xFF, 0xFF, 'I'}; - uint16_t info_cache_len; + uint8_t info_cache[sizeof(CInfo)] = {0xFF, 0xFF, 0xFF, 0xFF, 'I'}; + uint16_t info_cache_len; } g_QueryCache; class CBaseClient; @@ -190,30 +191,30 @@ class CBaseServer; typedef enum EAuthProtocol { - k_EAuthProtocolWONCertificate = 1, - k_EAuthProtocolHashedCDKey = 2, - k_EAuthProtocolSteam = 3, + k_EAuthProtocolWONCertificate = 1, + k_EAuthProtocolHashedCDKey = 2, + k_EAuthProtocolSteam = 3, } EAuthProtocol; const char *CSteamID::Render() const { - static char szSteamID[64]; - V_snprintf(szSteamID, sizeof(szSteamID), "STEAM_0:%u:%u", (m_steamid.m_comp.m_unAccountID % 2) ? 1 : 0, (int32)m_steamid.m_comp.m_unAccountID/2); - return szSteamID; + static char szSteamID[64]; + V_snprintf(szSteamID, sizeof(szSteamID), "STEAM_0:%u:%u", (m_steamid.m_comp.m_unAccountID % 2) ? 1 : 0, (int32)m_steamid.m_comp.m_unAccountID/2); + return szSteamID; } class CSteam3Server { public: - void *m_pSteamClient; - ISteamGameServer *m_pSteamGameServer; - void *m_pSteamGameServerUtils; - void *m_pSteamGameServerNetworking; - void *m_pSteamGameServerStats; - void *m_pSteamHTTP; - void *m_pSteamInventory; - void *m_pSteamUGC; - void *m_pSteamApps; + void *m_pSteamClient; + ISteamGameServer *m_pSteamGameServer; + void *m_pSteamGameServerUtils; + void *m_pSteamGameServerNetworking; + void *m_pSteamGameServerStats; + void *m_pSteamHTTP; + void *m_pSteamInventory; + void *m_pSteamUGC; + void *m_pSteamApps; } *g_pSteam3Server; CBaseServer *g_pBaseServer = NULL; @@ -236,68 +237,107 @@ Steam3ServerFunc g_pSteam3ServerFunc = NULL; RejectConnectionFunc g_pRejectConnectionFunc = NULL; SetSteamIDFunc g_pSetSteamIDFunc = NULL; +bool g_bSuppressBeginAuthSession = false; + CSteam3Server *Steam3Server() { - if(!g_pSteam3ServerFunc) - return NULL; + if(!g_pSteam3ServerFunc) + return NULL; - return g_pSteam3ServerFunc(); + return g_pSteam3ServerFunc(); } void RejectConnection(const netadr_t &address, int iClientChallenge, const char *pchReason) { - if(!g_pRejectConnectionFunc || !g_pBaseServer) - return; + if(!g_pRejectConnectionFunc || !g_pBaseServer) + return; #ifndef WIN32 - g_pRejectConnectionFunc(g_pBaseServer, address, iClientChallenge, pchReason); + g_pRejectConnectionFunc(g_pBaseServer, address, iClientChallenge, pchReason); #else - g_pRejectConnectionFunc(g_pBaseServer, NULL, address, iClientChallenge, pchReason); + g_pRejectConnectionFunc(g_pBaseServer, NULL, address, iClientChallenge, pchReason); #endif } void SetSteamID(CBaseClient *pClient, const CSteamID &steamID) { - if(!pClient || !g_pSetSteamIDFunc) - return; + if(!pClient || !g_pSetSteamIDFunc) + return; #ifndef WIN32 - g_pSetSteamIDFunc(pClient, steamID); + g_pSetSteamIDFunc(pClient, steamID); #else - g_pSetSteamIDFunc(pClient, NULL, steamID); + g_pSetSteamIDFunc(pClient, NULL, steamID); #endif } +class VFuncEmptyClass{}; + +int g_nBeginAuthSessionOffset = 0; +const void* g_lastAuthTicket; +int g_lastcbAuthTicket; +CSteamID g_lastClientSteamID; + +SH_DECL_MANUALHOOK3(MHook_BeginAuthSession, 0, 0, 0, EBeginAuthSessionResult, const void *, int, CSteamID); + +//took hook from nide +EBeginAuthSessionResult Hook_BeginAuthSession(const void *pAuthTicket, int cbAuthTicket, CSteamID steamID) +{ + if (!g_bSuppressBeginAuthSession) + { + RETURN_META_VALUE(MRES_IGNORED, k_EBeginAuthSessionResultOK); + } + g_bSuppressBeginAuthSession = false; + + if (strcmp(steamID.Render(), g_lastClientSteamID.Render()) == 0 + && g_lastAuthTicket == pAuthTicket + && g_lastcbAuthTicket == cbAuthTicket) + { + // Let the server know everything is fine + // g_pSM->LogMessage(myself, "You alright ;)"); + RETURN_META_VALUE(MRES_SUPERCEDE, k_EBeginAuthSessionResultOK); + } + + RETURN_META_VALUE(MRES_IGNORED, k_EBeginAuthSessionResultDuplicateRequest); +} + EBeginAuthSessionResult BeginAuthSession(const void *pAuthTicket, int cbAuthTicket, CSteamID steamID) { - if(!g_pSteam3Server || !g_pSteam3Server->m_pSteamGameServer) - return k_EBeginAuthSessionResultOK; + if (g_nBeginAuthSessionOffset == 0) + { + return k_EBeginAuthSessionResultInvalidTicket; + } - return g_pSteam3Server->m_pSteamGameServer->BeginAuthSession(pAuthTicket, cbAuthTicket, steamID); + if(!g_pSteam3Server || !g_pSteam3Server->m_pSteamGameServer) + { + return k_EBeginAuthSessionResultOK; + } + + return g_pSteam3Server->m_pSteamGameServer->BeginAuthSession(pAuthTicket, cbAuthTicket, steamID); } void EndAuthSession(CSteamID steamID) { - if(!g_pSteam3Server || !g_pSteam3Server->m_pSteamGameServer) - return; + if(!g_pSteam3Server || !g_pSteam3Server->m_pSteamGameServer) + return; - g_pSteam3Server->m_pSteamGameServer->EndAuthSession(steamID); + g_pSteam3Server->m_pSteamGameServer->EndAuthSession(steamID); } bool BLoggedOn() { - if(!g_pSteam3Server || !g_pSteam3Server->m_pSteamGameServer) - return false; + if(!g_pSteam3Server || !g_pSteam3Server->m_pSteamGameServer) + return false; - return g_pSteam3Server->m_pSteamGameServer->BLoggedOn(); + return g_pSteam3Server->m_pSteamGameServer->BLoggedOn(); } bool BSecure() { - if(!g_pSteam3Server || !g_pSteam3Server->m_pSteamGameServer) - return false; + if(!g_pSteam3Server || !g_pSteam3Server->m_pSteamGameServer) + return false; - return g_pSteam3Server->m_pSteamGameServer->BSecure(); + return g_pSteam3Server->m_pSteamGameServer->BSecure(); } CDetour *g_Detour_CBaseServer__ConnectClient = NULL; @@ -309,987 +349,1029 @@ CDetour *g_Detour_CSteam3Server__OnValidateAuthTicketResponse = NULL; class ConnectClientStorage { public: - void* pThis; + void* pThis; - netadr_t address; - int nProtocol; - int iChallenge; - int iClientChallenge; - int nAuthProtocol; - char pchName[256]; - char pchPassword[256]; - char pCookie[256]; - int cbCookie; - IClient *pClient; + netadr_t address; + int nProtocol; + int iChallenge; + int iClientChallenge; + int nAuthProtocol; + char pchName[256]; + char pchPassword[256]; + char pCookie[256]; + int cbCookie; + IClient *pClient; - uint64 ullSteamID; - ValidateAuthTicketResponse_t ValidateAuthTicketResponse; - bool GotValidateAuthTicketResponse; - bool SteamLegal; - bool SteamAuthFailed; + uint64 ullSteamID; + ValidateAuthTicketResponse_t ValidateAuthTicketResponse; + bool GotValidateAuthTicketResponse; + bool SteamLegal; + bool SteamAuthFailed; - ConnectClientStorage() { } - ConnectClientStorage(netadr_t address, int nProtocol, int iChallenge, int iClientChallenge, int nAuthProtocol, const char *pchName, const char *pchPassword, const char *pCookie, int cbCookie) - { - this->address = address; - this->nProtocol = nProtocol; - this->iChallenge = iChallenge; - this->iClientChallenge = iClientChallenge; - this->nAuthProtocol = nAuthProtocol; - strlcpy(this->pchName, pchName, sizeof(this->pchName)); - strlcpy(this->pchPassword, pchPassword, sizeof(this->pchPassword)); - strlcpy(this->pCookie, pCookie, sizeof(this->pCookie)); - this->cbCookie = cbCookie; - this->pClient = NULL; - this->GotValidateAuthTicketResponse = false; - this->SteamLegal = false; - this->SteamAuthFailed = false; - } + ConnectClientStorage() { } + ConnectClientStorage(netadr_t address, int nProtocol, int iChallenge, int iClientChallenge, int nAuthProtocol, const char *pchName, const char *pchPassword, const char *pCookie, int cbCookie) + { + this->address = address; + this->nProtocol = nProtocol; + this->iChallenge = iChallenge; + this->iClientChallenge = iClientChallenge; + this->nAuthProtocol = nAuthProtocol; + strlcpy(this->pchName, pchName, sizeof(this->pchName)); + strlcpy(this->pchPassword, pchPassword, sizeof(this->pchPassword)); + strlcpy(this->pCookie, pCookie, sizeof(this->pCookie)); + this->cbCookie = cbCookie; + this->pClient = NULL; + this->GotValidateAuthTicketResponse = false; + this->SteamLegal = false; + this->SteamAuthFailed = false; + } }; StringHashMap g_ConnectClientStorage; bool g_bEndAuthSessionOnRejectConnection = false; -CSteamID g_lastClientSteamID; bool g_bSuppressCheckChallengeType = false; DETOUR_DECL_MEMBER1(CSteam3Server__OnValidateAuthTicketResponse, int, ValidateAuthTicketResponse_t *, pResponse) { - char aSteamID[32]; - strlcpy(aSteamID, pResponse->m_SteamID.Render(), sizeof(aSteamID)); + char aSteamID[32]; + strlcpy(aSteamID, pResponse->m_SteamID.Render(), sizeof(aSteamID)); - bool SteamLegal = pResponse->m_eAuthSessionResponse == k_EAuthSessionResponseOK; - bool force = g_SvNoSteam.GetInt() || g_SvForceSteam.GetInt() || !BLoggedOn(); + bool SteamLegal = pResponse->m_eAuthSessionResponse == k_EAuthSessionResponseOK; + bool force = g_SvNoSteam.GetInt() || g_SvForceSteam.GetInt() || !BLoggedOn(); - if (g_SvLogging.GetInt()) - g_pSM->LogMessage(myself, "%s SteamLegal: %d (%d)", aSteamID, SteamLegal, pResponse->m_eAuthSessionResponse); + if (g_SvLogging.GetInt()) + g_pSM->LogMessage(myself, "%s SteamLegal: %d (%d)", aSteamID, SteamLegal, pResponse->m_eAuthSessionResponse); - if(!SteamLegal && force) - pResponse->m_eAuthSessionResponse = k_EAuthSessionResponseOK; + if(!SteamLegal && force) + pResponse->m_eAuthSessionResponse = k_EAuthSessionResponseOK; - ConnectClientStorage Storage; - if(g_ConnectClientStorage.retrieve(aSteamID, &Storage)) - { - if(!Storage.GotValidateAuthTicketResponse) - { - Storage.GotValidateAuthTicketResponse = true; - Storage.ValidateAuthTicketResponse = *pResponse; - Storage.SteamLegal = SteamLegal; - g_ConnectClientStorage.replace(aSteamID, Storage); - } - } + ConnectClientStorage Storage; + if(g_ConnectClientStorage.retrieve(aSteamID, &Storage)) + { + if(!Storage.GotValidateAuthTicketResponse) + { + Storage.GotValidateAuthTicketResponse = true; + Storage.ValidateAuthTicketResponse = *pResponse; + Storage.SteamLegal = SteamLegal; + g_ConnectClientStorage.replace(aSteamID, Storage); + } + } - return DETOUR_MEMBER_CALL(CSteam3Server__OnValidateAuthTicketResponse)(pResponse); + return DETOUR_MEMBER_CALL(CSteam3Server__OnValidateAuthTicketResponse)(pResponse); } +void *g_pLastHookedSteamGameServer = NULL; + DETOUR_DECL_MEMBER9(CBaseServer__ConnectClient, IClient *, netadr_t &, address, int, nProtocol, int, iChallenge, int, iClientChallenge, int, nAuthProtocol, const char *, pchName, const char *, pchPassword, const char *, pCookie, int, cbCookie) { - if(nAuthProtocol != k_EAuthProtocolSteam) - { - // This is likely a SourceTV client, we don't want to interfere here. - return DETOUR_MEMBER_CALL(CBaseServer__ConnectClient)(address, nProtocol, iChallenge, iClientChallenge, nAuthProtocol, pchName, pchPassword, pCookie, cbCookie); - } + if(nAuthProtocol != k_EAuthProtocolSteam) + { + // This is likely a SourceTV client, we don't want to interfere here. + return DETOUR_MEMBER_CALL(CBaseServer__ConnectClient)(address, nProtocol, iChallenge, iClientChallenge, nAuthProtocol, pchName, pchPassword, pCookie, cbCookie); + } - g_pBaseServer = (CBaseServer *)this; + if (g_pSteam3Server->m_pSteamGameServer != g_pLastHookedSteamGameServer) + { + //november 2025 edit. + //this just feels wrong man. instead the hook is supposed to survive i guess. but this ensures its reset once on every map so it works. + //g_pSM->LogMessage(myself, "Steam GameServer pointer changed! Old: %p, New: %p", g_pLastHookedSteamGameServer, g_pSteam3Server->m_pSteamGameServer); + // Remove old hook if it exists + if (g_pLastHookedSteamGameServer != NULL) + { + SH_REMOVE_MANUALHOOK(MHook_BeginAuthSession, g_pLastHookedSteamGameServer, SH_STATIC(Hook_BeginAuthSession), true); + } - if(pCookie == NULL || (size_t)cbCookie < sizeof(uint64)) - { - RejectConnection(address, iClientChallenge, "#GameUI_ServerRejectInvalidSteamCertLen"); - return NULL; - } + // Add hook to the new object + SH_MANUALHOOK_RECONFIGURE(MHook_BeginAuthSession, g_nBeginAuthSessionOffset, 0, 0); + SH_ADD_MANUALHOOK(MHook_BeginAuthSession, g_pSteam3Server->m_pSteamGameServer, SH_STATIC(Hook_BeginAuthSession), true); - char ipString[32]; - V_snprintf(ipString, sizeof(ipString), "%u.%u.%u.%u", address.ip[0], address.ip[1], address.ip[2], address.ip[3]); + g_pLastHookedSteamGameServer = g_pSteam3Server->m_pSteamGameServer; + } - char passwordBuffer[255]; - strlcpy(passwordBuffer, pchPassword, sizeof(passwordBuffer)); - uint64 ullSteamID = *(uint64 *)pCookie; + g_pBaseServer = (CBaseServer *)this; - void *pvTicket = (void *)((intptr_t)pCookie + sizeof(uint64)); - int cbTicket = cbCookie - sizeof(uint64); + if(pCookie == NULL || (size_t)cbCookie < sizeof(uint64)) + { + RejectConnection(address, iClientChallenge, "#GameUI_ServerRejectInvalidSteamCertLen"); + return NULL; + } - g_bEndAuthSessionOnRejectConnection = true; - g_lastClientSteamID = CSteamID(ullSteamID); + char ipString[32]; + V_snprintf(ipString, sizeof(ipString), "%u.%u.%u.%u", address.ip[0], address.ip[1], address.ip[2], address.ip[3]); - char aSteamID[32]; - strlcpy(aSteamID, g_lastClientSteamID.Render(), sizeof(aSteamID)); + char passwordBuffer[255]; + strlcpy(passwordBuffer, pchPassword, sizeof(passwordBuffer)); + uint64 ullSteamID = *(uint64 *)pCookie; - // If client is in async state remove the old object and fake an async retVal - // This can happen if the async ClientPreConnectEx takes too long to be called - // and the client auto-retries. - bool AsyncWaiting = false; - bool ExistingSteamid = false; - ConnectClientStorage Storage(address, nProtocol, iChallenge, iClientChallenge, nAuthProtocol, pchName, pchPassword, pCookie, cbCookie); - if(g_ConnectClientStorage.retrieve(aSteamID, &Storage)) - { - ExistingSteamid = true; - g_ConnectClientStorage.remove(aSteamID); - EndAuthSession(g_lastClientSteamID); + void *pvTicket = (void *)((intptr_t)pCookie + sizeof(uint64)); + int cbTicket = cbCookie - sizeof(uint64); - // Only wait for async on auto-retry, manual retries should go through the full chain - // Don't want to leave the client waiting forever if something breaks in the async forward - if(Storage.iClientChallenge == iClientChallenge) - AsyncWaiting = true; - } + g_bEndAuthSessionOnRejectConnection = true; + g_lastClientSteamID = CSteamID(ullSteamID); + g_lastcbAuthTicket = cbTicket; + g_lastAuthTicket = pvTicket; - bool NoSteam = g_SvNoSteam.GetInt() || !BLoggedOn(); - bool SteamAuthFailed = false; - EBeginAuthSessionResult result = BeginAuthSession(pvTicket, cbTicket, g_lastClientSteamID); - EndAuthSession(g_lastClientSteamID); // The engine might start its own auth session so end this one - if(result != k_EBeginAuthSessionResultOK) - { - if(!NoSteam) - { - RejectConnection(address, iClientChallenge, "#GameUI_ServerRejectSteam"); - return NULL; - } - Storage.SteamAuthFailed = SteamAuthFailed = true; - } + char aSteamID[32]; + strlcpy(aSteamID, g_lastClientSteamID.Render(), sizeof(aSteamID)); - if(ExistingSteamid && !AsyncWaiting) - { - // 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 - if(SteamAuthFailed) - { - RejectConnection(address, iClientChallenge, "Steam ID already in use."); - return NULL; - } + // If client is in async state remove the old object and fake an async retVal + // This can happen if the async ClientPreConnectEx takes too long to be called + // and the client auto-retries. + bool AsyncWaiting = false; + bool ExistingSteamid = false; + ConnectClientStorage Storage(address, nProtocol, iChallenge, iClientChallenge, nAuthProtocol, pchName, pchPassword, pCookie, cbCookie); + if(g_ConnectClientStorage.retrieve(aSteamID, &Storage)) + { + ExistingSteamid = true; + g_ConnectClientStorage.remove(aSteamID); + EndAuthSession(g_lastClientSteamID); - // Kick existing player - if(Storage.pClient) - { - Storage.pClient->Disconnect("Same Steam ID connected."); - } - else - { - RejectConnection(address, iClientChallenge, "Please try again later."); - return NULL; - } - } - } + // Only wait for async on auto-retry, manual retries should go through the full chain + // Don't want to leave the client waiting forever if something breaks in the async forward + if(Storage.iClientChallenge == iClientChallenge) + AsyncWaiting = true; + } - char rejectReason[255]; - cell_t retVal = 1; + bool NoSteam = g_SvNoSteam.GetInt() || !BLoggedOn(); + bool SteamAuthFailed = false; + EBeginAuthSessionResult result = BeginAuthSession(pvTicket, cbTicket, g_lastClientSteamID); + EndAuthSession(g_lastClientSteamID); // The engine might start its own auth session so end this one + if(result != k_EBeginAuthSessionResultOK) + { + if(!NoSteam) + { + RejectConnection(address, iClientChallenge, "#GameUI_ServerRejectSteam"); + return NULL; + } + Storage.SteamAuthFailed = SteamAuthFailed = true; + } - if(AsyncWaiting) - retVal = -1; // Fake async return code when waiting for async call - else - { - g_pConnectForward->PushString(pchName); - g_pConnectForward->PushStringEx(passwordBuffer, sizeof(passwordBuffer), SM_PARAM_STRING_UTF8 | SM_PARAM_STRING_COPY, SM_PARAM_COPYBACK); - g_pConnectForward->PushString(ipString); - g_pConnectForward->PushString(aSteamID); - g_pConnectForward->PushStringEx(rejectReason, sizeof(rejectReason), SM_PARAM_STRING_UTF8 | SM_PARAM_STRING_COPY, SM_PARAM_COPYBACK); - g_pConnectForward->Execute(&retVal); - pchPassword = passwordBuffer; - } + if(ExistingSteamid && !AsyncWaiting) + { + // 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 + if(SteamAuthFailed) + { + RejectConnection(address, iClientChallenge, "Steam ID already in use."); + return NULL; + } - if (g_SvLogging.GetInt()) - g_pSM->LogMessage(myself, "%s SteamAuthFailed: %d (%d) | retVal = %d", aSteamID, SteamAuthFailed, result, retVal); + // Kick existing player + if(Storage.pClient) + { + Storage.pClient->Disconnect("Same Steam ID connected."); + } + else + { + RejectConnection(address, iClientChallenge, "Please try again later."); + return NULL; + } + } + } - // k_OnClientPreConnectEx_Reject - if(retVal == 0) - { - g_ConnectClientStorage.remove(aSteamID); - RejectConnection(address, iClientChallenge, rejectReason); - return NULL; - } + char rejectReason[255]; + cell_t retVal = 1; - Storage.pThis = this; - Storage.ullSteamID = ullSteamID; - Storage.SteamAuthFailed = SteamAuthFailed; + if(AsyncWaiting) + retVal = -1; // Fake async return code when waiting for async call + else + { + g_pConnectForward->PushString(pchName); + g_pConnectForward->PushStringEx(passwordBuffer, sizeof(passwordBuffer), SM_PARAM_STRING_UTF8 | SM_PARAM_STRING_COPY, SM_PARAM_COPYBACK); + g_pConnectForward->PushString(ipString); + g_pConnectForward->PushString(aSteamID); + g_pConnectForward->PushStringEx(rejectReason, sizeof(rejectReason), SM_PARAM_STRING_UTF8 | SM_PARAM_STRING_COPY, SM_PARAM_COPYBACK); + g_pConnectForward->Execute(&retVal); + pchPassword = passwordBuffer; + } - if(!g_ConnectClientStorage.replace(aSteamID, Storage)) - { - RejectConnection(address, iClientChallenge, "Internal error."); - return NULL; - } + if (g_SvLogging.GetInt()) + g_pSM->LogMessage(myself, "%s SteamAuthFailed: %d (%d) | retVal = %d", aSteamID, SteamAuthFailed, result, retVal); - // k_OnClientPreConnectEx_Async - if(retVal == -1) - { - return NULL; - } + // k_OnClientPreConnectEx_Reject + if(retVal == 0) + { + g_ConnectClientStorage.remove(aSteamID); + RejectConnection(address, iClientChallenge, rejectReason); + return NULL; + } - // k_OnClientPreConnectEx_Accept - g_bSuppressCheckChallengeType = true; - IClient *pClient = DETOUR_MEMBER_CALL(CBaseServer__ConnectClient)(address, nProtocol, iChallenge, iClientChallenge, nAuthProtocol, pchName, pchPassword, pCookie, cbCookie); + Storage.pThis = this; + Storage.ullSteamID = ullSteamID; + Storage.SteamAuthFailed = SteamAuthFailed; - if(pClient) - strlcpy(g_ClientSteamIDMap[pClient->GetPlayerSlot() + 1], aSteamID, sizeof(*g_ClientSteamIDMap)); + if(!g_ConnectClientStorage.replace(aSteamID, Storage)) + { + RejectConnection(address, iClientChallenge, "Internal error."); + return NULL; + } - Storage.pClient = pClient; - g_ConnectClientStorage.replace(aSteamID, Storage); + // k_OnClientPreConnectEx_Async + if(retVal == -1) + { + return NULL; + } - if(pClient && SteamAuthFailed) - { - ValidateAuthTicketResponse_t Response; - Response.m_SteamID = g_lastClientSteamID; - Response.m_eAuthSessionResponse = k_EAuthSessionResponseAuthTicketInvalid; - Response.m_OwnerSteamID = Response.m_SteamID; - DETOUR_MEMBER_MCALL_CALLBACK(CSteam3Server__OnValidateAuthTicketResponse, g_pSteam3Server)(&Response); - } + // k_OnClientPreConnectEx_Accept + g_bSuppressCheckChallengeType = true; + g_bSuppressBeginAuthSession = true; + IClient *pClient = DETOUR_MEMBER_CALL(CBaseServer__ConnectClient)(address, nProtocol, iChallenge, iClientChallenge, nAuthProtocol, pchName, pchPassword, pCookie, cbCookie); + g_bSuppressBeginAuthSession = false; + if(pClient) + strlcpy(g_ClientSteamIDMap[pClient->GetPlayerSlot() + 1], aSteamID, sizeof(*g_ClientSteamIDMap)); - return pClient; + Storage.pClient = pClient; + g_ConnectClientStorage.replace(aSteamID, Storage); + + if(pClient && SteamAuthFailed) + { + ValidateAuthTicketResponse_t Response; + Response.m_SteamID = g_lastClientSteamID; + Response.m_eAuthSessionResponse = k_EAuthSessionResponseAuthTicketInvalid; + Response.m_OwnerSteamID = Response.m_SteamID; + DETOUR_MEMBER_MCALL_CALLBACK(CSteam3Server__OnValidateAuthTicketResponse, g_pSteam3Server)(&Response); + } + + return pClient; } DETOUR_DECL_MEMBER3(CBaseServer__RejectConnection, void, netadr_t &, address, int, iClientChallenge, const char *, pchReason) { - if(g_bEndAuthSessionOnRejectConnection) - { - EndAuthSession(g_lastClientSteamID); - g_bEndAuthSessionOnRejectConnection = false; - } + if(g_bEndAuthSessionOnRejectConnection) + { + EndAuthSession(g_lastClientSteamID); + g_bEndAuthSessionOnRejectConnection = false; + } - return DETOUR_MEMBER_CALL(CBaseServer__RejectConnection)(address, iClientChallenge, pchReason); + return DETOUR_MEMBER_CALL(CBaseServer__RejectConnection)(address, iClientChallenge, pchReason); } DETOUR_DECL_MEMBER7(CBaseServer__CheckChallengeType, bool, CBaseClient *, pClient, int, nUserID, netadr_t &, address, int, nAuthProtocol, const char *, pCookie, int, cbCookie, int, iClientChallenge) { - if(g_bSuppressCheckChallengeType) - { - g_bEndAuthSessionOnRejectConnection = false; + if(g_bSuppressCheckChallengeType) + { + g_bEndAuthSessionOnRejectConnection = false; - SetSteamID(pClient, g_lastClientSteamID); + SetSteamID(pClient, g_lastClientSteamID); - g_bSuppressCheckChallengeType = false; - return true; - } + g_bSuppressCheckChallengeType = false; + return true; + } - return DETOUR_MEMBER_CALL(CBaseServer__CheckChallengeType)(pClient, nUserID, address, nAuthProtocol, pCookie, cbCookie, iClientChallenge); + return DETOUR_MEMBER_CALL(CBaseServer__CheckChallengeType)(pClient, nUserID, address, nAuthProtocol, pCookie, cbCookie, iClientChallenge); } DETOUR_DECL_MEMBER0(CBaseServer__InactivateClients, void) { - for(int slot = 0; slot < iserver->GetClientCount(); slot++) - { - int client = slot + 1; - IClient *pClient = iserver->GetClient(slot); - if(!pClient) - continue; + for(int slot = 0; slot < iserver->GetClientCount(); slot++) + { + int client = slot + 1; + IClient *pClient = iserver->GetClient(slot); + if(!pClient) + continue; - // Disconnect all fake clients manually before the engine just nukes them. - if(pClient->IsFakeClient() && !pClient->IsHLTV()) - { - pClient->Disconnect(""); - } - } + // Disconnect all fake clients manually before the engine just nukes them. + if(pClient->IsFakeClient() && !pClient->IsHLTV()) + { + pClient->Disconnect(""); + } + } - return DETOUR_MEMBER_CALL(CBaseServer__InactivateClients)(); + return DETOUR_MEMBER_CALL(CBaseServer__InactivateClients)(); } void UpdateQueryCache() { - CQueryCache::CInfo &info = g_QueryCache.info; - info.aHostNameLen = strlcpy(info.aHostName, iserver->GetName(), sizeof(info.aHostName)); + CQueryCache::CInfo &info = g_QueryCache.info; + info.aHostNameLen = strlcpy(info.aHostName, iserver->GetName(), sizeof(info.aHostName)); - if(strcmp(g_SvMapName.GetString(), "default") == 0) - info.aMapNameLen = strlcpy(info.aMapName, iserver->GetMapName(), sizeof(info.aMapName)); - else - info.aMapNameLen = strlcpy(info.aMapName, g_SvMapName.GetString(), sizeof(info.aMapName)); + if(strcmp(g_SvMapName.GetString(), "default") == 0) + info.aMapNameLen = strlcpy(info.aMapName, iserver->GetMapName(), sizeof(info.aMapName)); + else + info.aMapNameLen = strlcpy(info.aMapName, g_SvMapName.GetString(), sizeof(info.aMapName)); - if(strcmp(g_SvGameDesc.GetString(), "default") == 0) - info.aGameDescriptionLen = strlcpy(info.aGameDescription, gamedll->GetGameDescription(), sizeof(info.aGameDescription)); - else - info.aGameDescriptionLen = strlcpy(info.aGameDescription, g_SvGameDesc.GetString(), sizeof(info.aGameDescription)); + if(strcmp(g_SvGameDesc.GetString(), "default") == 0) + info.aGameDescriptionLen = strlcpy(info.aGameDescription, gamedll->GetGameDescription(), sizeof(info.aGameDescription)); + else + info.aGameDescriptionLen = strlcpy(info.aGameDescription, g_SvGameDesc.GetString(), sizeof(info.aGameDescription)); - if(g_pSvVisibleMaxPlayers->GetInt() >= 0) - info.nMaxClients = g_pSvVisibleMaxPlayers->GetInt(); - else - info.nMaxClients = iserver->GetMaxClients(); - info.nPassword = iserver->GetPassword() ? 1 : 0; - info.bIsSecure = BSecure(); + if(g_pSvVisibleMaxPlayers->GetInt() >= 0) + info.nMaxClients = g_pSvVisibleMaxPlayers->GetInt(); + else + info.nMaxClients = iserver->GetMaxClients(); + info.nPassword = iserver->GetPassword() ? 1 : 0; + info.bIsSecure = BSecure(); - if(!(info.nNewFlags & 0x10) && engine->GetGameServerSteamID()) - { - info.iSteamID = engine->GetGameServerSteamID()->ConvertToUint64(); - info.nNewFlags |= 0x10; - } + if(!(info.nNewFlags & 0x10) && engine->GetGameServerSteamID()) + { + info.iSteamID = engine->GetGameServerSteamID()->ConvertToUint64(); + info.nNewFlags |= 0x10; + } - if(!(info.nNewFlags & 0x40) && hltvdirector->IsActive()) // tv_name can't change anymore - { - hltv = hltvdirector->GetHLTVServer(); - if(hltv) - { - IServer *ihltvserver = hltv->GetBaseServer(); - if(ihltvserver) - { - info.iHLTVUDPPort = ihltvserver->GetLocalUDPPort(); - info.aHLTVNameLen = strlcpy(info.aHLTVName, ihltvserver->GetName(), sizeof(info.aHLTVName)); - info.nNewFlags |= 0x40; - } - } - } + if(!(info.nNewFlags & 0x40) && hltvdirector->IsActive()) // tv_name can't change anymore + { + hltv = hltvdirector->GetHLTVServer(); + if(hltv) + { + IServer *ihltvserver = hltv->GetBaseServer(); + if(ihltvserver) + { + info.iHLTVUDPPort = ihltvserver->GetLocalUDPPort(); + info.aHLTVNameLen = strlcpy(info.aHLTVName, ihltvserver->GetName(), sizeof(info.aHLTVName)); + info.nNewFlags |= 0x40; + } + } + } - info.aKeywordsLen = strlcpy(info.aKeywords, g_pSvTags->GetString(), sizeof(info.aKeywords)); - if(info.aKeywordsLen) - info.nNewFlags |= 0x20; - else - info.nNewFlags &= ~0x20; + info.aKeywordsLen = strlcpy(info.aKeywords, g_pSvTags->GetString(), sizeof(info.aKeywords)); + if(info.aKeywordsLen) + info.nNewFlags |= 0x20; + else + info.nNewFlags &= ~0x20; - uint8_t *info_cache = g_QueryCache.info_cache; - uint16_t pos = 5; // header: FF FF FF FF I + uint8_t *info_cache = g_QueryCache.info_cache; + uint16_t pos = 5; // header: FF FF FF FF I - info_cache[pos++] = info.nProtocol; + info_cache[pos++] = info.nProtocol; - memcpy(&info_cache[pos], info.aHostName, info.aHostNameLen + 1); - pos += info.aHostNameLen + 1; + memcpy(&info_cache[pos], info.aHostName, info.aHostNameLen + 1); + pos += info.aHostNameLen + 1; - memcpy(&info_cache[pos], info.aMapName, info.aMapNameLen + 1); - pos += info.aMapNameLen + 1; + memcpy(&info_cache[pos], info.aMapName, info.aMapNameLen + 1); + pos += info.aMapNameLen + 1; - memcpy(&info_cache[pos], info.aGameDir, info.aGameDirLen + 1); - pos += info.aGameDirLen + 1; + memcpy(&info_cache[pos], info.aGameDir, info.aGameDirLen + 1); + pos += info.aGameDirLen + 1; - memcpy(&info_cache[pos], info.aGameDescription, info.aGameDescriptionLen + 1); - pos += info.aGameDescriptionLen + 1; + memcpy(&info_cache[pos], info.aGameDescription, info.aGameDescriptionLen + 1); + pos += info.aGameDescriptionLen + 1; - *(uint16_t *)&info_cache[pos] = info.iSteamAppID; - pos += 2; + *(uint16_t *)&info_cache[pos] = info.iSteamAppID; + pos += 2; - info_cache[pos++] = info.nNumClients; + info_cache[pos++] = info.nNumClients; - info_cache[pos++] = info.nMaxClients; + info_cache[pos++] = info.nMaxClients; - info_cache[pos++] = 0;//info.nFakeClients; + info_cache[pos++] = 0;//info.nFakeClients; - info_cache[pos++] = info.nServerType; + info_cache[pos++] = info.nServerType; - info_cache[pos++] = info.nEnvironment; + info_cache[pos++] = info.nEnvironment; - info_cache[pos++] = info.nPassword; + info_cache[pos++] = info.nPassword; - info_cache[pos++] = info.bIsSecure; + info_cache[pos++] = info.bIsSecure; - memcpy(&info_cache[pos], info.aVersion, info.aVersionLen + 1); - pos += info.aVersionLen + 1; + memcpy(&info_cache[pos], info.aVersion, info.aVersionLen + 1); + pos += info.aVersionLen + 1; - info_cache[pos++] = info.nNewFlags; + info_cache[pos++] = info.nNewFlags; - if(info.nNewFlags & 0x80) { - *(uint16_t *)&info_cache[pos] = info.iUDPPort; - pos += 2; - } + if(info.nNewFlags & 0x80) { + *(uint16_t *)&info_cache[pos] = info.iUDPPort; + pos += 2; + } - if(info.nNewFlags & 0x10) { - *(uint64_t *)&info_cache[pos] = info.iSteamID; - pos += 8; - } + if(info.nNewFlags & 0x10) { + *(uint64_t *)&info_cache[pos] = info.iSteamID; + pos += 8; + } - if(info.nNewFlags & 0x40) { - *(uint16_t *)&info_cache[pos] = info.iHLTVUDPPort; - pos += 2; + if(info.nNewFlags & 0x40) { + *(uint16_t *)&info_cache[pos] = info.iHLTVUDPPort; + pos += 2; - memcpy(&info_cache[pos], info.aHLTVName, info.aHLTVNameLen + 1); - pos += info.aHLTVNameLen + 1; - } + memcpy(&info_cache[pos], info.aHLTVName, info.aHLTVNameLen + 1); + pos += info.aHLTVNameLen + 1; + } - if(info.nNewFlags & 0x20) { - memcpy(&info_cache[pos], info.aKeywords, info.aKeywordsLen + 1); - pos += info.aKeywordsLen + 1; - } + if(info.nNewFlags & 0x20) { + memcpy(&info_cache[pos], info.aKeywords, info.aKeywordsLen + 1); + pos += info.aKeywordsLen + 1; + } - if(info.nNewFlags & 0x01) { - *(uint64_t *)&info_cache[pos] = info.iGameID; - pos += 8; - } + if(info.nNewFlags & 0x01) { + *(uint64_t *)&info_cache[pos] = info.iGameID; + pos += 8; + } - g_QueryCache.info_cache_len = pos; + g_QueryCache.info_cache_len = pos; } bool Hook_ProcessConnectionlessPacket(netpacket_t * packet) { - if(packet->size == 25 && packet->data[4] == 'T') - { - if(!CIPRateLimit__CheckIP(s_queryRateChecker, packet->from)) - RETURN_META_VALUE(MRES_SUPERCEDE, false); + if(packet->size == 25 && packet->data[4] == 'T') + { + if(!CIPRateLimit__CheckIP(s_queryRateChecker, packet->from)) + RETURN_META_VALUE(MRES_SUPERCEDE, false); - sockaddr_in to; - to.sin_family = AF_INET; - to.sin_port = packet->from.port; - to.sin_addr.s_addr = *(int32_t *)&packet->from.ip; + sockaddr_in to; + to.sin_family = AF_INET; + to.sin_port = packet->from.port; + to.sin_addr.s_addr = *(int32_t *)&packet->from.ip; - sendto(g_ServerUDPSocket, g_QueryCache.info_cache, g_QueryCache.info_cache_len, 0, (sockaddr *)&to, sizeof(to)); + sendto(g_ServerUDPSocket, g_QueryCache.info_cache, g_QueryCache.info_cache_len, 0, (sockaddr *)&to, sizeof(to)); - RETURN_META_VALUE(MRES_SUPERCEDE, true); - } + RETURN_META_VALUE(MRES_SUPERCEDE, true); + } - if((packet->size == 5 || packet->size == 9) && packet->data[4] == 'U') - { - if(!CIPRateLimit__CheckIP(s_queryRateChecker, packet->from)) - RETURN_META_VALUE(MRES_SUPERCEDE, false); + if((packet->size == 5 || packet->size == 9) && packet->data[4] == 'U') + { + if(!CIPRateLimit__CheckIP(s_queryRateChecker, packet->from)) + RETURN_META_VALUE(MRES_SUPERCEDE, false); - sockaddr_in to; - to.sin_family = AF_INET; - to.sin_port = packet->from.port; - to.sin_addr.s_addr = *(int32_t *)&packet->from.ip; + sockaddr_in to; + to.sin_family = AF_INET; + to.sin_port = packet->from.port; + to.sin_addr.s_addr = *(int32_t *)&packet->from.ip; - int32_t challengeNr = -1; - if(packet->size == 9) - challengeNr = *(int32_t *)&packet->data[5]; + int32_t challengeNr = -1; + if(packet->size == 9) + challengeNr = *(int32_t *)&packet->data[5]; - /* This is a complete nonsense challenge as the client can easily break it. - * The point of this challenge is to stop spoofed source DDoS reflection attacks, - * so it doesn't really matter if one single server out of thousands doesn't - * implement this correctly. If you do happen to use this on thousands of servers - * though then please do implement it correctly. - */ - int32_t realChallengeNr = *(int32_t *)&packet->from.ip ^ 0x55AADD88; - if(challengeNr != realChallengeNr) - { - uint8_t response[9] = {0xFF, 0xFF, 0xFF, 0xFF, 'A'}; - *(int32_t *)&response[5] = realChallengeNr; - sendto(g_ServerUDPSocket, response, sizeof(response), 0, (sockaddr *)&to, sizeof(to)); - RETURN_META_VALUE(MRES_SUPERCEDE, true); - } + /* This is a complete nonsense challenge as the client can easily break it. + * The point of this challenge is to stop spoofed source DDoS reflection attacks, + * so it doesn't really matter if one single server out of thousands doesn't + * implement this correctly. If you do happen to use this on thousands of servers + * though then please do implement it correctly. + */ + int32_t realChallengeNr = *(int32_t *)&packet->from.ip ^ 0x55AADD88; + if(challengeNr != realChallengeNr) + { + uint8_t response[9] = {0xFF, 0xFF, 0xFF, 0xFF, 'A'}; + *(int32_t *)&response[5] = realChallengeNr; + sendto(g_ServerUDPSocket, response, sizeof(response), 0, (sockaddr *)&to, sizeof(to)); + RETURN_META_VALUE(MRES_SUPERCEDE, true); + } - uint8_t response[4+1+1+SM_MAXPLAYERS*(1+MAX_PLAYER_NAME_LENGTH+4+4)] = {0xFF, 0xFF, 0xFF, 0xFF, 'D', 0}; - short pos = 6; - for(int i = 1; i <= SM_MAXPLAYERS; i++) - { - const CQueryCache::CPlayer &player = g_QueryCache.players[i]; - if(!player.active) - continue; + uint8_t response[4+1+1+SM_MAXPLAYERS*(1+MAX_PLAYER_NAME_LENGTH+4+4)] = {0xFF, 0xFF, 0xFF, 0xFF, 'D', 0}; + short pos = 6; + for(int i = 1; i <= SM_MAXPLAYERS; i++) + { + const CQueryCache::CPlayer &player = g_QueryCache.players[i]; + if(!player.active) + continue; - response[pos++] = response[5]; // Index | byte | Index of player chunk starting from 0. - response[5]++; // Players | byte | Number of players whose information was gathered. - memcpy(&response[pos], player.name, player.nameLen + 1); // Name | string | Name of the player. - pos += player.nameLen + 1; - *(int32_t *)&response[pos] = player.score; // Score | long | Player's score (usually "frags" or "kills".) - pos += 4; - *(float *)&response[pos] = *net_time - player.time; // Duration | float | Time (in seconds) player has been connected to the server. - pos += 4; - } + response[pos++] = response[5]; // Index | byte | Index of player chunk starting from 0. + response[5]++; // Players | byte | Number of players whose information was gathered. + memcpy(&response[pos], player.name, player.nameLen + 1); // Name | string | Name of the player. + pos += player.nameLen + 1; + *(int32_t *)&response[pos] = player.score; // Score | long | Player's score (usually "frags" or "kills".) + pos += 4; + *(float *)&response[pos] = *net_time - player.time; // Duration | float | Time (in seconds) player has been connected to the server. + pos += 4; + } - sendto(g_ServerUDPSocket, response, pos, 0, (sockaddr *)&to, sizeof(to)); + sendto(g_ServerUDPSocket, response, pos, 0, (sockaddr *)&to, sizeof(to)); - RETURN_META_VALUE(MRES_SUPERCEDE, true); - } + RETURN_META_VALUE(MRES_SUPERCEDE, true); + } - RETURN_META_VALUE(MRES_IGNORED, false); + RETURN_META_VALUE(MRES_IGNORED, false); } bool Connect::SDK_OnLoad(char *error, size_t maxlen, bool late) { - char conf_error[255] = ""; - if(!gameconfs->LoadGameConfigFile("connect2.games", &g_pGameConf, conf_error, sizeof(conf_error))) - { - if(conf_error[0]) - { - snprintf(error, maxlen, "Could not read connect2.games.txt: %s\n", conf_error); - } - return false; - } + char conf_error[255] = ""; + if(!gameconfs->LoadGameConfigFile("connect2.games", &g_pGameConf, conf_error, sizeof(conf_error))) + { + if(conf_error[0]) + { + snprintf(error, maxlen, "Could not read connect2.games.txt: %s\n", conf_error); + } + return false; + } - if(!g_pGameConf->GetMemSig("CBaseServer__RejectConnection", (void **)(&g_pRejectConnectionFunc)) || !g_pRejectConnectionFunc) - { - snprintf(error, maxlen, "Failed to find CBaseServer__RejectConnection function.\n"); - return false; - } + if(!g_pGameConf->GetMemSig("CBaseServer__RejectConnection", (void **)(&g_pRejectConnectionFunc)) || !g_pRejectConnectionFunc) + { + snprintf(error, maxlen, "Failed to find CBaseServer__RejectConnection function.\n"); + return false; + } - if(!g_pGameConf->GetMemSig("CBaseClient__SetSteamID", (void **)(&g_pSetSteamIDFunc)) || !g_pSetSteamIDFunc) - { - snprintf(error, maxlen, "Failed to find CBaseClient__SetSteamID function.\n"); - return false; - } + if(!g_pGameConf->GetMemSig("CBaseClient__SetSteamID", (void **)(&g_pSetSteamIDFunc)) || !g_pSetSteamIDFunc) + { + snprintf(error, maxlen, "Failed to find CBaseClient__SetSteamID function.\n"); + return false; + } #ifndef WIN32 - if(!g_pGameConf->GetMemSig("Steam3Server", (void **)(&g_pSteam3ServerFunc)) || !g_pSteam3ServerFunc) - { - snprintf(error, maxlen, "Failed to find Steam3Server function.\n"); - return false; - } + if(!g_pGameConf->GetMemSig("Steam3Server", (void **)(&g_pSteam3ServerFunc)) || !g_pSteam3ServerFunc) + { + snprintf(error, maxlen, "Failed to find Steam3Server function.\n"); + return false; + } #else - void *address; - if(!g_pGameConf->GetMemSig("CBaseServer__CheckMasterServerRequestRestart", &address) || !address) - { - snprintf(error, maxlen, "Failed to find CBaseServer__CheckMasterServerRequestRestart function.\n"); - return false; - } + void *address; + if(!g_pGameConf->GetMemSig("CBaseServer__CheckMasterServerRequestRestart", &address) || !address) + { + snprintf(error, maxlen, "Failed to find CBaseServer__CheckMasterServerRequestRestart function.\n"); + return false; + } - //META_CONPRINTF("CheckMasterServerRequestRestart: %p\n", address); - address = (void *)((intptr_t)address + 1); // Skip CALL opcode - intptr_t offset = (intptr_t)(*(void **)address); // Get offset + //META_CONPRINTF("CheckMasterServerRequestRestart: %p\n", address); + address = (void *)((intptr_t)address + 1); // Skip CALL opcode + intptr_t offset = (intptr_t)(*(void **)address); // Get offset - g_pSteam3ServerFunc = (Steam3ServerFunc)((intptr_t)address + offset + sizeof(intptr_t)); - //META_CONPRINTF("Steam3Server: %p\n", g_pSteam3ServerFunc); + g_pSteam3ServerFunc = (Steam3ServerFunc)((intptr_t)address + offset + sizeof(intptr_t)); + //META_CONPRINTF("Steam3Server: %p\n", g_pSteam3ServerFunc); #endif - g_pSteam3Server = Steam3Server(); - if(!g_pSteam3Server) - { - snprintf(error, maxlen, "Unable to get Steam3Server singleton.\n"); - return false; - } + g_pSteam3Server = Steam3Server(); + if(!g_pSteam3Server) + { + snprintf(error, maxlen, "Unable to get Steam3Server singleton.\n"); + return false; + } - /* - META_CONPRINTF("ISteamGameServer: %p\n", g_pSteam3Server->m_pSteamGameServer); - META_CONPRINTF("ISteamUtils: %p\n", g_pSteam3Server->m_pSteamGameServerUtils); - META_CONPRINTF("ISteamMasterServerUpdater: %p\n", g_pSteam3Server->m_pSteamMasterServerUpdater); - META_CONPRINTF("ISteamNetworking: %p\n", g_pSteam3Server->m_pSteamGameServerNetworking); - META_CONPRINTF("ISteamGameServerStats: %p\n", g_pSteam3Server->m_pSteamGameServerStats); - */ + /* + META_CONPRINTF("ISteamGameServer: %p\n", g_pSteam3Server->m_pSteamGameServer); + META_CONPRINTF("ISteamUtils: %p\n", g_pSteam3Server->m_pSteamGameServerUtils); + META_CONPRINTF("ISteamMasterServerUpdater: %p\n", g_pSteam3Server->m_pSteamMasterServerUpdater); + META_CONPRINTF("ISteamNetworking: %p\n", g_pSteam3Server->m_pSteamGameServerNetworking); + META_CONPRINTF("ISteamGameServerStats: %p\n", g_pSteam3Server->m_pSteamGameServerStats); + */ - if(!g_pGameConf->GetMemSig("s_queryRateChecker", &s_queryRateChecker) || !s_queryRateChecker) - { - snprintf(error, maxlen, "Failed to find s_queryRateChecker address.\n"); - return false; - } + if (!g_pGameConf->GetOffset("ISteamGameServer__BeginAuthSession", &g_nBeginAuthSessionOffset) || g_nBeginAuthSessionOffset == 0) + { + snprintf(error, maxlen, "Failed to find ISteamGameServer__BeginAuthSession offset.\n"); + return false; + } - if(!g_pGameConf->GetMemSig("CIPRateLimit__CheckIP", (void **)&CIPRateLimit__CheckIP) || !CIPRateLimit__CheckIP) - { - snprintf(error, maxlen, "Failed to find CIPRateLimit::CheckIP address.\n"); - return false; - } + SH_MANUALHOOK_RECONFIGURE(MHook_BeginAuthSession, g_nBeginAuthSessionOffset, 0, 0); + if (SH_ADD_MANUALHOOK(MHook_BeginAuthSession, g_pSteam3Server->m_pSteamGameServer, SH_STATIC(Hook_BeginAuthSession), true) == 0) + { + snprintf(error, maxlen, "Failed to setup ISteamGameServer__BeginAuthSession hook.\n"); + return false; + } - if(!g_pGameConf->GetMemSig("CBaseServer__ValidChallenge", (void **)&CBaseServer__ValidChallenge) || !CBaseServer__ValidChallenge) - { - snprintf(error, maxlen, "Failed to find CBaseServer::ValidChallenge address.\n"); - return false; - } + if(!g_pGameConf->GetMemSig("s_queryRateChecker", &s_queryRateChecker) || !s_queryRateChecker) + { + snprintf(error, maxlen, "Failed to find s_queryRateChecker address.\n"); + return false; + } - if(!g_pGameConf->GetMemSig("net_sockets", (void **)&net_sockets) || !net_sockets) - { - snprintf(error, maxlen, "Failed to find net_sockets address.\n"); - return false; - } + if(!g_pGameConf->GetMemSig("CIPRateLimit__CheckIP", (void **)&CIPRateLimit__CheckIP) || !CIPRateLimit__CheckIP) + { + snprintf(error, maxlen, "Failed to find CIPRateLimit::CheckIP address.\n"); + return false; + } - if(!g_pGameConf->GetMemSig("net_time", (void **)&net_time) || !net_time) - { - snprintf(error, maxlen, "Failed to find net_time address.\n"); - return false; - } + if(!g_pGameConf->GetMemSig("CBaseServer__ValidChallenge", (void **)&CBaseServer__ValidChallenge) || !CBaseServer__ValidChallenge) + { + snprintf(error, maxlen, "Failed to find CBaseServer::ValidChallenge address.\n"); + return false; + } - CDetourManager::Init(g_pSM->GetScriptingEngine(), g_pGameConf); + if(!g_pGameConf->GetMemSig("net_sockets", (void **)&net_sockets) || !net_sockets) + { + snprintf(error, maxlen, "Failed to find net_sockets address.\n"); + return false; + } - g_Detour_CBaseServer__ConnectClient = DETOUR_CREATE_MEMBER(CBaseServer__ConnectClient, "CBaseServer__ConnectClient"); - if(!g_Detour_CBaseServer__ConnectClient) - { - snprintf(error, maxlen, "Failed to detour CBaseServer__ConnectClient.\n"); - return false; - } - g_Detour_CBaseServer__ConnectClient->EnableDetour(); + if(!g_pGameConf->GetMemSig("net_time", (void **)&net_time) || !net_time) + { + snprintf(error, maxlen, "Failed to find net_time address.\n"); + return false; + } - g_Detour_CBaseServer__RejectConnection = DETOUR_CREATE_MEMBER(CBaseServer__RejectConnection, "CBaseServer__RejectConnection"); - if(!g_Detour_CBaseServer__RejectConnection) - { - snprintf(error, maxlen, "Failed to detour CBaseServer__RejectConnection.\n"); - return false; - } - g_Detour_CBaseServer__RejectConnection->EnableDetour(); + CDetourManager::Init(g_pSM->GetScriptingEngine(), g_pGameConf); - g_Detour_CBaseServer__CheckChallengeType = DETOUR_CREATE_MEMBER(CBaseServer__CheckChallengeType, "CBaseServer__CheckChallengeType"); - if(!g_Detour_CBaseServer__CheckChallengeType) - { - snprintf(error, maxlen, "Failed to detour CBaseServer__CheckChallengeType.\n"); - return false; - } - g_Detour_CBaseServer__CheckChallengeType->EnableDetour(); + g_Detour_CBaseServer__ConnectClient = DETOUR_CREATE_MEMBER(CBaseServer__ConnectClient, "CBaseServer__ConnectClient"); + if(!g_Detour_CBaseServer__ConnectClient) + { + snprintf(error, maxlen, "Failed to detour CBaseServer__ConnectClient.\n"); + return false; + } + g_Detour_CBaseServer__ConnectClient->EnableDetour(); - g_Detour_CBaseServer__InactivateClients = DETOUR_CREATE_MEMBER(CBaseServer__InactivateClients, "CBaseServer__InactivateClients"); - if(!g_Detour_CBaseServer__InactivateClients) - { - snprintf(error, maxlen, "Failed to detour CBaseServer__InactivateClients.\n"); - return false; - } - g_Detour_CBaseServer__InactivateClients->EnableDetour(); + g_Detour_CBaseServer__RejectConnection = DETOUR_CREATE_MEMBER(CBaseServer__RejectConnection, "CBaseServer__RejectConnection"); + if(!g_Detour_CBaseServer__RejectConnection) + { + snprintf(error, maxlen, "Failed to detour CBaseServer__RejectConnection.\n"); + return false; + } + g_Detour_CBaseServer__RejectConnection->EnableDetour(); - g_Detour_CSteam3Server__OnValidateAuthTicketResponse = DETOUR_CREATE_MEMBER(CSteam3Server__OnValidateAuthTicketResponse, "CSteam3Server__OnValidateAuthTicketResponse"); - if(!g_Detour_CSteam3Server__OnValidateAuthTicketResponse) - { - snprintf(error, maxlen, "Failed to detour CSteam3Server__OnValidateAuthTicketResponse.\n"); - return false; - } - g_Detour_CSteam3Server__OnValidateAuthTicketResponse->EnableDetour(); + g_Detour_CBaseServer__CheckChallengeType = DETOUR_CREATE_MEMBER(CBaseServer__CheckChallengeType, "CBaseServer__CheckChallengeType"); + if(!g_Detour_CBaseServer__CheckChallengeType) + { + snprintf(error, maxlen, "Failed to detour CBaseServer__CheckChallengeType.\n"); + return false; + } + g_Detour_CBaseServer__CheckChallengeType->EnableDetour(); - g_pConnectForward = g_pForwards->CreateForward("OnClientPreConnectEx", ET_LowEvent, 5, NULL, Param_String, Param_String, Param_String, Param_String, Param_String); + g_Detour_CBaseServer__InactivateClients = DETOUR_CREATE_MEMBER(CBaseServer__InactivateClients, "CBaseServer__InactivateClients"); + if(!g_Detour_CBaseServer__InactivateClients) + { + snprintf(error, maxlen, "Failed to detour CBaseServer__InactivateClients.\n"); + return false; + } + g_Detour_CBaseServer__InactivateClients->EnableDetour(); - g_pGameEvents->AddListener(&g_ConnectEvents, "player_connect", true); - g_pGameEvents->AddListener(&g_ConnectEvents, "player_disconnect", true); - g_pGameEvents->AddListener(&g_ConnectEvents, "player_changename", true); + g_Detour_CSteam3Server__OnValidateAuthTicketResponse = DETOUR_CREATE_MEMBER(CSteam3Server__OnValidateAuthTicketResponse, "CSteam3Server__OnValidateAuthTicketResponse"); + if(!g_Detour_CSteam3Server__OnValidateAuthTicketResponse) + { + snprintf(error, maxlen, "Failed to detour CSteam3Server__OnValidateAuthTicketResponse.\n"); + return false; + } + g_Detour_CSteam3Server__OnValidateAuthTicketResponse->EnableDetour(); - playerhelpers->AddClientListener(this); + g_pConnectForward = g_pForwards->CreateForward("OnClientPreConnectEx", ET_LowEvent, 5, NULL, Param_String, Param_String, Param_String, Param_String, Param_String); - return true; + g_pOnBeginAuthSessionResult = g_pForwards->CreateForward("OnBeginAuthSessionResult", ET_Ignore, 2, NULL, Param_String, Param_Cell); + + g_pGameEvents->AddListener(&g_ConnectEvents, "player_connect", true); + g_pGameEvents->AddListener(&g_ConnectEvents, "player_disconnect", true); + g_pGameEvents->AddListener(&g_ConnectEvents, "player_changename", true); + + playerhelpers->AddClientListener(this); + + return true; } bool Connect::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool late) { - GET_V_IFACE_CURRENT(GetEngineFactory, engine, IVEngineServer, INTERFACEVERSION_VENGINESERVER); - GET_V_IFACE_ANY(GetServerFactory, gamedll, IServerGameDLL, INTERFACEVERSION_SERVERGAMEDLL); - GET_V_IFACE_CURRENT(GetEngineFactory, g_pGameEvents, IGameEventManager2, INTERFACEVERSION_GAMEEVENTSMANAGER2); - GET_V_IFACE_CURRENT(GetEngineFactory, g_pCVar, ICvar, CVAR_INTERFACE_VERSION); - GET_V_IFACE_CURRENT(GetServerFactory, hltvdirector, IHLTVDirector, INTERFACEVERSION_HLTVDIRECTOR); + GET_V_IFACE_CURRENT(GetEngineFactory, engine, IVEngineServer, INTERFACEVERSION_VENGINESERVER); + GET_V_IFACE_ANY(GetServerFactory, gamedll, IServerGameDLL, INTERFACEVERSION_SERVERGAMEDLL); + GET_V_IFACE_CURRENT(GetEngineFactory, g_pGameEvents, IGameEventManager2, INTERFACEVERSION_GAMEEVENTSMANAGER2); + GET_V_IFACE_CURRENT(GetEngineFactory, g_pCVar, ICvar, CVAR_INTERFACE_VERSION); + GET_V_IFACE_CURRENT(GetServerFactory, hltvdirector, IHLTVDirector, INTERFACEVERSION_HLTVDIRECTOR); - gpGlobals = ismm->GetCGlobals(); - ConVar_Register(0, this); + gpGlobals = ismm->GetCGlobals(); + ConVar_Register(0, this); - g_pSvVisibleMaxPlayers = g_pCVar->FindVar("sv_visiblemaxplayers"); - g_pSvTags = g_pCVar->FindVar("sv_tags"); + g_pSvVisibleMaxPlayers = g_pCVar->FindVar("sv_visiblemaxplayers"); + g_pSvTags = g_pCVar->FindVar("sv_tags"); - return true; + return true; } void Connect::SDK_OnUnload() { - if(g_pConnectForward) - g_pForwards->ReleaseForward(g_pConnectForward); + if(g_pConnectForward) + g_pForwards->ReleaseForward(g_pConnectForward); - if(g_Detour_CBaseServer__ConnectClient) - { - g_Detour_CBaseServer__ConnectClient->Destroy(); - g_Detour_CBaseServer__ConnectClient = NULL; - } - if(g_Detour_CBaseServer__RejectConnection) - { - g_Detour_CBaseServer__RejectConnection->Destroy(); - g_Detour_CBaseServer__RejectConnection = NULL; - } - if(g_Detour_CBaseServer__CheckChallengeType) - { - g_Detour_CBaseServer__CheckChallengeType->Destroy(); - g_Detour_CBaseServer__CheckChallengeType = NULL; - } - if(g_Detour_CBaseServer__InactivateClients) - { - g_Detour_CBaseServer__InactivateClients->Destroy(); - g_Detour_CBaseServer__InactivateClients = NULL; - } - if(g_Detour_CSteam3Server__OnValidateAuthTicketResponse) - { - g_Detour_CSteam3Server__OnValidateAuthTicketResponse->Destroy(); - g_Detour_CSteam3Server__OnValidateAuthTicketResponse = NULL; - } + if(g_Detour_CBaseServer__ConnectClient) + { + g_Detour_CBaseServer__ConnectClient->Destroy(); + g_Detour_CBaseServer__ConnectClient = NULL; + } + if(g_Detour_CBaseServer__RejectConnection) + { + g_Detour_CBaseServer__RejectConnection->Destroy(); + g_Detour_CBaseServer__RejectConnection = NULL; + } + if(g_Detour_CBaseServer__CheckChallengeType) + { + g_Detour_CBaseServer__CheckChallengeType->Destroy(); + g_Detour_CBaseServer__CheckChallengeType = NULL; + } + if(g_Detour_CBaseServer__InactivateClients) + { + g_Detour_CBaseServer__InactivateClients->Destroy(); + g_Detour_CBaseServer__InactivateClients = NULL; + } + if(g_Detour_CSteam3Server__OnValidateAuthTicketResponse) + { + g_Detour_CSteam3Server__OnValidateAuthTicketResponse->Destroy(); + g_Detour_CSteam3Server__OnValidateAuthTicketResponse = NULL; + } - g_pGameEvents->RemoveListener(&g_ConnectEvents); + if (g_pOnBeginAuthSessionResult) + g_pForwards->ReleaseForward(g_pOnBeginAuthSessionResult); - playerhelpers->RemoveClientListener(this); + g_pGameEvents->RemoveListener(&g_ConnectEvents); - if(g_pConnectTimer) - timersys->KillTimer(g_pConnectTimer); + playerhelpers->RemoveClientListener(this); - gameconfs->CloseGameConfigFile(g_pGameConf); + if(g_pConnectTimer) + timersys->KillTimer(g_pConnectTimer); + + gameconfs->CloseGameConfigFile(g_pGameConf); } bool Connect::RegisterConCommandBase(ConCommandBase *pVar) { - /* Always call META_REGCVAR instead of going through the engine. */ - return META_REGCVAR(pVar); + /* Always call META_REGCVAR instead of going through the engine. */ + return META_REGCVAR(pVar); } cell_t ClientPreConnectEx(IPluginContext *pContext, const cell_t *params) { - char *pSteamID; - pContext->LocalToString(params[1], &pSteamID); + char *pSteamID; + pContext->LocalToString(params[1], &pSteamID); - int retVal = params[2]; + int retVal = params[2]; - char *rejectReason; - pContext->LocalToString(params[3], &rejectReason); + char *rejectReason; + pContext->LocalToString(params[3], &rejectReason); - ConnectClientStorage Storage; - if(!g_ConnectClientStorage.retrieve(pSteamID, &Storage)) - return 1; + ConnectClientStorage Storage; + if(!g_ConnectClientStorage.retrieve(pSteamID, &Storage)) + { + return 1; + } - if(retVal == 0) - { - RejectConnection(Storage.address, Storage.iClientChallenge, rejectReason); - return 0; - } + if(retVal == 0) + { + RejectConnection(Storage.address, Storage.iClientChallenge, rejectReason); + return 0; + } - g_bSuppressCheckChallengeType = true; - IClient *pClient = DETOUR_MEMBER_MCALL_ORIGINAL(CBaseServer__ConnectClient, Storage.pThis)(Storage.address, Storage.nProtocol, Storage.iChallenge, Storage.iClientChallenge, - Storage.nAuthProtocol, Storage.pchName, Storage.pchPassword, Storage.pCookie, Storage.cbCookie); + g_bSuppressCheckChallengeType = true; + IClient *pClient = DETOUR_MEMBER_MCALL_ORIGINAL(CBaseServer__ConnectClient, Storage.pThis)(Storage.address, Storage.nProtocol, Storage.iChallenge, Storage.iClientChallenge, + Storage.nAuthProtocol, Storage.pchName, Storage.pchPassword, Storage.pCookie, Storage.cbCookie); - if(!pClient) - return 1; + if(!pClient) + return 1; - bool force = g_SvNoSteam.GetInt() || g_SvForceSteam.GetInt() || !BLoggedOn(); + bool force = g_SvNoSteam.GetInt() || g_SvForceSteam.GetInt() || !BLoggedOn(); - if(Storage.SteamAuthFailed && force && !Storage.GotValidateAuthTicketResponse) - { - if (g_SvLogging.GetInt()) - g_pSM->LogMessage(myself, "%s Force ValidateAuthTicketResponse", pSteamID); + if(Storage.SteamAuthFailed && force && !Storage.GotValidateAuthTicketResponse) + { + if (g_SvLogging.GetInt()) + g_pSM->LogMessage(myself, "%s Force ValidateAuthTicketResponse", pSteamID); - Storage.ValidateAuthTicketResponse.m_SteamID = CSteamID(Storage.ullSteamID); - Storage.ValidateAuthTicketResponse.m_eAuthSessionResponse = k_EAuthSessionResponseOK; - Storage.ValidateAuthTicketResponse.m_OwnerSteamID = Storage.ValidateAuthTicketResponse.m_SteamID; - Storage.GotValidateAuthTicketResponse = true; - } + Storage.ValidateAuthTicketResponse.m_SteamID = CSteamID(Storage.ullSteamID); + Storage.ValidateAuthTicketResponse.m_eAuthSessionResponse = k_EAuthSessionResponseOK; + Storage.ValidateAuthTicketResponse.m_OwnerSteamID = Storage.ValidateAuthTicketResponse.m_SteamID; + Storage.GotValidateAuthTicketResponse = true; + } - // Make sure this is always called in order to verify the client on the server - if(Storage.GotValidateAuthTicketResponse) - { - if (g_SvLogging.GetInt()) - g_pSM->LogMessage(myself, "%s Replay ValidateAuthTicketResponse", pSteamID); + // Make sure this is always called in order to verify the client on the server + if(Storage.GotValidateAuthTicketResponse) + { + if (g_SvLogging.GetInt()) + g_pSM->LogMessage(myself, "%s Replay ValidateAuthTicketResponse", pSteamID); - DETOUR_MEMBER_MCALL_ORIGINAL(CSteam3Server__OnValidateAuthTicketResponse, g_pSteam3Server)(&Storage.ValidateAuthTicketResponse); - } + DETOUR_MEMBER_MCALL_ORIGINAL(CSteam3Server__OnValidateAuthTicketResponse, g_pSteam3Server)(&Storage.ValidateAuthTicketResponse); + } - return 0; + return 0; } cell_t SteamClientAuthenticated(IPluginContext *pContext, const cell_t *params) { - char *pSteamID; - pContext->LocalToString(params[1], &pSteamID); + char *pSteamID; + pContext->LocalToString(params[1], &pSteamID); - ConnectClientStorage Storage; - if(g_ConnectClientStorage.retrieve(pSteamID, &Storage)) - { - if (g_SvLogging.GetInt()) - g_pSM->LogMessage(myself, "%s SteamClientAuthenticated: %d", pSteamID, Storage.SteamLegal); + ConnectClientStorage Storage; + if(g_ConnectClientStorage.retrieve(pSteamID, &Storage)) + { + if (g_SvLogging.GetInt()) + g_pSM->LogMessage(myself, "%s SteamClientAuthenticated: %d", pSteamID, Storage.SteamLegal); - return Storage.SteamLegal; - } - if (g_SvLogging.GetInt()) - g_pSM->LogMessage(myself, "%s SteamClientAuthenticated: FALSE!", pSteamID); + return Storage.SteamLegal; + } + if (g_SvLogging.GetInt()) + g_pSM->LogMessage(myself, "%s SteamClientAuthenticated: FALSE!", pSteamID); - return false; + return false; } const sp_nativeinfo_t MyNatives[] = { - { "ClientPreConnectEx", ClientPreConnectEx }, - { "SteamClientAuthenticated", SteamClientAuthenticated }, - { NULL, NULL } + { "ClientPreConnectEx", ClientPreConnectEx }, + { "SteamClientAuthenticated", SteamClientAuthenticated }, + { NULL, NULL } }; void Connect::SDK_OnAllLoaded() { - sharesys->AddNatives(myself, MyNatives); + sharesys->AddNatives(myself, MyNatives); - SM_GET_LATE_IFACE(SDKTOOLS, g_pSDKTools); + SM_GET_LATE_IFACE(SDKTOOLS, g_pSDKTools); - iserver = g_pSDKTools->GetIServer(); - if (!iserver) { - smutils->LogError(myself, "Failed to get IServer interface from SDKTools!"); - return; - } + iserver = g_pSDKTools->GetIServer(); + if (!iserver) { + smutils->LogError(myself, "Failed to get IServer interface from SDKTools!"); + return; + } - int offset; - if (g_pGameConf->GetOffset("CBaseServer__m_Socket", &offset)) - { - int socknum = *((uint8_t *)iserver + offset); - g_ServerUDPSocket = (*net_sockets)[socknum].hUDP; - } - else - { - smutils->LogError(myself, "Failed to find CBaseServer::m_Socket offset."); - return; - } + int offset; + if (g_pGameConf->GetOffset("CBaseServer__m_Socket", &offset)) + { + int socknum = *((uint8_t *)iserver + offset); + g_ServerUDPSocket = (*net_sockets)[socknum].hUDP; + } + else + { + smutils->LogError(myself, "Failed to find CBaseServer::m_Socket offset."); + return; + } - if (g_pGameConf->GetOffset("IServer__ProcessConnectionlessPacket", &offset)) - { - SH_MANUALHOOK_RECONFIGURE(ProcessConnectionlessPacket, offset, 0, 0); - SH_ADD_MANUALHOOK(ProcessConnectionlessPacket, iserver, SH_STATIC(Hook_ProcessConnectionlessPacket), false); - } - else - { - smutils->LogError(myself, "Failed to find IServer::ProcessConnectionlessPacket offset."); - return; - } + if (g_pGameConf->GetOffset("IServer__ProcessConnectionlessPacket", &offset)) + { + SH_MANUALHOOK_RECONFIGURE(ProcessConnectionlessPacket, offset, 0, 0); + SH_ADD_MANUALHOOK(ProcessConnectionlessPacket, iserver, SH_STATIC(Hook_ProcessConnectionlessPacket), false); + } + else + { + smutils->LogError(myself, "Failed to find IServer::ProcessConnectionlessPacket offset."); + return; + } - g_pConnectTimer = timersys->CreateTimer(&g_ConnectTimer, 1.0, NULL, TIMER_FLAG_REPEAT); + g_pConnectTimer = timersys->CreateTimer(&g_ConnectTimer, 1.0, NULL, TIMER_FLAG_REPEAT); - // A2S_INFO - CQueryCache::CInfo &info = g_QueryCache.info; - info.aGameDirLen = strlcpy(info.aGameDir, smutils->GetGameFolderName(), sizeof(info.aGameDir)); + // A2S_INFO + CQueryCache::CInfo &info = g_QueryCache.info; + info.aGameDirLen = strlcpy(info.aGameDir, smutils->GetGameFolderName(), sizeof(info.aGameDir)); - info.iSteamAppID = engine->GetAppID(); + info.iSteamAppID = engine->GetAppID(); - info.aVersionLen = snprintf(info.aVersion, sizeof(info.aVersion), "%d", engine->GetServerVersion()); + info.aVersionLen = snprintf(info.aVersion, sizeof(info.aVersion), "%d", engine->GetServerVersion()); - info.iUDPPort = iserver->GetLocalUDPPort(); - info.nNewFlags |= 0x80; + info.iUDPPort = iserver->GetLocalUDPPort(); + info.nNewFlags |= 0x80; - info.iGameID = info.iSteamAppID; - info.nNewFlags |= 0x01; + info.iGameID = info.iSteamAppID; + info.nNewFlags |= 0x01; - UpdateQueryCache(); + UpdateQueryCache(); - // A2S_PLAYER - for(int slot = 0; slot < iserver->GetClientCount(); slot++) - { - int client = slot + 1; - IClient *pClient = iserver->GetClient(slot); - if(!pClient) - continue; + // A2S_PLAYER + for(int slot = 0; slot < iserver->GetClientCount(); slot++) + { + int client = slot + 1; + IClient *pClient = iserver->GetClient(slot); + if(!pClient) + continue; - CQueryCache::CPlayer &player = g_QueryCache.players[client]; - IGamePlayer *gplayer = playerhelpers->GetGamePlayer(client); + CQueryCache::CPlayer &player = g_QueryCache.players[client]; + IGamePlayer *gplayer = playerhelpers->GetGamePlayer(client); - if(!player.active) - { - g_QueryCache.info.nNumClients++; - if(pClient->IsFakeClient() && !pClient->IsHLTV() && (!gplayer || (gplayer->IsConnected() && !gplayer->IsSourceTV()))) - { - g_QueryCache.info.nFakeClients++; - player.fake = true; - } - } + if(!player.active) + { + g_QueryCache.info.nNumClients++; + if(pClient->IsFakeClient() && !pClient->IsHLTV() && (!gplayer || (gplayer->IsConnected() && !gplayer->IsSourceTV()))) + { + g_QueryCache.info.nFakeClients++; + player.fake = true; + } + } - player.active = true; - player.pClient = pClient; - player.nameLen = strlcpy(player.name, pClient->GetClientName(), sizeof(player.name)); + player.active = true; + player.pClient = pClient; + player.nameLen = strlcpy(player.name, pClient->GetClientName(), sizeof(player.name)); - INetChannelInfo *netinfo = (INetChannelInfo *)player.pClient->GetNetChannel(); - if(netinfo) - player.time = *net_time - netinfo->GetTimeConnected(); - else - player.time = 0; + INetChannelInfo *netinfo = (INetChannelInfo *)player.pClient->GetNetChannel(); + if(netinfo) + player.time = *net_time - netinfo->GetTimeConnected(); + else + player.time = 0; - if(gplayer && gplayer->IsConnected()) - { - IPlayerInfo *info = gplayer->GetPlayerInfo(); - if(info) - player.score = info->GetFragCount(); - else - player.score = 0; - } + if(gplayer && gplayer->IsConnected()) + { + IPlayerInfo *info = gplayer->GetPlayerInfo(); + if(info) + player.score = info->GetFragCount(); + else + player.score = 0; + } - g_UserIDtoClientMap[pClient->GetUserID()] = client; - } + g_UserIDtoClientMap[pClient->GetUserID()] = client; + } } void Connect::OnClientSettingsChanged(int client) { - if(client >= 1 && client <= SM_MAXPLAYERS) - { - CQueryCache::CPlayer &player = g_QueryCache.players[client]; - if(player.active && player.pClient) - player.nameLen = strlcpy(player.name, player.pClient->GetClientName(), sizeof(player.name)); - } + if(client >= 1 && client <= SM_MAXPLAYERS) + { + CQueryCache::CPlayer &player = g_QueryCache.players[client]; + if(player.active && player.pClient) + player.nameLen = strlcpy(player.name, player.pClient->GetClientName(), sizeof(player.name)); + } } void Connect::OnClientPutInServer(int client) { - if(client >= 1 && client <= SM_MAXPLAYERS) - { - CQueryCache::CPlayer &player = g_QueryCache.players[client]; - IGamePlayer *gplayer = playerhelpers->GetGamePlayer(client); - if(player.active && player.fake && gplayer->IsSourceTV()) - { - player.fake = false; - g_QueryCache.info.nFakeClients--; - } - } + if(client >= 1 && client <= SM_MAXPLAYERS) + { + CQueryCache::CPlayer &player = g_QueryCache.players[client]; + IGamePlayer *gplayer = playerhelpers->GetGamePlayer(client); + if(player.active && player.fake && gplayer->IsSourceTV()) + { + player.fake = false; + g_QueryCache.info.nFakeClients--; + } + } } void Connect::OnTimer() { - for(int client = 1; client <= SM_MAXPLAYERS; client++) - { - CQueryCache::CPlayer &player = g_QueryCache.players[client]; - if(!player.active) - continue; + for(int client = 1; client <= SM_MAXPLAYERS; client++) + { + CQueryCache::CPlayer &player = g_QueryCache.players[client]; + if(!player.active) + continue; - IGamePlayer *gplayer = playerhelpers->GetGamePlayer(client); - if(!gplayer || !gplayer->IsConnected()) - continue; + IGamePlayer *gplayer = playerhelpers->GetGamePlayer(client); + if(!gplayer || !gplayer->IsConnected()) + continue; - IPlayerInfo *info = gplayer->GetPlayerInfo(); - if(info) - player.score = info->GetFragCount(); - } + IPlayerInfo *info = gplayer->GetPlayerInfo(); + if(info) + player.score = info->GetFragCount(); + } - UpdateQueryCache(); + UpdateQueryCache(); } void ConnectEvents::FireGameEvent(IGameEvent *event) { - const char *name = event->GetName(); + const char *name = event->GetName(); - if(strcmp(name, "player_connect") == 0) - { - const int client = event->GetInt("index") + 1; - const int userid = event->GetInt("userid"); - const bool bot = event->GetBool("bot"); - const char *name = event->GetString("name"); + if(strcmp(name, "player_connect") == 0) + { + const int client = event->GetInt("index") + 1; + const int userid = event->GetInt("userid"); + const bool bot = event->GetBool("bot"); + const char *name = event->GetString("name"); - if (g_SvLogging.GetInt()) - g_pSM->LogMessage(myself, "player_connect(client=%d, userid=%d, bot=%d, name=%s)", client, userid, bot, name); + if (g_SvLogging.GetInt()) + g_pSM->LogMessage(myself, "player_connect(client=%d, userid=%d, bot=%d, name=%s)", client, userid, bot, name); - if(client >= 1 && client <= SM_MAXPLAYERS) - { - CQueryCache::CPlayer &player = g_QueryCache.players[client]; + if(client >= 1 && client <= SM_MAXPLAYERS) + { + CQueryCache::CPlayer &player = g_QueryCache.players[client]; - player.active = true; - player.fake = false; - player.pClient = iserver->GetClient(client - 1); - g_QueryCache.info.nNumClients++; - if(bot) - { - player.fake = true; - g_QueryCache.info.nFakeClients++; - } - player.time = *net_time; - player.score = 0; - player.nameLen = strlcpy(player.name, player.pClient->GetClientName(), sizeof(player.name)); + player.active = true; + player.fake = false; + player.pClient = iserver->GetClient(client - 1); + g_QueryCache.info.nNumClients++; + if(bot) + { + player.fake = true; + g_QueryCache.info.nFakeClients++; + } + player.time = *net_time; + player.score = 0; + player.nameLen = strlcpy(player.name, player.pClient->GetClientName(), sizeof(player.name)); - g_UserIDtoClientMap[userid] = client; + g_UserIDtoClientMap[userid] = client; - if (g_SvLogging.GetInt()) - g_pSM->LogMessage(myself, "\tCPlayer(active=%d, fake=%d, pClient=%p, name=%s)", player.active, player.fake, player.pClient, player.name); - } + if (g_SvLogging.GetInt()) + g_pSM->LogMessage(myself, "\tCPlayer(active=%d, fake=%d, pClient=%p, name=%s)", player.active, player.fake, player.pClient, player.name); + } - } - else if(strcmp(name, "player_disconnect") == 0) - { - const int userid = event->GetInt("userid"); - const int client = g_UserIDtoClientMap[userid]; - g_UserIDtoClientMap[userid] = 0; + } + else if(strcmp(name, "player_disconnect") == 0) + { + const int userid = event->GetInt("userid"); + const int client = g_UserIDtoClientMap[userid]; + g_UserIDtoClientMap[userid] = 0; - if (g_SvLogging.GetInt()) - g_pSM->LogMessage(myself, "player_disconnect(userid=%d, client=%d)", userid, client); + if (g_SvLogging.GetInt()) + g_pSM->LogMessage(myself, "player_disconnect(userid=%d, client=%d)", userid, client); - if(client >= 1 && client <= SM_MAXPLAYERS) - { - CQueryCache::CPlayer &player = g_QueryCache.players[client]; - if (g_SvLogging.GetInt()) - g_pSM->LogMessage(myself, "\tCPlayer(active=%d, fake=%d, pClient=%p, name=%s)", player.active, player.fake, player.pClient, player.name); + if(client >= 1 && client <= SM_MAXPLAYERS) + { + CQueryCache::CPlayer &player = g_QueryCache.players[client]; + if (g_SvLogging.GetInt()) + g_pSM->LogMessage(myself, "\tCPlayer(active=%d, fake=%d, pClient=%p, name=%s)", player.active, player.fake, player.pClient, player.name); - if(player.active) - { - g_QueryCache.info.nNumClients--; - if(player.fake) - g_QueryCache.info.nFakeClients--; - } - player.active = false; - player.pClient = NULL; - } + if(player.active) + { + g_QueryCache.info.nNumClients--; + if(player.fake) + g_QueryCache.info.nFakeClients--; + } + player.active = false; + player.pClient = NULL; + } - if(client >= 1 && client <= SM_MAXPLAYERS) - { - char *pSteamID = g_ClientSteamIDMap[client]; - if(*pSteamID) - { - if (g_SvLogging.GetInt()) - g_pSM->LogMessage(myself, "%s OnClientDisconnecting: %d", pSteamID, client); + if(client >= 1 && client <= SM_MAXPLAYERS) + { + char *pSteamID = g_ClientSteamIDMap[client]; + if(*pSteamID) + { + if (g_SvLogging.GetInt()) + g_pSM->LogMessage(myself, "%s OnClientDisconnecting: %d", pSteamID, client); - g_ConnectClientStorage.remove(pSteamID); - *pSteamID = 0; - } - } - } - else if(strcmp(name, "player_changename") == 0) - { - const int userid = event->GetInt("userid"); - const int client = g_UserIDtoClientMap[userid]; + g_ConnectClientStorage.remove(pSteamID); + *pSteamID = 0; + } + } + } + else if(strcmp(name, "player_changename") == 0) + { + const int userid = event->GetInt("userid"); + const int client = g_UserIDtoClientMap[userid]; - g_Connect.OnClientSettingsChanged(client); - } + g_Connect.OnClientSettingsChanged(client); + } } ResultType ConnectTimer::OnTimer(ITimer *pTimer, void *pData) { - g_Connect.OnTimer(); - return Pl_Continue; + g_Connect.OnTimer(); + return Pl_Continue; } void ConnectTimer::OnTimerEnd(ITimer *pTimer, void *pData) {} diff --git a/gamedata/connect2.games.txt b/gamedata/connect2.games.txt index b9edafb..057d5a0 100644 --- a/gamedata/connect2.games.txt +++ b/gamedata/connect2.games.txt @@ -4,21 +4,87 @@ { "#supported" { - "engine" "orangebox_valve" - "engine" "css" + "engine" "dods" + "engine" "css" + "engine" "hl2dm" + "engine" "tf2" + } + + "Offsets" + { + "ISteamGameServer__BeginAuthSession" + { + "linux" "29" + "linux64" "29" + "windows" "29" + } + + "ISteamGameServer__EndAuthSession" + { + "linux" "30" + "linux64" "30" + "windows" "30" + } + } + + "Signatures" + { + "Steam3Server" + { + "library" "engine" + "linux" "@_Z12Steam3Serverv" + "linux64" "@_Z12Steam3Serverv" + } + } + } + + "#default" + { + "#supported" + { + "engine" "dods" + "engine" "css" + "engine" "hl2dm" + "engine" "tf2" + } + + "Offsets" + { + "ISteamGameServer__BeginAuthSession" + { + "linux" "26" + "linux64" "26" + "windows" "26" + "windows64" "26" + } + + "ISteamGameServer__EndAuthSession" + { + "linux" "27" + "linux64" "27" + "windows" "27" + "windows64" "27" + } + + "CheckMasterServerRequestRestart_Steam3ServerFuncOffset" + { + "windows" "240" + "windows64" "299" + } } "Signatures" { "CBaseServer__ConnectClient" { - "library" "engine" - "linux" "@_ZN11CBaseServer13ConnectClientER8netadr_siiiiPKcS3_S3_i" - "mac" "@_ZN11CBaseServer13ConnectClientER8netadr_siiiiPKcS3_S3_i" - "windows" "\x55\x8B\xEC\x81\xEC\x04\x05\x00\x00\x56\x68\x2A\x2A\x2A\x2A\x8B\xF1" + "library" "engine" + "linux" "@_ZN11CBaseServer13ConnectClientER8netadr_siiiiPKcS3_S3_i" + "linux64" "@_ZN11CBaseServer13ConnectClientER8netadr_siiiiPKcS3_S3_i" + "windows" "\x55\x8B\xEC\x81\xEC\x24\x05\x00\x00\x53\x56\x57\x68\x2A\x2A\x2A\x2A" + "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" + "CBaseServer__CheckChallengeType" { "library" "engine" "linux" "@_ZN11CBaseServer18CheckChallengeTypeEP11CBaseClientiR8netadr_siPKcii" @@ -28,31 +94,39 @@ "CBaseServer__RejectConnection" { - "library" "engine" - "linux" "@_ZN11CBaseServer16RejectConnectionERK8netadr_siPKc" - "mac" "@_ZN11CBaseServer16RejectConnectionERK8netadr_siPKc" - "windows" "\x55\x8B\xEC\x81\xEC\x04\x05\x00\x00\x56\x6A\xFF" + "library" "engine" + "linux" "@_ZN11CBaseServer16RejectConnectionERK8netadr_siPKc" + "linux64" "@_ZN11CBaseServer16RejectConnectionERK8netadr_siPKc" + "windows" "\x55\x8B\xEC\x81\xEC\x04\x05\x00\x00\x57" + "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" - "mac" "@_ZN11CBaseClient10SetSteamIDERK8CSteamID" - "windows" "\x55\x8B\xEC\x8B\x55\x08\x8B\x02\x89\x41\x59\x8B\x42\x04" + "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" - "windows" "\xE8\x2A\x2A\x2A\x2A\x83\x38\x00\x74\x2A\xE8\x2A\x2A\x2A\x2A\x8B\x08\x8B\x01\x8B\x40\x2C\xFF\xD0" + "library" "engine" + "windows" "\x55\x8B\xEC\x83\xEC\x1C\x53\x57\x33\xD2" + "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" } - "Steam3Server" + "NET_SendPacket" { "library" "engine" - "linux" "@_Z12Steam3Serverv" - "mac" "@_Z12Steam3Serverv" + "linux" "@_Z14NET_SendPacketP11INetChanneliRK8netadr_sPKhiP8bf_writeb" + } + + "NET_CheckCleanupFakeIPConnection" + { + "library" "engine" + "linux" "@_Z32NET_CheckCleanupFakeIPConnectioniRK8netadr_s" } "CSteam3Server__OnValidateAuthTicketResponse" @@ -60,20 +134,17 @@ "library" "engine" "linux" "@_ZN13CSteam3Server28OnValidateAuthTicketResponseEP28ValidateAuthTicketResponse_t" } - - "s_queryRateChecker" + "s_queryRateChecker" { "library" "engine" "linux" "@_ZL18s_queryRateChecker" } - - "CIPRateLimit__CheckIP" + "CIPRateLimit__CheckIP" { "library" "engine" "linux" "@_ZN12CIPRateLimit7CheckIPE8netadr_s" } - - "CBaseServer__ValidChallenge" + "CBaseServer__ValidChallenge" { "library" "engine" "linux" "@_ZN11CBaseServer14ValidChallengeER8netadr_si" @@ -103,19 +174,5 @@ "linux" "@net_time" } } - - "Offsets" - { - "IServer__ProcessConnectionlessPacket" - { - "windows" "1" - "linux" "2" - } - - "CBaseServer__m_Socket" - { - "linux" "8" - } - } } }