diff --git a/include/Client.h b/include/Client.h index 860bcbc..9ab2dc7 100644 --- a/include/Client.h +++ b/include/Client.h @@ -24,6 +24,7 @@ #include #include #include +#include #include "BoostAliases.h" #include "Common.h" @@ -101,6 +102,8 @@ public: [[nodiscard]] TServer& Server() const; void UpdatePingTime(); int SecondsSinceLastPing(); + void SetMagic(std::vector magic) { mMagic = std::move(magic); } + [[nodiscard]] const std::vector& GetMagic() const { return mMagic; } private: void InsertVehicle(int ID, const std::string& Data); @@ -125,6 +128,7 @@ private: std::string mDID; int mID = -1; std::chrono::time_point mLastPingTime = std::chrono::high_resolution_clock::now(); + std::vector mMagic; }; std::optional> GetClient(class TServer& Server, int ID); diff --git a/include/Common.h b/include/Common.h index 9fedb90..abb866d 100644 --- a/include/Common.h +++ b/include/Common.h @@ -74,7 +74,7 @@ public: static TConsole& Console() { return mConsole; } static std::string ServerVersionString(); static const Version& ServerVersion() { return mVersion; } - static Version ClientMinimumVersion() { return Version { 2, 2, 0 }; } + static Version ClientMinimumVersion() { return Version { 2, 7, 0 }; } static std::string PPS() { return mPPS; } static void SetPPS(const std::string& NewPPS) { mPPS = NewPPS; } @@ -129,7 +129,7 @@ private: static inline std::mutex mShutdownHandlersMutex {}; static inline std::deque mShutdownHandlers {}; - static inline Version mVersion { 3, 8, 5 }; + static inline Version mVersion { 3, 9, 0 }; }; void SplitString(std::string const& str, const char delim, std::vector& out); diff --git a/include/TServer.h b/include/TServer.h index 1ff36c6..4ee9f96 100644 --- a/include/TServer.h +++ b/include/TServer.h @@ -44,7 +44,7 @@ public: void ForEachClient(const std::function)>& Fn); size_t ClientCount() const; - void GlobalParser(const std::weak_ptr& Client, std::vector&& Packet, TPPSMonitor& PPSMonitor, TNetwork& Network); + void GlobalParser(const std::weak_ptr& Client, std::vector&& Packet, TPPSMonitor& PPSMonitor, TNetwork& Network, bool udp); static void HandleEvent(TClient& c, const std::string& Data); RWMutex& GetClientMutex() const { return mClientsMutex; } diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index 7da9559..76ae3eb 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include typedef boost::asio::detail::socket_option::integer rcv_timeout_option; @@ -146,23 +148,30 @@ void TNetwork::UDPServerMain() { } if (Client->GetID() == ID) { - // not initialized yet - if (Client->GetUDPAddr() == ip::udp::endpoint {} || !Client->IsUDPConnected()) { - // same IP (just a sanity check) - if (remote_client_ep.address() == Client->GetTCPSock().remote_endpoint().address()) { - Client->SetUDPAddr(remote_client_ep); - Client->SetIsUDPConnected(true); - beammp_debugf("UDP connected for client {}", ID); - } else { - beammp_debugf("Denied initial UDP packet due to IP mismatch"); + if (Client->GetUDPAddr() == ip::udp::endpoint {} && !Client->IsUDPConnected() && !Client->GetMagic().empty()) { + if (Data.size() != 66) { + beammp_debugf("Invalid size for UDP value. IP: {} ID: {}", remote_client_ep.address().to_string(), ID); return false; } + + const std::vector Magic(Data.begin() + 2, Data.end()); + + if (Magic != Client->GetMagic()) { + beammp_debugf("Invalid value for UDP IP: {} ID: {}", remote_client_ep.address().to_string(), ID); + return false; + } + + Client->SetMagic({}); + Client->SetUDPAddr(remote_client_ep); + Client->SetIsUDPConnected(true); + return false; } + if (Client->GetUDPAddr() == remote_client_ep) { Data.erase(Data.begin(), Data.begin() + 2); - mServer.GlobalParser(ClientPtr, std::move(Data), mPPSMonitor, *this); + mServer.GlobalParser(ClientPtr, std::move(Data), mPPSMonitor, *this, true); } else { - beammp_debugf("Ignored UDP packet due to remote address mismatch"); + beammp_debugf("Ignored UDP packet for Client {} due to remote address mismatch. Source: {}, Client: {}", ID, remote_client_ep.address().to_string(), Client->GetUDPAddr().address().to_string()); return false; } } @@ -660,7 +669,7 @@ void TNetwork::TCPClient(const std::weak_ptr& c) { Client->Disconnect("TCPRcv failed"); break; } - mServer.GlobalParser(c, std::move(res), mPPSMonitor, *this); + mServer.GlobalParser(c, std::move(res), mPPSMonitor, *this, false); } if (QueueSync.joinable()) @@ -751,6 +760,18 @@ void TNetwork::OnConnect(const std::weak_ptr& c) { SyncResources(*LockedClient); if (LockedClient->IsDisconnected()) return; + std::vector buf(64); + int ret = RAND_bytes(buf.data(), buf.size()); + if (ret != 1) { + unsigned long error = ERR_get_error(); + beammp_errorf("RAND_bytes failed with error code {}", error); + beammp_assert(ret != 1); + return; + } + + LockedClient->SetMagic(buf); + buf.insert(buf.begin(), 'U'); + (void)Respond(*LockedClient, buf, true); (void)Respond(*LockedClient, StringToVector("M" + Application::Settings.getAsString(Settings::Key::General_Map)), true); // Send the Map on connect beammp_info(LockedClient->GetName() + " : Connected"); LuaAPI::MP::Engine->ReportErrors(LuaAPI::MP::Engine->TriggerEvent("onPlayerJoining", "", LockedClient->GetID())); diff --git a/src/TServer.cpp b/src/TServer.cpp index c47da67..ae16c1c 100644 --- a/src/TServer.cpp +++ b/src/TServer.cpp @@ -161,7 +161,7 @@ size_t TServer::ClientCount() const { return mClients.size(); } -void TServer::GlobalParser(const std::weak_ptr& Client, std::vector&& Packet, TPPSMonitor& PPSMonitor, TNetwork& Network) { +void TServer::GlobalParser(const std::weak_ptr& Client, std::vector&& Packet, TPPSMonitor& PPSMonitor, TNetwork& Network, bool udp) { constexpr std::string_view ABG = "ABG:"; if (Packet.size() >= ABG.size() && std::equal(Packet.begin(), Packet.begin() + ABG.size(), ABG.begin(), ABG.end())) { Packet.erase(Packet.begin(), Packet.begin() + ABG.size()); @@ -213,6 +213,10 @@ void TServer::GlobalParser(const std::weak_ptr& Client, std::vectorGetName(), LockedClient->GetID()); + return; + } if (!Network.SyncClient(Client)) { // TODO handle } @@ -226,12 +230,20 @@ void TServer::GlobalParser(const std::weak_ptr& Client, std::vectorGetName(), LockedClient->GetID()); + return; + } if (Packet.size() > 1000) { beammp_debug(("Received data from: ") + LockedClient->GetName() + (" Size: ") + std::to_string(Packet.size())); } ParseVehicle(*LockedClient, StringPacket, Network); return; case 'C': { + if (udp) { + beammp_debugf("Received 'C' packet over UDP from client '{}' ({}), ignoring it", LockedClient->GetName(), LockedClient->GetID()); + return; + } if (Packet.size() < 4 || std::find(Packet.begin() + 3, Packet.end(), ':') == Packet.end()) break; const auto PacketAsString = std::string(reinterpret_cast(Packet.data()), Packet.size()); @@ -262,6 +274,10 @@ void TServer::GlobalParser(const std::weak_ptr& Client, std::vectorGetName(), LockedClient->GetID()); + return; + } HandleEvent(*LockedClient, StringPacket); return; case 'N': @@ -304,6 +320,15 @@ void TServer::HandleEvent(TClient& c, const std::string& RawData) { } std::string Name = RawData.substr(2, NameDataSep - 2); std::string Data = RawData.substr(NameDataSep + 1); + + std::vector exclude = {"onInit", "onFileChanged","onVehicleDeleted","onConsoleInput","onPlayerAuth","postPlayerAuth", "onPlayerDisconnect", + "onPlayerConnecting","onPlayerJoining","onPlayerJoin","onChatMessage","postChatMessage","onVehicleSpawn","postVehicleSpawn","onVehicleEdited", "postVehicleEdited", + "onVehicleReset","onVehiclePaintChanged","onShutdown"}; + + if (std::ranges::find(exclude, Name) != exclude.end()) { + beammp_debugf("Excluded event triggered by client '{}' ({}): '{}', ignoring.", c.GetName(), c.GetID(), Name); + return; + } LuaAPI::MP::Engine->ReportErrors(LuaAPI::MP::Engine->TriggerEvent(Name, "", c.GetID(), Data)); }