diff --git a/include/Common.h b/include/Common.h index 488b8d17..12bd2a75 100644 --- a/include/Common.h +++ b/include/Common.h @@ -127,7 +127,7 @@ class Application final { static inline std::mutex mShutdownHandlersMutex {}; static inline std::deque mShutdownHandlers {}; - static inline Version mVersion { 3, 5, 0 }; + static inline Version mVersion { 3, 5, 1 }; }; void SplitString(std::string const& str, const char delim, std::vector& out); @@ -268,3 +268,9 @@ std::vector DeComp(std::span input); std::string GetPlatformAgnosticErrorString(); #define S_DSN SU_RAW + +class InvalidDataError : std::runtime_error { +public: + InvalidDataError() : std::runtime_error("Invalid data") { + } +}; diff --git a/src/Common.cpp b/src/Common.cpp index 82ab3364..017e4124 100644 --- a/src/Common.cpp +++ b/src/Common.cpp @@ -418,7 +418,11 @@ std::vector DeComp(std::span input) { output_size = output_buffer.size(); } else if (res != Z_OK) { beammp_error("zlib uncompress() failed: " + std::to_string(res)); - throw std::runtime_error("zlib uncompress() failed"); + if (res == Z_DATA_ERROR) { + throw InvalidDataError {}; + } else { + throw std::runtime_error("zlib uncompress() failed"); + } } else if (res == Z_OK) { break; } diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index dee33117..b50af560 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -546,7 +546,17 @@ std::vector TNetwork::TCPRcv(TClient& c) { constexpr std::string_view ABG = "ABG:"; if (Data.size() >= ABG.size() && std::equal(Data.begin(), Data.begin() + ABG.size(), ABG.begin(), ABG.end())) { Data.erase(Data.begin(), Data.begin() + ABG.size()); - return DeComp(Data); + try { + return DeComp(Data); + } catch (const InvalidDataError& ) { + beammp_errorf("Failed to decompress packet from a client. The receive failed and the client may be disconnected as a result"); + // return empty -> error + return std::vector(); + } catch (const std::runtime_error& e) { + beammp_errorf("Failed to decompress packet from a client: {}. The server may be out of RAM! The receive failed and the client may be disconnected as a result", e.what()); + // return empty -> error + return std::vector(); + } } else { return Data; } diff --git a/src/TServer.cpp b/src/TServer.cpp index b16ddd3d..f99bbb7e 100644 --- a/src/TServer.cpp +++ b/src/TServer.cpp @@ -165,7 +165,19 @@ void TServer::GlobalParser(const std::weak_ptr& Client, std::vector= ABG.size() && std::equal(Packet.begin(), Packet.begin() + ABG.size(), ABG.begin(), ABG.end())) { Packet.erase(Packet.begin(), Packet.begin() + ABG.size()); - Packet = DeComp(Packet); + try { + Packet = DeComp(Packet); + } catch (const InvalidDataError& ) { + auto LockedClient = Client.lock(); + beammp_errorf("Failed to decompress packet from client {}. The client sent invalid data and will now be disconnected.", LockedClient->GetID()); + Network.ClientKick(*LockedClient, "Sent invalid compressed packet (this is likely a bug on your end)"); + return; + } catch (const std::runtime_error& e) { + auto LockedClient = Client.lock(); + beammp_errorf("Failed to decompress packet from client {}: {}. The server might be out of RAM! The client will now be disconnected.", LockedClient->GetID(), e.what()); + Network.ClientKick(*LockedClient, "Decompression failed (likely a server-side problem)"); + return; + } } if (Packet.empty()) { return;