mirror of
https://github.com/BeamMP/BeamMP-Server.git
synced 2026-07-13 18:24:16 +00:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5afc07b0b3 | |||
| bc5e407d60 | |||
| df308c1dc5 | |||
| f26b091042 | |||
| a008015d78 |
@@ -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
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
@@ -48,7 +48,6 @@ public:
|
||||
private:
|
||||
void UDPServerMain();
|
||||
void TCPServerMain();
|
||||
|
||||
TServer& mServer;
|
||||
TPPSMonitor& mPPSMonitor;
|
||||
ip::udp::socket mUDPSock;
|
||||
|
||||
@@ -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
@@ -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>
|
||||
@@ -196,10 +197,18 @@ void TNetwork::Identify(TConnection&& RawConnection) {
|
||||
RawConnection.Socket.shutdown(socket_base::shutdown_both, ec);
|
||||
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 {
|
||||
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') {
|
||||
HandleDownload(std::move(RawConnection));
|
||||
} else if (Code == 'P') {
|
||||
@@ -389,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.";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user