aboutsummaryrefslogtreecommitdiff
path: root/NorthstarDedicatedTest
diff options
context:
space:
mode:
authorBobTheBob <32057864+BobTheBob9@users.noreply.github.com>2021-08-13 20:02:28 +0100
committerBobTheBob <32057864+BobTheBob9@users.noreply.github.com>2021-08-13 20:02:28 +0100
commitf425377e5b15dc97ce8caa484b3e282ec5df529c (patch)
treec3d9a27cb8be758839a90ca85b045144f39b8616 /NorthstarDedicatedTest
parent9a3e1ec2daf753106ee95d53719d94921d3b051f (diff)
downloadNorthstarLauncher-f425377e5b15dc97ce8caa484b3e282ec5df529c.tar.gz
NorthstarLauncher-f425377e5b15dc97ce8caa484b3e282ec5df529c.zip
add local http server for auth
Diffstat (limited to 'NorthstarDedicatedTest')
-rw-r--r--NorthstarDedicatedTest/convar.h2
-rw-r--r--NorthstarDedicatedTest/gameutils.cpp7
-rw-r--r--NorthstarDedicatedTest/gameutils.h4
-rw-r--r--NorthstarDedicatedTest/masterserver.cpp24
-rw-r--r--NorthstarDedicatedTest/masterserver.h8
-rw-r--r--NorthstarDedicatedTest/scriptserverbrowser.cpp4
-rw-r--r--NorthstarDedicatedTest/serverauthentication.cpp67
-rw-r--r--NorthstarDedicatedTest/serverauthentication.h12
-rw-r--r--NorthstarDedicatedTest/sourceconsole.cpp3
9 files changed, 100 insertions, 31 deletions
diff --git a/NorthstarDedicatedTest/convar.h b/NorthstarDedicatedTest/convar.h
index f2e35188..a9da3274 100644
--- a/NorthstarDedicatedTest/convar.h
+++ b/NorthstarDedicatedTest/convar.h
@@ -93,7 +93,7 @@ public:
void* unknown[10];
void(*UnregisterConCommand) (ICvar* cvar, ConCommand* pCommandBase);
void* unknown2[28];
- ConVar*(*FindVar)(const char* var_name);
+ ConVar*(*FindVar)(const char* var_name); // offset for this is currently very wrong
};
VTable* m_vtable;
diff --git a/NorthstarDedicatedTest/gameutils.cpp b/NorthstarDedicatedTest/gameutils.cpp
index 1cf919fb..fc6b2dc7 100644
--- a/NorthstarDedicatedTest/gameutils.cpp
+++ b/NorthstarDedicatedTest/gameutils.cpp
@@ -15,6 +15,9 @@ ConVar* Cvar_hostport;
// playlist stuff
GetCurrentPlaylistType GetCurrentPlaylistName;
+// uid
+char* g_LocalPlayerUserID;
+
void InitialiseEngineGameUtilFunctions(HMODULE baseAddress)
{
Cbuf_GetCurrentPlayer = (Cbuf_GetCurrentPlayerType)((char*)baseAddress + 0x120630);
@@ -22,7 +25,9 @@ void InitialiseEngineGameUtilFunctions(HMODULE baseAddress)
g_GameCHostStateSingleton = (CHostState*)((char*)baseAddress + 0x7CF180);
- Cvar_hostport = (ConVar*)((char*)baseAddress + 0x1FA6070);
+ Cvar_hostport = (ConVar*)((char*)baseAddress + 0x13FA6070);
GetCurrentPlaylistName = (GetCurrentPlaylistType)((char*)baseAddress + 0x18C640);
+
+ g_LocalPlayerUserID = (char*)baseAddress + 0x13F8E688;
}
diff --git a/NorthstarDedicatedTest/gameutils.h b/NorthstarDedicatedTest/gameutils.h
index 042e9bd5..ff987467 100644
--- a/NorthstarDedicatedTest/gameutils.h
+++ b/NorthstarDedicatedTest/gameutils.h
@@ -84,4 +84,8 @@ extern ConVar* Cvar_hostport;
typedef const char*(*GetCurrentPlaylistType)();
extern GetCurrentPlaylistType GetCurrentPlaylistName;
+// uid
+
+extern char* g_LocalPlayerUserID;
+
void InitialiseEngineGameUtilFunctions(HMODULE baseAddress); \ No newline at end of file
diff --git a/NorthstarDedicatedTest/masterserver.cpp b/NorthstarDedicatedTest/masterserver.cpp
index b8d1cd73..f5ba55f0 100644
--- a/NorthstarDedicatedTest/masterserver.cpp
+++ b/NorthstarDedicatedTest/masterserver.cpp
@@ -4,6 +4,7 @@
#include "gameutils.h"
#include "hookutils.h"
#include "httplib.h"
+#include "serverauthentication.h"
#include "rapidjson/document.h"
#include "rapidjson/error/en.h"
@@ -170,7 +171,7 @@ void MasterServerManager::RequestServerList()
requestThread.detach();
}
-void MasterServerManager::AuthenticateWithServer(char* serverId, char* password)
+void MasterServerManager::AuthenticateWithServer(char* uid, char* playerToken, char* serverId, char* password)
{
// dont wait, just stop if we're trying to do 2 auth requests at once
if (m_authenticatingWithGameServer)
@@ -180,14 +181,14 @@ void MasterServerManager::AuthenticateWithServer(char* serverId, char* password)
m_scriptAuthenticatingWithGameServer = true;
m_successfullyAuthenticatedWithGameServer = false;
- std::thread requestThread([this, serverId, password]()
+ std::thread requestThread([this, uid, playerToken, serverId, password]()
{
httplib::Client http(Cvar_ns_masterserver_hostname->m_pszString, Cvar_ns_masterserver_port->m_nValue);
http.set_connection_timeout(20);
spdlog::info("Attempting authentication with server of id \"{}\"", serverId);
- if (auto result = http.Post(fmt::format("/client/auth_with_server?server={}&password={}", serverId, password).c_str()))
+ if (auto result = http.Post(fmt::format("/client/auth_with_server?id={}&playerToken={}&server={}&password={}", uid, playerToken, serverId, password).c_str()))
{
m_successfullyConnected = true;
@@ -239,6 +240,7 @@ void MasterServerManager::AuthenticateWithServer(char* serverId, char* password)
spdlog::error("Failed authenticating with server: error {}", result.error());
m_successfullyConnected = false;
m_successfullyAuthenticatedWithGameServer = false;
+ m_scriptAuthenticatingWithGameServer = false;
}
REQUEST_END_CLEANUP:
@@ -249,7 +251,7 @@ void MasterServerManager::AuthenticateWithServer(char* serverId, char* password)
requestThread.detach();
}
-void MasterServerManager::AddSelfToServerList(int port, char* name, char* description, char* map, char* playlist, int maxPlayers, char* password)
+void MasterServerManager::AddSelfToServerList(int port, int authPort, char* name, char* description, char* map, char* playlist, int maxPlayers, char* password)
{
if (!Cvar_ns_report_server_to_masterserver->m_nValue)
return;
@@ -257,7 +259,7 @@ void MasterServerManager::AddSelfToServerList(int port, char* name, char* descri
if (!Cvar_ns_report_sp_server_to_masterserver->m_nValue && !strncmp(map, "sp_", 3))
return;
- std::thread requestThread([this, port, name, description, map, playlist, maxPlayers, password] {
+ std::thread requestThread([this, port, authPort, name, description, map, playlist, maxPlayers, password] {
httplib::Client http(Cvar_ns_masterserver_hostname->m_pszString, Cvar_ns_masterserver_port->m_nValue);
http.set_connection_timeout(20);
@@ -265,9 +267,9 @@ void MasterServerManager::AddSelfToServerList(int port, char* name, char* descri
std::string request;
if (*password)
- request = fmt::format("/server/add_server?port={}&name={}&description={}&map={}&playlist={}&maxPlayers={}&password={}", port, name, description, map, playlist, maxPlayers, password);
+ request = fmt::format("/server/add_server?port={}&authPort={}&name={}&description={}&map={}&playlist={}&maxPlayers={}&password={}", port, authPort, name, description, map, playlist, maxPlayers, password);
else
- request = fmt::format("/server/add_server?port={}&name={}&description={}&map={}&playlist={}&maxPlayers={}", port, name, description, map, playlist, maxPlayers);
+ request = fmt::format("/server/add_server?port={}&authPort={}&name={}&description={}&map={}&playlist={}&maxPlayers={}&password=", port, authPort, name, description, map, playlist, maxPlayers);
if (auto result = http.Post(request.c_str()))
{
@@ -419,7 +421,9 @@ void CHostState__State_NewGameHook(CHostState* hostState)
// not 100% we should do this here, but whatever
Cbuf_AddText(Cbuf_GetCurrentPlayer(), "exec autoexec_ns_server", cmd_source_t::kCommandSrcCode);
- g_MasterServerManager->AddSelfToServerList(Cvar_hostport->m_nValue, Cvar_ns_server_name->m_pszString, Cvar_ns_server_desc->m_pszString, hostState->m_levelName, (char*)GetCurrentPlaylistName(), 16, Cvar_ns_server_password->m_pszString);
+ g_MasterServerManager->AddSelfToServerList(Cvar_hostport->m_nValue, Cvar_ns_player_auth_port->m_nValue, Cvar_ns_server_name->m_pszString, Cvar_ns_server_desc->m_pszString, hostState->m_levelName, (char*)GetCurrentPlaylistName(), 16, Cvar_ns_server_password->m_pszString);
+ g_ServerAuthenticationManager->StartPlayerAuthServer();
+
CHostState__State_NewGame(hostState);
}
@@ -438,12 +442,14 @@ void CHostState__State_ChangeLevelSPHook(CHostState* hostState)
void CHostState__State_GameShutdownHook(CHostState* hostState)
{
g_MasterServerManager->RemoveSelfFromServerList();
+ g_ServerAuthenticationManager->StopPlayerAuthServer();
+
CHostState__State_GameShutdown(hostState);
}
void InitialiseSharedMasterServer(HMODULE baseAddress)
{
- Cvar_ns_masterserver_hostname = RegisterConVar("ns_masterserver_hostname", "localhost", FCVAR_NONE, "");
+ Cvar_ns_masterserver_hostname = RegisterConVar("ns_masterserver_hostname", "127.0.0.1", FCVAR_NONE, "");
Cvar_ns_masterserver_port = RegisterConVar("ns_masterserver_port", "8080", FCVAR_NONE, "");
Cvar_ns_server_name = RegisterConVar("ns_server_name", "Unnamed Northstar Server", FCVAR_GAMEDLL, "");
diff --git a/NorthstarDedicatedTest/masterserver.h b/NorthstarDedicatedTest/masterserver.h
index 9b8e8a89..17c77a02 100644
--- a/NorthstarDedicatedTest/masterserver.h
+++ b/NorthstarDedicatedTest/masterserver.h
@@ -55,13 +55,15 @@ public:
public:
void ClearServerList();
void RequestServerList();
- void AuthenticateWithServer(char* serverId, char* password);
- void AddSelfToServerList(int port, char* name, char* description, char* map, char* playlist, int maxPlayers, char* password);
+ void AuthenticateWithServer(char* uid, char* playerToken, char* serverId, char* password);
+ void AddSelfToServerList(int port, int authPort, char* name, char* description, char* map, char* playlist, int maxPlayers, char* password);
void UpdateServerMapAndPlaylist(char* map, char* playlist);
void UpdateServerPlayerCount(int playerCount);
+ void WritePlayerPersistentData(char* playerId, char* pdata);
void RemoveSelfFromServerList();
};
void InitialiseSharedMasterServer(HMODULE baseAddress);
-extern MasterServerManager* g_MasterServerManager; \ No newline at end of file
+extern MasterServerManager* g_MasterServerManager;
+extern ConVar* Cvar_ns_masterserver_hostname; \ No newline at end of file
diff --git a/NorthstarDedicatedTest/scriptserverbrowser.cpp b/NorthstarDedicatedTest/scriptserverbrowser.cpp
index c5446031..5db5b719 100644
--- a/NorthstarDedicatedTest/scriptserverbrowser.cpp
+++ b/NorthstarDedicatedTest/scriptserverbrowser.cpp
@@ -176,7 +176,7 @@ SQInteger SQ_TryAuthWithServer(void* sqvm)
}
// do auth
- g_MasterServerManager->AuthenticateWithServer(g_MasterServerManager->m_remoteServers[serverIndex].id, (char*)password);
+ g_MasterServerManager->AuthenticateWithServer(g_LocalPlayerUserID, (char*)"", g_MasterServerManager->m_remoteServers[serverIndex].id, (char*)password);
return 0;
}
@@ -210,8 +210,6 @@ SQInteger SQ_ConnectToAuthedServer(void* sqvm)
// i'm honestly not entirely sure how silentconnect works regarding ports and encryption so using connect for now
Cbuf_AddText(Cbuf_GetCurrentPlayer(), fmt::format("serverfilter {}", info.authToken).c_str(), cmd_source_t::kCommandSrcCode);
Cbuf_AddText(Cbuf_GetCurrentPlayer(), fmt::format("connect {}.{}.{}.{}:{}", info.ip.S_un.S_un_b.s_b1, info.ip.S_un.S_un_b.s_b2, info.ip.S_un.S_un_b.s_b3, info.ip.S_un.S_un_b.s_b4, info.port).c_str(), cmd_source_t::kCommandSrcCode);
-
- spdlog::info(fmt::format("connect {}.{}.{}.{}:{}", info.ip.S_un.S_un_b.s_b1, info.ip.S_un.S_un_b.s_b2, info.ip.S_un.S_un_b.s_b3, info.ip.S_un.S_un_b.s_b4, info.port));
g_MasterServerManager->m_hasPendingConnectionInfo = false;
return 0;
diff --git a/NorthstarDedicatedTest/serverauthentication.cpp b/NorthstarDedicatedTest/serverauthentication.cpp
index 964c6b16..9df23502 100644
--- a/NorthstarDedicatedTest/serverauthentication.cpp
+++ b/NorthstarDedicatedTest/serverauthentication.cpp
@@ -8,6 +8,8 @@
#include <filesystem>
#include <thread>
+const char* AUTHSERVER_VERIFY_STRING = "I am a northstar server!";
+
// hook types
typedef void*(*CBaseServer__ConnectClientType)(void* server, void* a2, void* a3, uint32_t a4, uint32_t a5, int32_t a6, void* a7, void* a8, char* serverFilter, void* a10, char a11, void* a12, char a13, char a14, int64_t uid, uint32_t a16, uint32_t a17);
@@ -35,39 +37,77 @@ ConVar* CVar_sv_quota_stringcmdspersecond;
void ServerAuthenticationManager::StartPlayerAuthServer()
{
+ if (m_runningPlayerAuthThread)
+ {
+ spdlog::warn("ServerAuthenticationManager::StartPlayerAuthServer was called while m_runningPlayerAuthThread is true");
+ return;
+ }
+
m_runningPlayerAuthThread = true;
+ // listen is a blocking call so thread this
std::thread serverThread([this] {
- while (m_runningPlayerAuthThread)
- {
+ // this is just a super basic way to verify that servers have ports open, masterserver will try to read this before ensuring server is legit
+ m_playerAuthServer.Get("/verify", [](const httplib::Request& request, httplib::Response& response) {
+ response.set_content(AUTHSERVER_VERIFY_STRING, "text/plain");
+ });
- }
- });
+ m_playerAuthServer.Post("/authenticate_incoming_player", [this](const httplib::Request& request, httplib::Response& response) {
+ if (!request.has_param("id") || !request.has_param("authToken") || request.remote_addr != Cvar_ns_masterserver_hostname->m_pszString)
+ {
+ response.set_content("{\"success\":false}", "application/json");
+ return;
+ }
+
+ AuthData newAuthData;
+ strncpy(newAuthData.uid, request.get_param_value("id").c_str(), sizeof(newAuthData.uid));
+ newAuthData.uid[sizeof(newAuthData.uid) - 1] = 0;
+
+ newAuthData.pdataSize = request.body.size();
+ newAuthData.pdata = new char[newAuthData.pdataSize];
+ memcpy(newAuthData.pdata, request.body.c_str(), newAuthData.pdataSize);
+
+ std::lock_guard<std::mutex> guard(m_authDataMutex);
+ m_authData.insert(std::make_pair(request.get_param_value("authToken"), newAuthData));
+ response.set_content("{\"success\":true}", "application/json");
+ });
+
+ m_playerAuthServer.listen("0.0.0.0", Cvar_ns_player_auth_port->m_nValue);
+ });
+
serverThread.detach();
}
-void ServerAuthenticationManager::AddPlayerAuthData(char* authToken, char* uid, char* pdata, size_t pdataSize)
+void ServerAuthenticationManager::StopPlayerAuthServer()
{
-
+ if (!m_runningPlayerAuthThread)
+ {
+ spdlog::warn("ServerAuthenticationManager::StopPlayerAuthServer was called while m_runningPlayerAuthThread is false");
+ return;
+ }
+
+ m_runningPlayerAuthThread = false;
+ m_playerAuthServer.stop();
}
bool ServerAuthenticationManager::AuthenticatePlayer(void* player, int64_t uid, char* authToken)
{
std::string strUid = std::to_string(uid);
- if (!m_authData.empty() && m_authData.count(authToken))
+ std::lock_guard<std::mutex> guard(m_authDataMutex);
+ if (!m_authData.empty() && m_authData.count(std::string(authToken)))
{
// use stored auth data
- AuthData* authData = m_authData[authToken];
- if (strcmp(strUid.c_str(), authData->uid)) // connecting client's uid is different from auth's uid
+ AuthData authData = m_authData[authToken];
+ if (strcmp(strUid.c_str(), authData.uid)) // connecting client's uid is different from auth's uid
return false;
// uuid
strcpy((char*)player + 0xF500, strUid.c_str());
// copy pdata into buffer
- memcpy((char*)player + 0x4FA, authData->pdata, authData->pdataSize);
+ memcpy((char*)player + 0x4FA, authData.pdata, authData.pdataSize);
// set persistent data as ready, we use 0x4 internally to mark the client as using remote persistence
*((char*)player + 0x4a0) = (char)0x4;
@@ -112,10 +152,13 @@ bool ServerAuthenticationManager::RemovePlayerAuthData(void* player)
// we don't have our auth token at this point, so lookup authdata by uid
for (auto& auth : m_authData)
{
- if (!strcmp((char*)player + 0xF500, auth.second->uid))
+ if (!strcmp((char*)player + 0xF500, auth.second.uid))
{
// pretty sure this is fine, since we don't iterate after the erase
// i think if we iterated after it'd be undefined behaviour tho
+ std::lock_guard<std::mutex> guard(m_authDataMutex);
+
+ delete[] auth.second.pdata;
m_authData.erase(auth.first);
return true;
}
@@ -196,6 +239,7 @@ void CBaseClient__DisconnectHook(void* self, uint32_t unknownButAlways1, const c
// dcing, write persistent data
g_ServerAuthenticationManager->WritePersistentData(self);
+ g_ServerAuthenticationManager->RemovePlayerAuthData(self); // won't do anything 99% of the time, but just in case
g_MasterServerManager->UpdateServerPlayerCount(playerCount = std::max(playerCount - 1, 0));
@@ -217,6 +261,7 @@ void InitialiseServerAuthentication(HMODULE baseAddress)
CVar_ns_auth_allow_insecure_write = RegisterConVar("ns_auth_allow_insecure_write", "0", FCVAR_GAMEDLL, "Whether the pdata of unauthenticated clients will be written to disk when changed");
// literally just stolen from a fix valve used in csgo
CVar_sv_quota_stringcmdspersecond = RegisterConVar("sv_quota_stringcmdspersecond", "40", FCVAR_NONE, "How many string commands per second clients are allowed to submit, 0 to disallow all string commands");
+ Cvar_ns_player_auth_port = RegisterConVar("Cvar_ns_player_auth_port", "8081", FCVAR_GAMEDLL, "");
HookEnabler hook;
ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x114430, &CBaseServer__ConnectClientHook, reinterpret_cast<LPVOID*>(&CBaseServer__ConnectClient));
diff --git a/NorthstarDedicatedTest/serverauthentication.h b/NorthstarDedicatedTest/serverauthentication.h
index e9aae4f0..b26ce2b2 100644
--- a/NorthstarDedicatedTest/serverauthentication.h
+++ b/NorthstarDedicatedTest/serverauthentication.h
@@ -1,10 +1,12 @@
#pragma once
+#include "convar.h"
+#include "httplib.h"
#include <unordered_map>
#include <string>
struct AuthData
{
- char* uid;
+ char uid[33];
// pdata
char* pdata;
@@ -13,13 +15,17 @@ struct AuthData
class ServerAuthenticationManager
{
+private:
+ httplib::Server m_playerAuthServer;
+
public:
- std::unordered_map<std::string, AuthData*> m_authData;
+ std::mutex m_authDataMutex;
+ std::unordered_map<std::string, AuthData> m_authData;
bool m_runningPlayerAuthThread = false;
public:
void StartPlayerAuthServer();
- void AddPlayerAuthData(char* authToken, char* uid, char* pdata, size_t pdataSize);
+ void StopPlayerAuthServer();
bool AuthenticatePlayer(void* player, int64_t uid, char* authToken);
bool RemovePlayerAuthData(void* player);
void WritePersistentData(void* player);
diff --git a/NorthstarDedicatedTest/sourceconsole.cpp b/NorthstarDedicatedTest/sourceconsole.cpp
index 88d038df..d5c7e347 100644
--- a/NorthstarDedicatedTest/sourceconsole.cpp
+++ b/NorthstarDedicatedTest/sourceconsole.cpp
@@ -16,6 +16,9 @@ void ConCommand_toggleconsole(const CCommand& arg)
void ConCommand_help(const CCommand& arg)
{
+ if (arg.ArgC() < 2)
+ return;
+
// todo: this should basically just call FindConVar once we have that working, then just print convar.GetHelpString
}