From e266b6d76477e4ec03e8024521f5d130d1b6657f Mon Sep 17 00:00:00 2001 From: nullsystem <15316579+nullsystem@users.noreply.github.com> Date: Sun, 7 Jul 2024 15:11:58 +0100 Subject: [PATCH] Build integrity + server print neo_version info * Server now just prints neo_version on startup * Server and client long git hashes are now matched up on startup to check build integrity. If they don't, the client cannot connect unless they have matching git hashes. * Server convar `neo_sv_build_integrity_check` to enable/disable this integrity check feature. Enabled by default. * fixes #437 * fixes #485 --- mp/src/game/client/CMakeLists.txt | 1 + mp/src/game/server/CMakeLists.txt | 1 + mp/src/game/server/gameinterface.cpp | 2 ++ mp/src/game/shared/neo/neo_gamerules.cpp | 21 +++++++++++++++++++++ mp/src/game/shared/neo/neo_version.cpp | 13 +++++++++---- mp/src/game/shared/neo/neo_version.h | 3 +++ 6 files changed, 37 insertions(+), 4 deletions(-) create mode 100644 mp/src/game/shared/neo/neo_version.h diff --git a/mp/src/game/client/CMakeLists.txt b/mp/src/game/client/CMakeLists.txt index 34a4b69e9..e52c9dce4 100644 --- a/mp/src/game/client/CMakeLists.txt +++ b/mp/src/game/client/CMakeLists.txt @@ -1550,6 +1550,7 @@ target_sources_grouped( ${CMAKE_SOURCE_DIR}/game/shared/neo/neo_shot_manipulator.cpp ${CMAKE_SOURCE_DIR}/game/shared/neo/neo_shot_manipulator.h ${CMAKE_SOURCE_DIR}/game/shared/neo/neo_version.cpp + ${CMAKE_SOURCE_DIR}/game/shared/neo/neo_version.h ) target_sources_grouped( diff --git a/mp/src/game/server/CMakeLists.txt b/mp/src/game/server/CMakeLists.txt index 92495889d..2e190150e 100644 --- a/mp/src/game/server/CMakeLists.txt +++ b/mp/src/game/server/CMakeLists.txt @@ -1317,6 +1317,7 @@ target_sources_grouped( ${CMAKE_SOURCE_DIR}/game/shared/neo/neo_shot_manipulator.cpp ${CMAKE_SOURCE_DIR}/game/shared/neo/neo_shot_manipulator.h ${CMAKE_SOURCE_DIR}/game/shared/neo/neo_version.cpp + ${CMAKE_SOURCE_DIR}/game/shared/neo/neo_version.h neo/neo_client.cpp neo/neo_detpack.cpp neo/neo_detpack.h diff --git a/mp/src/game/server/gameinterface.cpp b/mp/src/game/server/gameinterface.cpp index b9de58f8c..9f8bbcc62 100644 --- a/mp/src/game/server/gameinterface.cpp +++ b/mp/src/game/server/gameinterface.cpp @@ -132,6 +132,7 @@ extern ConVar tf_mm_servermode; #ifdef NEO #include "neo_mount_original.h" +#include "neo_version.h" #endif extern IToolFrameworkServer *g_pToolFrameworkServer; @@ -643,6 +644,7 @@ bool CServerGameDLL::DLLInit( CreateInterfaceFn appSystemFactory, { return false; } + neoVersionPrint(); #endif // Yes, both the client and game .dlls will try to Connect, the soundemittersystem.dll will handle this gracefully diff --git a/mp/src/game/shared/neo/neo_gamerules.cpp b/mp/src/game/shared/neo/neo_gamerules.cpp index 976407e95..6327c7541 100644 --- a/mp/src/game/shared/neo/neo_gamerules.cpp +++ b/mp/src/game/shared/neo/neo_gamerules.cpp @@ -1,5 +1,6 @@ #include "cbase.h" #include "neo_gamerules.h" +#include "neo_version_info.h" #include "in_buttons.h" #include "ammodef.h" @@ -36,6 +37,13 @@ ConVar neo_sv_player_restore("neo_sv_player_restore", "1", FCVAR_REPLICATED, "If ConVar neo_name("neo_name", "", FCVAR_USERINFO | FCVAR_ARCHIVE, "The nickname to set instead of the steam profile name."); ConVar cl_onlysteamnick("cl_onlysteamnick", "0", FCVAR_USERINFO | FCVAR_ARCHIVE, "Only show players Steam names, otherwise show player set names.", true, 0.0f, true, 1.0f); +#ifdef GAME_DLL +ConVar neo_sv_build_integrity_check("neo_sv_build_integrity_check", "1", FCVAR_GAMEDLL | FCVAR_REPLICATED, + "If enabled, the server checkes the build's Git hash between the client and" + " the server. If it doesn't match, the server rejects and disconnects the client.", + true, 0.0f, true, 1.0f); +#endif + REGISTER_GAMERULES_CLASS( CNEORules ); BEGIN_NETWORK_TABLE_NOBASE( CNEORules, DT_NEORules ) @@ -1291,6 +1299,19 @@ void CNEORules::RestartGame() #ifdef GAME_DLL bool CNEORules::ClientConnected(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen) { + if (neo_sv_build_integrity_check.GetBool()) + { + const char *clientGitHash = engine->GetClientConVarValue(engine->IndexOfEdict(pEntity), "__neo_cl_git_hash"); + if (V_strcmp(clientGitHash, GIT_LONGHASH)) + { + // Truncate the git hash so it's short hash and doesn't make message too long + static constexpr int MAX_GITHASH_SHOW = 7; + V_snprintf(reject, maxrejectlen, "Build integrity failed! Client vs server mis-match: Check your neo_version. " + "Client: %.*s | Server: %.*s", + MAX_GITHASH_SHOW, clientGitHash, MAX_GITHASH_SHOW, GIT_LONGHASH); + return false; + } + } return BaseClass::ClientConnected(pEntity, pszName, pszAddress, reject, maxrejectlen); #if(0) diff --git a/mp/src/game/shared/neo/neo_version.cpp b/mp/src/game/shared/neo/neo_version.cpp index a8b8211da..7c749bacd 100644 --- a/mp/src/game/shared/neo/neo_version.cpp +++ b/mp/src/game/shared/neo/neo_version.cpp @@ -3,12 +3,11 @@ #include "convar.h" #include "dbg.h" -namespace { -void neoVersionCallback() +void neoVersionPrint() { #if defined(GAME_DLL) static constexpr char HEADER[] = "neo_version (Server's build info):"; -#else defined(CLIENT_DLL) +#elif defined(CLIENT_DLL) static constexpr char HEADER[] = "neo_version (Client's build info):"; #endif Msg("%s\n" @@ -25,10 +24,16 @@ void neoVersionCallback() COMPILER_ID, COMPILER_VERSION); } +namespace { #ifdef CLIENT_DLL constexpr int NEO_VERSION_FLAGS = 0; #else constexpr int NEO_VERSION_FLAGS = FCVAR_HIDDEN; #endif -ConCommand neo_version("neo_version", neoVersionCallback, "Print out client/server's build's information.", NEO_VERSION_FLAGS); +ConCommand neo_version("neo_version", neoVersionPrint, "Print out client/server's build's information.", NEO_VERSION_FLAGS); + +#ifdef CLIENT_DLL +ConVar __neo_cl_git_hash("__neo_cl_git_hash", GIT_LONGHASH, + FCVAR_USERINFO | FCVAR_HIDDEN | FCVAR_DONTRECORD | FCVAR_NOT_CONNECTED | FCVAR_PRINTABLEONLY); +#endif } diff --git a/mp/src/game/shared/neo/neo_version.h b/mp/src/game/shared/neo/neo_version.h new file mode 100644 index 000000000..689776dd2 --- /dev/null +++ b/mp/src/game/shared/neo/neo_version.h @@ -0,0 +1,3 @@ +#pragma once + +void neoVersionPrint();