From 93a477e9c3421ee40ff244ab95b170b8ca705b59 Mon Sep 17 00:00:00 2001 From: sla-ppy Date: Thu, 20 Jun 2024 07:28:55 +0200 Subject: [PATCH] refactor dos protection --- CMakeLists.txt | 2 ++ include/TNetwork.h | 8 ----- src/TNetwork.cpp | 80 ++++++++-------------------------------------- 3 files changed, 15 insertions(+), 75 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e2f0e89..0bcbdd9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,6 +35,7 @@ set(PRJ_HEADERS include/Json.h include/LuaAPI.h include/RWMutex.h + include/RateLimiter.h include/SignalHandling.h include/TConfig.h include/TConsole.h @@ -72,6 +73,7 @@ set(PRJ_SOURCES src/TResourceManager.cpp src/TScopedTimer.cpp src/TServer.cpp + src/RateLimiter.cpp src/VehicleData.cpp src/Env.cpp src/Profiling.cpp diff --git a/include/TNetwork.h b/include/TNetwork.h index 7a646a2..575fa5b 100644 --- a/include/TNetwork.h +++ b/include/TNetwork.h @@ -27,14 +27,6 @@ struct TConnection; -class WatchingConnecting{ -public: - bool IsConnectionAllowed(const std::string& clientAddress); -private: - void BlockIP(const std::string& clientAddress); - bool IsIPBlocked(const std::string& clientAddress); -}; - class TNetwork { public: TNetwork(TServer& Server, TPPSMonitor& PPSMonitor, TResourceManager& ResourceManager); diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index b2cdfea..6728f66 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -20,6 +20,7 @@ #include "Client.h" #include "Common.h" #include "LuaAPI.h" +#include "RateLimiter.h" #include "TLuaEngine.h" #include "nlohmann/json.hpp" #include @@ -31,63 +32,6 @@ typedef boost::asio::detail::socket_option::integer rcv_timeout_option; -#include -#include -#include -#include -#include - -std::unordered_map>> connectionAttempts; -std::mutex connectionAttemptsMutex; - -bool WatchingConnecting::IsConnectionAllowed(const std::string& clientAddress) { - // we check if there is an IP in the blocked list - if (WatchingConnecting::IsIPBlocked(clientAddress)) { - return false; - } - std::lock_guard lock(connectionAttemptsMutex); - auto currentTime = std::chrono::high_resolution_clock::now(); - auto& violations = connectionAttempts[clientAddress]; - - // Deleting old violations (older than 5 seconds) - violations.erase(std::remove_if(violations.begin(), violations.end(), - [&](const auto& timestamp) { - return std::chrono::duration_cast(currentTime - timestamp).count() > 5; - }), violations.end()); - - // Adding the current violation - violations.push_back(currentTime); - - // We check the number of violations - if (violations.size() >= 4) { - WatchingConnecting::BlockIP(clientAddress); - beammp_errorf("[DOS] Blocked IP: {}", clientAddress); - return false; - } - - return true; // We allow the connection - } - -void WatchingConnecting::BlockIP(const std::string& clientAddress) { - std::ofstream blockFile("blocked_ips.txt", std::ios::app); - if (blockFile.is_open()) { - blockFile << clientAddress << std::endl; - } - } - -bool WatchingConnecting::IsIPBlocked(const std::string& clientAddress) { - std::ifstream blockFile("blocked_ips.txt"); - std::unordered_set blockedIPs; - - if (blockFile.is_open()) { - std::string line; - while (std::getline(blockFile, line)) { - blockedIPs.insert(line); - } - } - return blockedIPs.find(clientAddress) != blockedIPs.end(); -}; - std::vector StringToVector(const std::string& Str) { return std::vector(Str.data(), Str.data() + Str.size()); } @@ -253,16 +197,18 @@ void TNetwork::Identify(TConnection&& RawConnection) { RawConnection.Socket.shutdown(socket_base::shutdown_both, ec); return; } - std::string clientAddress = RawConnection.SockAddr.address().to_string(); - std::shared_ptr Client { nullptr }; - WatchingConnecting connectionManager; + std::string client_address = RawConnection.SockAddr.address().to_string(); + std::shared_ptr client { nullptr }; + RateLimiter ddos_protection; try { - if (Code == 'C') { - if (connectionManager.IsConnectionAllowed(clientAddress)) { - Client = Authentication(std::move(RawConnection)); - } else { + if (Code == 'C') { + if (ddos_protection.isConnectionAllowed(client_address)) { + beammp_infof("[DoS Protection] Client: [{}] is authorized to connect to the server", client_address); + client = Authentication(std::move(RawConnection)); + } else { + beammp_infof("[DoS Protection] Client: [{}] has been denied access to the server", client_address); RawConnection.Socket.shutdown(socket_base::shutdown_both, ec); - } + } } else if (Code == 'D') { HandleDownload(std::move(RawConnection)); } else if (Code == 'P') { @@ -355,7 +301,7 @@ std::shared_ptr TNetwork::Authentication(TConnection&& RawConnection) { std::string Key(reinterpret_cast(Data.data()), Data.size()); std::string AuthKey = Application::Settings.Key; std::string ClientIp = Client->GetIdentifiers().at("ip"); - + nlohmann::json AuthReq {}; std::string AuthResStr {}; try { @@ -452,7 +398,7 @@ std::shared_ptr TNetwork::Authentication(TConnection&& RawConnection) { return false; }); - if (!NotAllowedWithReason && !Application::Settings.AllowGuests && Client->IsGuest()) { //!NotAllowedWithReason because this message has the lowest priority + if (!NotAllowedWithReason && !Application::Settings.AllowGuests && Client->IsGuest()) { //! NotAllowedWithReason because this message has the lowest priority NotAllowedWithReason = true; Reason = "No guests are allowed on this server! To join, sign up at: forum.beammp.com."; }