summaryrefslogtreecommitdiff
path: root/engine/sv_filter.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /engine/sv_filter.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'engine/sv_filter.cpp')
-rw-r--r--engine/sv_filter.cpp957
1 files changed, 957 insertions, 0 deletions
diff --git a/engine/sv_filter.cpp b/engine/sv_filter.cpp
new file mode 100644
index 0000000..ef7a1a9
--- /dev/null
+++ b/engine/sv_filter.cpp
@@ -0,0 +1,957 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//===========================================================================//
+
+
+#include "server_pch.h"
+#include "vfilter.h" // Renamed to avoid conflict with Microsoft's filter.h
+#include "sv_filter.h"
+#include "sv_steamauth.h"
+#include "GameEventManager.h"
+#include "proto_oob.h"
+#include "tier1/CommandBuffer.h"
+#ifndef DEDICATED
+#include "cl_steamauth.h"
+#endif
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+static ConVar sv_filterban( "sv_filterban", "1", 0, "Set packet filtering by IP mode" );
+
+CUtlVector< ipfilter_t > g_IPFilters;
+CUtlVector< userfilter_t > g_UserFilters;
+
+#define BANNED_IP_FILENAME "banned_ip.cfg"
+#define BANNED_USER_FILENAME "banned_user.cfg"
+#define CONFIG_DIR "cfg/"
+#define STEAM_PREFIX "STEAM_"
+
+//-----------------------------------------------------------------------------
+// Purpose: Sends a message to prospective clients letting them know they're banned
+// Input : *adr -
+//-----------------------------------------------------------------------------
+void Filter_SendBan( const netadr_t& adr )
+{
+ NET_OutOfBandPrintf( NS_SERVER, adr, "%cBanned by server\n", A2A_PRINT );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Checks an IP address to see if it is banned
+// Input : *adr -
+// Output : bool
+//-----------------------------------------------------------------------------
+bool Filter_ShouldDiscard( const netadr_t& adr )
+{
+ if ( sv_filterban.GetInt() == 0 )
+ {
+ return false;
+ }
+
+ bool bNegativeFilter = sv_filterban.GetInt() == 1;
+
+ unsigned in = *(unsigned *)&adr.ip[0];
+
+ // Handle timeouts
+ for ( int i = g_IPFilters.Count() - 1 ; i >= 0 ; i--)
+ {
+ if ( ( g_IPFilters[i].compare != 0xffffffff) &&
+ ( g_IPFilters[i].banEndTime != 0.0f ) &&
+ ( g_IPFilters[i].banEndTime <= realtime ) )
+ {
+ g_IPFilters.Remove(i);
+ continue;
+ }
+
+ // Only get here if ban is still in effect.
+ if ( (in & g_IPFilters[i].mask) == g_IPFilters[i].compare)
+ {
+ return bNegativeFilter;
+ }
+ }
+
+ return !bNegativeFilter;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Takes an IP address string and fills in an ipfilter_t mask and compare (raw address)
+// Input : *s -
+// *f -
+// Output : bool Filter_ConvertString
+//-----------------------------------------------------------------------------
+bool Filter_ConvertString( const char *s, ipfilter_t *f )
+{
+ char num[128];
+ int i, j;
+ byte b[4];
+ byte m[4];
+
+ for (i=0 ; i<4 ; i++)
+ {
+ b[i] = 0;
+ m[i] = 0;
+ }
+
+ for (i=0 ; i<4 ; i++)
+ {
+ if (*s < '0' || *s > '9')
+ {
+ ConMsg("Bad filter address: %s\n", s);
+ return false;
+ }
+
+ j = 0;
+ while (*s >= '0' && *s <= '9')
+ {
+ num[j++] = *s++;
+ }
+ num[j] = 0;
+ b[i] = atoi(num);
+ if (b[i] != 0)
+ m[i] = 255;
+
+ if (!*s)
+ break;
+ s++;
+ }
+
+ f->mask = *(unsigned int *)m;
+ f->compare = *(unsigned int *)b;
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Adds an IP ban
+//-----------------------------------------------------------------------------
+static void Filter_Add_f( const CCommand& args )
+{
+ int i = 0;
+ float banTime;
+ bool bKick = true;
+ bool bFound = false;
+ char szDuration[256];
+ CGameClient *client = NULL;
+
+ if ( !Q_stricmp( args[0], "banip" ) )
+ {
+ ConMsg( "Note: should use \"addip\" instead of \"banip\".\n" );
+ }
+
+ if ( args.ArgC() != 3 )
+ {
+ ConMsg( "Usage: addip < minutes > < ipaddress >\nUse 0 minutes for permanent\n" );
+ return;
+ }
+
+ ipfilter_t f;
+ if ( !Filter_ConvertString( args[2], &f ) )
+ return;
+
+ for (i=0 ; i<g_IPFilters.Count(); i++)
+ {
+ if ( g_IPFilters[i].compare == 0xffffffff || ( g_IPFilters[i].compare == f.compare && g_IPFilters[i].mask == f.mask ) )
+ break; // free spot
+ }
+
+ if (i == g_IPFilters.Count())
+ {
+ if (g_IPFilters.Count() == MAX_IPFILTERS)
+ {
+ ConMsg( "addip: IP filter list is full\n" );
+ return;
+ }
+
+ i = g_IPFilters.AddToTail();
+ }
+ else
+ {
+ // updating in-place, so don't kick people
+ bKick = false;
+ }
+
+ banTime = atof( args[1] );
+ if (banTime < 0.01f)
+ {
+ banTime = 0.0f;
+ }
+
+ g_IPFilters[i].banTime = banTime;
+
+ // Time to unban.
+ g_IPFilters[i].banEndTime = ( banTime != 0.0 ) ? ( realtime + 60.0 * banTime ) : 0.0;
+
+ if ( !Filter_ConvertString( args[2], &g_IPFilters[i]) )
+ {
+ g_IPFilters[i].compare = 0xffffffff;
+ }
+
+ if ( bKick )
+ {
+ // Kick him if he's on
+ for ( i=0; i < sv.GetClientCount(); ++i )
+ {
+ client = sv.Client(i);
+ if ( !client || !client->IsActive() || !client->IsConnected() || !client->IsSpawned() )
+ continue;
+
+ if ( client->IsFakeClient() )
+ continue;
+
+ if ( !Filter_ShouldDiscard( client->GetNetChannel()->GetRemoteAddress() ) )
+ continue;
+
+ bFound = true;
+ break;
+ }
+ }
+
+ // Build a duration string for the ban
+ if ( banTime == 0.0 )
+ {
+ Q_snprintf( szDuration, sizeof( szDuration ), "permanently" );
+ }
+ else
+ {
+ Q_snprintf( szDuration, sizeof( szDuration ), "for %.2f minutes", banTime );
+ }
+
+ // fire the event
+
+ IGameEvent *event = g_GameEventManager.CreateEvent( "server_addban" );
+
+ if ( event )
+ {
+ if ( bFound && client )
+ {
+ event->SetString( "name", client->m_Name );
+ event->SetInt( "userid", client->GetUserID() );
+ event->SetString( "networkid", client->GetNetworkIDString() );
+ }
+ else
+ {
+ event->SetString( "name", "" );
+ event->SetInt( "userid", 0 );
+ event->SetString( "networkid", "" );
+ }
+
+ event->SetString( "ip", args[2] );
+ event->SetString( "duration", szDuration );
+ event->SetString( "by", ( cmd_source == src_command ) ? "Console" : host_client->m_Name );
+ event->SetBool( "kicked", bKick && bFound && client );
+
+ g_GameEventManager.FireEvent( event );
+ }
+
+ if ( bKick && bFound && client )
+ {
+ client->ClientPrintf ( "The server operator has added you to the banned list.\n" );
+ client->Disconnect( "Added to banned list" );
+ }
+}
+
+// IP Address filtering ConCommands
+static ConCommand addip( "addip", Filter_Add_f, "Add an IP address to the ban list." );
+static ConCommand banip( "banip", Filter_Add_f, "Add an IP address to the ban list." );
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Removes an IP ban
+//-----------------------------------------------------------------------------
+CON_COMMAND( removeip, "Remove an IP address from the ban list." )
+{
+ ipfilter_t f;
+ int i;
+
+ if ( args.ArgC() < 1 )
+ {
+ ConMsg( "Usage: removeip < slot | ipaddress >\n" );
+ return;
+ }
+
+ // if no "." in the string we'll assume it's a slot number
+ if ( !Q_strstr( args[1], "." ) )
+ {
+ int slot = Q_atoi( args[1] );
+ if ( slot > 0 && slot <= g_IPFilters.Count() )
+ {
+ byte b[4];
+ char szIP[32];
+
+ // array access is zero based
+ slot--;
+
+ *(unsigned *)b = g_IPFilters[slot].compare;
+ Q_snprintf( szIP, sizeof( szIP ), "%3i.%3i.%3i.%3i", b[0], b[1], b[2], b[3] );
+
+ g_IPFilters.Remove( slot );
+
+ // Tell server operator
+ ConMsg( "removeip: filter removed for %s, IP %s\n", args[1], szIP );
+
+ // send an event
+ IGameEvent *event = g_GameEventManager.CreateEvent( "server_removeban" );
+ if ( event )
+ {
+ event->SetString( "networkid", "" );
+ event->SetString( "ip", szIP );
+ event->SetString( "by", ( cmd_source == src_command ) ? "Console" : host_client->m_Name );
+
+ g_GameEventManager.FireEvent( event );
+ }
+ }
+ else
+ {
+ ConMsg( "removeip: invalid slot %i\n", slot );
+ }
+
+ return;
+ }
+
+ if ( !Filter_ConvertString( args[1], &f ) )
+ return;
+
+ for ( i = 0 ; i < g_IPFilters.Count() ; i++ )
+ {
+ if ( ( g_IPFilters[i].mask == f.mask ) &&
+ ( g_IPFilters[i].compare == f.compare ) )
+ {
+ g_IPFilters.Remove(i);
+ ConMsg( "removeip: filter removed for %s\n", args[1] );
+
+ // send an event
+ IGameEvent *event = g_GameEventManager.CreateEvent( "server_removeban" );
+
+ if ( event )
+ {
+ event->SetString( "networkid", "" );
+ event->SetString( "ip", args[1] );
+ event->SetString( "by", ( cmd_source == src_command ) ? "Console" : host_client->m_Name );
+ g_GameEventManager.FireEvent( event );
+ }
+
+ return;
+ }
+ }
+ ConMsg( "removeip: couldn't find %s\n", args[1] );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Lists IP bans
+//-----------------------------------------------------------------------------
+CON_COMMAND( listip, "List IP addresses on the ban list." )
+{
+ int i;
+ byte b[4];
+ int count = g_IPFilters.Count();
+
+ if ( !count )
+ {
+ ConMsg( "IP filter list: empty\n" );
+ return;
+ }
+ else
+ {
+ if ( count == 1 )
+ {
+ ConMsg( "IP filter list: %i entry\n", count );
+ }
+ else
+ {
+ ConMsg( "IP filter list: %i entries\n", count );
+ }
+ }
+
+ for ( i = 0 ; i < count ; i++ )
+ {
+ *(unsigned *)b = g_IPFilters[i].compare;
+
+ if ( g_IPFilters[i].banTime != 0.0f )
+ {
+ ConMsg( "%i %3i.%3i.%3i.%3i : %.3f min\n", i+1, b[0], b[1], b[2], b[3], g_IPFilters[i].banTime );
+ }
+ else
+ {
+ ConMsg( "%i %3i.%3i.%3i.%3i : permanent\n", i+1, b[0], b[1], b[2], b[3] );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Saves IP bans to a file
+//-----------------------------------------------------------------------------
+CON_COMMAND( writeip, "Save the ban list to " BANNED_IP_FILENAME "." )
+{
+ FileHandle_t f;
+ char name[MAX_OSPATH];
+ byte b[4];
+ int i;
+ float banTime;
+
+ Q_strncpy( name, CONFIG_DIR BANNED_IP_FILENAME, sizeof( name ) );
+
+ ConMsg( "Writing %s.\n", name );
+
+ f = g_pFileSystem->Open ( name, "wb" );
+ if ( !f )
+ {
+ ConMsg( "Couldn't open %s\n", name );
+ return;
+ }
+
+ for ( i = 0 ; i < g_IPFilters.Count() ; i++ )
+ {
+ *(unsigned *)b = g_IPFilters[i].compare;
+
+ // Only store out the permanent bad guys from this server.
+ banTime = g_IPFilters[i].banTime;
+
+ if ( banTime != 0.0f )
+ {
+ continue;
+ }
+
+ g_pFileSystem->FPrintf( f, "addip 0 %i.%i.%i.%i\r\n", b[0], b[1], b[2], b[3] );
+ }
+
+ g_pFileSystem->Close( f );
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Checks a USERID_t to see if the Steam ID has been banned
+//-----------------------------------------------------------------------------
+bool Filter_IsUserBanned( const USERID_t& userid )
+{
+#ifndef _XBOX
+ if ( sv_filterban.GetInt() == 0 )
+ return false;
+
+ bool bNegativeFilter = sv_filterban.GetInt() == 1;
+
+ // Handle timeouts
+ for ( int i =g_UserFilters.Count() - 1 ; i >= 0 ; i-- )
+ {
+ // Time out old filters
+ if ( ( g_UserFilters[i].banEndTime != 0.0f ) &&
+ ( g_UserFilters[i].banEndTime <= realtime ) )
+ {
+ g_UserFilters.Remove( i );
+ continue;
+ }
+
+ // Only get here if ban is still in effect.
+ if ( Steam3Server().CompareUserID( userid, g_UserFilters[i].userid ) )
+ {
+ return bNegativeFilter;
+ }
+ }
+
+ return !bNegativeFilter;
+#else
+ return false;
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Converts a "STEAM_X:Y:Z" string into a USERID_t
+//-----------------------------------------------------------------------------
+USERID_t *Filter_StringToUserID( const char *str )
+{
+ static USERID_t id;
+ Q_memset( &id, 0, sizeof( id ) );
+
+ if ( str && str[ 0 ] )
+ {
+ char szTemp[128];
+ if ( !Q_strnicmp( str, STEAM_PREFIX, strlen( STEAM_PREFIX ) ) )
+ {
+ Q_strncpy( szTemp, str + Q_strlen( STEAM_PREFIX ), sizeof( szTemp ) - 1 );
+ id.idtype = IDTYPE_STEAM;
+
+ szTemp[ sizeof( szTemp ) - 1 ] = '\0';
+
+ CCommand args;
+ args.Tokenize( szTemp );
+ if ( args.ArgC() >= 5 )
+ {
+ // allow settings from old style steam2 format
+ TSteamGlobalUserID steam2ID;
+
+ steam2ID.m_SteamInstanceID = (SteamInstanceID_t)atoi( args[ 0 ] );
+ steam2ID.m_SteamLocalUserID.Split.High32bits = (int)atoi( args[ 2 ] );
+ steam2ID.m_SteamLocalUserID.Split.Low32bits = (int)atoi( args[ 4 ] );
+ EUniverse eUniverse = k_EUniversePublic;
+ if ( Steam3Server().GetGSSteamID().IsValid() )
+ eUniverse = Steam3Server().GetGSSteamID().GetEUniverse();
+#ifndef DEDICATED
+ else if ( Steam3Client().SteamUser() )
+ eUniverse = Steam3Client().SteamUser()->GetSteamID().GetEUniverse();
+#endif
+ id.steamid.SetFromSteam2( &steam2ID, eUniverse );
+ }
+ }
+ else
+ {
+ id.steamid.SetFromString( str, k_EUniversePublic );
+ if ( id.steamid.IsValid() )
+ id.idtype = IDTYPE_STEAM;
+ }
+
+ }
+ return &id;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Saves Steam ID bans to a file
+//-----------------------------------------------------------------------------
+CON_COMMAND( writeid, "Writes a list of permanently-banned user IDs to " BANNED_USER_FILENAME "." )
+{
+ FileHandle_t f;
+ char name[MAX_OSPATH];
+ int i;
+ float banTime;
+
+ Q_strncpy( name, CONFIG_DIR BANNED_USER_FILENAME, sizeof( name ) );
+
+ ConMsg( "Writing %s.\n", name );
+
+ f = g_pFileSystem->Open ( name, "wb" );
+ if ( !f )
+ {
+ ConMsg( "Couldn't open %s\n", name );
+ return;
+ }
+
+ for ( i = 0 ; i < g_UserFilters.Count() ; i++ )
+ {
+ banTime = g_UserFilters[i].banTime;
+
+ if ( banTime != 0.0f )
+ {
+ continue;
+ }
+
+ g_pFileSystem->FPrintf( f, "banid 0 %s\r\n", GetUserIDString( g_UserFilters[i].userid ) );
+ }
+
+ g_pFileSystem->Close( f );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Removes a Steam ID ban
+//-----------------------------------------------------------------------------
+CON_COMMAND( removeid, "Remove a user ID from the ban list." )
+{
+ int i = 0;
+ const char *pszArg1 = NULL;
+ char szSearchString[64];
+
+ if ( args.ArgC() != 2 && args.ArgC() != 6 )
+ {
+ ConMsg( "Usage: removeid < slot | uniqueid >\n" );
+ return;
+ }
+
+ // get the first argument
+ pszArg1 = args[1];
+
+ // don't need the # if they're using it
+ if ( !Q_strncmp( pszArg1, "#", 1 ) )
+ {
+ ConMsg( "Usage: removeid < userid | uniqueid >\n" );
+ ConMsg( "No # necessary\n" );
+ return;
+ }
+
+ // if the first letter is a character then
+ // we're searching for a uniqueid ( e.g. STEAM_ )
+ if ( *pszArg1 < '0' || *pszArg1 > '9' || V_atoi64( pszArg1 ) > ( (uint32)~0 ) )
+ {
+ bool bValid = false;
+
+ // SteamID ( need to reassemble it )
+ if ( !Q_strnicmp( pszArg1, STEAM_PREFIX, Q_strlen( STEAM_PREFIX ) ) && Q_strstr( args[2], ":" ) )
+ {
+ Q_snprintf( szSearchString, sizeof( szSearchString ), "%s:%s:%s", pszArg1, args[3], args[5] );
+
+ USERID_t *id = Filter_StringToUserID( szSearchString );
+ if ( id )
+ {
+ bValid = id->steamid.IsValid();
+ if ( bValid )
+ V_sprintf_safe( szSearchString, "%s", id->steamid.Render() );
+ }
+ }
+ else
+ {
+ CSteamID cSteamIDCheck;
+ const char *pchUUID = args.ArgS();
+ if ( pchUUID )
+ {
+ cSteamIDCheck.SetFromString( pchUUID, k_EUniversePublic );
+ bValid = cSteamIDCheck.IsValid();
+ if ( bValid )
+ V_sprintf_safe( szSearchString, "%s", cSteamIDCheck.Render() );
+ }
+ }
+ // some other ID (e.g. "UNKNOWN", "STEAM_ID_PENDING", "STEAM_ID_LAN")
+ // NOTE: assumed to be one argument
+ if ( !bValid )
+ {
+ ConMsg( "removeid: invalid ban ID \"%s\"\n", pszArg1 );
+ return;
+ }
+
+ for ( i = 0 ; i < g_UserFilters.Count() ; i++ )
+ {
+ if ( Q_stricmp( GetUserIDString( g_UserFilters[i].userid ), szSearchString ) )
+ continue;
+
+ g_UserFilters.Remove( i );
+ ConMsg( "removeid: filter removed for %s\n", szSearchString );
+
+ // send an event
+ IGameEvent *event = g_GameEventManager.CreateEvent( "server_removeban" );
+
+ if ( event )
+ {
+ event->SetString( "networkid", szSearchString );
+ event->SetString( "ip", "" );
+ event->SetString( "by", ( cmd_source == src_command ) ? "Console" : host_client->m_Name );
+ g_GameEventManager.FireEvent( event );
+ }
+
+ return;
+ }
+
+ ConMsg( "removeid: couldn't find %s\n", szSearchString );
+ }
+ // this is a userid
+ else
+ {
+ int slot = Q_atoi( pszArg1 );
+ if ( slot > 0 && slot <= g_UserFilters.Count() )
+ {
+ USERID_t id;
+
+ // array access is zero based
+ slot--;
+
+ // Copy off slot
+ id = g_UserFilters[slot].userid;
+
+ g_UserFilters.Remove( slot );
+
+ // Tell server operator
+ ConMsg( "removeid: filter removed for %s, ID %s\n", pszArg1, GetUserIDString( id ) );
+
+ // send an event
+ IGameEvent *event = g_GameEventManager.CreateEvent( "server_removeban" );
+
+ if ( event )
+ {
+ event->SetString( "networkid", GetUserIDString( id ) );
+ event->SetString( "ip", "" );
+ event->SetString( "by", ( cmd_source == src_command ) ? "Console" : host_client->m_Name );
+ g_GameEventManager.FireEvent( event );
+ }
+ }
+ else
+ {
+ ConMsg( "removeid: invalid slot %i\n", slot );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Prints Steam ID bans to the console
+//-----------------------------------------------------------------------------
+CON_COMMAND( listid, "Lists banned users." )
+{
+ int i;
+ int count = g_UserFilters.Count();
+
+ if ( !count )
+ {
+ ConMsg( "ID filter list: empty\n" );
+ return;
+ }
+ else
+ {
+ if ( count == 1 )
+ {
+ ConMsg( "ID filter list: %i entry\n", count );
+ }
+ else
+ {
+ ConMsg( "ID filter list: %i entries\n", count );
+ }
+ }
+
+ for ( i = 0 ; i < count ; i++ )
+ {
+ if ( g_UserFilters[i].banTime != 0.0 )
+ {
+ ConMsg( "%i %s : %.3f min\n", i+1, GetUserIDString( g_UserFilters[i].userid ), g_UserFilters[i].banTime );
+ }
+ else
+ {
+ ConMsg( "%i %s : permanent\n", i+1, GetUserIDString( g_UserFilters[i].userid ) );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Bans a Steam ID
+//-----------------------------------------------------------------------------
+CON_COMMAND( banid, "Add a user ID to the ban list." )
+{
+#ifndef _XBOX
+ int i;
+ float banTime;
+ USERID_t localId;
+ USERID_t * id = NULL;
+ int iSearchIndex = -1;
+ char szDuration[256];
+ char szSearchString[64];
+ bool bKick = false;
+ bool bPlaying = false;
+ const char *pszArg2 = NULL;
+ CGameClient *client = NULL;
+
+ if ( Steam3Server().BLanOnly() )
+ {
+ ConMsg( "Can't ban users on a LAN\n" );
+ return;
+ }
+
+ if ( args.ArgC() < 3 || args.ArgC() > 8 )
+ {
+ ConMsg( "Usage: banid < minutes > < userid | uniqueid > { kick }\n" );
+ ConMsg( "Use 0 minutes for permanent\n");
+ return;
+ }
+
+ banTime = Q_atof( args[1] );
+ if ( banTime < 0.01 )
+ {
+ banTime = 0.0;
+ }
+
+ // get the first argument
+ pszArg2 = args[2];
+
+ // don't need the # if they're using it
+ if ( !Q_strncmp( pszArg2, "#", 1 ) )
+ {
+ ConMsg( "Usage: banid < minutes > < userid | uniqueid > { kick }\n" );
+ ConMsg( "No # necessary\n");
+ return;
+ }
+
+ bKick = ( args.ArgC() >= 3 && Q_strcasecmp( args[ args.ArgC() - 1 ], "kick" ) == 0 );
+
+
+ // if the first letter is a character then
+ // we're searching for a uniqueid ( e.g. STEAM_ )
+ if ( *pszArg2 < '0' || *pszArg2 > '9' || V_atoi64( pszArg2 ) > ((uint32)~0) )
+ {
+ bool bValid = false;
+ iSearchIndex = -1;
+
+ // SteamID (need to reassemble it)
+ if ( !Q_strnicmp( pszArg2, STEAM_PREFIX, strlen( STEAM_PREFIX ) ) && Q_strstr( args[3], ":" ) )
+ {
+ Q_snprintf( szSearchString, sizeof( szSearchString ), "%s:%s:%s", pszArg2, args[4], args[6] );
+ bValid = true;
+ }
+ else
+ {
+ CSteamID cSteamIDCheck;
+ const char *pchArgs = args.ArgS();
+ const char *pchUUID = strchr( pchArgs, ' ' );
+ if ( pchUUID )
+ {
+ cSteamIDCheck.SetFromString( pchUUID + 1, k_EUniversePublic );
+ bValid = cSteamIDCheck.IsValid();
+ if ( bValid )
+ V_sprintf_safe( szSearchString, "%s", cSteamIDCheck.Render() );
+ }
+ }
+ // some other ID (e.g. "UNKNOWN", "STEAM_ID_PENDING", "STEAM_ID_LAN")
+ // NOTE: assumed to be one argument
+ if ( !bValid )
+ {
+ ConMsg( "Can't ban users with ID \"%s\"\n", pszArg2 );
+ return;
+ }
+ }
+ else
+ {
+ // see if it is a userid
+ iSearchIndex = Q_atoi( pszArg2 );
+ }
+
+ // find this client (if they're currently in the server)
+ for ( i = 0; i < sv.GetClientCount(); i++ )
+ {
+ client = sv.Client(i);
+
+ if ( !client || !client->IsActive() || !client->IsConnected() || !client->IsSpawned() )
+ {
+ continue;
+ }
+
+ if ( client->IsFakeClient() )
+ {
+ continue;
+ }
+
+ // searching by UserID
+ if ( iSearchIndex != -1 )
+ {
+ if ( client->GetUserID() == iSearchIndex )
+ {
+ // found!
+ localId = client->GetNetworkID();
+ id = &localId;
+ bPlaying = true;
+ break;
+ }
+ }
+ // searching by UniqueID
+ else
+ {
+ if ( Q_stricmp( client->GetNetworkIDString(), szSearchString ) == 0 )
+ {
+ // found!
+ localId = client->GetNetworkID();
+ id = &localId;
+ bPlaying = true;
+ break;
+ }
+ }
+ }
+
+ // if we were searching by userid and we didn't find the person, we're done
+ if ( iSearchIndex != -1 && !id )
+ {
+ ConMsg( "banid: couldn't find userid %d\n", iSearchIndex );
+ return;
+ }
+
+ if ( !id )
+ {
+ // we're searching by SteamID and we haven't found them actively playing
+ id = Filter_StringToUserID( szSearchString );
+
+ if ( !id )
+ {
+ ConMsg( "banid: Couldn't resolve uniqueid \"%s\".\n", szSearchString );
+ ConMsg( "Usage: banid < minutes > < userid | uniqueid > { kick }\n" );
+ ConMsg( "Use 0 minutes for permanent\n");
+ return;
+ }
+ }
+
+ if ( !id )
+ {
+ // Should never occur!!!
+ ConMsg( "SV_BanId_f: id == NULL\n" );
+ return;
+ }
+
+ // See if it's in the list already
+ for ( i = 0 ; i < g_UserFilters.Count() ; i++ )
+ {
+ // We're just updating an existing id
+ if ( Steam3Server().CompareUserID( g_UserFilters[i].userid, *id ) )
+ break;
+ }
+
+ //
+ // Adding a new one
+ if ( i >= g_UserFilters.Count() )
+ {
+ // See if we have space for it
+ if ( g_UserFilters.Count() >= MAX_USERFILTERS )
+ {
+ ConMsg( "banid: user filter list is full\n" );
+ return;
+ }
+ userfilter_t nullUser;
+ memset( &nullUser, 0, sizeof(nullUser) );
+ i = g_UserFilters.AddToTail( nullUser );
+ }
+
+ g_UserFilters[i].banTime = banTime;
+ g_UserFilters[i].banEndTime = ( banTime != 0.0 ) ? ( realtime + 60.0 * banTime ) : 0.0;
+ g_UserFilters[i].userid = *id;
+
+ // Build a duration string for the ban
+ if ( banTime == 0.0 )
+ {
+ Q_snprintf( szDuration, sizeof( szDuration ), "permanently" );
+ }
+ else
+ {
+ Q_snprintf( szDuration, sizeof( szDuration ), "for %.2f minutes", banTime );
+ }
+
+ // fire the event
+ IGameEvent *event = g_GameEventManager.CreateEvent( "server_addban" );
+
+ if ( event )
+ {
+ if ( bPlaying )
+ {
+ event->SetString( "name", client->m_Name );
+ event->SetInt( "userid", client->GetUserID() );
+ event->SetString( "networkid", client->GetNetworkIDString() );
+ }
+ else
+ {
+ event->SetString( "name", "" );
+ event->SetInt( "userid", 0 );
+ event->SetString( "networkid", GetUserIDString( *id ) );
+ }
+
+ event->SetString( "ip", "" );
+ event->SetString( "duration", szDuration );
+ event->SetString( "by", ( cmd_source == src_command ) ? "Console" : host_client->m_Name );
+ event->SetInt( "kicked", ( bKick && bPlaying && client ) ? 1 : 0 );
+
+ g_GameEventManager.FireEvent( event );
+ }
+
+ if ( bKick && bPlaying && client )
+ {
+ client->ClientPrintf ( "You have been kicked and banned %s by the server.\n", szDuration );
+ client->Disconnect( "Kicked and banned" );
+ }
+#endif
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void Filter_Init( void )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void Filter_Shutdown( void )
+{
+}