mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Apply resource limits to proxied clients:
Resource limits were not properly applied to connections with known IP addresses but no corresponding users. Add unit tests for unlimited vs. limited ports.
This commit is contained in:
committed by
Nik Bougalis
parent
872478d965
commit
504b3441dd
@@ -276,13 +276,13 @@ Status doCommand (
|
||||
! context.headers.forwardedFor.empty())
|
||||
{
|
||||
JLOG(context.j.debug()) << "start command: " << handler->name_ <<
|
||||
", X-User: " << context.headers.user << ", X-Forwarded-For: " <<
|
||||
", user: " << context.headers.user << ", forwarded for: " <<
|
||||
context.headers.forwardedFor;
|
||||
|
||||
auto ret = callMethod (context, method, handler->name_, result);
|
||||
|
||||
JLOG(context.j.debug()) << "finish command: " << handler->name_ <<
|
||||
", X-User: " << context.headers.user << ", X-Forwarded-For: " <<
|
||||
", user: " << context.headers.user << ", forwarded for: " <<
|
||||
context.headers.forwardedFor;
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/rpc/Role.h>
|
||||
#include <boost/beast/core/string.hpp>
|
||||
#include <algorithm>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -56,7 +58,7 @@ isAdmin (Port const& port, Json::Value const& params,
|
||||
Role
|
||||
requestRole (Role const& required, Port const& port,
|
||||
Json::Value const& params, beast::IP::Endpoint const& remoteIp,
|
||||
std::string const& user)
|
||||
boost::string_view const& user)
|
||||
{
|
||||
if (isAdmin(port, params, remoteIp.address()))
|
||||
return Role::ADMIN;
|
||||
@@ -64,8 +66,12 @@ requestRole (Role const& required, Port const& port,
|
||||
if (required == Role::ADMIN)
|
||||
return Role::FORBID;
|
||||
|
||||
if (isIdentified(port, remoteIp.address(), user))
|
||||
return Role::IDENTIFIED;
|
||||
if (ipAllowed(remoteIp.address(), port.secure_gateway_ip))
|
||||
{
|
||||
if (user.size())
|
||||
return Role::IDENTIFIED;
|
||||
return Role::PROXY;
|
||||
}
|
||||
|
||||
return Role::GUEST;
|
||||
}
|
||||
@@ -73,41 +79,66 @@ requestRole (Role const& required, Port const& port,
|
||||
/**
|
||||
* ADMIN and IDENTIFIED roles shall have unlimited resources.
|
||||
*/
|
||||
bool
|
||||
isUnlimited (Role const& required, Port const& port,
|
||||
Json::Value const¶ms, beast::IP::Endpoint const& remoteIp,
|
||||
std::string const& user)
|
||||
{
|
||||
Role role = requestRole(required, port, params, remoteIp, user);
|
||||
|
||||
if (role == Role::ADMIN || role == Role::IDENTIFIED)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
isUnlimited (Role const& role)
|
||||
{
|
||||
return role == Role::ADMIN || role == Role::IDENTIFIED;
|
||||
}
|
||||
|
||||
bool
|
||||
isUnlimited (Role const& required, Port const& port,
|
||||
Json::Value const& params, beast::IP::Endpoint const& remoteIp,
|
||||
std::string const& user)
|
||||
{
|
||||
return isUnlimited(requestRole(required, port, params, remoteIp, user));
|
||||
}
|
||||
|
||||
Resource::Consumer
|
||||
requestInboundEndpoint (Resource::Manager& manager,
|
||||
beast::IP::Endpoint const& remoteAddress,
|
||||
Port const& port, std::string const& user)
|
||||
beast::IP::Endpoint const& remoteAddress, Role const& role,
|
||||
boost::string_view const& user, boost::string_view const& forwardedFor)
|
||||
{
|
||||
if (isUnlimited (Role::GUEST, port, Json::Value(), remoteAddress, user))
|
||||
return manager.newUnlimitedEndpoint (to_string (remoteAddress));
|
||||
if (isUnlimited(role))
|
||||
return manager.newUnlimitedEndpoint (remoteAddress);
|
||||
|
||||
return manager.newInboundEndpoint(remoteAddress);
|
||||
return manager.newInboundEndpoint(remoteAddress, role == Role::PROXY,
|
||||
forwardedFor);
|
||||
}
|
||||
|
||||
bool
|
||||
isIdentified (Port const& port, beast::IP::Address const& remoteIp,
|
||||
std::string const& user)
|
||||
boost::string_view
|
||||
forwardedFor(http_request_type const& request)
|
||||
{
|
||||
return ! user.empty() && ipAllowed (remoteIp, port.secure_gateway_ip);
|
||||
auto it = request.find("X-Forwarded-For");
|
||||
if (it != request.end())
|
||||
{
|
||||
return boost::beast::http::ext_list{
|
||||
it->value()}.begin()->first;
|
||||
}
|
||||
|
||||
it = request.find("Forwarded");
|
||||
if (it != request.end())
|
||||
{
|
||||
static std::string const forStr{"for="};
|
||||
auto found = std::search(it->value().begin(), it->value().end(),
|
||||
forStr.begin(), forStr.end(),
|
||||
[](char c1, char c2)
|
||||
{
|
||||
return boost::beast::detail::ascii_tolower(c1) ==
|
||||
boost::beast::detail::ascii_tolower(c2);
|
||||
}
|
||||
);
|
||||
|
||||
if (found == it->value().end())
|
||||
return {};
|
||||
|
||||
found += forStr.size();
|
||||
auto pos{it->value().find(';', forStr.size())};
|
||||
if (pos != boost::string_view::npos)
|
||||
return {found, pos + 1};
|
||||
return {found, it->value().size() - forStr.size()};
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include <ripple/resource/ResourceManager.h>
|
||||
#include <ripple/resource/Fees.h>
|
||||
#include <ripple/rpc/impl/Tuning.h>
|
||||
#include <ripple/rpc/Role.h>
|
||||
#include <ripple/rpc/RPCHandler.h>
|
||||
#include <ripple/server/SimpleWriter.h>
|
||||
#include <boost/beast/http/fields.hpp>
|
||||
@@ -199,11 +200,14 @@ ServerHandlerImp::onHandoff(
|
||||
}
|
||||
|
||||
auto is {std::make_shared<WSInfoSub>(m_networkOPs, ws)};
|
||||
auto const beast_remote_address =
|
||||
beast::IPAddressConversion::from_asio(remote_address);
|
||||
is->getConsumer() = requestInboundEndpoint(
|
||||
m_resourceManager,
|
||||
beast::IPAddressConversion::from_asio(remote_address),
|
||||
session.port(),
|
||||
is->user());
|
||||
m_resourceManager, beast_remote_address,
|
||||
requestRole(Role::GUEST, session.port(), Json::Value(),
|
||||
beast_remote_address, is->user()),
|
||||
is->user(),
|
||||
is->forwarded_for());
|
||||
ws->appDefined = std::move(is);
|
||||
ws->run();
|
||||
|
||||
@@ -489,12 +493,6 @@ ServerHandlerImp::processSession(
|
||||
else
|
||||
{
|
||||
jr[jss::status] = jss::success;
|
||||
|
||||
// For testing resource limits on this connection.
|
||||
if (is->getConsumer().isUnlimited() &&
|
||||
jv[jss::command].isString() &&
|
||||
jv[jss::command].asString() == "ping")
|
||||
jr[jss::unlimited] = true;
|
||||
}
|
||||
|
||||
if (jv.isMember(jss::id))
|
||||
@@ -517,23 +515,14 @@ ServerHandlerImp::processSession (std::shared_ptr<Session> const& session,
|
||||
session->request().body().data()),
|
||||
session->remoteAddress().at_port (0),
|
||||
makeOutput (*session), coro,
|
||||
[&]
|
||||
{
|
||||
auto const iter =
|
||||
session->request().find(
|
||||
"X-Forwarded-For");
|
||||
if(iter != session->request().end())
|
||||
return iter->value().to_string();
|
||||
return std::string{};
|
||||
}(),
|
||||
[&]
|
||||
{
|
||||
forwardedFor(session->request()),
|
||||
[&]{
|
||||
auto const iter =
|
||||
session->request().find(
|
||||
"X-User");
|
||||
if(iter != session->request().end())
|
||||
return iter->value().to_string();
|
||||
return std::string{};
|
||||
return iter->value();
|
||||
return boost::beast::string_view{};
|
||||
}());
|
||||
|
||||
if(beast::rfc2616::is_keep_alive(session->request()))
|
||||
@@ -562,7 +551,7 @@ void
|
||||
ServerHandlerImp::processRequest (Port const& port,
|
||||
std::string const& request, beast::IP::Endpoint const& remoteIPAddress,
|
||||
Output&& output, std::shared_ptr<JobQueue::Coro> coro,
|
||||
std::string forwardedFor, std::string user)
|
||||
boost::string_view forwardedFor, boost::string_view user)
|
||||
{
|
||||
auto rpcJ = app_.journal ("RPC");
|
||||
|
||||
@@ -636,12 +625,12 @@ ServerHandlerImp::processRequest (Port const& port,
|
||||
Resource::Consumer usage;
|
||||
if (isUnlimited(role))
|
||||
{
|
||||
usage = m_resourceManager.newUnlimitedEndpoint(
|
||||
remoteIPAddress.to_string());
|
||||
usage = m_resourceManager.newUnlimitedEndpoint(remoteIPAddress);
|
||||
}
|
||||
else
|
||||
{
|
||||
usage = m_resourceManager.newInboundEndpoint(remoteIPAddress);
|
||||
usage = m_resourceManager.newInboundEndpoint(remoteIPAddress,
|
||||
role == Role::PROXY, forwardedFor);
|
||||
if (usage.disconnect())
|
||||
{
|
||||
if (!batch)
|
||||
@@ -774,7 +763,7 @@ ServerHandlerImp::processRequest (Port const& port,
|
||||
* Clear header-assigned values if not positively identified from a
|
||||
* secure_gateway.
|
||||
*/
|
||||
if (role != Role::IDENTIFIED)
|
||||
if (role != Role::IDENTIFIED && role != Role::PROXY)
|
||||
{
|
||||
forwardedFor.clear();
|
||||
user.clear();
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <ripple/rpc/RPCHandler.h>
|
||||
#include <ripple/app/main/CollectorManager.h>
|
||||
#include <ripple/json/Output.h>
|
||||
#include <boost/utility/string_view.hpp>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
@@ -180,7 +181,7 @@ private:
|
||||
processRequest (Port const& port, std::string const& request,
|
||||
beast::IP::Endpoint const& remoteIPAddress, Output&&,
|
||||
std::shared_ptr<JobQueue::Coro> coro,
|
||||
std::string forwardedFor, std::string user);
|
||||
boost::string_view forwardedFor, boost::string_view user);
|
||||
|
||||
Handoff
|
||||
statusResponse(http_request_type const& request) const;
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <ripple/beast/net/IPAddressConversion.h>
|
||||
#include <ripple/json/json_writer.h>
|
||||
#include <ripple/rpc/Role.h>
|
||||
#include <boost/utility/string_view.hpp>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
@@ -42,26 +43,23 @@ public:
|
||||
, ws_(ws)
|
||||
{
|
||||
auto const& h = ws->request();
|
||||
auto it = h.find("X-User");
|
||||
if (it != h.end() &&
|
||||
isIdentified(
|
||||
ws->port(), beast::IPAddressConversion::from_asio(
|
||||
ws->remote_endpoint()).address(), it->value().to_string()))
|
||||
if (ipAllowed(beast::IPAddressConversion::from_asio(
|
||||
ws->remote_endpoint()).address(), ws->port().secure_gateway_ip))
|
||||
{
|
||||
user_ = it->value().to_string();
|
||||
it = h.find("X-Forwarded-For");
|
||||
auto it = h.find("X-User");
|
||||
if (it != h.end())
|
||||
fwdfor_ = it->value().to_string();
|
||||
user_ = it->value().to_string();
|
||||
fwdfor_ = std::string(forwardedFor(h));
|
||||
}
|
||||
}
|
||||
|
||||
std::string
|
||||
boost::string_view
|
||||
user() const
|
||||
{
|
||||
return user_;
|
||||
}
|
||||
|
||||
std::string
|
||||
boost::string_view
|
||||
forwarded_for() const
|
||||
{
|
||||
return fwdfor_;
|
||||
|
||||
Reference in New Issue
Block a user