mirror of
https://github.com/XRPLF/clio.git
synced 2025-11-04 11:55:51 +00:00
@@ -201,7 +201,9 @@ if(tests)
|
||||
unittests/backend/cassandra/AsyncExecutorTests.cpp
|
||||
# Webserver
|
||||
unittests/webserver/ServerTest.cpp
|
||||
unittests/webserver/RPCServerHandlerTest.cpp)
|
||||
unittests/webserver/RPCServerHandlerTest.cpp
|
||||
unittests/webserver/WhitelistHandlerTest.cpp
|
||||
unittests/webserver/SweepHandlerTest.cpp)
|
||||
|
||||
include(CMake/deps/gtest.cmake)
|
||||
|
||||
|
||||
@@ -179,7 +179,8 @@ try
|
||||
|
||||
// Rate limiter, to prevent abuse
|
||||
auto sweepHandler = IntervalSweepHandler{config, ioc};
|
||||
auto dosGuard = DOSGuard{config, sweepHandler};
|
||||
auto whitelistHandler = WhitelistHandler{config};
|
||||
auto dosGuard = DOSGuard{config, whitelistHandler, sweepHandler};
|
||||
|
||||
// Interface to the database
|
||||
auto backend = Backend::make_Backend(ioc, config);
|
||||
|
||||
@@ -19,15 +19,16 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <config/Config.h>
|
||||
#include <webserver/impl/WhitelistHandler.h>
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/iterator/transform_iterator.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
#include <config/Config.h>
|
||||
#include <ctime>
|
||||
|
||||
namespace clio {
|
||||
|
||||
@@ -43,9 +44,10 @@ public:
|
||||
/**
|
||||
* @brief A simple denial of service guard used for rate limiting.
|
||||
*
|
||||
* @tparam SweepHandler Type of the sweep handler
|
||||
* @tparam Type of the Whitelist Handler
|
||||
* @tparam Type of the Sweep Handler
|
||||
*/
|
||||
template <typename SweepHandler>
|
||||
template <typename WhitelistHandlerType, typename SweepHandlerType>
|
||||
class BasicDOSGuard : public BaseDOSGuard
|
||||
{
|
||||
// Accumulated state per IP, state will be reset accordingly
|
||||
@@ -61,7 +63,7 @@ class BasicDOSGuard : public BaseDOSGuard
|
||||
// accumulated states map
|
||||
std::unordered_map<std::string, ClientState> ipState_;
|
||||
std::unordered_map<std::string, std::uint32_t> ipConnCount_;
|
||||
std::unordered_set<std::string> const whitelist_;
|
||||
std::reference_wrapper<WhitelistHandlerType const> whitelistHandler_;
|
||||
|
||||
std::uint32_t const maxFetches_;
|
||||
std::uint32_t const maxConnCount_;
|
||||
@@ -73,10 +75,14 @@ public:
|
||||
* @brief Constructs a new DOS guard.
|
||||
*
|
||||
* @param config Clio config
|
||||
* @param sweepHandler Sweep handler that implements the sweeping behaviour
|
||||
* @param WhitelistHandlerType Whitelist handler that checks whitelist for ip addresses
|
||||
* @param SweepHandlerType Sweep handler that implements the sweeping behaviour
|
||||
*/
|
||||
BasicDOSGuard(clio::Config const& config, SweepHandler& sweepHandler)
|
||||
: whitelist_{getWhitelist(config)}
|
||||
BasicDOSGuard(
|
||||
clio::Config const& config,
|
||||
WhitelistHandlerType const& whitelistHandler,
|
||||
SweepHandlerType& sweepHandler)
|
||||
: whitelistHandler_{std::cref(whitelistHandler)}
|
||||
, maxFetches_{config.valueOr("dos_guard.max_fetches", 1000000u)}
|
||||
, maxConnCount_{config.valueOr("dos_guard.max_connections", 20u)}
|
||||
, maxRequestCount_{config.valueOr("dos_guard.max_requests", 20u)}
|
||||
@@ -92,9 +98,9 @@ public:
|
||||
* @return false
|
||||
*/
|
||||
[[nodiscard]] bool
|
||||
isWhiteListed(std::string const& ip) const noexcept
|
||||
isWhiteListed(std::string_view const ip) const noexcept
|
||||
{
|
||||
return whitelist_.contains(ip);
|
||||
return whitelistHandler_.get().isWhiteListed(ip);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -107,7 +113,7 @@ public:
|
||||
[[nodiscard]] bool
|
||||
isOk(std::string const& ip) const noexcept
|
||||
{
|
||||
if (whitelist_.contains(ip))
|
||||
if (whitelistHandler_.get().isWhiteListed(ip))
|
||||
return true;
|
||||
|
||||
{
|
||||
@@ -144,7 +150,7 @@ public:
|
||||
void
|
||||
increment(std::string const& ip) noexcept
|
||||
{
|
||||
if (whitelist_.contains(ip))
|
||||
if (whitelistHandler_.get().isWhiteListed(ip))
|
||||
return;
|
||||
std::scoped_lock lck{mtx_};
|
||||
ipConnCount_[ip]++;
|
||||
@@ -158,7 +164,7 @@ public:
|
||||
void
|
||||
decrement(std::string const& ip) noexcept
|
||||
{
|
||||
if (whitelist_.contains(ip))
|
||||
if (whitelistHandler_.get().isWhiteListed(ip))
|
||||
return;
|
||||
std::scoped_lock lck{mtx_};
|
||||
assert(ipConnCount_[ip] > 0);
|
||||
@@ -182,7 +188,7 @@ public:
|
||||
[[maybe_unused]] bool
|
||||
add(std::string const& ip, uint32_t numObjects) noexcept
|
||||
{
|
||||
if (whitelist_.contains(ip))
|
||||
if (whitelistHandler_.get().isWhiteListed(ip))
|
||||
return true;
|
||||
|
||||
{
|
||||
@@ -207,7 +213,7 @@ public:
|
||||
[[maybe_unused]] bool
|
||||
request(std::string const& ip) noexcept
|
||||
{
|
||||
if (whitelist_.contains(ip))
|
||||
if (whitelistHandler_.get().isWhiteListed(ip))
|
||||
return true;
|
||||
|
||||
{
|
||||
@@ -303,6 +309,6 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
using DOSGuard = BasicDOSGuard<IntervalSweepHandler>;
|
||||
using DOSGuard = BasicDOSGuard<WhitelistHandler, IntervalSweepHandler>;
|
||||
|
||||
} // namespace clio
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <webserver/PlainWsSession.h>
|
||||
#include <webserver/details/HttpBase.h>
|
||||
#include <webserver/impl/HttpBase.h>
|
||||
|
||||
namespace Server {
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <webserver/details/WsBase.h>
|
||||
#include <webserver/impl/WsBase.h>
|
||||
|
||||
namespace Server {
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#include <rpc/common/impl/APIVersionParser.h>
|
||||
#include <util/JsonUtils.h>
|
||||
#include <util/Profiler.h>
|
||||
#include <webserver/details/ErrorHandling.h>
|
||||
#include <webserver/impl/ErrorHandling.h>
|
||||
|
||||
#include <boost/json/parse.hpp>
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <webserver/SslWsSession.h>
|
||||
#include <webserver/details/HttpBase.h>
|
||||
#include <webserver/impl/HttpBase.h>
|
||||
|
||||
namespace Server {
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <webserver/details/WsBase.h>
|
||||
#include <webserver/impl/WsBase.h>
|
||||
|
||||
namespace Server {
|
||||
|
||||
|
||||
167
src/webserver/impl/WhitelistHandler.h
Normal file
167
src/webserver/impl/WhitelistHandler.h
Normal file
@@ -0,0 +1,167 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of clio: https://github.com/XRPLF/clio
|
||||
Copyright (c) 2023, 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 <boost/asio.hpp>
|
||||
#include <fmt/core.h>
|
||||
|
||||
#include <regex>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace clio {
|
||||
|
||||
/**
|
||||
* @brief A whitelist to remove rate limits of certain IP addresses
|
||||
*
|
||||
*/
|
||||
class Whitelist
|
||||
{
|
||||
std::vector<boost::asio::ip::network_v4> subnetsV4_;
|
||||
std::vector<boost::asio::ip::network_v6> subnetsV6_;
|
||||
std::vector<boost::asio::ip::address> ips_;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Add network address to whitelist
|
||||
*
|
||||
* @param net Network part of the ip address
|
||||
* @throws std::runtime::error when the network address is not valid
|
||||
*/
|
||||
void
|
||||
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
|
||||
*
|
||||
* @param ip IP address
|
||||
* @throws std::runtime::error when the network address is not valid
|
||||
*/
|
||||
bool
|
||||
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:
|
||||
static bool
|
||||
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
|
||||
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
|
||||
isV4(std::string_view net) const
|
||||
{
|
||||
static const std::regex 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
|
||||
isV6(std::string_view net) const
|
||||
{
|
||||
static const std::regex 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
|
||||
isMask(std::string_view net) const
|
||||
{
|
||||
return net.find('/') != std::string_view::npos;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A simple handler to add/check elements in a whitelist
|
||||
*
|
||||
* @param arr map of net addresses to add to whitelist
|
||||
*/
|
||||
class WhitelistHandler
|
||||
{
|
||||
Whitelist whitelist_;
|
||||
|
||||
public:
|
||||
WhitelistHandler(clio::Config const& config)
|
||||
{
|
||||
std::unordered_set<std::string> arr = getWhitelist(config);
|
||||
for (auto const& net : arr)
|
||||
whitelist_.add(net);
|
||||
}
|
||||
|
||||
bool
|
||||
isWhiteListed(std::string_view ip) const
|
||||
{
|
||||
return whitelist_.isWhiteListed(ip);
|
||||
}
|
||||
|
||||
private:
|
||||
[[nodiscard]] std::unordered_set<std::string> const
|
||||
getWhitelist(clio::Config const& config) const
|
||||
{
|
||||
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 clio
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
#include <boost/json/parse.hpp>
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using namespace testing;
|
||||
using namespace clio;
|
||||
@@ -38,28 +39,26 @@ constexpr static auto JSONData = R"JSON(
|
||||
"sweep_interval": 1,
|
||||
"max_connections": 2,
|
||||
"max_requests": 3,
|
||||
"whitelist": ["127.0.0.1"]
|
||||
}
|
||||
}
|
||||
)JSON";
|
||||
|
||||
constexpr static auto JSONData2 = R"JSON(
|
||||
{
|
||||
"dos_guard": {
|
||||
"max_fetches": 100,
|
||||
"sweep_interval": 0.1,
|
||||
"max_connections": 2,
|
||||
"whitelist": ["127.0.0.1"]
|
||||
"whitelist": [
|
||||
"127.0.0.1"
|
||||
]
|
||||
}
|
||||
}
|
||||
)JSON";
|
||||
|
||||
constexpr static auto IP = "127.0.0.2";
|
||||
|
||||
struct MockWhitelistHandler
|
||||
{
|
||||
MOCK_METHOD(bool, isWhiteListed, (std::string_view ip), (const));
|
||||
};
|
||||
|
||||
using MockWhitelistHandlerType = NiceMock<MockWhitelistHandler>;
|
||||
|
||||
class FakeSweepHandler
|
||||
{
|
||||
private:
|
||||
using guard_type = BasicDOSGuard<FakeSweepHandler>;
|
||||
using guard_type = BasicDOSGuard<MockWhitelistHandlerType, FakeSweepHandler>;
|
||||
guard_type* dosGuard_;
|
||||
|
||||
public:
|
||||
@@ -82,13 +81,16 @@ class DOSGuardTest : public NoLoggerFixture
|
||||
protected:
|
||||
Config cfg{json::parse(JSONData)};
|
||||
FakeSweepHandler sweepHandler;
|
||||
BasicDOSGuard<FakeSweepHandler> guard{cfg, sweepHandler};
|
||||
MockWhitelistHandlerType whitelistHandler;
|
||||
BasicDOSGuard<MockWhitelistHandlerType, FakeSweepHandler> guard{cfg, whitelistHandler, sweepHandler};
|
||||
};
|
||||
|
||||
TEST_F(DOSGuardTest, Whitelisting)
|
||||
{
|
||||
EXPECT_CALL(whitelistHandler, isWhiteListed("127.0.0.1")).Times(1).WillOnce(Return(false));
|
||||
EXPECT_FALSE(guard.isWhiteListed("127.0.0.1"));
|
||||
EXPECT_CALL(whitelistHandler, isWhiteListed("127.0.0.1")).Times(1).WillOnce(Return(true));
|
||||
EXPECT_TRUE(guard.isWhiteListed("127.0.0.1"));
|
||||
EXPECT_FALSE(guard.isWhiteListed(IP));
|
||||
}
|
||||
|
||||
TEST_F(DOSGuardTest, ConnectionCount)
|
||||
@@ -150,28 +152,3 @@ TEST_F(DOSGuardTest, RequestLimitOnTimer)
|
||||
sweepHandler.sweep();
|
||||
EXPECT_TRUE(guard.isOk(IP)); // can request again
|
||||
}
|
||||
|
||||
template <typename SweepHandler>
|
||||
struct BasicDOSGuardMock : public BaseDOSGuard
|
||||
{
|
||||
BasicDOSGuardMock(SweepHandler& handler)
|
||||
{
|
||||
handler.setup(this);
|
||||
}
|
||||
|
||||
MOCK_METHOD(void, clear, (), (noexcept, override));
|
||||
};
|
||||
|
||||
class DOSGuardIntervalSweepHandlerTest : public SyncAsioContextTest
|
||||
{
|
||||
protected:
|
||||
Config cfg{json::parse(JSONData2)};
|
||||
IntervalSweepHandler sweepHandler{cfg, ctx};
|
||||
BasicDOSGuardMock<IntervalSweepHandler> guard{sweepHandler};
|
||||
};
|
||||
|
||||
TEST_F(DOSGuardIntervalSweepHandlerTest, SweepAfterInterval)
|
||||
{
|
||||
EXPECT_CALL(guard, clear()).Times(AtLeast(2));
|
||||
ctx.run_for(std::chrono::milliseconds(400));
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <rpc/Factories.h>
|
||||
#include <rpc/common/Specs.h>
|
||||
#include <rpc/common/Validators.h>
|
||||
#include <webserver/DOSGuard.h>
|
||||
|
||||
#include <boost/json/value.hpp>
|
||||
#include <boost/json/value_from.hpp>
|
||||
@@ -175,4 +176,15 @@ struct HandlerWithoutInputMock
|
||||
MOCK_METHOD(Result, process, (RPC::Context const&), (const));
|
||||
};
|
||||
|
||||
// testing sweep handler by mocking dos guard
|
||||
template <typename SweepHandler>
|
||||
struct BasicDOSGuardMock : public clio::BaseDOSGuard
|
||||
{
|
||||
BasicDOSGuardMock(SweepHandler& handler)
|
||||
{
|
||||
handler.setup(this);
|
||||
}
|
||||
|
||||
MOCK_METHOD(void, clear, (), (noexcept, override));
|
||||
};
|
||||
} // namespace unittests::detail
|
||||
|
||||
@@ -145,11 +145,13 @@ protected:
|
||||
boost::asio::io_context ctxSync;
|
||||
clio::Config cfg{boost::json::parse(JSONData)};
|
||||
clio::IntervalSweepHandler sweepHandler = clio::IntervalSweepHandler{cfg, ctxSync};
|
||||
clio::DOSGuard dosGuard = clio::DOSGuard{cfg, sweepHandler};
|
||||
clio::WhitelistHandler whitelistHandler = clio::WhitelistHandler{cfg};
|
||||
clio::DOSGuard dosGuard = clio::DOSGuard{cfg, whitelistHandler, sweepHandler};
|
||||
|
||||
clio::Config cfgOverload{boost::json::parse(JSONDataOverload)};
|
||||
clio::IntervalSweepHandler sweepHandlerOverload = clio::IntervalSweepHandler{cfgOverload, ctxSync};
|
||||
clio::DOSGuard dosGuardOverload = clio::DOSGuard{cfgOverload, sweepHandlerOverload};
|
||||
clio::WhitelistHandler whitelistHandlerOverload = clio::WhitelistHandler{cfgOverload};
|
||||
clio::DOSGuard dosGuardOverload = clio::DOSGuard{cfgOverload, whitelistHandlerOverload, sweepHandlerOverload};
|
||||
// this ctx is for http server
|
||||
boost::asio::io_context ctx;
|
||||
|
||||
|
||||
54
unittests/webserver/SweepHandlerTest.cpp
Normal file
54
unittests/webserver/SweepHandlerTest.cpp
Normal file
@@ -0,0 +1,54 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of clio: https://github.com/XRPLF/clio
|
||||
Copyright (c) 2023, 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 <config/Config.h>
|
||||
#include <rpc/handlers/impl/FakesAndMocks.h>
|
||||
#include <util/Fixtures.h>
|
||||
#include <webserver/DOSGuard.h>
|
||||
|
||||
#include <boost/json/parse.hpp>
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
using namespace clio;
|
||||
using namespace testing;
|
||||
|
||||
constexpr static auto JSONData = R"JSON(
|
||||
{
|
||||
"dos_guard": {
|
||||
"max_fetches": 100,
|
||||
"sweep_interval": 0.1,
|
||||
"max_connections": 2,
|
||||
"whitelist": ["127.0.0.1"]
|
||||
}
|
||||
}
|
||||
)JSON";
|
||||
|
||||
class DOSGuardIntervalSweepHandlerTest : public SyncAsioContextTest
|
||||
{
|
||||
protected:
|
||||
Config cfg{boost::json::parse(JSONData)};
|
||||
IntervalSweepHandler sweepHandler{cfg, ctx};
|
||||
unittests::detail::BasicDOSGuardMock<IntervalSweepHandler> guard{sweepHandler};
|
||||
};
|
||||
|
||||
TEST_F(DOSGuardIntervalSweepHandlerTest, SweepAfterInterval)
|
||||
{
|
||||
EXPECT_CALL(guard, clear()).Times(AtLeast(2));
|
||||
ctx.run_for(std::chrono::milliseconds(400));
|
||||
}
|
||||
75
unittests/webserver/WhitelistHandlerTest.cpp
Normal file
75
unittests/webserver/WhitelistHandlerTest.cpp
Normal file
@@ -0,0 +1,75 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of clio: https://github.com/XRPLF/clio
|
||||
Copyright (c) 2023, 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 <config/Config.h>
|
||||
#include <util/Fixtures.h>
|
||||
#include <webserver/DOSGuard.h>
|
||||
|
||||
#include <boost/json/parse.hpp>
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
using namespace clio;
|
||||
|
||||
constexpr static auto JSONDataIPV4 = R"JSON(
|
||||
{
|
||||
"dos_guard": {
|
||||
"whitelist": [
|
||||
"127.0.0.1",
|
||||
"192.168.0.1/22",
|
||||
"10.0.0.1"
|
||||
]
|
||||
}
|
||||
}
|
||||
)JSON";
|
||||
|
||||
constexpr static auto JSONDataIPV6 = R"JSON(
|
||||
{
|
||||
"dos_guard": {
|
||||
"whitelist": [
|
||||
"2002:1dd8:85a7:0000:0000:8a6e:0000:1111",
|
||||
"2001:0db8:85a3:0000:0000:8a2e:0000:0000/22"
|
||||
]
|
||||
}
|
||||
}
|
||||
)JSON";
|
||||
|
||||
class WhitelistHandlerTest : public NoLoggerFixture
|
||||
{
|
||||
};
|
||||
|
||||
TEST_F(WhitelistHandlerTest, TestWhiteListIPV4)
|
||||
{
|
||||
Config cfg{boost::json::parse(JSONDataIPV4)};
|
||||
WhitelistHandler whitelistHandler{cfg};
|
||||
|
||||
EXPECT_TRUE(whitelistHandler.isWhiteListed("192.168.1.10"));
|
||||
EXPECT_FALSE(whitelistHandler.isWhiteListed("193.168.0.123"));
|
||||
EXPECT_TRUE(whitelistHandler.isWhiteListed("10.0.0.1"));
|
||||
EXPECT_FALSE(whitelistHandler.isWhiteListed("10.0.0.2"));
|
||||
}
|
||||
|
||||
TEST_F(WhitelistHandlerTest, TestWhiteListIPV6)
|
||||
{
|
||||
Config cfg{boost::json::parse(JSONDataIPV6)};
|
||||
WhitelistHandler whitelistHandler{cfg};
|
||||
|
||||
EXPECT_TRUE(whitelistHandler.isWhiteListed("2002:1dd8:85a7:0000:0000:8a6e:0000:1111"));
|
||||
EXPECT_FALSE(whitelistHandler.isWhiteListed("2002:1dd8:85a7:1101:0000:8a6e:0000:1111"));
|
||||
EXPECT_TRUE(whitelistHandler.isWhiteListed("2001:0db8:85a3:0000:0000:8a2e:0000:0000"));
|
||||
EXPECT_TRUE(whitelistHandler.isWhiteListed("2001:0db8:85a3:0000:1111:8a2e:0370:7334"));
|
||||
}
|
||||
Reference in New Issue
Block a user