2016-05-08 22:12:08 +02:00
/**
* vim : set ts = 4 :
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* SourceMod Sample Extension
* Copyright ( C ) 2004 - 2008 AlliedModders LLC . All rights reserved .
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*
* This program is free software ; you can redistribute it and / or modify it under
* the terms of the GNU General Public License , version 3.0 , as published by the
* Free Software Foundation .
2019-07-27 20:56:27 +02:00
*
2016-05-08 22:12:08 +02:00
* This program is distributed in the hope that it will be useful , but WITHOUT
* ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE . See the GNU General Public License for more
* details .
*
* You should have received a copy of the GNU General Public License along with
* this program . If not , see < http : //www.gnu.org/licenses/>.
*
* As a special exception , AlliedModders LLC gives you permission to link the
* code of this program ( as well as its derivative works ) to " Half-Life 2, " the
* " Source Engine, " the " SourcePawn JIT, " and any Game MODs that run on software
* by the Valve Corporation . You must obey the GNU General Public License in
* all respects for all other code used . Additionally , AlliedModders LLC grants
* this exception to all derivative works . AlliedModders LLC defines further
* exceptions , found in LICENSE . txt ( as of this writing , version JULY - 31 - 2007 ) ,
* or < http : //www.sourcemod.net/license.php>.
*
* Version : $ Id $
*/
# include "extension.h"
# include "CDetour/detours.h"
2017-02-03 15:36:13 +01:00
# include "steam/steam_gameserver.h"
# include "sm_namehashset.h"
2019-07-27 20:56:27 +02:00
# include <sourcehook.h>
# include <bitbuf.h>
# include <netadr.h>
# include <ISDKTools.h>
# include <iserver.h>
2018-09-06 12:57:57 +02:00
# include <iclient.h>
2019-07-27 20:56:27 +02:00
# include <iplayerinfo.h>
# include <ihltvdirector.h>
# include <ihltv.h>
# include <inetchannelinfo.h>
# include <sys/socket.h>
# include <netinet/in.h>
size_t
strlcpy ( char * dst , const char * src , size_t 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 ;
}
}
/* 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 */
}
2016-05-08 22:12:08 +02:00
/**
* @ file extension . cpp
* @ brief Implement extension code here .
*/
Connect g_Connect ; /**< Global singleton for extension's main interface */
2018-09-06 19:03:52 +02:00
ConnectEvents g_ConnectEvents ;
2019-07-27 20:56:27 +02:00
ConnectTimer g_ConnectTimer ;
2016-05-08 22:12:08 +02:00
SMEXT_LINK ( & g_Connect ) ;
ConVar g_ConnectVersion ( " connect_version " , SMEXT_CONF_VERSION , FCVAR_REPLICATED | FCVAR_NOTIFY , SMEXT_CONF_DESCRIPTION " Version " ) ;
2017-02-12 20:11:59 +01:00
ConVar g_SvNoSteam ( " sv_nosteam " , " 0 " , FCVAR_NOTIFY , " Disable steam validation and force steam authentication. " ) ;
ConVar g_SvForceSteam ( " sv_forcesteam " , " 0 " , FCVAR_NOTIFY , " Force steam authentication. " ) ;
2019-07-27 20:56:27 +02:00
ConVar * g_pSvVisibleMaxPlayers ;
ConVar * g_pSvTags ;
2016-05-08 22:12:08 +02:00
IGameConfig * g_pGameConf = NULL ;
IForward * g_pConnectForward = NULL ;
2018-09-06 19:03:52 +02:00
IGameEventManager2 * g_pGameEvents = NULL ;
2019-07-27 20:56:27 +02:00
ITimer * g_pConnectTimer = NULL ;
ISDKTools * g_pSDKTools = NULL ;
IServer * iserver = NULL ;
CGlobalVars * gpGlobals = NULL ;
IHLTVDirector * hltvdirector = NULL ;
IHLTVServer * hltv = NULL ;
2019-07-28 15:41:03 +02:00
double * net_time = NULL ;
2016-05-08 22:12:08 +02:00
2019-07-27 20:56:27 +02:00
uint8_t g_UserIDtoClientMap [ USHRT_MAX + 1 ] ;
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
} 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()
} netsocket_t ;
CUtlVector < netsocket_t > * net_sockets ;
int g_ServerUDPSocket = 0 ;
2016-05-08 22:12:08 +02:00
2019-07-27 20:56:27 +02:00
SH_DECL_MANUALHOOK1 ( ProcessConnectionlessPacket , 0 , 0 , 0 , bool , netpacket_t * ) ; // virtual bool IServer::ProcessConnectionlessPacket( netpacket_t *packet ) = 0;
void * s_queryRateChecker = NULL ;
bool ( * CIPRateLimit__CheckIP ) ( void * pThis , netadr_t adr ) ;
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 ;
2019-07-28 15:41:03 +02:00
double time ;
2019-07-27 20:56:27 +02:00
} 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 ; // 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 ; // 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 ; // 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 ;
} g_QueryCache ;
class CBaseClient ;
2016-05-08 22:12:08 +02:00
class CBaseServer ;
typedef enum EAuthProtocol
{
k_EAuthProtocolWONCertificate = 1 ,
k_EAuthProtocolHashedCDKey = 2 ,
k_EAuthProtocolSteam = 3 ,
} EAuthProtocol ;
const char * CSteamID : : Render ( ) const
{
static char szSteamID [ 64 ] ;
2017-02-03 15:36:13 +01:00
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 ) ;
2016-05-08 22:12:08 +02:00
return szSteamID ;
}
class CSteam3Server
{
public :
2017-02-03 15:36:13 +01:00
ISteamGameServer * m_pSteamGameServer ;
2016-05-08 22:12:08 +02:00
void * m_pSteamGameServerUtils ;
void * m_pSteamGameServerNetworking ;
void * m_pSteamGameServerStats ;
void * m_pSteamHTTP ;
} * g_pSteam3Server ;
CBaseServer * g_pBaseServer = NULL ;
typedef CSteam3Server * ( * Steam3ServerFunc ) ( ) ;
# ifndef WIN32
typedef void ( * RejectConnectionFunc ) ( CBaseServer * , const netadr_t & address , int iClientChallenge , const char * pchReason ) ;
# else
typedef void ( __fastcall * RejectConnectionFunc ) ( CBaseServer * , void * , const netadr_t & address , int iClientChallenge , const char * pchReason ) ;
# endif
# ifndef WIN32
typedef void ( * SetSteamIDFunc ) ( CBaseClient * , const CSteamID & steamID ) ;
# else
typedef void ( __fastcall * SetSteamIDFunc ) ( CBaseClient * , void * , const CSteamID & steamID ) ;
# endif
Steam3ServerFunc g_pSteam3ServerFunc = NULL ;
RejectConnectionFunc g_pRejectConnectionFunc = NULL ;
SetSteamIDFunc g_pSetSteamIDFunc = NULL ;
CSteam3Server * Steam3Server ( )
{
if ( ! g_pSteam3ServerFunc )
return NULL ;
return g_pSteam3ServerFunc ( ) ;
}
void RejectConnection ( const netadr_t & address , int iClientChallenge , const char * pchReason )
{
if ( ! g_pRejectConnectionFunc | | ! g_pBaseServer )
return ;
# ifndef WIN32
g_pRejectConnectionFunc ( g_pBaseServer , address , iClientChallenge , pchReason ) ;
# else
g_pRejectConnectionFunc ( g_pBaseServer , NULL , address , iClientChallenge , pchReason ) ;
# endif
}
void SetSteamID ( CBaseClient * pClient , const CSteamID & steamID )
{
if ( ! pClient | | ! g_pSetSteamIDFunc )
return ;
# ifndef WIN32
g_pSetSteamIDFunc ( pClient , steamID ) ;
# else
g_pSetSteamIDFunc ( pClient , NULL , steamID ) ;
# endif
}
EBeginAuthSessionResult BeginAuthSession ( const void * pAuthTicket , int cbAuthTicket , CSteamID steamID )
{
2017-02-03 15:36:13 +01:00
if ( ! g_pSteam3Server | | ! g_pSteam3Server - > m_pSteamGameServer )
2016-05-08 22:12:08 +02:00
return k_EBeginAuthSessionResultOK ;
2017-02-03 15:36:13 +01:00
return g_pSteam3Server - > m_pSteamGameServer - > BeginAuthSession ( pAuthTicket , cbAuthTicket , steamID ) ;
2016-05-08 22:12:08 +02:00
}
void EndAuthSession ( CSteamID steamID )
{
2017-02-03 15:36:13 +01:00
if ( ! g_pSteam3Server | | ! g_pSteam3Server - > m_pSteamGameServer )
2016-05-08 22:12:08 +02:00
return ;
2017-02-03 15:36:13 +01:00
g_pSteam3Server - > m_pSteamGameServer - > EndAuthSession ( steamID ) ;
}
2016-05-08 22:12:08 +02:00
2017-02-03 15:36:13 +01:00
bool BLoggedOn ( )
{
if ( ! g_pSteam3Server | | ! g_pSteam3Server - > m_pSteamGameServer )
return false ;
2016-05-08 22:12:08 +02:00
2017-02-03 15:36:13 +01:00
return g_pSteam3Server - > m_pSteamGameServer - > BLoggedOn ( ) ;
2016-05-08 22:12:08 +02:00
}
2019-07-27 20:56:27 +02:00
bool BSecure ( )
{
if ( ! g_pSteam3Server | | ! g_pSteam3Server - > m_pSteamGameServer )
return false ;
return g_pSteam3Server - > m_pSteamGameServer - > BSecure ( ) ;
}
2016-05-08 22:12:08 +02:00
CDetour * g_Detour_CBaseServer__ConnectClient = NULL ;
CDetour * g_Detour_CBaseServer__RejectConnection = NULL ;
CDetour * g_Detour_CBaseServer__CheckChallengeType = NULL ;
CDetour * g_Detour_CSteam3Server__OnValidateAuthTicketResponse = NULL ;
class ConnectClientStorage
{
public :
void * pThis ;
netadr_t address ;
int nProtocol ;
int iChallenge ;
int iClientChallenge ;
int nAuthProtocol ;
2018-02-11 18:52:05 +01:00
char pchName [ 256 ] ;
char pchPassword [ 256 ] ;
char pCookie [ 256 ] ;
2016-05-08 22:12:08 +02:00
int cbCookie ;
2018-09-06 12:57:57 +02:00
IClient * pClient ;
2016-05-08 22:12:08 +02:00
uint64 ullSteamID ;
2017-02-12 20:11:59 +01:00
ValidateAuthTicketResponse_t ValidateAuthTicketResponse ;
bool GotValidateAuthTicketResponse ;
2018-03-22 19:37:12 +01:00
bool SteamLegal ;
bool SteamAuthFailed ;
2016-05-08 22:12:08 +02:00
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 ;
2019-07-27 20:56:27 +02:00
strlcpy ( this - > pchName , pchName , sizeof ( this - > pchName ) ) ;
strlcpy ( this - > pchPassword , pchPassword , sizeof ( this - > pchPassword ) ) ;
strlcpy ( this - > pCookie , pCookie , sizeof ( this - > pCookie ) ) ;
2016-05-08 22:12:08 +02:00
this - > cbCookie = cbCookie ;
2018-09-06 12:57:57 +02:00
this - > pClient = NULL ;
2017-02-12 20:11:59 +01:00
this - > GotValidateAuthTicketResponse = false ;
2018-03-22 19:37:12 +01:00
this - > SteamLegal = false ;
this - > SteamAuthFailed = false ;
2016-05-08 22:12:08 +02:00
}
} ;
StringHashMap < ConnectClientStorage > g_ConnectClientStorage ;
bool g_bEndAuthSessionOnRejectConnection = false ;
CSteamID g_lastClientSteamID ;
bool g_bSuppressCheckChallengeType = false ;
2017-02-12 20:11:59 +01:00
DETOUR_DECL_MEMBER1 ( CSteam3Server__OnValidateAuthTicketResponse , int , ValidateAuthTicketResponse_t * , pResponse )
2017-02-03 15:36:13 +01:00
{
char aSteamID [ 32 ] ;
2019-07-27 20:56:27 +02:00
strlcpy ( aSteamID , pResponse - > m_SteamID . Render ( ) , sizeof ( aSteamID ) ) ;
2017-02-03 15:36:13 +01:00
2018-03-22 19:37:12 +01:00
bool SteamLegal = pResponse - > m_eAuthSessionResponse = = k_EAuthSessionResponseOK ;
bool force = g_SvNoSteam . GetInt ( ) | | g_SvForceSteam . GetInt ( ) | | ! BLoggedOn ( ) ;
2018-08-17 23:29:43 +02:00
2018-09-06 12:57:57 +02:00
g_pSM - > LogMessage ( myself , " %s SteamLegal: %d (%d) " , aSteamID , SteamLegal , pResponse - > m_eAuthSessionResponse ) ;
2018-08-17 23:29:43 +02:00
2018-03-22 19:37:12 +01:00
if ( ! SteamLegal & & force )
pResponse - > m_eAuthSessionResponse = k_EAuthSessionResponseOK ;
2017-02-03 15:36:13 +01:00
ConnectClientStorage Storage ;
if ( g_ConnectClientStorage . retrieve ( aSteamID , & Storage ) )
{
2018-08-17 23:29:43 +02:00
if ( ! Storage . GotValidateAuthTicketResponse )
{
Storage . GotValidateAuthTicketResponse = true ;
Storage . ValidateAuthTicketResponse = * pResponse ;
Storage . SteamLegal = SteamLegal ;
g_ConnectClientStorage . replace ( aSteamID , Storage ) ;
}
2017-02-03 15:36:13 +01:00
}
2017-02-12 20:11:59 +01:00
return DETOUR_MEMBER_CALL ( CSteam3Server__OnValidateAuthTicketResponse ) ( pResponse ) ;
2017-02-03 15:36:13 +01:00
}
2016-05-08 22:12:08 +02:00
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 ) ;
}
g_pBaseServer = ( CBaseServer * ) this ;
if ( pCookie = = NULL | | ( size_t ) cbCookie < sizeof ( uint64 ) )
{
RejectConnection ( address , iClientChallenge , " #GameUI_ServerRejectInvalidSteamCertLen " ) ;
return NULL ;
}
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 passwordBuffer [ 255 ] ;
2019-07-27 20:56:27 +02:00
strlcpy ( passwordBuffer , pchPassword , sizeof ( passwordBuffer ) ) ;
2016-05-08 22:12:08 +02:00
uint64 ullSteamID = * ( uint64 * ) pCookie ;
void * pvTicket = ( void * ) ( ( intptr_t ) pCookie + sizeof ( uint64 ) ) ;
int cbTicket = cbCookie - sizeof ( uint64 ) ;
g_bEndAuthSessionOnRejectConnection = true ;
g_lastClientSteamID = CSteamID ( ullSteamID ) ;
char aSteamID [ 32 ] ;
2019-07-27 20:56:27 +02:00
strlcpy ( aSteamID , g_lastClientSteamID . Render ( ) , sizeof ( aSteamID ) ) ;
2016-05-08 22:12:08 +02:00
2018-09-08 22:07:59 +02:00
// 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 ) ;
// 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 ;
}
2018-09-06 12:57:57 +02:00
bool NoSteam = g_SvNoSteam . GetInt ( ) | | ! BLoggedOn ( ) ;
bool SteamAuthFailed = false ;
EBeginAuthSessionResult result = BeginAuthSession ( pvTicket , cbTicket , g_lastClientSteamID ) ;
if ( result ! = k_EBeginAuthSessionResultOK )
{
if ( ! NoSteam )
{
RejectConnection ( address , iClientChallenge , " #GameUI_ServerRejectSteam " ) ;
return NULL ;
}
2018-09-08 22:07:59 +02:00
Storage . SteamAuthFailed = SteamAuthFailed = true ;
2018-09-06 12:57:57 +02:00
}
2018-09-08 22:07:59 +02:00
if ( ExistingSteamid & & ! AsyncWaiting )
2016-05-08 22:12:08 +02:00
{
2018-09-06 12:57:57 +02:00
// 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 ;
}
// Kick existing player
if ( Storage . pClient )
{
Storage . pClient - > Disconnect ( " Same Steam ID connected. " ) ;
}
else
{
RejectConnection ( address , iClientChallenge , " Please try again later. " ) ;
return NULL ;
}
}
2016-05-08 22:12:08 +02:00
}
2018-09-08 22:07:59 +02:00
char rejectReason [ 255 ] ;
cell_t retVal = 1 ;
2016-05-08 22:12:08 +02:00
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 ;
}
2018-09-06 12:57:57 +02:00
g_pSM - > LogMessage ( myself , " %s SteamAuthFailed: %d (%d) | retVal = %d " , aSteamID , SteamAuthFailed , result , retVal ) ;
2018-03-22 19:37:12 +01:00
2016-05-08 22:12:08 +02:00
// k_OnClientPreConnectEx_Reject
if ( retVal = = 0 )
{
2018-03-22 19:37:12 +01:00
g_ConnectClientStorage . remove ( aSteamID ) ;
2016-05-08 22:12:08 +02:00
RejectConnection ( address , iClientChallenge , rejectReason ) ;
return NULL ;
}
2018-03-22 19:37:12 +01:00
Storage . pThis = this ;
Storage . ullSteamID = ullSteamID ;
Storage . SteamAuthFailed = SteamAuthFailed ;
if ( ! g_ConnectClientStorage . replace ( aSteamID , Storage ) )
{
RejectConnection ( address , iClientChallenge , " Internal error. " ) ;
return NULL ;
}
2016-05-08 22:12:08 +02:00
// k_OnClientPreConnectEx_Async
if ( retVal = = - 1 )
{
return NULL ;
}
// k_OnClientPreConnectEx_Accept
g_bSuppressCheckChallengeType = true ;
2017-02-03 15:36:13 +01:00
IClient * pClient = DETOUR_MEMBER_CALL ( CBaseServer__ConnectClient ) ( address , nProtocol , iChallenge , iClientChallenge , nAuthProtocol , pchName , pchPassword , pCookie , cbCookie ) ;
2019-07-27 20:56:27 +02:00
if ( pClient )
strlcpy ( g_ClientSteamIDMap [ pClient - > GetPlayerSlot ( ) + 1 ] , aSteamID , sizeof ( * g_ClientSteamIDMap ) ) ;
2018-09-06 12:57:57 +02:00
Storage . pClient = pClient ;
g_ConnectClientStorage . replace ( aSteamID , Storage ) ;
2018-03-22 19:37:12 +01:00
if ( pClient & & SteamAuthFailed )
2017-02-12 20:11:59 +01:00
{
ValidateAuthTicketResponse_t Response ;
Response . m_SteamID = g_lastClientSteamID ;
2018-03-22 19:37:12 +01:00
Response . m_eAuthSessionResponse = k_EAuthSessionResponseAuthTicketInvalid ;
2017-02-12 20:11:59 +01:00
Response . m_OwnerSteamID = Response . m_SteamID ;
DETOUR_MEMBER_MCALL_CALLBACK ( CSteam3Server__OnValidateAuthTicketResponse , g_pSteam3Server ) ( & Response ) ;
}
2017-02-03 15:36:13 +01:00
return pClient ;
2016-05-08 22:12:08 +02:00
}
DETOUR_DECL_MEMBER3 ( CBaseServer__RejectConnection , void , netadr_t & , address , int , iClientChallenge , const char * , pchReason )
{
if ( g_bEndAuthSessionOnRejectConnection )
{
EndAuthSession ( g_lastClientSteamID ) ;
g_bEndAuthSessionOnRejectConnection = false ;
}
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 ;
SetSteamID ( pClient , g_lastClientSteamID ) ;
g_bSuppressCheckChallengeType = false ;
return true ;
}
return DETOUR_MEMBER_CALL ( CBaseServer__CheckChallengeType ) ( pClient , nUserID , address , nAuthProtocol , pCookie , cbCookie , iClientChallenge ) ;
}
2019-07-27 20:56:27 +02:00
void UpdateQueryCache ( )
{
CQueryCache : : CInfo & info = g_QueryCache . info ;
info . aHostNameLen = strlcpy ( info . aHostName , iserver - > GetName ( ) , sizeof ( info . aHostName ) ) ;
info . aMapNameLen = strlcpy ( info . aMapName , iserver - > GetMapName ( ) , sizeof ( info . aMapName ) ) ;
info . aGameDescriptionLen = strlcpy ( info . aGameDescription , gamedll - > GetGameDescription ( ) , 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 ( ! ( 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 - > GetUDPPort ( ) ;
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 ;
uint8_t * info_cache = g_QueryCache . info_cache ;
uint16_t pos = 5 ; // header: FF FF FF FF I
info_cache [ pos + + ] = info . nProtocol ;
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 . aGameDir , info . aGameDirLen + 1 ) ;
pos + = info . aGameDirLen + 1 ;
memcpy ( & info_cache [ pos ] , info . aGameDescription , info . aGameDescriptionLen + 1 ) ;
pos + = info . aGameDescriptionLen + 1 ;
* ( uint16_t * ) & info_cache [ pos ] = info . iSteamAppID ;
pos + = 2 ;
info_cache [ pos + + ] = info . nNumClients ;
info_cache [ pos + + ] = info . nMaxClients ;
info_cache [ pos + + ] = info . nFakeClients ;
info_cache [ pos + + ] = info . nServerType ;
info_cache [ pos + + ] = info . nEnvironment ;
info_cache [ pos + + ] = info . nPassword ;
info_cache [ pos + + ] = info . bIsSecure ;
memcpy ( & info_cache [ pos ] , info . aVersion , info . aVersionLen + 1 ) ;
pos + = info . aVersionLen + 1 ;
info_cache [ pos + + ] = info . nNewFlags ;
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 & 0x40 ) {
* ( uint16_t * ) & info_cache [ pos ] = info . iHLTVUDPPort ;
pos + = 2 ;
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 & 0x01 ) {
* ( uint64_t * ) & info_cache [ pos ] = info . iGameID ;
pos + = 8 ;
}
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 ) ;
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 ) ) ;
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 ) ;
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 ] ;
/* 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 = 0 ; i < SM_MAXPLAYERS ; i + + )
{
2019-07-30 23:19:45 +02:00
const CQueryCache : : CPlayer & player = g_QueryCache . players [ i ] ;
2019-07-27 20:56:27 +02:00
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 ;
2019-07-28 15:41:03 +02:00
* ( float * ) & response [ pos ] = * net_time - player . time ; // Duration | float | Time (in seconds) player has been connected to the server.
2019-07-27 20:56:27 +02:00
pos + = 4 ;
}
sendto ( g_ServerUDPSocket , response , pos , 0 , ( sockaddr * ) & to , sizeof ( to ) ) ;
RETURN_META_VALUE ( MRES_SUPERCEDE , true ) ;
}
RETURN_META_VALUE ( MRES_IGNORED , false ) ;
}
2016-05-08 22:12:08 +02:00
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 ;
}
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 ;
}
# ifndef WIN32
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 ;
}
//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);
# endif
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 ) ;
*/
2019-07-27 20:56:27 +02:00
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 ( " CIPRateLimit__CheckIP " , ( void * * ) & CIPRateLimit__CheckIP ) | | ! CIPRateLimit__CheckIP )
{
snprintf ( error , maxlen , " Failed to find CIPRateLimit::CheckIP 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 ;
}
if ( ! g_pGameConf - > GetMemSig ( " net_sockets " , ( void * * ) & net_sockets ) | | ! net_sockets )
{
snprintf ( error , maxlen , " Failed to find net_sockets address. \n " ) ;
return false ;
}
2019-07-28 15:41:03 +02:00
if ( ! g_pGameConf - > GetMemSig ( " net_time " , ( void * * ) & net_time ) | | ! net_time )
{
snprintf ( error , maxlen , " Failed to find net_time address. \n " ) ;
return false ;
}
2016-05-08 22:12:08 +02:00
CDetourManager : : Init ( g_pSM - > GetScriptingEngine ( ) , g_pGameConf ) ;
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__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_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_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_pConnectForward = g_pForwards - > CreateForward ( " OnClientPreConnectEx " , ET_LowEvent , 5 , NULL , Param_String , Param_String , Param_String , Param_String , Param_String ) ;
2019-07-27 20:56:27 +02:00
g_pGameEvents - > AddListener ( & g_ConnectEvents , " player_connect " , true ) ;
2018-09-06 19:03:52 +02:00
g_pGameEvents - > AddListener ( & g_ConnectEvents , " player_disconnect " , true ) ;
2018-09-06 12:57:57 +02:00
2019-07-27 20:56:27 +02:00
playerhelpers - > AddClientListener ( this ) ;
2016-05-08 22:12:08 +02:00
return true ;
}
bool Connect : : SDK_OnMetamodLoad ( ISmmAPI * ismm , char * error , size_t maxlen , bool late )
{
2019-07-27 20:56:27 +02:00
GET_V_IFACE_CURRENT ( GetEngineFactory , engine , IVEngineServer , INTERFACEVERSION_VENGINESERVER ) ;
GET_V_IFACE_ANY ( GetServerFactory , gamedll , IServerGameDLL , INTERFACEVERSION_SERVERGAMEDLL ) ;
2018-09-06 19:03:52 +02:00
GET_V_IFACE_CURRENT ( GetEngineFactory , g_pGameEvents , IGameEventManager2 , INTERFACEVERSION_GAMEEVENTSMANAGER2 ) ;
2016-05-08 22:12:08 +02:00
GET_V_IFACE_CURRENT ( GetEngineFactory , g_pCVar , ICvar , CVAR_INTERFACE_VERSION ) ;
2019-07-27 20:56:27 +02:00
GET_V_IFACE_CURRENT ( GetServerFactory , hltvdirector , IHLTVDirector , INTERFACEVERSION_HLTVDIRECTOR ) ;
gpGlobals = ismm - > GetCGlobals ( ) ;
2016-05-08 22:12:08 +02:00
ConVar_Register ( 0 , this ) ;
2019-07-27 20:56:27 +02:00
g_pSvVisibleMaxPlayers = g_pCVar - > FindVar ( " sv_visiblemaxplayers " ) ;
g_pSvTags = g_pCVar - > FindVar ( " sv_tags " ) ;
2016-05-08 22:12:08 +02:00
return true ;
}
void Connect : : SDK_OnUnload ( )
{
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_CSteam3Server__OnValidateAuthTicketResponse )
{
g_Detour_CSteam3Server__OnValidateAuthTicketResponse - > Destroy ( ) ;
g_Detour_CSteam3Server__OnValidateAuthTicketResponse = NULL ;
}
2018-09-06 19:03:52 +02:00
g_pGameEvents - > RemoveListener ( & g_ConnectEvents ) ;
2018-09-06 12:57:57 +02:00
2019-07-27 20:56:27 +02:00
playerhelpers - > RemoveClientListener ( this ) ;
2019-07-30 23:19:45 +02:00
if ( g_pConnectTimer )
timersys - > KillTimer ( g_pConnectTimer ) ;
2019-07-27 20:56:27 +02:00
2016-05-08 22:12:08 +02:00
gameconfs - > CloseGameConfigFile ( g_pGameConf ) ;
}
bool Connect : : RegisterConCommandBase ( ConCommandBase * 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 ) ;
int retVal = params [ 2 ] ;
char * rejectReason ;
pContext - > LocalToString ( params [ 3 ] , & rejectReason ) ;
ConnectClientStorage Storage ;
if ( ! g_ConnectClientStorage . retrieve ( pSteamID , & Storage ) )
return 1 ;
if ( retVal = = 0 )
{
RejectConnection ( Storage . address , Storage . iClientChallenge , rejectReason ) ;
return 0 ;
}
g_bSuppressCheckChallengeType = true ;
2017-02-12 20:11:59 +01:00
IClient * pClient = DETOUR_MEMBER_MCALL_ORIGINAL ( CBaseServer__ConnectClient , Storage . pThis ) ( Storage . address , Storage . nProtocol , Storage . iChallenge , Storage . iClientChallenge ,
2016-05-08 22:12:08 +02:00
Storage . nAuthProtocol , Storage . pchName , Storage . pchPassword , Storage . pCookie , Storage . cbCookie ) ;
2017-02-12 20:11:59 +01:00
if ( ! pClient )
return 1 ;
2018-03-22 19:37:12 +01:00
bool force = g_SvNoSteam . GetInt ( ) | | g_SvForceSteam . GetInt ( ) | | ! BLoggedOn ( ) ;
if ( Storage . SteamAuthFailed & & force & & ! Storage . GotValidateAuthTicketResponse )
2017-02-12 20:11:59 +01:00
{
2018-09-06 12:57:57 +02:00
g_pSM - > LogMessage ( myself , " %s Force ValidateAuthTicketResponse " , pSteamID ) ;
2017-02-12 20:11:59 +01:00
Storage . ValidateAuthTicketResponse . m_SteamID = CSteamID ( Storage . ullSteamID ) ;
Storage . ValidateAuthTicketResponse . m_eAuthSessionResponse = k_EAuthSessionResponseOK ;
Storage . ValidateAuthTicketResponse . m_OwnerSteamID = Storage . ValidateAuthTicketResponse . m_SteamID ;
Storage . GotValidateAuthTicketResponse = true ;
}
2016-05-08 22:12:08 +02:00
// Make sure this is always called in order to verify the client on the server
2017-02-12 20:11:59 +01:00
if ( Storage . GotValidateAuthTicketResponse )
2018-03-22 19:37:12 +01:00
{
2018-09-06 12:57:57 +02:00
g_pSM - > LogMessage ( myself , " %s Replay ValidateAuthTicketResponse " , pSteamID ) ;
2017-02-12 20:11:59 +01:00
DETOUR_MEMBER_MCALL_ORIGINAL ( CSteam3Server__OnValidateAuthTicketResponse , g_pSteam3Server ) ( & Storage . ValidateAuthTicketResponse ) ;
2018-03-22 19:37:12 +01:00
}
2016-05-08 22:12:08 +02:00
return 0 ;
}
2018-03-22 19:37:12 +01:00
cell_t SteamClientAuthenticated ( IPluginContext * pContext , const cell_t * params )
{
char * pSteamID ;
pContext - > LocalToString ( params [ 1 ] , & pSteamID ) ;
ConnectClientStorage Storage ;
if ( g_ConnectClientStorage . retrieve ( pSteamID , & Storage ) )
{
2018-09-06 12:57:57 +02:00
g_pSM - > LogMessage ( myself , " %s SteamClientAuthenticated: %d " , pSteamID , Storage . SteamLegal ) ;
2018-03-22 19:37:12 +01:00
return Storage . SteamLegal ;
}
2018-09-06 12:57:57 +02:00
g_pSM - > LogMessage ( myself , " %s SteamClientAuthenticated: FALSE! " , pSteamID ) ;
2018-03-22 19:37:12 +01:00
return false ;
}
2016-05-08 22:12:08 +02:00
const sp_nativeinfo_t MyNatives [ ] =
{
{ " ClientPreConnectEx " , ClientPreConnectEx } ,
2018-03-22 19:37:12 +01:00
{ " SteamClientAuthenticated " , SteamClientAuthenticated } ,
2016-05-08 22:12:08 +02:00
{ NULL , NULL }
} ;
void Connect : : SDK_OnAllLoaded ( )
{
sharesys - > AddNatives ( myself , MyNatives ) ;
2019-07-27 20:56:27 +02:00
SM_GET_LATE_IFACE ( SDKTOOLS , g_pSDKTools ) ;
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 ;
}
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 ;
}
2019-07-30 23:19:45 +02:00
g_pConnectTimer = timersys - > CreateTimer ( & g_ConnectTimer , 1.0 , NULL , TIMER_FLAG_REPEAT ) ;
2019-07-27 20:56:27 +02:00
// A2S_INFO
CQueryCache : : CInfo & info = g_QueryCache . info ;
info . aGameDirLen = strlcpy ( info . aGameDir , smutils - > GetGameFolderName ( ) , sizeof ( info . aGameDir ) ) ;
info . iSteamAppID = engine - > GetAppID ( ) ;
info . aVersionLen = snprintf ( info . aVersion , sizeof ( info . aVersion ) , " %d " , engine - > GetServerVersion ( ) ) ;
info . iUDPPort = iserver - > GetUDPPort ( ) ;
info . nNewFlags | = 0x80 ;
info . iGameID = info . iSteamAppID ;
info . nNewFlags | = 0x01 ;
UpdateQueryCache ( ) ;
// A2S_PLAYER
2019-07-30 23:19:45 +02:00
for ( int slot = 0 ; slot < iserver - > GetClientCount ( ) ; slot + + )
2019-07-27 20:56:27 +02:00
{
2019-07-30 23:19:45 +02:00
int client = slot + 1 ;
IClient * pClient = iserver - > GetClient ( slot ) ;
if ( ! pClient | | ! pClient - > IsConnected ( ) )
continue ;
2019-07-27 20:56:27 +02:00
CQueryCache : : CPlayer & player = g_QueryCache . players [ client ] ;
IGamePlayer * gplayer = playerhelpers - > GetGamePlayer ( client ) ;
if ( ! player . active )
{
g_QueryCache . info . nNumClients + + ;
2019-07-30 23:19:45 +02:00
if ( pClient - > IsFakeClient ( ) & & ! pClient - > IsHLTV ( ) & & ( ! gplayer | | ( gplayer - > IsConnected ( ) & & ! gplayer - > IsSourceTV ( ) ) ) )
2019-07-27 20:56:27 +02:00
{
g_QueryCache . info . nFakeClients + + ;
player . fake = true ;
}
}
player . active = true ;
2019-07-30 23:19:45 +02:00
player . pClient = pClient ;
player . nameLen = strlcpy ( player . name , pClient - > GetClientName ( ) , sizeof ( player . name ) ) ;
2019-07-27 20:56:27 +02:00
INetChannelInfo * netinfo = ( INetChannelInfo * ) player . pClient - > GetNetChannel ( ) ;
if ( netinfo )
2019-07-28 15:41:03 +02:00
player . time = * net_time - netinfo - > GetTimeConnected ( ) ;
2019-07-27 20:56:27 +02:00
else
player . time = 0 ;
2019-07-30 23:19:45 +02:00
if ( gplayer & & gplayer - > IsConnected ( ) )
{
IPlayerInfo * info = gplayer - > GetPlayerInfo ( ) ;
if ( info )
player . score = info - > GetFragCount ( ) ;
else
player . score = 0 ;
}
2019-07-27 20:56:27 +02:00
2019-07-30 23:19:45 +02:00
g_UserIDtoClientMap [ pClient - > GetUserID ( ) ] = client ;
2019-07-27 20:56:27 +02:00
}
}
void Connect : : OnClientSettingsChanged ( int client )
{
if ( client > = 1 & & client < = SM_MAXPLAYERS )
{
CQueryCache : : CPlayer & player = g_QueryCache . players [ client ] ;
2019-07-30 23:19:45 +02:00
if ( player . active & & player . pClient )
player . nameLen = strlcpy ( player . name , player . pClient - > GetClientName ( ) , sizeof ( player . name ) ) ;
2019-07-27 20:56:27 +02:00
}
}
void Connect : : OnClientPutInServer ( int client )
{
if ( client > = 1 & & client < = SM_MAXPLAYERS )
{
CQueryCache : : CPlayer & player = g_QueryCache . players [ client ] ;
IGamePlayer * gplayer = playerhelpers - > GetGamePlayer ( client ) ;
2019-07-30 23:19:45 +02:00
if ( player . active & & player . fake & & gplayer - > IsSourceTV ( ) )
2019-07-27 20:56:27 +02:00
{
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 ;
IGamePlayer * gplayer = playerhelpers - > GetGamePlayer ( client ) ;
if ( ! gplayer | | ! gplayer - > IsConnected ( ) )
continue ;
IPlayerInfo * info = gplayer - > GetPlayerInfo ( ) ;
if ( info )
player . score = info - > GetFragCount ( ) ;
}
2019-07-30 23:19:45 +02:00
/* SANITY CHECK */
int countedClients = 0 ;
for ( int client = 1 ; client < = SM_MAXPLAYERS ; client + + )
{
CQueryCache : : CPlayer & player = g_QueryCache . players [ client ] ;
IClient * pClient = NULL ;
if ( ( client - 1 ) < iserver - > GetClientCount ( ) )
pClient = iserver - > GetClient ( client - 1 ) ;
if ( ! pClient | | ! pClient - > IsConnected ( ) )
{
if ( player . active )
{
g_pSM - > LogMessage ( myself , " SANITY_CHECK_FAIL: player.active(True) != pClient->IsConnected(False) " ) ;
g_pSM - > LogMessage ( myself , " \t CPlayer(client=%d, active=%d, fake=%d, pClient=%p, name=%s) " , client , player . active , player . fake , player . pClient , player . name ) ;
player . active = false ;
player . pClient = NULL ;
}
continue ;
}
if ( ! player . active )
{
g_pSM - > LogMessage ( myself , " SANITY_CHECK_FAIL: player.active(False) != pClient->IsConnected(True) " ) ;
g_pSM - > LogMessage ( myself , " \t CPlayer(client=%d, name=%s) \n " , client , pClient - > GetClientName ( ) ) ;
}
countedClients + + ;
}
if ( countedClients ! = g_QueryCache . info . nNumClients )
{
g_pSM - > LogMessage ( myself , " SANITY_CHECK_FAIL: countedClients(%d) != nNumClients(%d) " , countedClients , g_QueryCache . info . nNumClients ) ;
g_QueryCache . info . nNumClients = countedClients ;
}
/* SANITY CHECK */
2019-07-27 20:56:27 +02:00
UpdateQueryCache ( ) ;
2016-05-08 22:12:08 +02:00
}
2018-03-22 19:37:12 +01:00
2018-09-06 19:03:52 +02:00
void ConnectEvents : : FireGameEvent ( IGameEvent * event )
2018-03-22 19:37:12 +01:00
{
2018-09-06 19:03:52 +02:00
const char * name = event - > GetName ( ) ;
2019-07-27 20:56:27 +02:00
if ( strcmp ( name , " player_connect " ) = = 0 )
{
2019-07-30 23:19:45 +02:00
const int client = event - > GetInt ( " index " ) + 1 ;
const int userid = event - > GetInt ( " userid " ) ;
const bool bot = event - > GetBool ( " bot " ) ;
2019-07-27 20:56:27 +02:00
const char * name = event - > GetString ( " name " ) ;
2019-07-30 23:19:45 +02:00
g_pSM - > LogMessage ( myself , " player_connect(client=%d, userid=%d, bot=%d, name=%s) " , client , userid , bot , name ) ;
2019-07-27 20:56:27 +02:00
if ( client > = 1 & & client < = SM_MAXPLAYERS )
{
CQueryCache : : CPlayer & player = g_QueryCache . players [ client ] ;
2019-07-30 23:19:45 +02:00
g_pSM - > LogMessage ( myself , " \t PRE CPlayer(active=%d, fake=%d, pClient=%p) " , player . active , player . fake , player . pClient ) ;
2019-07-27 20:56:27 +02:00
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 + + ;
}
2019-07-28 15:41:03 +02:00
player . time = * net_time ;
2019-07-27 20:56:27 +02:00
player . score = 0 ;
player . nameLen = strlcpy ( player . name , player . pClient - > GetClientName ( ) , sizeof ( player . name ) ) ;
g_UserIDtoClientMap [ userid ] = client ;
2019-07-30 23:19:45 +02:00
g_pSM - > LogMessage ( myself , " \t POST CPlayer(active=%d, fake=%d, pClient=%p, name=%s) " , player . active , player . fake , player . pClient , player . name ) ;
2019-07-27 20:56:27 +02:00
}
2019-07-30 23:19:45 +02:00
else
g_pSM - > LogMessage ( myself , " \t IF_CLIENT_FAILED " ) ;
2019-07-27 20:56:27 +02:00
}
else if ( strcmp ( name , " player_disconnect " ) = = 0 )
2018-03-22 19:37:12 +01:00
{
2019-07-30 23:19:45 +02:00
const int userid = event - > GetInt ( " userid " ) ;
const int client = g_UserIDtoClientMap [ userid ] ;
2019-07-27 20:56:27 +02:00
g_UserIDtoClientMap [ client ] = 0 ;
2019-07-30 23:19:45 +02:00
g_pSM - > LogMessage ( myself , " player_disconnect(userid=%d, client=%d) " , userid , client ) ;
2019-07-27 20:56:27 +02:00
if ( client > = 1 & & client < = SM_MAXPLAYERS )
{
CQueryCache : : CPlayer & player = g_QueryCache . players [ client ] ;
2019-07-30 23:19:45 +02:00
g_pSM - > LogMessage ( myself , " \t CPlayer(active=%d, fake=%d, pClient=%p, name=%s) " , player . active , player . fake , player . pClient , player . name ) ;
2019-07-27 20:56:27 +02:00
if ( player . active )
{
g_QueryCache . info . nNumClients - - ;
if ( player . fake )
g_QueryCache . info . nFakeClients - - ;
}
player . active = false ;
player . pClient = NULL ;
}
2019-07-30 23:19:45 +02:00
else
g_pSM - > LogMessage ( myself , " \t IF_CLIENT_FAILED " ) ;
2018-09-06 19:03:52 +02:00
2019-07-27 20:56:27 +02:00
if ( client > = 1 & & client < = SM_MAXPLAYERS )
2018-09-06 19:03:52 +02:00
{
2019-07-27 20:56:27 +02:00
char * pSteamID = g_ClientSteamIDMap [ client ] ;
if ( * pSteamID )
{
g_pSM - > LogMessage ( myself , " %s OnClientDisconnecting: %d " , pSteamID , client ) ;
g_ConnectClientStorage . remove ( pSteamID ) ;
* pSteamID = 0 ;
}
2018-09-06 19:03:52 +02:00
}
2018-03-22 19:37:12 +01:00
}
}
2019-07-27 20:56:27 +02:00
ResultType ConnectTimer : : OnTimer ( ITimer * pTimer , void * pData )
{
g_Connect . OnTimer ( ) ;
return Pl_Continue ;
}
void ConnectTimer : : OnTimerEnd ( ITimer * pTimer , void * pData ) { }