aboutsummaryrefslogtreecommitdiff
path: root/NorthstarDLL/masterserver
diff options
context:
space:
mode:
authorpg9182 <96569817+pg9182@users.noreply.github.com>2023-03-06 12:02:53 -0500
committerpg9182 <96569817+pg9182@users.noreply.github.com>2023-04-17 14:50:10 -0400
commit87bd14cbe83c0eca42a6c15f4712415627941df2 (patch)
tree303e089a46e174b5db1766e915254d87c90b746d /NorthstarDLL/masterserver
parent45819c0ef2881610ca26261792995a58e6f68631 (diff)
downloadNorthstarLauncher-87bd14cbe83c0eca42a6c15f4712415627941df2.tar.gz
NorthstarLauncher-87bd14cbe83c0eca42a6c15f4712415627941df2.zip
Replace HTTP auth server with Atlas connectionless packet
Diffstat (limited to 'NorthstarDLL/masterserver')
-rw-r--r--NorthstarDLL/masterserver/masterserver.cpp173
-rw-r--r--NorthstarDLL/masterserver/masterserver.h3
2 files changed, 171 insertions, 5 deletions
diff --git a/NorthstarDLL/masterserver/masterserver.cpp b/NorthstarDLL/masterserver/masterserver.cpp
index 9b439027..c71be961 100644
--- a/NorthstarDLL/masterserver/masterserver.cpp
+++ b/NorthstarDLL/masterserver/masterserver.cpp
@@ -7,6 +7,7 @@
#include "mods/modmanager.h"
#include "shared/misccommands.h"
#include "util/version.h"
+#include "server/auth/bansystem.h"
#include "rapidjson/document.h"
#include "rapidjson/stringbuffer.h"
@@ -783,7 +784,171 @@ void MasterServerManager::ProcessConnectionlessPacketSigreq1(std::string data)
std::string type = obj["type"].GetString();
- // TODO
+ if (type == "connect")
+ {
+ if (!obj.HasMember("token") || !obj["token"].IsString())
+ {
+ spdlog::error("failed to handle Atlas connect request: missing or invalid connection token field");
+ return;
+ }
+ std::string token = obj["token"].GetString();
+
+ if (!m_handledServerConnections.contains(token))
+ m_handledServerConnections.insert(token);
+ else
+ return; // already handled
+
+ spdlog::info("handling Atlas connect request {}", data);
+
+ if (!obj.HasMember("uid") || !obj["uid"].IsUint64())
+ {
+ spdlog::error("failed to handle Atlas connect request {}: missing or invalid uid field", token);
+ return;
+ }
+ uint64_t uid = obj["uid"].GetUint64();
+
+ std::string username;
+ if (obj.HasMember("username") && obj["username"].IsString())
+ username = obj["username"].GetString();
+
+ std::string reject;
+ if (!g_pBanSystem->IsUIDAllowed(uid))
+ reject = "Banned from this server.";
+
+ std::string pdata;
+ if (reject == "")
+ {
+ spdlog::info("getting pdata for connection {} (uid={} username={})", token, uid, username);
+
+ CURL* curl = curl_easy_init();
+ SetCommonHttpClientOptions(curl);
+
+ curl_easy_setopt(
+ curl,
+ CURLOPT_URL,
+ fmt::format("{}/server/connect?serverId={}&token={}", Cvar_ns_masterserver_hostname->GetString(), m_sOwnServerId, token)
+ .c_str());
+
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWriteToStringBufferCallback);
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, &pdata);
+
+ CURLcode result = curl_easy_perform(curl);
+ if (result != CURLcode::CURLE_OK)
+ {
+ spdlog::error("failed to make Atlas connect pdata request {}: {}", token, curl_easy_strerror(result));
+ curl_easy_cleanup(curl);
+ return;
+ }
+
+ long respStatus = -1;
+ curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &respStatus);
+
+ curl_easy_cleanup(curl);
+
+ if (respStatus != 200)
+ {
+ rapidjson_document obj;
+ obj.Parse(pdata.c_str());
+
+ if (!obj.HasParseError() && obj.HasMember("error") && obj["error"].IsObject())
+ spdlog::error(
+ "failed to make Atlas connect pdata request {}: response status {}, error: {} ({})",
+ token,
+ respStatus,
+ ((obj["error"].HasMember("enum") && obj["error"]["enum"].IsString()) ? obj["error"]["enum"].GetString() : ""),
+ ((obj["error"].HasMember("msg") && obj["error"]["msg"].IsString()) ? obj["error"]["msg"].GetString() : ""));
+ else
+ spdlog::error("failed to make Atlas connect pdata request {}: response status {}", token, respStatus);
+ return;
+ }
+
+ if (!pdata.length())
+ {
+ spdlog::error("failed to make Atlas connect pdata request {}: pdata response is empty", token);
+ return;
+ }
+
+ if (pdata.length() > R2::PERSISTENCE_MAX_SIZE)
+ {
+ spdlog::error(
+ "failed to make Atlas connect pdata request {}: pdata is too large (max={} len={})",
+ token,
+ R2::PERSISTENCE_MAX_SIZE,
+ pdata.length());
+ return;
+ }
+ }
+
+ if (reject == "")
+ spdlog::info("accepting connection {} (uid={} username={}) with {} bytes of pdata", token, uid, username, pdata.length());
+ else
+ spdlog::info("rejecting connection {} (uid={} username={}) with reason \"{}\"", token, uid, username, reject);
+
+ if (reject == "")
+ g_pServerAuthentication->AddRemotePlayer(token, uid, username, pdata);
+
+ {
+ CURL* curl = curl_easy_init();
+ SetCommonHttpClientOptions(curl);
+
+ char* rejectEnc = curl_easy_escape(curl, reject.c_str(), reject.length());
+ if (!rejectEnc)
+ {
+ spdlog::error("failed to handle Atlas connect request {}: failed to escape reject", token);
+ return;
+ }
+ curl_easy_setopt(
+ curl,
+ CURLOPT_URL,
+ fmt::format(
+ "{}/server/connect?serverId={}&token={}&reject={}",
+ Cvar_ns_masterserver_hostname->GetString(),
+ m_sOwnServerId,
+ token,
+ rejectEnc)
+ .c_str());
+ curl_free(rejectEnc);
+
+ // note: we don't actually have any POST data, so we can't use CURLOPT_POST or the behavior is undefined (e.g., hangs in wine)
+ curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
+
+ std::string buf;
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWriteToStringBufferCallback);
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buf);
+
+ CURLcode result = curl_easy_perform(curl);
+ if (result != CURLcode::CURLE_OK)
+ {
+ spdlog::error("failed to respond to Atlas connect request {}: {}", token, curl_easy_strerror(result));
+ curl_easy_cleanup(curl);
+ return;
+ }
+
+ long respStatus = -1;
+ curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &respStatus);
+
+ curl_easy_cleanup(curl);
+
+ if (respStatus != 200)
+ {
+ rapidjson_document obj;
+ obj.Parse(buf.c_str());
+
+ if (!obj.HasParseError() && obj.HasMember("error") && obj["error"].IsObject())
+ spdlog::error(
+ "failed to respond to Atlas connect request {}: response status {}, error: {} ({})",
+ token,
+ respStatus,
+ ((obj["error"].HasMember("enum") && obj["error"]["enum"].IsString()) ? obj["error"]["enum"].GetString() : ""),
+ ((obj["error"].HasMember("msg") && obj["error"]["msg"].IsString()) ? obj["error"]["msg"].GetString() : ""));
+ else
+ spdlog::error("failed to respond to Atlas connect request {}: response status {}", token, respStatus);
+ return;
+ }
+ }
+
+ return;
+ }
spdlog::error("invalid Atlas connectionless packet request: unknown type {}", type);
}
@@ -1037,10 +1202,9 @@ void MasterServerPresenceReporter::InternalAddServer(const ServerPresence* pServ
CURLOPT_URL,
fmt::format(
"{}/server/"
- "add_server?port={}&authPort={}&name={}&description={}&map={}&playlist={}&maxPlayers={}&password={}",
+ "add_server?port={}&authPort=udp&name={}&description={}&map={}&playlist={}&maxPlayers={}&password={}",
hostname.c_str(),
threadedPresence.m_iPort,
- threadedPresence.m_iAuthPort,
nameEscaped,
descEscaped,
mapEscaped,
@@ -1185,12 +1349,11 @@ void MasterServerPresenceReporter::InternalUpdateServer(const ServerPresence* pS
CURLOPT_URL,
fmt::format(
"{}/server/"
- "update_values?id={}&port={}&authPort={}&name={}&description={}&map={}&playlist={}&playerCount={}&"
+ "update_values?id={}&port={}&authPort=udp&name={}&description={}&map={}&playlist={}&playerCount={}&"
"maxPlayers={}&password={}",
hostname.c_str(),
serverId.c_str(),
threadedPresence.m_iPort,
- threadedPresence.m_iAuthPort,
nameEscaped,
descEscaped,
mapEscaped,
diff --git a/NorthstarDLL/masterserver/masterserver.h b/NorthstarDLL/masterserver/masterserver.h
index 5cd6a695..e87b31a2 100644
--- a/NorthstarDLL/masterserver/masterserver.h
+++ b/NorthstarDLL/masterserver/masterserver.h
@@ -6,6 +6,7 @@
#include <string>
#include <cstring>
#include <future>
+#include <unordered_set>
extern ConVar* Cvar_ns_masterserver_hostname;
extern ConVar* Cvar_ns_curl_log_enable;
@@ -116,6 +117,8 @@ class MasterServerManager
std::optional<RemoteServerInfo> m_currentServer;
std::string m_sCurrentServerPassword;
+ std::unordered_set<std::string> m_handledServerConnections;
+
public:
MasterServerManager();