diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index b6bb27f..02fb55b 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -670,7 +670,13 @@ void TNetwork::TCPClient(const std::weak_ptr& c) { Client->Disconnect("TCPRcv failed"); break; } - mServer.GlobalParser(c, std::move(res), mPPSMonitor, *this, false); + try { + mServer.GlobalParser(c, std::move(res), mPPSMonitor, *this, false); + } catch (const std::exception& e) { + beammp_warnf("Failed to receive/parse packet via TCP from client {}: {}", Client->GetID(), e.what()); + Client->Disconnect("Failed to parse packet"); + break; + } } if (QueueSync.joinable()) diff --git a/src/TServer.cpp b/src/TServer.cpp index 2618840..e38fb04 100644 --- a/src/TServer.cpp +++ b/src/TServer.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include @@ -54,6 +55,15 @@ static std::optional> GetPidVid(const std::string& str) { return std::nullopt; } +static std::optional ExtractStructuredPayload(const std::string& PacketData, char BeginMarker) { + auto FoundPos = PacketData.find(BeginMarker); + if (FoundPos == std::string::npos) { + return std::nullopt; + } + + return PacketData.substr(FoundPos); +} + TEST_CASE("GetPidVid") { SUBCASE("Valid singledigit") { const auto MaybePidVid = GetPidVid("0-1"); @@ -121,6 +131,13 @@ TEST_CASE("GetPidVid") { } } +TEST_CASE("ExtractStructuredPayload") { + CHECK_EQ(ExtractStructuredPayload("1-2:{\"reset\":true}", '{').value(), "{\"reset\":true}"); + CHECK_EQ(ExtractStructuredPayload("1-2:[0,1,2,3]", '[').value(), "[0,1,2,3]"); + CHECK_FALSE(ExtractStructuredPayload("1-2:null", '{').has_value()); + CHECK_FALSE(ExtractStructuredPayload("1-2:null", '[').has_value()); +} + TServer::TServer(const std::vector& Arguments) { beammp_info("BeamMP Server v" + Application::ServerVersionString()); Application::SetSubsystemStatus("Server", Application::Status::Starting); @@ -472,7 +489,13 @@ void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TNetwork& Networ } if (PID != -1 && VID != -1 && PID == c.GetID()) { - Data = Data.substr(Data.find('{')); + auto ResetData = ExtractStructuredPayload(Data, '{'); + if (!ResetData.has_value()) { + beammp_warnf("Malformed 'Or' packet from client {}: missing '{{' in '{}'", c.GetID(), Packet); + return; + } + + Data = std::move(ResetData.value()); LuaAPI::MP::Engine->ReportErrors(LuaAPI::MP::Engine->TriggerEvent("onVehicleReset", "", c.GetID(), VID, Data)); Network.SendToAll(&c, StringToVector(Packet), false, true); } @@ -501,7 +524,13 @@ void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TNetwork& Networ } if (PID != -1 && VID != -1 && PID == c.GetID()) { - Data = Data.substr(Data.find('[')); + auto PaintData = ExtractStructuredPayload(Data, '['); + if (!PaintData.has_value()) { + beammp_warnf("Malformed 'Op' packet from client {}: missing '[' in '{}'", c.GetID(), Packet); + return; + } + + Data = std::move(PaintData.value()); LuaAPI::MP::Engine->ReportErrors(LuaAPI::MP::Engine->TriggerEvent("onVehiclePaintChanged", "", c.GetID(), VID, Data)); Network.SendToAll(&c, StringToVector(Packet), false, true);