refactor: Create interface for DOSGuard (#1602)

For #919.
This commit is contained in:
Sergey Kuznetsov
2024-08-13 17:26:47 +01:00
committed by GitHub
parent 49e9d5eda0
commit b7c8ed7e3a
26 changed files with 535 additions and 270 deletions

View File

@@ -33,11 +33,11 @@
#include "util/config/Config.hpp" #include "util/config/Config.hpp"
#include "util/log/Logger.hpp" #include "util/log/Logger.hpp"
#include "util/prometheus/Prometheus.hpp" #include "util/prometheus/Prometheus.hpp"
#include "web/DOSGuard.hpp"
#include "web/IntervalSweepHandler.hpp"
#include "web/RPCServerHandler.hpp" #include "web/RPCServerHandler.hpp"
#include "web/Server.hpp" #include "web/Server.hpp"
#include "web/WhitelistHandler.hpp" #include "web/dosguard/DOSGuard.hpp"
#include "web/dosguard/IntervalSweepHandler.hpp"
#include "web/dosguard/WhitelistHandler.hpp"
#include <boost/asio/io_context.hpp> #include <boost/asio/io_context.hpp>
@@ -93,9 +93,9 @@ ClioApplication::run()
boost::asio::io_context ioc{threads}; boost::asio::io_context ioc{threads};
// Rate limiter, to prevent abuse // Rate limiter, to prevent abuse
auto whitelistHandler = web::WhitelistHandler{config_}; auto whitelistHandler = web::dosguard::WhitelistHandler{config_};
auto dosGuard = web::DOSGuard{config_, whitelistHandler}; auto dosGuard = web::dosguard::DOSGuard{config_, whitelistHandler};
auto sweepHandler = web::IntervalSweepHandler{config_, ioc, dosGuard}; auto sweepHandler = web::dosguard::IntervalSweepHandler{config_, ioc, dosGuard};
// Interface to the database // Interface to the database
auto backend = data::make_Backend(config_); auto backend = data::make_Backend(config_);

View File

@@ -28,7 +28,7 @@
#include "rpc/common/impl/ForwardingProxy.hpp" #include "rpc/common/impl/ForwardingProxy.hpp"
#include "util/log/Logger.hpp" #include "util/log/Logger.hpp"
#include "web/Context.hpp" #include "web/Context.hpp"
#include "web/DOSGuard.hpp" #include "web/dosguard/DOSGuardInterface.hpp"
#include <boost/asio/spawn.hpp> #include <boost/asio/spawn.hpp>
#include <boost/json.hpp> #include <boost/json.hpp>
@@ -65,7 +65,7 @@ class RPCEngine {
util::Logger log_{"RPC"}; util::Logger log_{"RPC"};
std::shared_ptr<BackendInterface> backend_; std::shared_ptr<BackendInterface> backend_;
std::reference_wrapper<web::DOSGuard const> dosGuard_; std::reference_wrapper<web::dosguard::DOSGuardInterface const> dosGuard_;
std::reference_wrapper<WorkQueue> workQueue_; std::reference_wrapper<WorkQueue> workQueue_;
std::reference_wrapper<Counters> counters_; std::reference_wrapper<Counters> counters_;
@@ -87,7 +87,7 @@ public:
RPCEngine( RPCEngine(
std::shared_ptr<BackendInterface> const& backend, std::shared_ptr<BackendInterface> const& backend,
std::shared_ptr<etl::LoadBalancer> const& balancer, std::shared_ptr<etl::LoadBalancer> const& balancer,
web::DOSGuard const& dosGuard, web::dosguard::DOSGuardInterface const& dosGuard,
WorkQueue& workQueue, WorkQueue& workQueue,
Counters& counters, Counters& counters,
std::shared_ptr<HandlerProvider const> const& handlerProvider std::shared_ptr<HandlerProvider const> const& handlerProvider
@@ -116,7 +116,7 @@ public:
make_RPCEngine( make_RPCEngine(
std::shared_ptr<BackendInterface> const& backend, std::shared_ptr<BackendInterface> const& backend,
std::shared_ptr<etl::LoadBalancer> const& balancer, std::shared_ptr<etl::LoadBalancer> const& balancer,
web::DOSGuard const& dosGuard, web::dosguard::DOSGuardInterface const& dosGuard,
WorkQueue& workQueue, WorkQueue& workQueue,
Counters& counters, Counters& counters,
std::shared_ptr<HandlerProvider const> const& handlerProvider std::shared_ptr<HandlerProvider const> const& handlerProvider

View File

@@ -1,8 +1,15 @@
add_library(clio_web) add_library(clio_web)
target_sources( target_sources(
clio_web PRIVATE impl/AdminVerificationStrategy.cpp impl/ServerSslContext.cpp IntervalSweepHandler.cpp Resolver.cpp clio_web
Server.cpp PRIVATE Resolver.cpp
Server.cpp
dosguard/DOSGuard.cpp
dosguard/IntervalSweepHandler.cpp
dosguard/WhitelistHandler.cpp
impl/AdminVerificationStrategy.cpp
impl/ServerSslContext.cpp
ng/Server.cpp
) )
target_link_libraries(clio_web PUBLIC clio_util) target_link_libraries(clio_web PUBLIC clio_util)

View File

@@ -20,8 +20,8 @@
#pragma once #pragma once
#include "util/Taggable.hpp" #include "util/Taggable.hpp"
#include "web/DOSGuard.hpp"
#include "web/PlainWsSession.hpp" #include "web/PlainWsSession.hpp"
#include "web/dosguard/DOSGuardInterface.hpp"
#include "web/impl/HttpBase.hpp" #include "web/impl/HttpBase.hpp"
#include "web/interface/ConnectionBase.hpp" #include "web/interface/ConnectionBase.hpp"
@@ -70,7 +70,7 @@ public:
std::string const& ip, std::string const& ip,
std::shared_ptr<impl::AdminVerificationStrategy> const& adminVerification, std::shared_ptr<impl::AdminVerificationStrategy> const& adminVerification,
std::reference_wrapper<util::TagDecoratorFactory const> tagFactory, std::reference_wrapper<util::TagDecoratorFactory const> tagFactory,
std::reference_wrapper<web::DOSGuard> dosGuard, std::reference_wrapper<dosguard::DOSGuardInterface> dosGuard,
std::shared_ptr<HandlerType> const& handler, std::shared_ptr<HandlerType> const& handler,
boost::beast::flat_buffer buffer boost::beast::flat_buffer buffer
) )

View File

@@ -20,7 +20,7 @@
#pragma once #pragma once
#include "util/Taggable.hpp" #include "util/Taggable.hpp"
#include "web/DOSGuard.hpp" #include "web/dosguard/DOSGuardInterface.hpp"
#include "web/impl/WsBase.hpp" #include "web/impl/WsBase.hpp"
#include "web/interface/ConnectionBase.hpp" #include "web/interface/ConnectionBase.hpp"
@@ -68,7 +68,7 @@ public:
boost::asio::ip::tcp::socket&& socket, boost::asio::ip::tcp::socket&& socket,
std::string ip, std::string ip,
std::reference_wrapper<util::TagDecoratorFactory const> tagFactory, std::reference_wrapper<util::TagDecoratorFactory const> tagFactory,
std::reference_wrapper<web::DOSGuard> dosGuard, std::reference_wrapper<dosguard::DOSGuardInterface> dosGuard,
std::shared_ptr<HandlerType> const& handler, std::shared_ptr<HandlerType> const& handler,
boost::beast::flat_buffer&& buffer, boost::beast::flat_buffer&& buffer,
bool isAdmin bool isAdmin
@@ -102,7 +102,7 @@ class WsUpgrader : public std::enable_shared_from_this<WsUpgrader<HandlerType>>
boost::optional<http::request_parser<http::string_body>> parser_; boost::optional<http::request_parser<http::string_body>> parser_;
boost::beast::flat_buffer buffer_; boost::beast::flat_buffer buffer_;
std::reference_wrapper<util::TagDecoratorFactory const> tagFactory_; std::reference_wrapper<util::TagDecoratorFactory const> tagFactory_;
std::reference_wrapper<web::DOSGuard> dosGuard_; std::reference_wrapper<dosguard::DOSGuardInterface> dosGuard_;
http::request<http::string_body> req_; http::request<http::string_body> req_;
std::string ip_; std::string ip_;
std::shared_ptr<HandlerType> const handler_; std::shared_ptr<HandlerType> const handler_;
@@ -125,7 +125,7 @@ public:
boost::beast::tcp_stream&& stream, boost::beast::tcp_stream&& stream,
std::string ip, std::string ip,
std::reference_wrapper<util::TagDecoratorFactory const> tagFactory, std::reference_wrapper<util::TagDecoratorFactory const> tagFactory,
std::reference_wrapper<web::DOSGuard> dosGuard, std::reference_wrapper<dosguard::DOSGuardInterface> dosGuard,
std::shared_ptr<HandlerType> const& handler, std::shared_ptr<HandlerType> const& handler,
boost::beast::flat_buffer&& buffer, boost::beast::flat_buffer&& buffer,
http::request<http::string_body> request, http::request<http::string_body> request,

View File

@@ -21,9 +21,9 @@
#include "util/Taggable.hpp" #include "util/Taggable.hpp"
#include "util/log/Logger.hpp" #include "util/log/Logger.hpp"
#include "web/DOSGuard.hpp"
#include "web/HttpSession.hpp" #include "web/HttpSession.hpp"
#include "web/SslHttpSession.hpp" #include "web/SslHttpSession.hpp"
#include "web/dosguard/DOSGuardInterface.hpp"
#include "web/impl/ServerSslContext.hpp" #include "web/impl/ServerSslContext.hpp"
#include "web/interface/Concepts.hpp" #include "web/interface/Concepts.hpp"
@@ -91,7 +91,7 @@ class Detector : public std::enable_shared_from_this<Detector<PlainSessionType,
boost::beast::tcp_stream stream_; boost::beast::tcp_stream stream_;
std::optional<std::reference_wrapper<boost::asio::ssl::context>> ctx_; std::optional<std::reference_wrapper<boost::asio::ssl::context>> ctx_;
std::reference_wrapper<util::TagDecoratorFactory const> tagFactory_; std::reference_wrapper<util::TagDecoratorFactory const> tagFactory_;
std::reference_wrapper<web::DOSGuard> const dosGuard_; std::reference_wrapper<dosguard::DOSGuardInterface> const dosGuard_;
std::shared_ptr<HandlerType> const handler_; std::shared_ptr<HandlerType> const handler_;
boost::beast::flat_buffer buffer_; boost::beast::flat_buffer buffer_;
std::shared_ptr<impl::AdminVerificationStrategy> const adminVerification_; std::shared_ptr<impl::AdminVerificationStrategy> const adminVerification_;
@@ -111,7 +111,7 @@ public:
tcp::socket&& socket, tcp::socket&& socket,
std::optional<std::reference_wrapper<boost::asio::ssl::context>> ctx, std::optional<std::reference_wrapper<boost::asio::ssl::context>> ctx,
std::reference_wrapper<util::TagDecoratorFactory const> tagFactory, std::reference_wrapper<util::TagDecoratorFactory const> tagFactory,
std::reference_wrapper<web::DOSGuard> dosGuard, std::reference_wrapper<dosguard::DOSGuardInterface> dosGuard,
std::shared_ptr<HandlerType> handler, std::shared_ptr<HandlerType> handler,
std::shared_ptr<impl::AdminVerificationStrategy> adminVerification std::shared_ptr<impl::AdminVerificationStrategy> adminVerification
) )
@@ -213,7 +213,7 @@ class Server : public std::enable_shared_from_this<Server<PlainSessionType, SslS
std::reference_wrapper<boost::asio::io_context> ioc_; std::reference_wrapper<boost::asio::io_context> ioc_;
std::optional<boost::asio::ssl::context> ctx_; std::optional<boost::asio::ssl::context> ctx_;
util::TagDecoratorFactory tagFactory_; util::TagDecoratorFactory tagFactory_;
std::reference_wrapper<web::DOSGuard> dosGuard_; std::reference_wrapper<dosguard::DOSGuardInterface> dosGuard_;
std::shared_ptr<HandlerType> handler_; std::shared_ptr<HandlerType> handler_;
tcp::acceptor acceptor_; tcp::acceptor acceptor_;
std::shared_ptr<impl::AdminVerificationStrategy> adminVerification_; std::shared_ptr<impl::AdminVerificationStrategy> adminVerification_;
@@ -235,7 +235,7 @@ public:
std::optional<boost::asio::ssl::context> ctx, std::optional<boost::asio::ssl::context> ctx,
tcp::endpoint endpoint, tcp::endpoint endpoint,
util::TagDecoratorFactory tagFactory, util::TagDecoratorFactory tagFactory,
web::DOSGuard& dosGuard, dosguard::DOSGuardInterface& dosGuard,
std::shared_ptr<HandlerType> handler, std::shared_ptr<HandlerType> handler,
std::optional<std::string> adminPassword std::optional<std::string> adminPassword
) )
@@ -327,7 +327,7 @@ static std::shared_ptr<HttpServer<HandlerType>>
make_HttpServer( make_HttpServer(
util::Config const& config, util::Config const& config,
boost::asio::io_context& ioc, boost::asio::io_context& ioc,
web::DOSGuard& dosGuard, dosguard::DOSGuardInterface& dosGuard,
std::shared_ptr<HandlerType> const& handler std::shared_ptr<HandlerType> const& handler
) )
{ {

View File

@@ -20,9 +20,10 @@
#pragma once #pragma once
#include "util/Taggable.hpp" #include "util/Taggable.hpp"
#include "web/DOSGuard.hpp"
#include "web/SslWsSession.hpp" #include "web/SslWsSession.hpp"
#include "web/dosguard/DOSGuardInterface.hpp"
#include "web/impl/HttpBase.hpp" #include "web/impl/HttpBase.hpp"
#include "web/interface/Concepts.hpp"
#include "web/interface/ConnectionBase.hpp" #include "web/interface/ConnectionBase.hpp"
#include <boost/asio/ip/tcp.hpp> #include <boost/asio/ip/tcp.hpp>
@@ -78,7 +79,7 @@ public:
std::shared_ptr<impl::AdminVerificationStrategy> const& adminVerification, std::shared_ptr<impl::AdminVerificationStrategy> const& adminVerification,
boost::asio::ssl::context& ctx, boost::asio::ssl::context& ctx,
std::reference_wrapper<util::TagDecoratorFactory const> tagFactory, std::reference_wrapper<util::TagDecoratorFactory const> tagFactory,
std::reference_wrapper<web::DOSGuard> dosGuard, std::reference_wrapper<dosguard::DOSGuardInterface> dosGuard,
std::shared_ptr<HandlerType> const& handler, std::shared_ptr<HandlerType> const& handler,
boost::beast::flat_buffer buffer boost::beast::flat_buffer buffer
) )

View File

@@ -20,7 +20,7 @@
#pragma once #pragma once
#include "util/Taggable.hpp" #include "util/Taggable.hpp"
#include "web/DOSGuard.hpp" #include "web/dosguard/DOSGuardInterface.hpp"
#include "web/impl/WsBase.hpp" #include "web/impl/WsBase.hpp"
#include "web/interface/ConnectionBase.hpp" #include "web/interface/ConnectionBase.hpp"
@@ -69,7 +69,7 @@ public:
boost::beast::ssl_stream<boost::beast::tcp_stream>&& stream, boost::beast::ssl_stream<boost::beast::tcp_stream>&& stream,
std::string ip, std::string ip,
std::reference_wrapper<util::TagDecoratorFactory const> tagFactory, std::reference_wrapper<util::TagDecoratorFactory const> tagFactory,
std::reference_wrapper<web::DOSGuard> dosGuard, std::reference_wrapper<dosguard::DOSGuardInterface> dosGuard,
std::shared_ptr<HandlerType> const& handler, std::shared_ptr<HandlerType> const& handler,
boost::beast::flat_buffer&& buffer, boost::beast::flat_buffer&& buffer,
bool isAdmin bool isAdmin
@@ -102,7 +102,7 @@ class SslWsUpgrader : public std::enable_shared_from_this<SslWsUpgrader<HandlerT
boost::beast::flat_buffer buffer_; boost::beast::flat_buffer buffer_;
std::string ip_; std::string ip_;
std::reference_wrapper<util::TagDecoratorFactory const> tagFactory_; std::reference_wrapper<util::TagDecoratorFactory const> tagFactory_;
std::reference_wrapper<web::DOSGuard> dosGuard_; std::reference_wrapper<dosguard::DOSGuardInterface> dosGuard_;
std::shared_ptr<HandlerType> const handler_; std::shared_ptr<HandlerType> const handler_;
http::request<http::string_body> req_; http::request<http::string_body> req_;
bool isAdmin_; bool isAdmin_;
@@ -124,7 +124,7 @@ public:
boost::beast::ssl_stream<boost::beast::tcp_stream> stream, boost::beast::ssl_stream<boost::beast::tcp_stream> stream,
std::string ip, std::string ip,
std::reference_wrapper<util::TagDecoratorFactory const> tagFactory, std::reference_wrapper<util::TagDecoratorFactory const> tagFactory,
std::reference_wrapper<web::DOSGuard> dosGuard, std::reference_wrapper<dosguard::DOSGuardInterface> dosGuard,
std::shared_ptr<HandlerType> handler, std::shared_ptr<HandlerType> handler,
boost::beast::flat_buffer&& buffer, boost::beast::flat_buffer&& buffer,
http::request<http::string_body> request, http::request<http::string_body> request,

View File

@@ -0,0 +1,148 @@
//------------------------------------------------------------------------------
/*
This file is part of clio: https://github.com/XRPLF/clio
Copyright (c) 2024, the clio developers.
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include "web/dosguard/DOSGuard.hpp"
#include "util/Assert.hpp"
#include "util/config/Config.hpp"
#include "util/log/Logger.hpp"
#include "web/dosguard/WhitelistHandlerInterface.hpp"
#include <boost/iterator/transform_iterator.hpp>
#include <cstdint>
#include <functional>
#include <mutex>
#include <string>
#include <string_view>
#include <unordered_set>
namespace web::dosguard {
DOSGuard::DOSGuard(util::Config const& config, WhitelistHandlerInterface const& whitelistHandler)
: whitelistHandler_{std::cref(whitelistHandler)}
, maxFetches_{config.valueOr("dos_guard.max_fetches", DEFAULT_MAX_FETCHES)}
, maxConnCount_{config.valueOr("dos_guard.max_connections", DEFAULT_MAX_CONNECTIONS)}
, maxRequestCount_{config.valueOr("dos_guard.max_requests", DEFAULT_MAX_REQUESTS)}
{
}
[[nodiscard]] bool
DOSGuard::isWhiteListed(std::string_view const ip) const noexcept
{
return whitelistHandler_.get().isWhiteListed(ip);
}
[[nodiscard]] bool
DOSGuard::isOk(std::string const& ip) const noexcept
{
if (whitelistHandler_.get().isWhiteListed(ip))
return true;
{
std::scoped_lock const lck(mtx_);
if (ipState_.find(ip) != ipState_.end()) {
auto [transferedByte, requests] = ipState_.at(ip);
if (transferedByte > maxFetches_ || requests > maxRequestCount_) {
LOG(log_.warn()) << "Dosguard: Client surpassed the rate limit. ip = " << ip
<< " Transfered Byte: " << transferedByte << "; Requests: " << requests;
return false;
}
}
auto it = ipConnCount_.find(ip);
if (it != ipConnCount_.end()) {
if (it->second > maxConnCount_) {
LOG(log_.warn()) << "Dosguard: Client surpassed the rate limit. ip = " << ip
<< " Concurrent connection: " << it->second;
return false;
}
}
}
return true;
}
void
DOSGuard::increment(std::string const& ip) noexcept
{
if (whitelistHandler_.get().isWhiteListed(ip))
return;
std::scoped_lock const lck{mtx_};
ipConnCount_[ip]++;
}
void
DOSGuard::decrement(std::string const& ip) noexcept
{
if (whitelistHandler_.get().isWhiteListed(ip))
return;
std::scoped_lock const lck{mtx_};
ASSERT(ipConnCount_[ip] > 0, "Connection count for ip {} can't be 0", ip);
ipConnCount_[ip]--;
if (ipConnCount_[ip] == 0)
ipConnCount_.erase(ip);
}
[[maybe_unused]] bool
DOSGuard::add(std::string const& ip, uint32_t numObjects) noexcept
{
if (whitelistHandler_.get().isWhiteListed(ip))
return true;
{
std::scoped_lock const lck(mtx_);
ipState_[ip].transferedByte += numObjects;
}
return isOk(ip);
}
[[maybe_unused]] bool
DOSGuard::request(std::string const& ip) noexcept
{
if (whitelistHandler_.get().isWhiteListed(ip))
return true;
{
std::scoped_lock const lck(mtx_);
ipState_[ip].requestsCount++;
}
return isOk(ip);
}
void
DOSGuard::clear() noexcept
{
std::scoped_lock const lck(mtx_);
ipState_.clear();
}
[[nodiscard]] std::unordered_set<std::string>
DOSGuard::getWhitelist(util::Config const& config)
{
using T = std::unordered_set<std::string> const;
auto whitelist = config.arrayOr("dos_guard.whitelist", {});
auto const transform = [](auto const& elem) { return elem.template value<std::string>(); };
return T{
boost::transform_iterator(std::begin(whitelist), transform),
boost::transform_iterator(std::end(whitelist), transform)
};
}
} // namespace web::dosguard

View File

@@ -19,11 +19,10 @@
#pragma once #pragma once
#include "util/Assert.hpp"
#include "util/config/Config.hpp" #include "util/config/Config.hpp"
#include "util/log/Logger.hpp" #include "util/log/Logger.hpp"
#include "web/IntervalSweepHandler.hpp" #include "web/dosguard/DOSGuardInterface.hpp"
#include "web/WhitelistHandler.hpp" #include "web/dosguard/WhitelistHandlerInterface.hpp"
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <boost/iterator/transform_iterator.hpp> #include <boost/iterator/transform_iterator.hpp>
@@ -31,48 +30,32 @@
#include <cstdint> #include <cstdint>
#include <functional> #include <functional>
#include <iterator>
#include <mutex> #include <mutex>
#include <string> #include <string>
#include <string_view> #include <string_view>
#include <unordered_map> #include <unordered_map>
#include <unordered_set> #include <unordered_set>
namespace web { namespace web::dosguard {
/**
* @brief The interface of a denial of service guard.
*/
class BaseDOSGuard {
public:
virtual ~BaseDOSGuard() = default;
/**
* @brief Clears implementation-defined counters.
*/
virtual void
clear() noexcept = 0;
};
/** /**
* @brief A simple denial of service guard used for rate limiting. * @brief A simple denial of service guard used for rate limiting.
* *
* @tparam WhitelistHandlerType The type of the whitelist handler * @tparam WhitelistHandlerType The type of the whitelist handler
*/ */
template <typename WhitelistHandlerType> class DOSGuard : public DOSGuardInterface {
class BasicDOSGuard : public BaseDOSGuard {
/** /**
* @brief Accumulated state per IP, state will be reset accordingly * @brief Accumulated state per IP, state will be reset accordingly
*/ */
struct ClientState { struct ClientState {
std::uint32_t transferedByte = 0; /**< Accumulated transfered byte */ std::uint32_t transferedByte = 0; /**< Accumulated transferred byte */
std::uint32_t requestsCount = 0; /**< Accumulated served requests count */ std::uint32_t requestsCount = 0; /**< Accumulated served requests count */
}; };
mutable std::mutex mtx_; mutable std::mutex mtx_;
std::unordered_map<std::string, ClientState> ipState_; std::unordered_map<std::string, ClientState> ipState_;
std::unordered_map<std::string, std::uint32_t> ipConnCount_; std::unordered_map<std::string, std::uint32_t> ipConnCount_;
std::reference_wrapper<WhitelistHandlerType const> whitelistHandler_; std::reference_wrapper<WhitelistHandlerInterface const> whitelistHandler_;
std::uint32_t const maxFetches_; std::uint32_t const maxFetches_;
std::uint32_t const maxConnCount_; std::uint32_t const maxConnCount_;
@@ -90,13 +73,7 @@ public:
* @param config Clio config * @param config Clio config
* @param whitelistHandler Whitelist handler that checks whitelist for IP addresses * @param whitelistHandler Whitelist handler that checks whitelist for IP addresses
*/ */
BasicDOSGuard(util::Config const& config, WhitelistHandlerType const& whitelistHandler) DOSGuard(util::Config const& config, WhitelistHandlerInterface const& whitelistHandler);
: whitelistHandler_{std::cref(whitelistHandler)}
, maxFetches_{config.valueOr("dos_guard.max_fetches", DEFAULT_MAX_FETCHES)}
, maxConnCount_{config.valueOr("dos_guard.max_connections", DEFAULT_MAX_CONNECTIONS)}
, maxRequestCount_{config.valueOr("dos_guard.max_requests", DEFAULT_MAX_REQUESTS)}
{
}
/** /**
* @brief Check whether an ip address is in the whitelist or not. * @brief Check whether an ip address is in the whitelist or not.
@@ -106,10 +83,7 @@ public:
* @return false * @return false
*/ */
[[nodiscard]] bool [[nodiscard]] bool
isWhiteListed(std::string_view const ip) const noexcept isWhiteListed(std::string_view const ip) const noexcept override;
{
return whitelistHandler_.get().isWhiteListed(ip);
}
/** /**
* @brief Check whether an ip address is currently rate limited or not. * @brief Check whether an ip address is currently rate limited or not.
@@ -119,32 +93,7 @@ public:
* @return false If rate limited and the request should not be processed * @return false If rate limited and the request should not be processed
*/ */
[[nodiscard]] bool [[nodiscard]] bool
isOk(std::string const& ip) const noexcept isOk(std::string const& ip) const noexcept override;
{
if (whitelistHandler_.get().isWhiteListed(ip))
return true;
{
std::scoped_lock const lck(mtx_);
if (ipState_.find(ip) != ipState_.end()) {
auto [transferedByte, requests] = ipState_.at(ip);
if (transferedByte > maxFetches_ || requests > maxRequestCount_) {
LOG(log_.warn()) << "Dosguard: Client surpassed the rate limit. ip = " << ip
<< " Transfered Byte: " << transferedByte << "; Requests: " << requests;
return false;
}
}
auto it = ipConnCount_.find(ip);
if (it != ipConnCount_.end()) {
if (it->second > maxConnCount_) {
LOG(log_.warn()) << "Dosguard: Client surpassed the rate limit. ip = " << ip
<< " Concurrent connection: " << it->second;
return false;
}
}
}
return true;
}
/** /**
* @brief Increment connection count for the given ip address. * @brief Increment connection count for the given ip address.
@@ -152,13 +101,7 @@ public:
* @param ip * @param ip
*/ */
void void
increment(std::string const& ip) noexcept increment(std::string const& ip) noexcept override;
{
if (whitelistHandler_.get().isWhiteListed(ip))
return;
std::scoped_lock const lck{mtx_};
ipConnCount_[ip]++;
}
/** /**
* @brief Decrement connection count for the given ip address. * @brief Decrement connection count for the given ip address.
@@ -166,16 +109,7 @@ public:
* @param ip * @param ip
*/ */
void void
decrement(std::string const& ip) noexcept decrement(std::string const& ip) noexcept override;
{
if (whitelistHandler_.get().isWhiteListed(ip))
return;
std::scoped_lock const lck{mtx_};
ASSERT(ipConnCount_[ip] > 0, "Connection count for ip {} can't be 0", ip);
ipConnCount_[ip]--;
if (ipConnCount_[ip] == 0)
ipConnCount_.erase(ip);
}
/** /**
* @brief Adds numObjects of usage for the given ip address. * @brief Adds numObjects of usage for the given ip address.
@@ -190,18 +124,7 @@ public:
* @return false * @return false
*/ */
[[maybe_unused]] bool [[maybe_unused]] bool
add(std::string const& ip, uint32_t numObjects) noexcept add(std::string const& ip, uint32_t numObjects) noexcept override;
{
if (whitelistHandler_.get().isWhiteListed(ip))
return true;
{
std::scoped_lock const lck(mtx_);
ipState_[ip].transferedByte += numObjects;
}
return isOk(ip);
}
/** /**
* @brief Adds one request for the given ip address. * @brief Adds one request for the given ip address.
@@ -215,46 +138,17 @@ public:
* @return false * @return false
*/ */
[[maybe_unused]] bool [[maybe_unused]] bool
request(std::string const& ip) noexcept request(std::string const& ip) noexcept override;
{
if (whitelistHandler_.get().isWhiteListed(ip))
return true;
{
std::scoped_lock const lck(mtx_);
ipState_[ip].requestsCount++;
}
return isOk(ip);
}
/** /**
* @brief Instantly clears all fetch counters added by @see add(std::string const&, uint32_t). * @brief Instantly clears all fetch counters added by @see add(std::string const&, uint32_t).
*/ */
void void
clear() noexcept override clear() noexcept override;
{
std::scoped_lock const lck(mtx_);
ipState_.clear();
}
private: private:
[[nodiscard]] std::unordered_set<std::string> [[nodiscard]] static std::unordered_set<std::string>
getWhitelist(util::Config const& config) const getWhitelist(util::Config const& config);
{
using T = std::unordered_set<std::string> const;
auto whitelist = config.arrayOr("dos_guard.whitelist", {});
auto const transform = [](auto const& elem) { return elem.template value<std::string>(); };
return T{
boost::transform_iterator(std::begin(whitelist), transform),
boost::transform_iterator(std::end(whitelist), transform)
};
}
}; };
/** } // namespace web::dosguard
* @brief A simple denial of service guard used for rate limiting.
*/
using DOSGuard = BasicDOSGuard<web::WhitelistHandler>;
} // namespace web

View File

@@ -0,0 +1,110 @@
//------------------------------------------------------------------------------
/*
This file is part of clio: https://github.com/XRPLF/clio
Copyright (c) 2024, the clio developers.
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#pragma once
#include <cstdint>
#include <string>
#include <string_view>
namespace web::dosguard {
/**
* @brief The interface of a denial of service guard.
*/
class BaseDOSGuard {
public:
virtual ~BaseDOSGuard() = default;
/**
* @brief Clears implementation-defined counters.
*/
virtual void
clear() noexcept = 0;
};
/**
* @brief The interface of a denial of service guard.
*/
class DOSGuardInterface : public BaseDOSGuard {
public:
/**
* @brief Check whether an ip address is in the whitelist or not.
*
* @param ip The ip address to check
* @return true
* @return false
*/
[[nodiscard]] virtual bool
isWhiteListed(std::string_view const ip) const noexcept = 0;
/**
* @brief Check whether an ip address is currently rate limited or not.
*
* @param ip The ip address to check
* @return true If not rate limited
* @return false If rate limited and the request should not be processed
*/
[[nodiscard]] virtual bool
isOk(std::string const& ip) const noexcept = 0;
/**
* @brief Increment connection count for the given ip address.
*
* @param ip
*/
virtual void
increment(std::string const& ip) noexcept = 0;
/**
* @brief Decrement connection count for the given ip address.
*
* @param ip
*/
virtual void
decrement(std::string const& ip) noexcept = 0;
/**
* @brief Adds numObjects of usage for the given ip address.
*
* If the total sums up to a value equal or larger than maxFetches_
* the operation is no longer allowed and false is returned; true is
* returned otherwise.
*
* @param ip
* @param numObjects
* @return true
* @return false
*/
[[maybe_unused]] virtual bool
add(std::string const& ip, uint32_t numObjects) noexcept = 0;
/**
* @brief Adds one request for the given ip address.
*
*
* @param ip
* @return If the total sums up to a value equal or larger than maxRequestCount_
* the operation is no longer allowed and false is returned; true is
* returned otherwise.
*/
[[maybe_unused]] virtual bool
request(std::string const& ip) noexcept = 0;
};
} // namespace web::dosguard

View File

@@ -17,10 +17,10 @@
*/ */
//============================================================================== //==============================================================================
#include "web/IntervalSweepHandler.hpp" #include "web/dosguard/IntervalSweepHandler.hpp"
#include "util/config/Config.hpp" #include "util/config/Config.hpp"
#include "web/DOSGuard.hpp" #include "web/dosguard/DOSGuardInterface.hpp"
#include <boost/asio/io_context.hpp> #include <boost/asio/io_context.hpp>
#include <boost/system/detail/error_code.hpp> #include <boost/system/detail/error_code.hpp>
@@ -29,12 +29,12 @@
#include <chrono> #include <chrono>
#include <functional> #include <functional>
namespace web { namespace web::dosguard {
IntervalSweepHandler::IntervalSweepHandler( IntervalSweepHandler::IntervalSweepHandler(
util::Config const& config, util::Config const& config,
boost::asio::io_context& ctx, boost::asio::io_context& ctx,
web::BaseDOSGuard& dosGuard BaseDOSGuard& dosGuard
) )
: repeat_{std::ref(ctx)} : repeat_{std::ref(ctx)}
{ {
@@ -44,4 +44,4 @@ IntervalSweepHandler::IntervalSweepHandler(
repeat_.start(sweepInterval, [&dosGuard] { dosGuard.clear(); }); repeat_.start(sweepInterval, [&dosGuard] { dosGuard.clear(); });
} }
} // namespace web } // namespace web::dosguard

View File

@@ -24,7 +24,7 @@
#include <boost/asio/io_context.hpp> #include <boost/asio/io_context.hpp>
namespace web { namespace web::dosguard {
class BaseDOSGuard; class BaseDOSGuard;
@@ -42,7 +42,11 @@ public:
* @param ctx The boost::asio::io_context to use * @param ctx The boost::asio::io_context to use
* @param dosGuard The DOS guard to use * @param dosGuard The DOS guard to use
*/ */
IntervalSweepHandler(util::Config const& config, boost::asio::io_context& ctx, web::BaseDOSGuard& dosGuard); IntervalSweepHandler(
util::Config const& config,
boost::asio::io_context& ctx,
web::dosguard::BaseDOSGuard& dosGuard
);
}; };
} // namespace web } // namespace web::dosguard

View File

@@ -0,0 +1,118 @@
//------------------------------------------------------------------------------
/*
This file is part of clio: https://github.com/XRPLF/clio
Copyright (c) 2024, the clio developers.
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include "web/dosguard/WhitelistHandler.hpp"
#include <boost/asio.hpp>
#include <boost/asio/ip/address.hpp>
#include <boost/asio/ip/network_v4.hpp>
#include <boost/asio/ip/network_v6.hpp>
#include <boost/iterator/transform_iterator.hpp>
#include <fmt/core.h>
#include <algorithm>
#include <functional>
#include <regex>
#include <stdexcept>
#include <string>
#include <string_view>
#include <unordered_map>
#include <unordered_set>
#include <vector>
namespace web::dosguard {
void
Whitelist::add(std::string_view net)
{
using namespace boost::asio;
if (not isMask(net)) {
ips_.push_back(ip::make_address(net));
return;
}
if (isV4(net)) {
subnetsV4_.push_back(ip::make_network_v4(net));
} else if (isV6(net)) {
subnetsV6_.push_back(ip::make_network_v6(net));
} else {
throw std::runtime_error(fmt::format("malformed network: {}", net.data()));
}
}
bool
Whitelist::isWhiteListed(std::string_view ip) const
{
using namespace boost::asio;
auto const addr = ip::make_address(ip);
if (std::find(std::begin(ips_), std::end(ips_), addr) != std::end(ips_))
return true;
if (addr.is_v4()) {
return std::find_if(
std::begin(subnetsV4_), std::end(subnetsV4_), std::bind_front(&isInV4Subnet, std::cref(addr))
) != std::end(subnetsV4_);
}
if (addr.is_v6()) {
return std::find_if(
std::begin(subnetsV6_), std::end(subnetsV6_), std::bind_front(&isInV6Subnet, std::cref(addr))
) != std::end(subnetsV6_);
}
return false;
}
bool
Whitelist::isInV4Subnet(boost::asio::ip::address const& addr, boost::asio::ip::network_v4 const& subnet)
{
auto const range = subnet.hosts();
return range.find(addr.to_v4()) != range.end();
}
bool
Whitelist::isInV6Subnet(boost::asio::ip::address const& addr, boost::asio::ip::network_v6 const& subnet)
{
auto const range = subnet.hosts();
return range.find(addr.to_v6()) != range.end();
}
bool
Whitelist::isV4(std::string_view net)
{
static std::regex const ipv4CidrRegex(R"(^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/\d{1,2}$)");
return std::regex_match(std::string(net), ipv4CidrRegex);
}
bool
Whitelist::isV6(std::string_view net)
{
static std::regex const ipv6CidrRegex(R"(^([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4}/\d{1,3}$)");
return std::regex_match(std::string(net), ipv6CidrRegex);
}
bool
Whitelist::isMask(std::string_view net)
{
return net.find('/') != std::string_view::npos;
}
} // namespace web::dosguard

View File

@@ -21,6 +21,7 @@
#include "util/config/Config.hpp" #include "util/config/Config.hpp"
#include "web/Resolver.hpp" #include "web/Resolver.hpp"
#include "web/dosguard/WhitelistHandlerInterface.hpp"
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <boost/asio/ip/address.hpp> #include <boost/asio/ip/address.hpp>
@@ -30,16 +31,14 @@
#include <fmt/core.h> #include <fmt/core.h>
#include <algorithm> #include <algorithm>
#include <functional>
#include <regex> #include <regex>
#include <stdexcept>
#include <string> #include <string>
#include <string_view> #include <string_view>
#include <unordered_map> #include <unordered_map>
#include <unordered_set> #include <unordered_set>
#include <vector> #include <vector>
namespace web { namespace web::dosguard {
/** /**
* @brief A whitelist to remove rate limits of certain IP addresses. * @brief A whitelist to remove rate limits of certain IP addresses.
@@ -57,23 +56,7 @@ public:
* @throws std::runtime::error when the network address is not valid * @throws std::runtime::error when the network address is not valid
*/ */
void void
add(std::string_view net) add(std::string_view net);
{
using namespace boost::asio;
if (not isMask(net)) {
ips_.push_back(ip::make_address(net));
return;
}
if (isV4(net)) {
subnetsV4_.push_back(ip::make_network_v4(net));
} else if (isV6(net)) {
subnetsV6_.push_back(ip::make_network_v6(net));
} else {
throw std::runtime_error(fmt::format("malformed network: {}", net.data()));
}
}
/** /**
* @brief Checks to see if ip address is whitelisted. * @brief Checks to see if ip address is whitelisted.
@@ -83,69 +66,29 @@ public:
* @return true if the given IP is whitelisted; false otherwise * @return true if the given IP is whitelisted; false otherwise
*/ */
bool bool
isWhiteListed(std::string_view ip) const isWhiteListed(std::string_view ip) const;
{
using namespace boost::asio;
auto const addr = ip::make_address(ip);
if (std::find(std::begin(ips_), std::end(ips_), addr) != std::end(ips_))
return true;
if (addr.is_v4()) {
return std::find_if(
std::begin(subnetsV4_), std::end(subnetsV4_), std::bind_front(&isInV4Subnet, std::cref(addr))
) != std::end(subnetsV4_);
}
if (addr.is_v6()) {
return std::find_if(
std::begin(subnetsV6_), std::end(subnetsV6_), std::bind_front(&isInV6Subnet, std::cref(addr))
) != std::end(subnetsV6_);
}
return false;
}
private: private:
static bool static bool
isInV4Subnet(boost::asio::ip::address const& addr, boost::asio::ip::network_v4 const& subnet) isInV4Subnet(boost::asio::ip::address const& addr, boost::asio::ip::network_v4 const& subnet);
{
auto const range = subnet.hosts();
return range.find(addr.to_v4()) != range.end();
}
static bool static bool
isInV6Subnet(boost::asio::ip::address const& addr, boost::asio::ip::network_v6 const& subnet) isInV6Subnet(boost::asio::ip::address const& addr, boost::asio::ip::network_v6 const& subnet);
{
auto const range = subnet.hosts();
return range.find(addr.to_v6()) != range.end();
}
static bool static bool
isV4(std::string_view net) isV4(std::string_view net);
{
static std::regex const ipv4CidrRegex(R"(^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/\d{1,2}$)");
return std::regex_match(std::string(net), ipv4CidrRegex);
}
static bool static bool
isV6(std::string_view net) isV6(std::string_view net);
{
static std::regex const ipv6CidrRegex(R"(^([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4}/\d{1,3}$)");
return std::regex_match(std::string(net), ipv6CidrRegex);
}
static bool static bool
isMask(std::string_view net) isMask(std::string_view net);
{
return net.find('/') != std::string_view::npos;
}
}; };
/** /**
* @brief A simple handler to add/check elements in a whitelist. * @brief A simple handler to add/check elements in a whitelist.
*/ */
class WhitelistHandler { class WhitelistHandler : public WhitelistHandlerInterface {
Whitelist whitelist_; Whitelist whitelist_;
public: public:
@@ -170,7 +113,7 @@ public:
* @return true if the given IP is whitelisted; false otherwise * @return true if the given IP is whitelisted; false otherwise
*/ */
bool bool
isWhiteListed(std::string_view ip) const isWhiteListed(std::string_view ip) const override
{ {
return whitelist_.isWhiteListed(ip); return whitelist_.isWhiteListed(ip);
} }
@@ -200,4 +143,4 @@ private:
} }
}; };
} // namespace web } // namespace web::dosguard

View File

@@ -0,0 +1,44 @@
//------------------------------------------------------------------------------
/*
This file is part of clio: https://github.com/XRPLF/clio
Copyright (c) 2024, the clio developers.
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#pragma once
#include <string_view>
namespace web::dosguard {
/**
* @brief Interface for a whitelist handler
*/
class WhitelistHandlerInterface {
public:
/** @brief Virtual destructor */
virtual ~WhitelistHandlerInterface() = default;
/**
* @brief Checks to see if the given IP is whitelisted
*
* @param ip The IP to check
* @return true if the given IP is whitelisted; false otherwise
*/
[[nodiscard]] virtual bool
isWhiteListed(std::string_view ip) const = 0;
};
} // namespace web::dosguard

View File

@@ -24,7 +24,7 @@
#include "util/build/Build.hpp" #include "util/build/Build.hpp"
#include "util/log/Logger.hpp" #include "util/log/Logger.hpp"
#include "util/prometheus/Http.hpp" #include "util/prometheus/Http.hpp"
#include "web/DOSGuard.hpp" #include "web/dosguard/DOSGuardInterface.hpp"
#include "web/impl/AdminVerificationStrategy.hpp" #include "web/impl/AdminVerificationStrategy.hpp"
#include "web/interface/Concepts.hpp" #include "web/interface/Concepts.hpp"
#include "web/interface/ConnectionBase.hpp" #include "web/interface/ConnectionBase.hpp"
@@ -114,7 +114,7 @@ class HttpBase : public ConnectionBase {
protected: protected:
boost::beast::flat_buffer buffer_; boost::beast::flat_buffer buffer_;
http::request<http::string_body> req_; http::request<http::string_body> req_;
std::reference_wrapper<web::DOSGuard> dosGuard_; std::reference_wrapper<dosguard::DOSGuardInterface> dosGuard_;
std::shared_ptr<HandlerType> const handler_; std::shared_ptr<HandlerType> const handler_;
util::Logger log_{"WebServer"}; util::Logger log_{"WebServer"};
util::Logger perfLog_{"Performance"}; util::Logger perfLog_{"Performance"};
@@ -154,7 +154,7 @@ public:
std::string const& ip, std::string const& ip,
std::reference_wrapper<util::TagDecoratorFactory const> tagFactory, std::reference_wrapper<util::TagDecoratorFactory const> tagFactory,
std::shared_ptr<AdminVerificationStrategy> adminVerification, std::shared_ptr<AdminVerificationStrategy> adminVerification,
std::reference_wrapper<web::DOSGuard> dosGuard, std::reference_wrapper<dosguard::DOSGuardInterface> dosGuard,
std::shared_ptr<HandlerType> handler, std::shared_ptr<HandlerType> handler,
boost::beast::flat_buffer buffer boost::beast::flat_buffer buffer
) )

View File

@@ -23,7 +23,7 @@
#include "rpc/common/Types.hpp" #include "rpc/common/Types.hpp"
#include "util/Taggable.hpp" #include "util/Taggable.hpp"
#include "util/log/Logger.hpp" #include "util/log/Logger.hpp"
#include "web/DOSGuard.hpp" #include "web/dosguard/DOSGuardInterface.hpp"
#include "web/interface/Concepts.hpp" #include "web/interface/Concepts.hpp"
#include "web/interface/ConnectionBase.hpp" #include "web/interface/ConnectionBase.hpp"
@@ -72,7 +72,7 @@ class WsBase : public ConnectionBase, public std::enable_shared_from_this<WsBase
using std::enable_shared_from_this<WsBase<Derived, HandlerType>>::shared_from_this; using std::enable_shared_from_this<WsBase<Derived, HandlerType>>::shared_from_this;
boost::beast::flat_buffer buffer_; boost::beast::flat_buffer buffer_;
std::reference_wrapper<web::DOSGuard> dosGuard_; std::reference_wrapper<dosguard::DOSGuardInterface> dosGuard_;
bool sending_ = false; bool sending_ = false;
std::queue<std::shared_ptr<std::string>> messages_; std::queue<std::shared_ptr<std::string>> messages_;
std::shared_ptr<HandlerType> const handler_; std::shared_ptr<HandlerType> const handler_;
@@ -99,7 +99,7 @@ public:
explicit WsBase( explicit WsBase(
std::string ip, std::string ip,
std::reference_wrapper<util::TagDecoratorFactory const> tagFactory, std::reference_wrapper<util::TagDecoratorFactory const> tagFactory,
std::reference_wrapper<web::DOSGuard> dosGuard, std::reference_wrapper<dosguard::DOSGuardInterface> dosGuard,
std::shared_ptr<HandlerType> const& handler, std::shared_ptr<HandlerType> const& handler,
boost::beast::flat_buffer&& buffer boost::beast::flat_buffer&& buffer
) )

0
src/web/ng/Server.cpp Normal file
View File

0
src/web/ng/Server.hpp Normal file
View File

View File

@@ -23,7 +23,6 @@
#include "rpc/common/Specs.hpp" #include "rpc/common/Specs.hpp"
#include "rpc/common/Types.hpp" #include "rpc/common/Types.hpp"
#include "rpc/common/Validators.hpp" #include "rpc/common/Validators.hpp"
#include "web/DOSGuard.hpp"
#include <boost/json/conversion.hpp> #include <boost/json/conversion.hpp>
#include <boost/json/value.hpp> #include <boost/json/value.hpp>

View File

@@ -12,7 +12,6 @@ target_sources(
data/cassandra/ExecutionStrategyTests.cpp data/cassandra/ExecutionStrategyTests.cpp
data/cassandra/RetryPolicyTests.cpp data/cassandra/RetryPolicyTests.cpp
data/cassandra/SettingsProviderTests.cpp data/cassandra/SettingsProviderTests.cpp
DOSGuardTests.cpp
# ETL # ETL
etl/AmendmentBlockHandlerTests.cpp etl/AmendmentBlockHandlerTests.cpp
etl/CacheLoaderSettingsTests.cpp etl/CacheLoaderSettingsTests.cpp
@@ -127,11 +126,12 @@ target_sources(
util/TxUtilTests.cpp util/TxUtilTests.cpp
# Webserver # Webserver
web/AdminVerificationTests.cpp web/AdminVerificationTests.cpp
web/dosguard/DOSGuardTests.cpp
web/dosguard/IntervalSweepHandlerTests.cpp
web/dosguard/WhitelistHandlerTests.cpp
web/impl/ServerSslContextTests.cpp web/impl/ServerSslContextTests.cpp
web/RPCServerHandlerTests.cpp web/RPCServerHandlerTests.cpp
web/ServerTests.cpp web/ServerTests.cpp
web/IntervalSweepHandlerTests.cpp
web/WhitelistHandlerTests.cpp
# New Config # New Config
util/newconfig/ArrayViewTests.cpp util/newconfig/ArrayViewTests.cpp
util/newconfig/ObjectViewTests.cpp util/newconfig/ObjectViewTests.cpp

View File

@@ -24,10 +24,11 @@
#include "util/config/Config.hpp" #include "util/config/Config.hpp"
#include "util/prometheus/Label.hpp" #include "util/prometheus/Label.hpp"
#include "util/prometheus/Prometheus.hpp" #include "util/prometheus/Prometheus.hpp"
#include "web/DOSGuard.hpp"
#include "web/IntervalSweepHandler.hpp"
#include "web/Server.hpp" #include "web/Server.hpp"
#include "web/WhitelistHandler.hpp" #include "web/dosguard/DOSGuard.hpp"
#include "web/dosguard/DOSGuardInterface.hpp"
#include "web/dosguard/IntervalSweepHandler.hpp"
#include "web/dosguard/WhitelistHandler.hpp"
#include "web/impl/AdminVerificationStrategy.hpp" #include "web/impl/AdminVerificationStrategy.hpp"
#include "web/interface/ConnectionBase.hpp" #include "web/interface/ConnectionBase.hpp"
@@ -127,14 +128,14 @@ struct WebServerTest : NoLoggerFixture {
boost::asio::io_context ctxSync; boost::asio::io_context ctxSync;
std::string const port = std::to_string(tests::util::generateFreePort()); std::string const port = std::to_string(tests::util::generateFreePort());
Config cfg{generateJSONWithDynamicPort(port)}; Config cfg{generateJSONWithDynamicPort(port)};
WhitelistHandler whitelistHandler{cfg}; dosguard::WhitelistHandler whitelistHandler{cfg};
DOSGuard dosGuard{cfg, whitelistHandler}; dosguard::DOSGuard dosGuard{cfg, whitelistHandler};
IntervalSweepHandler sweepHandler{cfg, ctxSync, dosGuard}; dosguard::IntervalSweepHandler sweepHandler{cfg, ctxSync, dosGuard};
Config cfgOverload{generateJSONDataOverload(port)}; Config cfgOverload{generateJSONDataOverload(port)};
WhitelistHandler whitelistHandlerOverload{cfgOverload}; dosguard::WhitelistHandler whitelistHandlerOverload{cfgOverload};
DOSGuard dosGuardOverload{cfgOverload, whitelistHandlerOverload}; dosguard::DOSGuard dosGuardOverload{cfgOverload, whitelistHandlerOverload};
IntervalSweepHandler sweepHandlerOverload{cfgOverload, ctxSync, dosGuardOverload}; dosguard::IntervalSweepHandler sweepHandlerOverload{cfgOverload, ctxSync, dosGuardOverload};
// this ctx is for http server // this ctx is for http server
boost::asio::io_context ctx; boost::asio::io_context ctx;
@@ -178,7 +179,7 @@ std::shared_ptr<web::HttpServer<Executor>>
makeServerSync( makeServerSync(
util::Config const& config, util::Config const& config,
boost::asio::io_context& ioc, boost::asio::io_context& ioc,
web::DOSGuard& dosGuard, web::dosguard::DOSGuardInterface& dosGuard,
std::shared_ptr<Executor> const& handler std::shared_ptr<Executor> const& handler
) )
{ {

View File

@@ -19,7 +19,8 @@
#include "util/LoggerFixtures.hpp" #include "util/LoggerFixtures.hpp"
#include "util/config/Config.hpp" #include "util/config/Config.hpp"
#include "web/DOSGuard.hpp" #include "web/dosguard/DOSGuard.hpp"
#include "web/dosguard/WhitelistHandlerInterface.hpp"
#include <boost/json/parse.hpp> #include <boost/json/parse.hpp>
#include <gmock/gmock.h> #include <gmock/gmock.h>
@@ -30,11 +31,11 @@
using namespace testing; using namespace testing;
using namespace util; using namespace util;
using namespace std; using namespace std;
using namespace web; using namespace web::dosguard;
namespace json = boost::json; namespace json = boost::json;
namespace { struct DOSGuardTest : NoLoggerFixture {
constexpr auto JSONData = R"JSON( static constexpr auto JSONData = R"JSON(
{ {
"dos_guard": { "dos_guard": {
"max_fetches": 100, "max_fetches": 100,
@@ -47,20 +48,15 @@ constexpr auto JSONData = R"JSON(
} }
)JSON"; )JSON";
constexpr auto IP = "127.0.0.2"; static constexpr auto IP = "127.0.0.2";
struct MockWhitelistHandler { struct MockWhitelistHandler : WhitelistHandlerInterface {
MOCK_METHOD(bool, isWhiteListed, (std::string_view ip), (const)); MOCK_METHOD(bool, isWhiteListed, (std::string_view ip), (const));
}; };
using MockWhitelistHandlerType = NiceMock<MockWhitelistHandler>;
}; // namespace
class DOSGuardTest : public NoLoggerFixture {
protected:
Config cfg{json::parse(JSONData)}; Config cfg{json::parse(JSONData)};
MockWhitelistHandlerType whitelistHandler; NiceMock<MockWhitelistHandler> whitelistHandler;
BasicDOSGuard<MockWhitelistHandlerType> guard{cfg, whitelistHandler}; DOSGuard guard{cfg, whitelistHandler};
}; };
TEST_F(DOSGuardTest, Whitelisting) TEST_F(DOSGuardTest, Whitelisting)

View File

@@ -19,8 +19,8 @@
#include "util/AsioContextTestFixture.hpp" #include "util/AsioContextTestFixture.hpp"
#include "util/config/Config.hpp" #include "util/config/Config.hpp"
#include "web/DOSGuard.hpp" #include "web/dosguard/DOSGuardInterface.hpp"
#include "web/IntervalSweepHandler.hpp" #include "web/dosguard/IntervalSweepHandler.hpp"
#include <boost/json/parse.hpp> #include <boost/json/parse.hpp>
#include <gmock/gmock.h> #include <gmock/gmock.h>
@@ -28,7 +28,7 @@
#include <chrono> #include <chrono>
using namespace web; using namespace web::dosguard;
struct IntervalSweepHandlerTest : SyncAsioContextTest { struct IntervalSweepHandlerTest : SyncAsioContextTest {
protected: protected:

View File

@@ -18,7 +18,7 @@
//============================================================================== //==============================================================================
#include "util/LoggerFixtures.hpp" #include "util/LoggerFixtures.hpp"
#include "util/config/Config.hpp" #include "util/config/Config.hpp"
#include "web/WhitelistHandler.hpp" #include "web/dosguard/WhitelistHandler.hpp"
#include <boost/json/parse.hpp> #include <boost/json/parse.hpp>
#include <gmock/gmock.h> #include <gmock/gmock.h>
@@ -29,7 +29,7 @@
#include <vector> #include <vector>
using namespace util; using namespace util;
using namespace web; using namespace web::dosguard;
struct WhitelistHandlerTest : NoLoggerFixture {}; struct WhitelistHandlerTest : NoLoggerFixture {};