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
@@ -273,6 +273,12 @@ public:
|
||||
The command is examined and used to build
|
||||
the correct JSON as per the arguments.
|
||||
*/
|
||||
template<class... Args>
|
||||
Json::Value
|
||||
rpc(std::unordered_map<std::string, std::string> const& headers,
|
||||
std::string const& cmd,
|
||||
Args&&... args);
|
||||
|
||||
template<class... Args>
|
||||
Json::Value
|
||||
rpc(std::string const& cmd, Args&&... args);
|
||||
@@ -641,7 +647,8 @@ protected:
|
||||
TER ter_ = tesSUCCESS;
|
||||
|
||||
Json::Value
|
||||
do_rpc(std::vector<std::string> const& args);
|
||||
do_rpc(std::vector<std::string> const& args,
|
||||
std::unordered_map<std::string, std::string> const& headers = {});
|
||||
|
||||
void
|
||||
autofill_sig (JTx& jt);
|
||||
@@ -734,13 +741,22 @@ protected:
|
||||
AccountID, Account> map_;
|
||||
};
|
||||
|
||||
template<class... Args>
|
||||
Json::Value
|
||||
Env::rpc(std::unordered_map<std::string, std::string> const& headers,
|
||||
std::string const& cmd,
|
||||
Args&&... args)
|
||||
{
|
||||
return do_rpc(std::vector<std::string>{cmd, std::forward<Args>(args)...},
|
||||
headers);
|
||||
}
|
||||
|
||||
template<class... Args>
|
||||
Json::Value
|
||||
Env::rpc(std::string const& cmd, Args&&... args)
|
||||
{
|
||||
std::vector<std::string> vs{cmd,
|
||||
std::forward<Args>(args)...};
|
||||
return do_rpc(vs);
|
||||
return rpc(std::unordered_map<std::string, std::string>(), cmd,
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
} // jtx
|
||||
|
||||
@@ -47,7 +47,8 @@ public:
|
||||
|
||||
/** Returns a client operating through WebSockets/S. */
|
||||
std::unique_ptr<WSClient>
|
||||
makeWSClient(Config const& cfg, bool v2 = true, unsigned rpc_version = 2);
|
||||
makeWSClient(Config const& cfg, bool v2 = true, unsigned rpc_version = 2,
|
||||
std::unordered_map<std::string, std::string> const& headers = {});
|
||||
|
||||
} // test
|
||||
} // ripple
|
||||
|
||||
@@ -86,6 +86,9 @@ envconfig(F&& modfunc, Args&&... args)
|
||||
std::unique_ptr<Config>
|
||||
no_admin(std::unique_ptr<Config>);
|
||||
|
||||
std::unique_ptr<Config>
|
||||
secure_gateway(std::unique_ptr<Config>);
|
||||
|
||||
/// @brief adjust configuration with params needed to be a validator
|
||||
///
|
||||
/// this is intended for use with envconfig, as in
|
||||
|
||||
@@ -442,9 +442,10 @@ Env::st (JTx const& jt)
|
||||
}
|
||||
|
||||
Json::Value
|
||||
Env::do_rpc(std::vector<std::string> const& args)
|
||||
Env::do_rpc(std::vector<std::string> const& args,
|
||||
std::unordered_map<std::string, std::string> const& headers)
|
||||
{
|
||||
return rpcClient(args, app().config(), app().logs()).second;
|
||||
return rpcClient(args, app().config(), app().logs(), headers).second;
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -27,6 +27,10 @@
|
||||
#include <boost/beast/websocket.hpp>
|
||||
|
||||
#include <condition_variable>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <ripple/beast/unit_test.h>
|
||||
|
||||
@@ -125,7 +129,8 @@ class WSClientImpl : public WSClient
|
||||
}
|
||||
|
||||
public:
|
||||
WSClientImpl(Config const& cfg, bool v2, unsigned rpc_version)
|
||||
WSClientImpl(Config const& cfg, bool v2, unsigned rpc_version,
|
||||
std::unordered_map<std::string, std::string> const& headers = {})
|
||||
: work_(ios_)
|
||||
, strand_(ios_)
|
||||
, thread_([&]{ ios_.run(); })
|
||||
@@ -137,8 +142,13 @@ public:
|
||||
{
|
||||
auto const ep = getEndpoint(cfg, v2);
|
||||
stream_.connect(ep);
|
||||
ws_.handshake(ep.address().to_string() +
|
||||
":" + std::to_string(ep.port()), "/");
|
||||
ws_.handshake_ex(ep.address().to_string() +
|
||||
":" + std::to_string(ep.port()), "/",
|
||||
[&](boost::beast::websocket::request_type &req)
|
||||
{
|
||||
for (auto const& h : headers)
|
||||
req.set(h.first, h.second);
|
||||
});
|
||||
ws_.async_read(rb_,
|
||||
strand_.wrap(std::bind(&WSClientImpl::on_read_msg,
|
||||
this, std::placeholders::_1)));
|
||||
@@ -294,9 +304,10 @@ private:
|
||||
};
|
||||
|
||||
std::unique_ptr<WSClient>
|
||||
makeWSClient(Config const& cfg, bool v2, unsigned rpc_version)
|
||||
makeWSClient(Config const& cfg, bool v2, unsigned rpc_version,
|
||||
std::unordered_map<std::string, std::string> const& headers)
|
||||
{
|
||||
return std::make_unique<WSClientImpl>(cfg, v2, rpc_version);
|
||||
return std::make_unique<WSClientImpl>(cfg, v2, rpc_version, headers);
|
||||
}
|
||||
|
||||
} // test
|
||||
|
||||
@@ -72,6 +72,15 @@ no_admin(std::unique_ptr<Config> cfg)
|
||||
return cfg;
|
||||
}
|
||||
|
||||
std::unique_ptr<Config>
|
||||
secure_gateway(std::unique_ptr<Config> cfg)
|
||||
{
|
||||
(*cfg)["port_rpc"].set("admin", "");
|
||||
(*cfg)["port_ws"].set("admin","");
|
||||
(*cfg)["port_rpc"].set("secure_gateway", getEnvLocalhostAddr());
|
||||
return cfg;
|
||||
}
|
||||
|
||||
auto constexpr defaultseed = "shUwVw52ofnCUX5m7kPTKzJdr4HEH";
|
||||
|
||||
std::unique_ptr<Config>
|
||||
|
||||
@@ -80,9 +80,12 @@ public:
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void testDrop (beast::Journal j)
|
||||
void testDrop (beast::Journal j, bool limited)
|
||||
{
|
||||
testcase ("Warn/drop");
|
||||
if (limited)
|
||||
testcase("Limited warn/drop");
|
||||
else
|
||||
testcase("Unlimited warn/drop");
|
||||
|
||||
TestLogic logic (j);
|
||||
|
||||
@@ -90,8 +93,14 @@ public:
|
||||
beast::IP::Endpoint const addr (
|
||||
beast::IP::Endpoint::from_string ("192.0.2.2"));
|
||||
|
||||
using namespace std::placeholders;
|
||||
|
||||
std::function<Consumer(beast::IP::Endpoint)> ep = limited ?
|
||||
std::bind(&TestLogic::newInboundEndpoint, &logic, _1) :
|
||||
std::bind(&TestLogic::newUnlimitedEndpoint, &logic, _1);
|
||||
|
||||
{
|
||||
Consumer c (logic.newInboundEndpoint (addr));
|
||||
Consumer c (ep(addr));
|
||||
|
||||
// Create load until we get a warning
|
||||
int n = 10000;
|
||||
@@ -100,13 +109,19 @@ public:
|
||||
{
|
||||
if (n == 0)
|
||||
{
|
||||
fail ("Loop count exceeded without warning");
|
||||
if (limited)
|
||||
fail ("Loop count exceeded without warning");
|
||||
else
|
||||
pass();
|
||||
return;
|
||||
}
|
||||
|
||||
if (c.charge (fee) == warn)
|
||||
{
|
||||
pass ();
|
||||
if (limited)
|
||||
pass();
|
||||
else
|
||||
fail ("Should loop forever with no warning");
|
||||
break;
|
||||
}
|
||||
++logic.clock ();
|
||||
@@ -117,14 +132,17 @@ public:
|
||||
{
|
||||
if (n == 0)
|
||||
{
|
||||
fail ("Loop count exceeded without dropping");
|
||||
if (limited)
|
||||
fail ("Loop count exceeded without dropping");
|
||||
else
|
||||
pass();
|
||||
return;
|
||||
}
|
||||
|
||||
if (c.charge (fee) == drop)
|
||||
{
|
||||
// Disconnect abusive Consumer
|
||||
BEAST_EXPECT(c.disconnect ());
|
||||
BEAST_EXPECT(c.disconnect () == limited);
|
||||
break;
|
||||
}
|
||||
++logic.clock ();
|
||||
@@ -137,7 +155,10 @@ public:
|
||||
logic.periodicActivity();
|
||||
if (c.disposition () != drop)
|
||||
{
|
||||
fail ("Dropped consumer not put on blacklist");
|
||||
if (limited)
|
||||
fail ("Dropped consumer not put on blacklist");
|
||||
else
|
||||
pass();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -250,7 +271,8 @@ public:
|
||||
using namespace beast::severities;
|
||||
test::SuiteJournal journal ("ResourceManager_test", *this);
|
||||
|
||||
testDrop (journal);
|
||||
testDrop (journal, true);
|
||||
testDrop (journal, false);
|
||||
testCharges (journal);
|
||||
testImports (journal);
|
||||
testImport (journal);
|
||||
|
||||
113
src/test/rpc/Roles_test.cpp
Normal file
113
src/test/rpc/Roles_test.cpp
Normal file
@@ -0,0 +1,113 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2019 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or 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 <ripple/beast/unit_test.h>
|
||||
#include <ripple/protocol/ErrorCodes.h>
|
||||
#include <ripple/protocol/JsonFields.h>
|
||||
#include <test/jtx.h>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
namespace test {
|
||||
|
||||
class Roles_test : public beast::unit_test::suite
|
||||
{
|
||||
void
|
||||
testRoles()
|
||||
{
|
||||
using namespace test::jtx;
|
||||
|
||||
{
|
||||
Env env(*this);
|
||||
|
||||
BEAST_EXPECT(env.rpc("ping")["result"]["role"] == "admin");
|
||||
BEAST_EXPECT(makeWSClient(
|
||||
env.app().config())->invoke(
|
||||
"ping")["result"]["unlimited"].asBool());
|
||||
}
|
||||
{
|
||||
Env env { *this, envconfig(no_admin) };
|
||||
|
||||
BEAST_EXPECT(! env.rpc("ping")["result"].isMember("role"));
|
||||
auto wsRes = makeWSClient(
|
||||
env.app().config())->invoke("ping")["result"];
|
||||
BEAST_EXPECT(
|
||||
!wsRes.isMember("unlimited") || !wsRes["unlimited"].asBool());
|
||||
}
|
||||
{
|
||||
Env env { *this, envconfig(secure_gateway) };
|
||||
|
||||
BEAST_EXPECT(env.rpc("ping")["result"]["role"] == "proxied");
|
||||
auto wsRes = makeWSClient(
|
||||
env.app().config())->invoke("ping")["result"];
|
||||
BEAST_EXPECT(
|
||||
!wsRes.isMember("unlimited") || !wsRes["unlimited"].asBool());
|
||||
|
||||
std::unordered_map<std::string, std::string> headers;
|
||||
headers["X-Forwarded-For"] = "12.34.56.78";
|
||||
auto rpcRes = env.rpc(headers, "ping")["result"];
|
||||
BEAST_EXPECT(rpcRes["role"] == "proxied");
|
||||
BEAST_EXPECT(rpcRes["ip"] == "12.34.56.78");
|
||||
|
||||
headers["X-Forwarded-For"] = "87.65.43.21, 44.33.22.11";
|
||||
rpcRes = env.rpc(headers, "ping")["result"];
|
||||
BEAST_EXPECT(rpcRes["ip"] == "87.65.43.21");
|
||||
headers.erase("X-Forwarded-For");
|
||||
|
||||
headers["Forwarded"] = "for=88.77.66.55";
|
||||
rpcRes = env.rpc(headers, "ping")["result"];
|
||||
BEAST_EXPECT(rpcRes["ip"] == "88.77.66.55");
|
||||
|
||||
headers["Forwarded"] = "what=where;for=55.66.77.88;for=nobody;"
|
||||
"who=3";
|
||||
rpcRes = env.rpc(headers, "ping")["result"];
|
||||
BEAST_EXPECT(rpcRes["ip"] == "55.66.77.88");
|
||||
|
||||
wsRes = makeWSClient(
|
||||
env.app().config(), true, 2, headers)->invoke("ping")["result"];
|
||||
BEAST_EXPECT(
|
||||
!wsRes.isMember("unlimited") || !wsRes["unlimited"].asBool());
|
||||
|
||||
std::string const name = "xrposhi";
|
||||
headers["X-User"] = name;
|
||||
rpcRes = env.rpc(headers, "ping")["result"];
|
||||
BEAST_EXPECT(rpcRes["role"] == "identified");
|
||||
BEAST_EXPECT(rpcRes["username"] == name);
|
||||
BEAST_EXPECT(rpcRes["ip"] == "55.66.77.88");
|
||||
wsRes = makeWSClient(
|
||||
env.app().config(), true, 2, headers)->invoke("ping")["result"];
|
||||
BEAST_EXPECT(wsRes["unlimited"].asBool());
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
void
|
||||
run() override
|
||||
{
|
||||
testRoles();
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(Roles, app, ripple);
|
||||
|
||||
} // namespace test
|
||||
|
||||
} // namespace ripple
|
||||
@@ -43,6 +43,7 @@
|
||||
#include <test/rpc/OwnerInfo_test.cpp>
|
||||
#include <test/rpc/Peers_test.cpp>
|
||||
#include <test/rpc/RobustTransaction_test.cpp>
|
||||
#include <test/rpc/Roles_test.cpp>
|
||||
#include <test/rpc/RPCCall_test.cpp>
|
||||
#include <test/rpc/RPCOverload_test.cpp>
|
||||
#include <test/rpc/ServerInfo_test.cpp>
|
||||
|
||||
Reference in New Issue
Block a user