refactor dos protection

This commit is contained in:
sla-ppy 2024-06-20 07:28:55 +02:00
parent df308c1dc5
commit bc5e407d60
3 changed files with 15 additions and 75 deletions

View File

@ -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

View File

@ -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);

View File

@ -20,6 +20,7 @@
#include "Client.h"
#include "Common.h"
#include "LuaAPI.h"
#include "RateLimiter.h"
#include "TLuaEngine.h"
#include "nlohmann/json.hpp"
#include <CustomAssert.h>
@ -31,63 +32,6 @@
typedef boost::asio::detail::socket_option::integer<SOL_SOCKET, SO_RCVTIMEO> rcv_timeout_option;
#include <iostream>
#include <unordered_map>
#include <fstream>
#include <chrono>
#include <mutex>
std::unordered_map<std::string, std::vector<std::chrono::time_point<std::chrono::high_resolution_clock>>> 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<std::mutex> 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<std::chrono::seconds>(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<std::string> blockedIPs;
if (blockFile.is_open()) {
std::string line;
while (std::getline(blockFile, line)) {
blockedIPs.insert(line);
}
}
return blockedIPs.find(clientAddress) != blockedIPs.end();
};
std::vector<uint8_t> StringToVector(const std::string& Str) {
return std::vector<uint8_t>(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<TClient> Client { nullptr };
WatchingConnecting connectionManager;
std::string client_address = RawConnection.SockAddr.address().to_string();
std::shared_ptr<TClient> client { nullptr };
RateLimiter ddos_protection;
try {
if (Code == 'C') {
if (connectionManager.IsConnectionAllowed(clientAddress)) {
Client = Authentication(std::move(RawConnection));
} else {
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') {
@ -452,7 +398,7 @@ std::shared_ptr<TClient> 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.";
}