mirror of
https://github.com/XRPLF/clio.git
synced 2026-06-03 00:36:44 +00:00
refactor: Use error code in make_address() calls (#3044)
Function `ip::make_address()` throws an exception on an invalid IP. Refactor to a better error handling without exceptions.
This commit is contained in:
@@ -92,9 +92,14 @@ ClioApplication::run(bool const useNgWebServer)
|
||||
boost::asio::io_context ioc{threads};
|
||||
|
||||
// Rate limiter, to prevent abuse
|
||||
auto whitelistHandler = web::dosguard::WhitelistHandler{config_};
|
||||
auto whitelistHandler = web::dosguard::WhitelistHandler::create(config_);
|
||||
if (not whitelistHandler.has_value()) {
|
||||
LOG(util::LogService::fatal()) << whitelistHandler.error();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
auto const dosguardWeights = web::dosguard::Weights::make(config_);
|
||||
auto dosGuard = web::dosguard::DOSGuard{config_, whitelistHandler, dosguardWeights};
|
||||
auto dosGuard = web::dosguard::DOSGuard{config_, *whitelistHandler, dosguardWeights};
|
||||
auto sweepHandler = web::dosguard::IntervalSweepHandler{config_, ioc, dosGuard};
|
||||
|
||||
auto cache = data::LedgerCache{};
|
||||
@@ -222,10 +227,15 @@ ClioApplication::run(bool const useNgWebServer)
|
||||
config_, backend, rpcEngine, etl, dosGuard
|
||||
);
|
||||
|
||||
auto const httpServer = web::makeHttpServer(config_, ioc, dosGuard, handler, cache);
|
||||
auto const expectedHttpServer = web::makeHttpServer(config_, ioc, dosGuard, handler, cache);
|
||||
if (not expectedHttpServer.has_value()) {
|
||||
LOG(util::LogService::fatal()) << expectedHttpServer.error();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
appStopper_.setOnStop(
|
||||
Stopper::makeOnStopCallback(
|
||||
*httpServer,
|
||||
**expectedHttpServer,
|
||||
*balancer,
|
||||
*etl,
|
||||
*subscriptions,
|
||||
|
||||
@@ -312,7 +312,8 @@ getClioConfig()
|
||||
{"num_markers",
|
||||
ConfigValue{ConfigType::Integer}.optional().withConstraint(gValidateNumMarkers)},
|
||||
|
||||
{"dos_guard.whitelist.[]", Array{ConfigValue{ConfigType::String}.optional()}},
|
||||
{"dos_guard.whitelist.[]",
|
||||
Array{ConfigValue{ConfigType::String}.optional().withConstraint(gValidateIp)}},
|
||||
{"dos_guard.max_fetches",
|
||||
ConfigValue{ConfigType::Integer}.defaultValue(1000'000u).withConstraint(gValidateUint32)},
|
||||
{"dos_guard.max_connections",
|
||||
@@ -361,7 +362,8 @@ getClioConfig()
|
||||
{"server.ws_max_sending_queue_size",
|
||||
ConfigValue{ConfigType::Integer}.defaultValue(1500).withConstraint(gValidateUint32)},
|
||||
{"server.__ng_web_server", ConfigValue{ConfigType::Boolean}.defaultValue(false)},
|
||||
{"server.proxy.ips.[]", Array{ConfigValue{ConfigType::String}}},
|
||||
{"server.proxy.ips.[]",
|
||||
Array{ConfigValue{ConfigType::String}.withConstraint(gValidateIp)}},
|
||||
{"server.proxy.tokens.[]", Array{ConfigValue{ConfigType::String}}},
|
||||
|
||||
{"prometheus.enabled", ConfigValue{ConfigType::Boolean}.defaultValue(true)},
|
||||
|
||||
@@ -375,7 +375,7 @@ using HttpServer = Server<HttpSession, SslHttpSession, HandlerType>;
|
||||
* @return The server instance
|
||||
*/
|
||||
template <typename HandlerType>
|
||||
static std::shared_ptr<HttpServer<HandlerType>>
|
||||
static std::expected<std::shared_ptr<HttpServer<HandlerType>>, std::string>
|
||||
makeHttpServer(
|
||||
util::config::ClioConfigDefinition const& config,
|
||||
boost::asio::io_context& ioc,
|
||||
@@ -388,19 +388,24 @@ makeHttpServer(
|
||||
|
||||
auto expectedSslContext = ng::impl::makeServerSslContext(config);
|
||||
if (not expectedSslContext) {
|
||||
LOG(log.error()) << "Failed to create SSL context: " << expectedSslContext.error();
|
||||
return nullptr;
|
||||
return std::unexpected(
|
||||
fmt::format("Failed to create SSL context: {}", expectedSslContext.error())
|
||||
);
|
||||
}
|
||||
|
||||
auto const serverConfig = config.getObject("server");
|
||||
auto const address = boost::asio::ip::make_address(serverConfig.get<std::string>("ip"));
|
||||
|
||||
auto const ipFromConfig = serverConfig.get<std::string>("ip");
|
||||
boost::system::error_code ec;
|
||||
auto const address = boost::asio::ip::make_address(ipFromConfig, ec);
|
||||
if (ec.failed())
|
||||
return std::unexpected(fmt::format("Invalid 'server.ip' config value: {}", ipFromConfig));
|
||||
|
||||
auto const port = serverConfig.get<unsigned short>("port");
|
||||
|
||||
auto expectedAdminVerification = makeAdminVerificationStrategy(config);
|
||||
if (not expectedAdminVerification.has_value()) {
|
||||
LOG(log.error()) << expectedAdminVerification.error();
|
||||
throw std::logic_error{expectedAdminVerification.error()};
|
||||
}
|
||||
if (not expectedAdminVerification.has_value())
|
||||
return std::unexpected(expectedAdminVerification.error());
|
||||
|
||||
// If the transactions number is 200 per ledger, A client which subscribes everything will send
|
||||
// 400+ feeds for each ledger. we allow user delay 3 ledgers by default
|
||||
|
||||
@@ -8,32 +8,48 @@
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <regex>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace web::dosguard {
|
||||
|
||||
void
|
||||
WhitelistHandler::WhitelistHandler(Whitelist whitelist) : whitelist_(std::move(whitelist))
|
||||
{
|
||||
}
|
||||
|
||||
std::expected<void, std::string>
|
||||
Whitelist::add(std::string_view net)
|
||||
{
|
||||
using namespace boost::asio;
|
||||
|
||||
if (not isMask(net)) {
|
||||
ips_.push_back(ip::make_address(net));
|
||||
return;
|
||||
boost::system::error_code ec;
|
||||
auto const ip = ip::make_address(net, ec);
|
||||
if (ec.failed())
|
||||
return std::unexpected{fmt::format("Malformed whitelist ip address: {}. ", net)};
|
||||
ips_.push_back(ip);
|
||||
return {};
|
||||
}
|
||||
|
||||
if (isV4(net)) {
|
||||
subnetsV4_.push_back(ip::make_network_v4(net));
|
||||
boost::system::error_code ec;
|
||||
auto const net4 = ip::make_network_v4(net, ec);
|
||||
if (ec.failed())
|
||||
return std::unexpected{fmt::format("Malformed network: {}. ", net)};
|
||||
subnetsV4_.push_back(net4);
|
||||
} else if (isV6(net)) {
|
||||
subnetsV6_.push_back(ip::make_network_v6(net));
|
||||
boost::system::error_code ec;
|
||||
auto const net6 = ip::make_network_v6(net, ec);
|
||||
if (ec.failed())
|
||||
return std::unexpected{fmt::format("Malformed network: {}. ", net)};
|
||||
subnetsV6_.push_back(net6);
|
||||
} else {
|
||||
throw std::runtime_error(fmt::format("malformed network: {}", net.data()));
|
||||
return std::unexpected{fmt::format("Malformed network: {}. ", net)};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -41,7 +57,11 @@ Whitelist::isWhiteListed(std::string_view ip) const
|
||||
{
|
||||
using namespace boost::asio;
|
||||
|
||||
auto const addr = ip::make_address(ip);
|
||||
boost::system::error_code ec;
|
||||
auto const addr = ip::make_address(ip, ec);
|
||||
if (ec.failed())
|
||||
return false;
|
||||
|
||||
if (std::ranges::find(ips_, addr) != std::end(ips_))
|
||||
return true;
|
||||
|
||||
@@ -95,7 +115,7 @@ Whitelist::isV6(std::string_view net)
|
||||
bool
|
||||
Whitelist::isMask(std::string_view net)
|
||||
{
|
||||
return net.find('/') != std::string_view::npos;
|
||||
return net.contains('/');
|
||||
}
|
||||
|
||||
} // namespace web::dosguard
|
||||
|
||||
@@ -14,11 +14,11 @@
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <regex>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace web::dosguard {
|
||||
@@ -36,16 +36,15 @@ 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
|
||||
* @return void on success, or an error string if the address is not valid
|
||||
*/
|
||||
void
|
||||
std::expected<void, std::string>
|
||||
add(std::string_view net);
|
||||
|
||||
/**
|
||||
* @brief Checks to see if ip address is whitelisted.
|
||||
*
|
||||
* @param ip IP address
|
||||
* @throws std::runtime::error when the network address is not valid
|
||||
* @return true if the given IP is whitelisted; false otherwise
|
||||
*/
|
||||
bool
|
||||
@@ -76,21 +75,38 @@ class WhitelistHandler : public WhitelistHandlerInterface {
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Adds all whitelisted IPs and masks from the given config.
|
||||
* @brief Constructs a WhitelistHandler from an already-built Whitelist.
|
||||
*
|
||||
* @param whitelist The whitelist to use
|
||||
*/
|
||||
explicit WhitelistHandler(Whitelist whitelist);
|
||||
|
||||
/**
|
||||
* @brief Creates a WhitelistHandler by loading all whitelisted IPs and masks from config.
|
||||
*
|
||||
* @param config The Clio config to use
|
||||
* @param resolver The resolver to use for hostname resolution
|
||||
* @return The WhitelistHandler on success, or an error string if any whitelist entry is invalid
|
||||
*/
|
||||
template <SomeResolver HostnameResolverType = Resolver>
|
||||
WhitelistHandler(
|
||||
util::config::ClioConfigDefinition const& config,
|
||||
HostnameResolverType&& resolver = {}
|
||||
)
|
||||
static std::expected<WhitelistHandler, std::string>
|
||||
create(util::config::ClioConfigDefinition const& config, HostnameResolverType&& resolver = {})
|
||||
{
|
||||
std::unordered_set<std::string> const arr =
|
||||
getWhitelist(config, std::forward<HostnameResolverType>(resolver));
|
||||
for (auto const& net : arr)
|
||||
whitelist_.add(net);
|
||||
Whitelist whitelist;
|
||||
std::optional<std::string> errors;
|
||||
for (auto const& net : arr) {
|
||||
if (auto result = whitelist.add(net); !result.has_value()) {
|
||||
if (!errors.has_value())
|
||||
errors.emplace();
|
||||
errors->append(std::move(result).error());
|
||||
}
|
||||
}
|
||||
if (errors.has_value()) {
|
||||
return std::unexpected{std::move(errors).value()};
|
||||
}
|
||||
return WhitelistHandler(std::move(whitelist));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user