Compare commits

...

3 Commits

Author SHA1 Message Date
sla-ppy 70967a81a3 add RateLimiter class 2024-06-20 16:47:20 +02:00
sla-ppy 93a477e9c3 refactor dos protection 2024-06-20 16:47:17 +02:00
Igor 2c05a442ee add a simple DOS protection system 2024-06-20 16:47:04 +02:00
5 changed files with 85 additions and 5 deletions
+2
View File
@@ -35,6 +35,7 @@ set(PRJ_HEADERS
include/Json.h include/Json.h
include/LuaAPI.h include/LuaAPI.h
include/RWMutex.h include/RWMutex.h
include/RateLimiter.h
include/SignalHandling.h include/SignalHandling.h
include/TConfig.h include/TConfig.h
include/TConsole.h include/TConsole.h
@@ -72,6 +73,7 @@ set(PRJ_SOURCES
src/TResourceManager.cpp src/TResourceManager.cpp
src/TScopedTimer.cpp src/TScopedTimer.cpp
src/TServer.cpp src/TServer.cpp
src/RateLimiter.cpp
src/VehicleData.cpp src/VehicleData.cpp
src/Env.cpp src/Env.cpp
src/Profiling.cpp src/Profiling.cpp
+20
View File
@@ -0,0 +1,20 @@
#include "Common.h"
#include <chrono>
#include <fstream>
#include <iostream>
#include <mutex>
#include <unordered_map>
#include <unordered_set>
class RateLimiter {
public:
RateLimiter();
bool isConnectionAllowed(const std::string& client_address);
private:
std::unordered_map<std::string, std::vector<std::chrono::time_point<std::chrono::high_resolution_clock>>> m_connection;
std::mutex m_connection_mutex;
void blockIP(const std::string& client_address);
bool isIPBlocked(const std::string& client_address);
};
-1
View File
@@ -48,7 +48,6 @@ public:
private: private:
void UDPServerMain(); void UDPServerMain();
void TCPServerMain(); void TCPServerMain();
TServer& mServer; TServer& mServer;
TPPSMonitor& mPPSMonitor; TPPSMonitor& mPPSMonitor;
ip::udp::socket mUDPSock; ip::udp::socket mUDPSock;
+50
View File
@@ -0,0 +1,50 @@
#include "RateLimiter.h"
RateLimiter::RateLimiter() {};
bool RateLimiter::isConnectionAllowed(const std::string& client_address) {
if (RateLimiter::isIPBlocked(client_address)) {
return false;
}
std::lock_guard<std::mutex> lock(m_connection_mutex);
auto current_time = std::chrono::high_resolution_clock::now();
auto& violations = m_connection[client_address];
// Deleting old violations (older than 5 seconds)
violations.erase(std::remove_if(violations.begin(), violations.end(),
[&](const auto& timestamp) {
return std::chrono::duration_cast<std::chrono::seconds>(current_time - timestamp).count() > 5;
}),
violations.end());
violations.push_back(current_time);
if (violations.size() >= 4) {
RateLimiter::blockIP(client_address);
beammp_errorf("[DoS Protection] Client with the IP: {} surpassed the violation treshhold and is now on the blocked list", client_address);
return false;
}
return true; // We allow the connection
}
void RateLimiter::blockIP(const std::string& client_address) {
std::ofstream block_file("blocked_ips.txt", std::ios::app);
if (block_file.is_open()) {
block_file << client_address << std::endl;
}
}
bool RateLimiter::isIPBlocked(const std::string& client_address) {
std::ifstream block_file("blocked_ips.txt");
std::unordered_set<std::string> blockedIPs;
if (block_file.is_open()) {
std::string line;
while (std::getline(block_file, line)) {
blockedIPs.insert(line);
}
}
return blockedIPs.contains(client_address);
};
+12 -3
View File
@@ -20,6 +20,7 @@
#include "Client.h" #include "Client.h"
#include "Common.h" #include "Common.h"
#include "LuaAPI.h" #include "LuaAPI.h"
#include "RateLimiter.h"
#include "TLuaEngine.h" #include "TLuaEngine.h"
#include "nlohmann/json.hpp" #include "nlohmann/json.hpp"
#include <CustomAssert.h> #include <CustomAssert.h>
@@ -196,10 +197,18 @@ void TNetwork::Identify(TConnection&& RawConnection) {
RawConnection.Socket.shutdown(socket_base::shutdown_both, ec); RawConnection.Socket.shutdown(socket_base::shutdown_both, ec);
return; return;
} }
std::shared_ptr<TClient> Client { nullptr }; std::string client_address = RawConnection.SockAddr.address().to_string();
std::shared_ptr<TClient> client { nullptr };
RateLimiter ddos_protection;
try { try {
if (Code == 'C') { if (Code == 'C') {
Client = Authentication(std::move(RawConnection)); 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') { } else if (Code == 'D') {
HandleDownload(std::move(RawConnection)); HandleDownload(std::move(RawConnection));
} else if (Code == 'P') { } else if (Code == 'P') {
@@ -389,7 +398,7 @@ std::shared_ptr<TClient> TNetwork::Authentication(TConnection&& RawConnection) {
return false; 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; NotAllowedWithReason = true;
Reason = "No guests are allowed on this server! To join, sign up at: forum.beammp.com."; Reason = "No guests are allowed on this server! To join, sign up at: forum.beammp.com.";
} }