mirror of
https://github.com/BeamMP/BeamMP-Server.git
synced 2025-07-01 23:35:41 +00:00
refactor dos protection
This commit is contained in:
parent
2c05a442ee
commit
93a477e9c3
@ -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
|
||||||
|
@ -27,14 +27,6 @@
|
|||||||
|
|
||||||
struct TConnection;
|
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 {
|
class TNetwork {
|
||||||
public:
|
public:
|
||||||
TNetwork(TServer& Server, TPPSMonitor& PPSMonitor, TResourceManager& ResourceManager);
|
TNetwork(TServer& Server, TPPSMonitor& PPSMonitor, TResourceManager& ResourceManager);
|
||||||
|
@ -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>
|
||||||
@ -31,63 +32,6 @@
|
|||||||
|
|
||||||
typedef boost::asio::detail::socket_option::integer<SOL_SOCKET, SO_RCVTIMEO> rcv_timeout_option;
|
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) {
|
std::vector<uint8_t> StringToVector(const std::string& Str) {
|
||||||
return std::vector<uint8_t>(Str.data(), Str.data() + Str.size());
|
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);
|
RawConnection.Socket.shutdown(socket_base::shutdown_both, ec);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
std::string clientAddress = RawConnection.SockAddr.address().to_string();
|
std::string client_address = RawConnection.SockAddr.address().to_string();
|
||||||
std::shared_ptr<TClient> Client { nullptr };
|
std::shared_ptr<TClient> client { nullptr };
|
||||||
WatchingConnecting connectionManager;
|
RateLimiter ddos_protection;
|
||||||
try {
|
try {
|
||||||
if (Code == 'C') {
|
if (Code == 'C') {
|
||||||
if (connectionManager.IsConnectionAllowed(clientAddress)) {
|
if (ddos_protection.isConnectionAllowed(client_address)) {
|
||||||
Client = Authentication(std::move(RawConnection));
|
beammp_infof("[DoS Protection] Client: [{}] is authorized to connect to the server", client_address);
|
||||||
} else {
|
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);
|
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') {
|
||||||
@ -355,7 +301,7 @@ std::shared_ptr<TClient> TNetwork::Authentication(TConnection&& RawConnection) {
|
|||||||
std::string Key(reinterpret_cast<const char*>(Data.data()), Data.size());
|
std::string Key(reinterpret_cast<const char*>(Data.data()), Data.size());
|
||||||
std::string AuthKey = Application::Settings.Key;
|
std::string AuthKey = Application::Settings.Key;
|
||||||
std::string ClientIp = Client->GetIdentifiers().at("ip");
|
std::string ClientIp = Client->GetIdentifiers().at("ip");
|
||||||
|
|
||||||
nlohmann::json AuthReq {};
|
nlohmann::json AuthReq {};
|
||||||
std::string AuthResStr {};
|
std::string AuthResStr {};
|
||||||
try {
|
try {
|
||||||
@ -452,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.";
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user