mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-27 06:25:51 +00:00
Allow multiple incoming connections from the same IP:
Multiple servers behind NAT might share a single public IP, making it difficult for them to connect to the Ripple network since multiple incoming connections from the same non-private IP are currently not allowed. RippleD now automatically allows between 2 and 5 incoming connections, from the same public IP based on the total number of peers that it is configured to accept. Administrators can manually change the limit by adding an "ip_limit" key value pair in the [overlay] stanza of the configuration file and specifying a positive non-zero number. For example: [overlay] ip_limit=3 The previous "one connection per IP" strategy can be emulated by setting "ip_limit" to 1. The implementation imposes both soft and hard upper limits and will adjust the value so that a single IP cannot consume all inbound slots.
This commit is contained in:
@@ -373,6 +373,15 @@
|
|||||||
# Peers will use this information to reject attempt to proxy
|
# Peers will use this information to reject attempt to proxy
|
||||||
# connections to or from this server.
|
# connections to or from this server.
|
||||||
#
|
#
|
||||||
|
# ip_limit = <number>
|
||||||
|
#
|
||||||
|
# The maximum number of incoming peer connections allowed by a single
|
||||||
|
# IP that isn't classified as "private" in RFC1918. The implementation
|
||||||
|
# imposes some hard and soft upper limits on this value to prevent a
|
||||||
|
# single host from consuming all inbound slots. If the value is not
|
||||||
|
# present the server will autoconfigure an appropriate limit.
|
||||||
|
#
|
||||||
|
#
|
||||||
#
|
#
|
||||||
# [transaction_queue] EXPERIMENTAL
|
# [transaction_queue] EXPERIMENTAL
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -208,7 +208,7 @@ public:
|
|||||||
|
|
||||||
// Peer networking parameters
|
// Peer networking parameters
|
||||||
bool PEER_PRIVATE = false; // True to ask peers not to relay current IP.
|
bool PEER_PRIVATE = false; // True to ask peers not to relay current IP.
|
||||||
unsigned int PEERS_MAX = 0;
|
int PEERS_MAX = 0;
|
||||||
|
|
||||||
int WEBSOCKET_PING_FREQ = 5 * 60;
|
int WEBSOCKET_PING_FREQ = 5 * 60;
|
||||||
|
|
||||||
|
|||||||
@@ -371,11 +371,12 @@ void Config::loadFromString (std::string const& fileContents)
|
|||||||
(void) getSingleSection (secConfig, SECTION_VALIDATORS_SITE, VALIDATORS_SITE, j_);
|
(void) getSingleSection (secConfig, SECTION_VALIDATORS_SITE, VALIDATORS_SITE, j_);
|
||||||
|
|
||||||
std::string strTemp;
|
std::string strTemp;
|
||||||
|
|
||||||
if (getSingleSection (secConfig, SECTION_PEER_PRIVATE, strTemp, j_))
|
if (getSingleSection (secConfig, SECTION_PEER_PRIVATE, strTemp, j_))
|
||||||
PEER_PRIVATE = beast::lexicalCastThrow <bool> (strTemp);
|
PEER_PRIVATE = beast::lexicalCastThrow <bool> (strTemp);
|
||||||
|
|
||||||
if (getSingleSection (secConfig, SECTION_PEERS_MAX, strTemp, j_))
|
if (getSingleSection (secConfig, SECTION_PEERS_MAX, strTemp, j_))
|
||||||
PEERS_MAX = beast::lexicalCastThrow <int> (strTemp);
|
PEERS_MAX = std::max (0, beast::lexicalCastThrow <int> (strTemp));
|
||||||
|
|
||||||
if (getSingleSection (secConfig, SECTION_NODE_SIZE, strTemp, j_))
|
if (getSingleSection (secConfig, SECTION_NODE_SIZE, strTemp, j_))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ public:
|
|||||||
std::shared_ptr<boost::asio::ssl::context> context;
|
std::shared_ptr<boost::asio::ssl::context> context;
|
||||||
bool expire = false;
|
bool expire = false;
|
||||||
beast::IP::Address public_ip;
|
beast::IP::Address public_ip;
|
||||||
|
int ipLimit = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
using PeerSequence = std::vector <Peer::ptr>;
|
using PeerSequence = std::vector <Peer::ptr>;
|
||||||
|
|||||||
@@ -506,6 +506,7 @@ OverlayImpl::onPrepare()
|
|||||||
!app_.config().PEER_PRIVATE;
|
!app_.config().PEER_PRIVATE;
|
||||||
config.listeningPort = port;
|
config.listeningPort = port;
|
||||||
config.features = "";
|
config.features = "";
|
||||||
|
config.ipLimit = setup_.ipLimit;
|
||||||
|
|
||||||
// Enforce business rules
|
// Enforce business rules
|
||||||
config.applyTuning();
|
config.applyTuning();
|
||||||
@@ -1056,6 +1057,10 @@ setup_Overlay (BasicConfig const& config)
|
|||||||
setup.context = make_SSLContext();
|
setup.context = make_SSLContext();
|
||||||
setup.expire = get<bool>(section, "expire", false);
|
setup.expire = get<bool>(section, "expire", false);
|
||||||
|
|
||||||
|
set (setup.ipLimit, "ip_limit", section);
|
||||||
|
if (setup.ipLimit < 0)
|
||||||
|
throw std::runtime_error ("Configured IP limit is invalid");
|
||||||
|
|
||||||
std::string ip;
|
std::string ip;
|
||||||
set (ip, "public_ip", section);
|
set (ip, "public_ip", section);
|
||||||
if (! ip.empty ())
|
if (! ip.empty ())
|
||||||
|
|||||||
@@ -73,6 +73,9 @@ struct Config
|
|||||||
/** The set of features we advertise. */
|
/** The set of features we advertise. */
|
||||||
std::string features;
|
std::string features;
|
||||||
|
|
||||||
|
/** Limit how many incoming connections we allow per IP */
|
||||||
|
int ipLimit;
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
/** Create a configuration with default values. */
|
/** Create a configuration with default values. */
|
||||||
|
|||||||
@@ -263,13 +263,13 @@ public:
|
|||||||
// Check for duplicate connection
|
// Check for duplicate connection
|
||||||
if (is_public (remote_endpoint))
|
if (is_public (remote_endpoint))
|
||||||
{
|
{
|
||||||
auto const iter = connectedAddresses_.find (
|
auto const count = connectedAddresses_.count (
|
||||||
remote_endpoint.address());
|
remote_endpoint.address());
|
||||||
if (iter != connectedAddresses_.end())
|
if (count > config_.ipLimit)
|
||||||
{
|
{
|
||||||
if (m_journal.debug) m_journal.debug << beast::leftw (18) <<
|
if (m_journal.debug) m_journal.debug << beast::leftw (18) <<
|
||||||
"Logic dropping inbound " << remote_endpoint <<
|
"Logic dropping inbound " << remote_endpoint <<
|
||||||
" as duplicate";
|
" because of ip limits.";
|
||||||
return SlotImp::ptr();
|
return SlotImp::ptr();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ Config::Config()
|
|||||||
, wantIncoming (true)
|
, wantIncoming (true)
|
||||||
, autoConnect (true)
|
, autoConnect (true)
|
||||||
, listeningPort (0)
|
, listeningPort (0)
|
||||||
|
, ipLimit (0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,6 +46,25 @@ void Config::applyTuning ()
|
|||||||
if (maxPeers < Tuning::minOutCount)
|
if (maxPeers < Tuning::minOutCount)
|
||||||
maxPeers = Tuning::minOutCount;
|
maxPeers = Tuning::minOutCount;
|
||||||
outPeers = calcOutPeers ();
|
outPeers = calcOutPeers ();
|
||||||
|
|
||||||
|
auto const inPeers = maxPeers - outPeers;
|
||||||
|
|
||||||
|
if (ipLimit == 0)
|
||||||
|
{
|
||||||
|
// Unless a limit is explicitly set, we allow between
|
||||||
|
// 2 and 5 connections from non RFC-1918 "private"
|
||||||
|
// IP addresses.
|
||||||
|
ipLimit = 2;
|
||||||
|
|
||||||
|
if (inPeers > Tuning::defaultMaxPeers)
|
||||||
|
ipLimit += std::min(5,
|
||||||
|
static_cast<int>(inPeers / Tuning::defaultMaxPeers));
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't allow a single IP to consume all incoming slots,
|
||||||
|
// unless we only have one incoming slot available.
|
||||||
|
ipLimit = std::max(1,
|
||||||
|
std::min(ipLimit, static_cast<int>(inPeers / 2)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Config::onWrite (beast::PropertyStream::Map &map)
|
void Config::onWrite (beast::PropertyStream::Map &map)
|
||||||
@@ -55,6 +75,7 @@ void Config::onWrite (beast::PropertyStream::Map &map)
|
|||||||
map ["auto_connect"] = autoConnect;
|
map ["auto_connect"] = autoConnect;
|
||||||
map ["port"] = listeningPort;
|
map ["port"] = listeningPort;
|
||||||
map ["features"] = features;
|
map ["features"] = features;
|
||||||
|
map ["ip_limit"] = ipLimit;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user