mirror of
https://github.com/XRPLF/rippled.git
synced 2026-06-02 08:17:13 +00:00
feat: Add verify_endpoints to help local peer network development (#7268)
Co-authored-by: xrplf-ai-reviewer[bot] <266832837+xrplf-ai-reviewer[bot]@users.noreply.github.com>
This commit is contained in:
@@ -527,6 +527,17 @@
|
||||
#
|
||||
# The current default (which is subject to change) is 300 seconds.
|
||||
#
|
||||
# verify_endpoints = <0 | 1>
|
||||
#
|
||||
# If set to 0, the server will skip validation of endpoint
|
||||
# addresses received in TMEndpoints peer protocol messages,
|
||||
# allowing addresses that are not publicly routable or have a
|
||||
# port of 0. The default is 1 (verification enabled).
|
||||
#
|
||||
# WARNING: Disabling this option is a security risk and should
|
||||
# only be used for local testing and debugging. Do not disable
|
||||
# on mainnet.
|
||||
#
|
||||
#
|
||||
# [transaction_queue] EXPERIMENTAL
|
||||
#
|
||||
|
||||
@@ -326,3 +326,4 @@ words:
|
||||
- xrplf
|
||||
- xxhash
|
||||
- xxhasher
|
||||
- CGNAT
|
||||
|
||||
@@ -14,7 +14,45 @@ isPrivate(AddressV4 const& addr)
|
||||
bool
|
||||
isPublic(AddressV4 const& addr)
|
||||
{
|
||||
return !isPrivate(addr) && !addr.is_multicast();
|
||||
if (isPrivate(addr))
|
||||
return false;
|
||||
if (addr.is_multicast())
|
||||
return false;
|
||||
|
||||
auto const ip = addr.to_uint();
|
||||
|
||||
// 0.0.0.0/8 "This network"
|
||||
if ((ip & 0xff000000) == 0x00000000)
|
||||
return false;
|
||||
// 100.64.0.0/10 Shared Address Space (CGNAT) - RFC 6598
|
||||
if ((ip & 0xffc00000) == 0x64400000)
|
||||
return false;
|
||||
// 169.254.0.0/16 Link-local
|
||||
if ((ip & 0xffff0000) == 0xa9fe0000)
|
||||
return false;
|
||||
// 192.0.0.0/24 IETF Protocol Assignments - RFC 6890
|
||||
if ((ip & 0xffffff00) == 0xc0000000)
|
||||
return false;
|
||||
// 192.0.2.0/24 TEST-NET-1 (documentation) - RFC 5737
|
||||
if ((ip & 0xffffff00) == 0xc0000200)
|
||||
return false;
|
||||
// 192.88.99.0/24 6to4 Relay Anycast (deprecated) - RFC 7526
|
||||
if ((ip & 0xffffff00) == 0xc0586300)
|
||||
return false;
|
||||
// 198.18.0.0/15 Benchmarking - RFC 2544
|
||||
if ((ip & 0xfffe0000) == 0xc6120000)
|
||||
return false;
|
||||
// 198.51.100.0/24 TEST-NET-2 (documentation) - RFC 5737
|
||||
if ((ip & 0xffffff00) == 0xc6336400)
|
||||
return false;
|
||||
// 203.0.113.0/24 TEST-NET-3 (documentation) - RFC 5737
|
||||
if ((ip & 0xffffff00) == 0xcb007100)
|
||||
return false;
|
||||
// 240.0.0.0/4 Reserved for future use - RFC 1112
|
||||
if ((ip & 0xf0000000) == 0xf0000000)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
char
|
||||
|
||||
@@ -9,17 +9,53 @@ namespace beast::IP {
|
||||
bool
|
||||
isPrivate(AddressV6 const& addr)
|
||||
{
|
||||
return (
|
||||
((addr.to_bytes()[0] & 0xfd) != 0) || // TODO fc00::/8 too ?
|
||||
(addr.is_v4_mapped() &&
|
||||
isPrivate(boost::asio::ip::make_address_v4(boost::asio::ip::v4_mapped, addr))));
|
||||
// fc00::/7 - Unique Local Address (ULA), covers fc00:: and fd00::
|
||||
if ((addr.to_bytes()[0] & 0xfe) == 0xfc)
|
||||
return true;
|
||||
if (addr.is_v4_mapped())
|
||||
return isPrivate(boost::asio::ip::make_address_v4(boost::asio::ip::v4_mapped, addr));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
isPublic(AddressV6 const& addr)
|
||||
{
|
||||
// TODO is this correct?
|
||||
return !isPrivate(addr) && !addr.is_multicast();
|
||||
if (addr.is_loopback())
|
||||
return false;
|
||||
if (addr.is_v4_mapped())
|
||||
return isPublic(boost::asio::ip::make_address_v4(boost::asio::ip::v4_mapped, addr));
|
||||
if (isPrivate(addr))
|
||||
return false;
|
||||
if (addr.is_multicast())
|
||||
return false;
|
||||
if (addr.is_unspecified())
|
||||
return false;
|
||||
|
||||
auto const b = addr.to_bytes();
|
||||
|
||||
// fe80::/10 - Link-local
|
||||
if (b[0] == 0xfe && (b[1] & 0xc0) == 0x80)
|
||||
return false;
|
||||
// 100::/64 - Discard prefix (RFC 6666)
|
||||
if (b[0] == 0x01 && b[1] == 0x00 && b[2] == 0 && b[3] == 0 && b[4] == 0 && b[5] == 0 &&
|
||||
b[6] == 0 && b[7] == 0)
|
||||
return false;
|
||||
// 2001:db8::/32 - Documentation (RFC 3849)
|
||||
if (b[0] == 0x20 && b[1] == 0x01 && b[2] == 0x0d && b[3] == 0xb8)
|
||||
return false;
|
||||
// 2001::/32 - IETF Protocol Assignments / Teredo (RFC 4380)
|
||||
if (b[0] == 0x20 && b[1] == 0x01 && b[2] == 0x00 && b[3] == 0x00)
|
||||
return false;
|
||||
// 2001:20::/28 - ORCHIDv2 (RFC 7343)
|
||||
// 28-bit prefix: 0x2001002 => b[0]=0x20, b[1]=0x01, b[2]=0x00,
|
||||
// top nibble of b[3]=0x2
|
||||
if (b[0] == 0x20 && b[1] == 0x01 && b[2] == 0x00 && (b[3] & 0xf0) == 0x20)
|
||||
return false;
|
||||
// 2002::/16 - 6to4 (RFC 3056, deprecated by RFC 7526)
|
||||
if (b[0] == 0x20 && b[1] == 0x02)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace beast::IP
|
||||
|
||||
@@ -424,7 +424,7 @@ public:
|
||||
(c.PEERS_MAX == max && c.PEERS_IN_MAX == 0 && c.PEERS_OUT_MAX == 0) ||
|
||||
(c.PEERS_IN_MAX == *maxIn && c.PEERS_OUT_MAX == *maxOut));
|
||||
|
||||
Config const config = Config::makeConfig(c, port, false, 0);
|
||||
Config const config = Config::makeConfig(c, port, false, 0, true);
|
||||
|
||||
Counts counts;
|
||||
counts.onConfig(config);
|
||||
|
||||
@@ -1357,7 +1357,7 @@ ApplicationImp::setup(boost::program_options::variables_map const& cmdline)
|
||||
// if (!config_.standalone())
|
||||
overlay_ = makeOverlay(
|
||||
*this,
|
||||
setupOverlay(*config_),
|
||||
setupOverlay(*config_, journal_),
|
||||
*serverHandler_,
|
||||
*resourceManager_,
|
||||
*resolver_,
|
||||
|
||||
@@ -47,6 +47,7 @@ public:
|
||||
std::uint32_t crawlOptions = 0;
|
||||
std::optional<std::uint32_t> networkID;
|
||||
bool vlEnabled = true;
|
||||
bool verifyEndpoints = true;
|
||||
};
|
||||
|
||||
using PeerSequence = std::vector<std::shared_ptr<Peer>>;
|
||||
|
||||
@@ -508,7 +508,8 @@ OverlayImpl::start()
|
||||
app_.config(),
|
||||
serverHandler_.setup().overlay.port(),
|
||||
app_.getValidationPublicKey().has_value(),
|
||||
setup_.ipLimit);
|
||||
setup_.ipLimit,
|
||||
setup_.verifyEndpoints);
|
||||
|
||||
peerFinder_->setConfig(config);
|
||||
peerFinder_->start();
|
||||
@@ -1510,7 +1511,7 @@ OverlayImpl::deleteIdlePeers()
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
Overlay::Setup
|
||||
setupOverlay(BasicConfig const& config)
|
||||
setupOverlay(BasicConfig const& config, beast::Journal j)
|
||||
{
|
||||
Overlay::Setup setup;
|
||||
|
||||
@@ -1528,9 +1529,17 @@ setupOverlay(BasicConfig const& config)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
setup.publicIp = boost::asio::ip::make_address(ip, ec);
|
||||
if (ec || beast::IP::isPrivate(setup.publicIp))
|
||||
if (ec || !beast::IP::isPublic(setup.publicIp))
|
||||
Throw<std::runtime_error>("Configured public IP is invalid");
|
||||
}
|
||||
|
||||
set(setup.verifyEndpoints, true, "verify_endpoints", section);
|
||||
if (!setup.verifyEndpoints)
|
||||
{
|
||||
JLOG(j.warn()) << "Endpoint verification is disabled. This is a "
|
||||
"security risk and should only be used for "
|
||||
"testing.";
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
namespace xrpl {
|
||||
|
||||
Overlay::Setup
|
||||
setupOverlay(BasicConfig const& config);
|
||||
setupOverlay(BasicConfig const& config, beast::Journal j);
|
||||
|
||||
/** Creates the implementation of Overlay. */
|
||||
std::unique_ptr<Overlay>
|
||||
|
||||
@@ -59,6 +59,9 @@ struct Config
|
||||
/** Limit how many incoming connections we allow per IP */
|
||||
int ipLimit{0};
|
||||
|
||||
/** `true` if we want to verify endpoints in TMEndpoints messages */
|
||||
bool verifyEndpoints = true;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/** Create a configuration with default values. */
|
||||
@@ -81,6 +84,8 @@ struct Config
|
||||
* @param port server's listening port
|
||||
* @param validationPublicKey true if validation public key is not empty
|
||||
* @param ipLimit limit of incoming connections per IP
|
||||
* @param verifyEndpoints `true` if we want to verify endpoints in
|
||||
* TMEndpoints messages
|
||||
* @return PeerFinder::Config
|
||||
*/
|
||||
static Config
|
||||
@@ -88,10 +93,11 @@ struct Config
|
||||
xrpl::Config const& config,
|
||||
std::uint16_t port,
|
||||
bool validationPublicKey,
|
||||
int ipLimit);
|
||||
int ipLimit,
|
||||
bool verifyEndpoints);
|
||||
|
||||
friend bool
|
||||
operator==(Config const& lhs, Config const& rhs);
|
||||
operator==(Config const& lhs, Config const& rhs) = default;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -696,7 +696,7 @@ public:
|
||||
}
|
||||
|
||||
// Discard invalid addresses
|
||||
if (!isValidAddress(ep.address))
|
||||
if (config_.verifyEndpoints && !isValidAddress(ep.address))
|
||||
{
|
||||
JLOG(journal.debug())
|
||||
<< beast::Leftw(18) << "Endpoints drop " << ep.address << " as invalid";
|
||||
@@ -1088,6 +1088,8 @@ public:
|
||||
{
|
||||
if (isUnspecified(address))
|
||||
return false;
|
||||
if (isLoopback(address))
|
||||
return false;
|
||||
if (!isPublic(address))
|
||||
return false;
|
||||
if (address.port() == 0)
|
||||
|
||||
@@ -15,16 +15,6 @@ Config::Config() : outPeers(calcOutPeers())
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
operator==(Config const& lhs, Config const& rhs)
|
||||
{
|
||||
return lhs.autoConnect == rhs.autoConnect && lhs.peerPrivate == rhs.peerPrivate &&
|
||||
lhs.wantIncoming == rhs.wantIncoming && lhs.inPeers == rhs.inPeers &&
|
||||
lhs.maxPeers == rhs.maxPeers && lhs.outPeers == rhs.outPeers &&
|
||||
lhs.features == rhs.features && lhs.ipLimit == rhs.ipLimit &&
|
||||
lhs.listeningPort == rhs.listeningPort;
|
||||
}
|
||||
|
||||
std::size_t
|
||||
Config::calcOutPeers() const
|
||||
{
|
||||
@@ -61,6 +51,7 @@ Config::onWrite(beast::PropertyStream::Map& map) const
|
||||
map["port"] = listeningPort;
|
||||
map["features"] = features;
|
||||
map["ip_limit"] = ipLimit;
|
||||
map["verify_endpoints"] = verifyEndpoints;
|
||||
}
|
||||
|
||||
Config
|
||||
@@ -68,7 +59,8 @@ Config::makeConfig(
|
||||
xrpl::Config const& cfg,
|
||||
std::uint16_t port,
|
||||
bool validationPublicKey,
|
||||
int ipLimit)
|
||||
int ipLimit,
|
||||
bool verifyEndpoints)
|
||||
{
|
||||
PeerFinder::Config config;
|
||||
|
||||
@@ -121,6 +113,7 @@ Config::makeConfig(
|
||||
config.listeningPort = port;
|
||||
config.features = "";
|
||||
config.ipLimit = ipLimit;
|
||||
config.verifyEndpoints = verifyEndpoints;
|
||||
|
||||
// Enforce business rules
|
||||
config.applyTuning();
|
||||
|
||||
Reference in New Issue
Block a user