From 243c3cc80fa91ef5e0294cbb18e312a75e0d72ac Mon Sep 17 00:00:00 2001 From: Alibek Omarov Date: Thu, 15 Jun 2023 04:46:22 +0300 Subject: [PATCH] engine: server: port old engine's userinfo penalty --- engine/server/server.h | 10 +++++++- engine/server/sv_client.c | 54 ++++++++++++++++++++++++++++++++++++++- engine/server/sv_main.c | 11 ++++++++ 3 files changed, 73 insertions(+), 2 deletions(-) diff --git a/engine/server/server.h b/engine/server/server.h index 26bb775f..99f77ef1 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -261,6 +261,11 @@ typedef struct sv_client_s int ignorecmdtime_warns; // how many times client time was faster than server during this session qboolean ignorecmdtime_warned; // did we warn our server operator in the log for this batch of commands? + + double fullupdate_next_calltime; + double userinfo_next_changetime; + double userinfo_penalty; + int userinfo_change_attempts; } sv_client_t; /* @@ -462,6 +467,10 @@ extern convar_t sv_novis; extern convar_t sv_hostmap; extern convar_t sv_validate_changelevel; extern convar_t sv_maxclients; +extern convar_t sv_userinfo_enable_penalty; +extern convar_t sv_userinfo_penalty_time; +extern convar_t sv_userinfo_penalty_multiplier; +extern convar_t sv_userinfo_penalty_attempts; //=========================================================== // @@ -479,7 +488,6 @@ int SV_CalcPacketLoss( sv_client_t *cl ); void SV_ExecuteUserCommand (char *s); void SV_InitOperatorCommands( void ); void SV_KillOperatorCommands( void ); -void SV_UserinfoChanged( sv_client_t *cl ); void SV_RemoteCommand( netadr_t from, sizebuf_t *msg ); void SV_PrepWorldFrame( void ); void SV_ProcessFile( sv_client_t *cl, const char *filename ); diff --git a/engine/server/sv_client.c b/engine/server/sv_client.c index 8a9c2f92..88e2e175 100644 --- a/engine/server/sv_client.c +++ b/engine/server/sv_client.c @@ -42,6 +42,8 @@ typedef struct ucmd_s static int g_userid = 1; +static void SV_UserinfoChanged( sv_client_t *cl ); + /* ================= SV_GetPlayerCount @@ -1775,6 +1777,50 @@ static qboolean SV_Pause_f( sv_client_t *cl ) return true; } +static qboolean SV_ShouldUpdateUserinfo( sv_client_t *cl ) +{ + qboolean allow = true; // predict state + + if( !sv_userinfo_enable_penalty.value ) + return allow; + + if( FBitSet( cl->flags, FCL_FAKECLIENT )) + return allow; + + // start from 1 second + if( !cl->userinfo_penalty ) + cl->userinfo_penalty = sv_userinfo_penalty_time.value; + + // player changes userinfo after limit time window, but before + // next timewindow + // he seems to be spammer, so just increase change attempts + if( host.realtime < cl->userinfo_next_changetime + cl->userinfo_penalty * sv_userinfo_penalty_multiplier.value ) + { + // player changes userinfo too quick! ignore! + if( host.realtime < cl->userinfo_next_changetime ) + { + Con_Reportf( "SV_ShouldUpdateUserinfo: ignore userinfo update for %s: penalty %f, attempts %i\n", + cl->name, cl->userinfo_penalty, cl->userinfo_change_attempts ); + allow = false; + } + + cl->userinfo_change_attempts++; + } + + // they spammed too fast, increase penalty + if( cl->userinfo_change_attempts > sv_userinfo_penalty_attempts.value ) + { + Con_Reportf( "SV_ShouldUpdateUserinfo: penalty set %f for %s\n", + cl->userinfo_penalty, cl->name ); + cl->userinfo_penalty *= sv_userinfo_penalty_multiplier.value; + cl->userinfo_change_attempts = 0; + } + + cl->userinfo_next_changetime = host.realtime + cl->userinfo_penalty; + + return allow; +} + /* ================= SV_UserinfoChanged @@ -1783,7 +1829,7 @@ Pull specific info from a newly changed userinfo string into a more C freindly form. ================= */ -void SV_UserinfoChanged( sv_client_t *cl ) +static void SV_UserinfoChanged( sv_client_t *cl ) { int i, dupc = 1; edict_t *ent = cl->edict; @@ -1794,6 +1840,12 @@ void SV_UserinfoChanged( sv_client_t *cl ) if( !COM_CheckString( cl->userinfo )) return; + if( !SV_ShouldUpdateUserinfo( cl )) + return; + + if( !Info_IsValid( cl->userinfo )) + return; + val = Info_ValueForKey( cl->userinfo, "name" ); Q_strncpy( name2, val, sizeof( name2 )); COM_TrimSpace( name2, name1 ); diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index 7d7e8384..74f288dc 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -140,6 +140,12 @@ static CVAR_DEFINE_AUTO( sv_allow_touch, "1", FCVAR_ARCHIVE, "allow connect with static CVAR_DEFINE_AUTO( sv_allow_vr, "1", FCVAR_ARCHIVE, "allow connect from vr version" ); static CVAR_DEFINE_AUTO( sv_allow_noinputdevices, "1", FCVAR_ARCHIVE, "allow connect from old versions without useragent" ); +CVAR_DEFINE_AUTO( sv_userinfo_enable_penalty, "1", FCVAR_ARCHIVE, "enable penalty time for too fast userinfo updates(name, model, etc)" ); +CVAR_DEFINE_AUTO( sv_userinfo_penalty_time, "0.3", FCVAR_ARCHIVE, "initial penalty time" ); +CVAR_DEFINE_AUTO( sv_userinfo_penalty_multiplier, "2", FCVAR_ARCHIVE, "penalty time multiplier" ); +CVAR_DEFINE_AUTO( sv_userinfo_penalty_attempts, "4", FCVAR_ARCHIVE, "if max attempts count was exceeded, penalty time will be increased" ); + + //============================================================================ /* ================ @@ -928,6 +934,11 @@ void SV_Init( void ) Cvar_RegisterVariable( &sv_allow_vr ); Cvar_RegisterVariable( &sv_allow_noinputdevices ); + Cvar_RegisterVariable( &sv_userinfo_enable_penalty ); + Cvar_RegisterVariable( &sv_userinfo_penalty_time ); + Cvar_RegisterVariable( &sv_userinfo_penalty_multiplier ); + Cvar_RegisterVariable( &sv_userinfo_penalty_attempts ); + // when we in developer-mode automatically turn cheats on if( host_developer.value ) Cvar_SetValue( "sv_cheats", 1.0f );