Compare commits

..

22 Commits

Author SHA1 Message Date
Nik Bougalis
ad2383bd4b Set version to 0.30.0-hf2 2016-01-27 12:27:27 -08:00
Nik Bougalis
5b5a01989c Improve compile-time OpenSSL version check 2016-01-27 12:27:18 -08:00
seelabs
c17f7e8b37 Enforce no-ripple constraints 2016-01-26 13:52:41 -08:00
Nik Bougalis
aa4f347e7c Set version to 0.30.0-hf1 2015-11-05 16:47:41 -08:00
Vinnie Falco
0a0adaac6d Set admin privileges on websocket:
When the websocket connection is established, any configured administrative
privileges are applied to resource limits.
2015-11-05 16:45:19 -08:00
JoelKatz
3d2aae9ea5 Make close time consensus detection use montonic close time rules 2015-11-04 13:49:54 -08:00
JoelKatz
3d5ff2b4cd Prevent some missed proposals, faster consensus catch up 2015-11-04 13:49:54 -08:00
David Schwartz
d20f0d5014 Make sure LedgerHistory::builtLedger gets called 2015-11-03 14:00:28 -08:00
Vinnie Falco
a8859b495b Set version to 0.30.0 2015-10-21 18:26:02 -07:00
Miguel Portilla
caccee1d98 Set version to 0.30.0-rc1 2015-10-01 14:18:56 -04:00
seelabs
379110a8a2 Improve treatment of signature components 2015-09-30 21:44:02 -04:00
Miguel Portilla
8d37cd9169 Disable RPC coroutines 2015-09-30 19:05:00 -04:00
Nik Bougalis
b40ade5165 Set version to 0.30.0-b1 2015-09-28 17:30:42 -07:00
wilsonianb
c475b23c7d Fix and update rippled.spec for rpm builds 2015-09-28 17:24:05 -07:00
Miguel Portilla
d6b9cfcc34 Enable websocket coroutines 2015-09-28 17:24:05 -07:00
JoelKatz
0c05bd3def Improve transport security:
* Add fields for local and remote IP addresses in hello.
* Add configuration for known local public IP address
* Set fields appropriately
* Check the fields
* Disallow self connection by key
2015-09-28 17:24:05 -07:00
JoelKatz
8f7ab21423 IPAddressV4 fixes:
* Loopback addresses are not publicly routable
* The Internet is not classful
2015-09-28 17:24:04 -07:00
JoelKatz
07418cfb34 Make transaction ordering much more difficult to predict
Randomize the initial transaction execution order for closed
ledgers based on the hash of the consensus set. Transaction
processing change will take effect October 27, 2015 at
11:00 AM Pacific time.
2015-09-28 17:24:04 -07:00
Vinnie Falco
ac9816c01d Release PeerFinder slot on error 2015-09-28 17:24:04 -07:00
Nik Bougalis
bd3e4ac11c Correctly parse the --rpc_port command line argument 2015-09-28 16:49:46 -07:00
Nik Bougalis
926d08db6f Adjust ledger switch time and disambiguate logging:
- The new activation date for 1e9624270d
  is now October 27, 2015 at 11:00 PDT
2015-09-28 16:49:35 -07:00
Nik Bougalis
a23f6457dc Initialize HTTP client after the config is loaded 2015-09-27 13:17:20 -07:00
27 changed files with 276 additions and 148 deletions

View File

@@ -1,14 +1,18 @@
%define rippled_branch %(echo $RIPPLED_BRANCH)
Name: rippled
Version: 0.29.1-rc1
Release: 1%{?dist}
# Version must be limited to MAJOR.MINOR.PATCH
Version: 0.30.0
# Release should include either the build or hotfix number (ex: hf1%{?dist} or b2%{?dist})
# If there is no b# or hf#, then use 1%{?dist}
Release: %{?dist}
Summary: Ripple peer-to-peer network daemon
Group: Applications/Internet
License: ISC
URL: https://github.com/ripple/rippled
# curl -L -o SOURCES/rippled-release.zip https://github.com/ripple/rippled/archive/release.zip
Source0: rippled-release.zip
# curl -L -o SOURCES/rippled-release.zip https://github.com/ripple/rippled/archive/${RIPPLED_BRANCH}.zip
Source0: rippled-%{rippled_branch}.zip
BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)
BuildRequires: gcc-c++ scons openssl-devel protobuf-devel
@@ -20,13 +24,11 @@ Rippled is the server component of the Ripple network.
%prep
%setup -n rippled-release
%setup -n rippled-%{rippled_branch}
%build
# Assume boost is manually installed
export RIPPLED_BOOST_HOME=/usr/local/boost_1_55_0
scons -j `grep -c processor /proc/cpuinfo` build/rippled
scons -j `grep -c processor /proc/cpuinfo`
%install
@@ -49,4 +51,4 @@ rm -rf %{buildroot}
%defattr(-,root,root,-)
/usr/bin/rippled
/usr/share/rippled/LICENSE
/etc/rippled/rippled-example.cfg
%config(noreplace) /etc/rippled/rippled.cfg

View File

@@ -114,7 +114,13 @@ AddOption('--ninja', dest='ninja', action='store_true',
help='generate ninja build file build.ninja')
def parse_time(t):
return time.strptime(t, '%a %b %d %H:%M:%S %Z %Y')
l = len(t.split())
if l==5:
return time.strptime(t, '%a %b %d %H:%M:%S %Y')
elif l==3:
return time.strptime(t, '%d %b %Y')
else:
return time.strptime(t, '%a %b %d %H:%M:%S %Z %Y')
CHECK_PLATFORMS = 'Debian', 'Ubuntu'
CHECK_COMMAND = 'openssl version -a'
@@ -126,17 +132,24 @@ UNITY_BUILD_DIRECTORY = 'src/ripple/unity/'
USE_CPP_14 = os.getenv('RIPPLED_USE_CPP_14')
def check_openssl():
if Beast.system.platform in CHECK_PLATFORMS:
for line in subprocess.check_output(CHECK_COMMAND.split()).splitlines():
if line.startswith(CHECK_LINE):
line = line[len(CHECK_LINE):]
if parse_time(line) < parse_time(BUILD_TIME):
raise Exception(OPENSSL_ERROR % (line, BUILD_TIME))
else:
break
else:
raise Exception("Didn't find any '%s' line in '$ %s'" %
(CHECK_LINE, CHECK_COMMAND))
if Beast.system.platform not in ['Debian', 'Ubuntu']:
return
line = subprocess.check_output('openssl version -b'.split()).strip()
check_line = 'built on: '
if not line.startswith(check_line):
raise Exception("Didn't find any '%s' line in '$ %s'" %
(check_line, 'openssl version -b'))
d = line[len(check_line):]
if 'date unspecified' in d:
words = subprocess.check_output('openssl version'.split()).split()
if len(words)!=5:
raise Exception("Didn't find version date in '$ openssl version'")
d = ' '.join(words[-3:])
build_time = 'Mon Apr 7 20:33:19 UTC 2014'
if parse_time(d) < parse_time(build_time):
raise Exception('Your openSSL was built on %s; '
'rippled needs a version built on or after %s.'
% (line, build_time))
def set_implicit_cache():

View File

@@ -359,38 +359,18 @@
#
#
#
# [overlay] EXPERIMENTAL
# [overlay]
#
# This section is EXPERIMENTAL, and should not be
# present for production configuration settings.
# Controls settings related to the peer to peer overlay.
#
# A set of key/value pair parameters to configure the overlay.
#
# auto_connect = 0 | 1
#
# When set, activates the autoconnect feature. This maintains outgoing
# connections using PeerFinder's "Outgoing Connection Strategy."
#
# become_superpeer = 'never' | 'always' | 'auto'
#
# Controls the selection of peer roles:
#
# 'never' Always handshake in the leaf role.
# 'always' Always handshake in the superpeer role.
# 'auto' Start as a leaf, promote to superpeer after
# passing capability check (default).
#
# In the leaf role, a peer does not advertise its IP and port for
# the purpose of receiving incoming connections. The peer also does
# not forward transactions and validations received from other peers.
#
# In the superpeer role, a peer advertises its IP and port for
# receiving incoming connections after passing an incoming connection
# test. Superpeers forward transactions and protocol messages to all
# other peers. Superpeers do not forward validations to other superpeers.
# Instead, a validation received by a superpeer from a leaf is forwarded
# only to other leaf connections.
# public_ip = <IP-address>
#
# If the server has a known, fixed public IPv4 address,
# specify that IP address here in dotted decimal notation.
# Peers will use this information to reject attempt to proxy
# connections to or from this server.
#
#
#-------------------------------------------------------------------------------

View File

@@ -147,8 +147,7 @@ bool is_public (AddressV4 const& addr)
{
return
! is_private (addr) &&
! is_multicast (addr) &&
(addr != AddressV4::broadcast (addr));
! is_multicast (addr);
}
//------------------------------------------------------------------------------

View File

@@ -298,6 +298,13 @@ LedgerConsensusImp::LedgerConsensusImp (
// update the network status table as to whether we're
// proposing/validating
consensus_.setProposing (mProposing, mValidating);
playbackProposals ();
if (mPeerPositions.size () > (mPreviousProposers / 2))
{
// We may be falling behind, don't wait for the timer
timerEntry ();
}
}
Json::Value LedgerConsensusImp::getJson (bool full)
@@ -479,9 +486,15 @@ void LedgerConsensusImp::mapCompleteInternal (
else
assert (false); // We don't have our own position?!
}
else
else if (!mOurPosition)
JLOG (j_.debug)
<< "Not creating disputes: no position yet.";
else if (mOurPosition->isBowOut ())
JLOG (j_.warning)
<< "Not ready to create disputes";
<< "Not creating disputes: not participating.";
else
JLOG (j_.debug)
<< "Not creating disputes: identical position.";
mAcquired[hash] = map;
@@ -970,8 +983,6 @@ void LedgerConsensusImp::accept (std::shared_ptr<SHAMap> set)
consensus_.takePosition (mPreviousLedger->info().seq, set);
assert (set->getHash () == mOurPosition->getCurrentHash ());
// these are now obsolete
consensus_.peekStoredProposals ().clear ();
}
auto closeTime = mOurPosition->getCloseTime();
@@ -993,8 +1004,8 @@ void LedgerConsensusImp::accept (std::shared_ptr<SHAMap> set)
// If we don't have a close time, then we just agree to disagree
bool const closeTimeCorrect = (closeTime != 0);
// Switch to new semantics on Sep 30, 2015 at 11:00:00am PDT
if (mPreviousLedger->info().closeTime > 497296800)
// Switch to new semantics on Oct 27, 2015 at 11:00:00am PDT
if (mPreviousLedger->info().closeTime > 499284000)
{
// Ledger close times should increase strictly monotonically
if (closeTime <= mPreviousLedger->info().closeTime)
@@ -1017,7 +1028,7 @@ void LedgerConsensusImp::accept (std::shared_ptr<SHAMap> set)
<< "Report: TxSt = " << set->getHash ()
<< ", close " << closeTime << (closeTimeCorrect ? "" : "X");
// Put failed transactions into a deterministic order
// Put transactions into a deterministic, but unpredictable, order
CanonicalTXSet retriableTxs (set->getHash ());
// Build the new last closed ledger
@@ -1540,8 +1551,10 @@ void LedgerConsensusImp::updateOurPositions ()
else
{
// proposal is still fresh
++closeTimes[roundCloseTime (
it->second->getCloseTime (), mCloseResolution)];
++closeTimes[std::max (
roundCloseTime (it->second->getCloseTime (),
mCloseResolution),
mPreviousLedger->info().closeTime + 1)];
++it;
}
}
@@ -1593,16 +1606,20 @@ void LedgerConsensusImp::updateOurPositions ()
{
// no other times
mHaveCloseTimeConsensus = true;
closeTime = roundCloseTime (
mOurPosition->getCloseTime (), mCloseResolution);
closeTime = std::max(
roundCloseTime (mOurPosition->getCloseTime (),
mCloseResolution),
mPreviousLedger->info().closeTime + 1);
}
else
{
int participants = mPeerPositions.size ();
if (mProposing)
{
++closeTimes[roundCloseTime (
mOurPosition->getCloseTime (), mCloseResolution)];
++closeTimes[std::max (
roundCloseTime (mOurPosition->getCloseTime (),
mCloseResolution),
mPreviousLedger->info().closeTime + 1)];
++participants;
}
@@ -1652,8 +1669,7 @@ void LedgerConsensusImp::updateOurPositions ()
}
if (!changes &&
((closeTime != roundCloseTime (
mOurPosition->getCloseTime (), mCloseResolution))
((closeTime != mOurPosition->getCloseTime ())
|| mOurPosition->isStale (ourCutoff)))
{
// close time changed or our position is stale
@@ -1866,6 +1882,11 @@ void applyTransactions (
CanonicalTXSet& retriableTxs,
ApplyFlags flags)
{
// Switch to new transaction ordering on
// October 27, 2015 at 11:00AM PDT
bool const newTxOrder = checkLedger->info().closeTime > 499284000;
auto j = app.journal ("LedgerConsensus");
if (set)
{
@@ -1889,11 +1910,15 @@ void applyTransactions (
if (txn)
{
if (applyTransaction(app, view, txn, true, flags, j) ==
if (newTxOrder)
{
// All transactions execute in canonical order
retriableTxs.insert (txn);
}
else if (applyTransaction(app, view, txn, true, flags, j) ==
LedgerConsensusImp::resultRetry)
{
// On failure, stash the failed transaction for
// later retry.
// Failures are retried in canonical order
retriableTxs.insert (txn);
}
}

View File

@@ -972,6 +972,8 @@ public:
<< "Consensus triggered check of ledger";
checkAccept (maxLedger, maxSeq);
}
mLedgerHistory.builtLedger (ledger);
}
void advanceThread()

View File

@@ -282,7 +282,7 @@ int run (int argc, char** argv)
("conf", po::value<std::string> (), "Specify the configuration file.")
("rpc", "Perform rpc command (default).")
("rpc_ip", po::value <std::string> (), "Specify the IP address for RPC command. Format: <ip-address>[':'<port-number>]")
("rpc_port", po::value <int> (), "Specify the port number for RPC command.")
("rpc_port", po::value <std::uint16_t> (), "Specify the port number for RPC command.")
("standalone,a", "Run with no peers.")
("shutdowntest", po::value <std::string> ()->implicit_value (""), "Perform shutdown tests.")
("unittest,u", po::value <std::string> ()->implicit_value (""), "Perform unit tests.")
@@ -438,9 +438,9 @@ int run (int argc, char** argv)
{
try
{
config->rpc_ip =
config->rpc_ip.emplace (
boost::asio::ip::address_v4::from_string(
vm["rpc_ip"].as<std::string>());
vm["rpc_ip"].as<std::string>()));
}
catch(...)
{
@@ -456,7 +456,8 @@ int run (int argc, char** argv)
{
try
{
config->rpc_port = vm["rpc_port"].as<std::uint16_t>();
config->rpc_port.emplace (
vm["rpc_port"].as<std::uint16_t>());
if (*config->rpc_port == 0)
throw std::domain_error ("");

View File

@@ -76,17 +76,17 @@ public:
using const_iterator = std::map <Key, std::shared_ptr<STTx const>>::const_iterator;
public:
explicit CanonicalTXSet (LedgerHash const& lastClosedLedgerHash)
: mSetHash (lastClosedLedgerHash)
explicit CanonicalTXSet (LedgerHash const& saltHash)
: mSetHash (saltHash)
{
}
void insert (std::shared_ptr<STTx const> const& txn);
// VFALCO TODO remove this function
void reset (LedgerHash const& newLastClosedLedgerHash)
void reset (LedgerHash const& saltHash)
{
mSetHash = newLastClosedLedgerHash;
mSetHash = saltHash;
mMap.clear ();
}

View File

@@ -1384,6 +1384,9 @@ void NetworkOPsImp::processTrustedProposal (
bool relay = true;
if (mConsensus)
mConsensus->storeProposal (proposal, nodePublic);
if (!haveConsensusObject ())
{
m_journal.info << "Received proposal outside consensus window";
@@ -1393,8 +1396,6 @@ void NetworkOPsImp::processTrustedProposal (
}
else
{
mConsensus->storeProposal (proposal, nodePublic);
if (mLedgerConsensus->getLCL () == proposal->getPrevLedger ())
{
relay = mLedgerConsensus->peerPosition (proposal);

View File

@@ -242,7 +242,8 @@ Json::Value PathRequest::doCreate (
if (parseJson (value) != PFR_PJ_INVALID)
{
valid = isValid (cache);
status = valid ? doUpdate(cache, true) : jvStatus;
if (! hasCompletion())
status = valid ? doUpdate(cache, true) : jvStatus;
}
else
{

View File

@@ -799,6 +799,19 @@ TER PathState::checkNoRipple (
if (terStatus != tesSUCCESS)
return terStatus;
}
if (!nodes_[i - 1].isAccount() &&
nodes_[i].isAccount() &&
nodes_[i + 1].isAccount() &&
nodes_[i -1].issue_.account != nodes_[i].account_)
{ // offer -> account -> account
auto const& currencyID = nodes_[i].issue_.currency;
terStatus = checkNoRipple (
nodes_[i-1].issue_.account, nodes_[i].account_, nodes_[i+1].account_,
currencyID);
if (terStatus != tesSUCCESS)
return terStatus;
}
}
return tesSUCCESS;

View File

@@ -270,8 +270,6 @@ void Config::setup (std::string const& strConf, bool bQuiet)
}
}
HTTPClient::initializeSSLContext(*this);
// Update default values
load ();
{
@@ -290,6 +288,8 @@ void Config::setup (std::string const& strConf, bool bQuiet)
boost::str (boost::format ("Can not create %s") % dataDir));
legacy ("database_path", boost::filesystem::absolute (dataDir).string ());
HTTPClient::initializeSSLContext(*this);
}
void Config::load ()

View File

@@ -98,7 +98,7 @@ public:
: m_skip (0)
{
// The format is: <02> <length of signature> <signature>
if ((sig[0] != 0x02) || (size < 3))
if ((size < 3) || (sig[0] != 0x02))
return;
std::size_t const len (sig[1]);

View File

@@ -271,12 +271,13 @@ unsigned long RFC1751::extract (char const* s, int start, int length)
assert (length >= 0);
assert (start + length <= 66);
int const shiftR = 24 - (length + (start % 8));
cl = s[start / 8]; // get components
cc = s[start / 8 + 1];
cr = s[start / 8 + 2];
cc = (shiftR < 16) ? s[start / 8 + 1] : 0;
cr = (shiftR < 8) ? s[start / 8 + 2] : 0;
x = ((long) (cl << 8 | cc) << 8 | cr) ; // Put bits together
x = x >> (24 - (length + (start % 8))); // Right justify number
x = x >> shiftR; // Right justify number
x = ( x & (0xffff >> (16 - length) ) ); // Trim extra bits.
return x;

View File

@@ -67,10 +67,9 @@ public:
struct Setup
{
bool auto_connect = true;
Promote promote = Promote::automatic;
std::shared_ptr<boost::asio::ssl::context> context;
bool expire = false;
beast::IP::Address public_ip;
};
using PeerSequence = std::vector <Peer::ptr>;

View File

@@ -218,7 +218,11 @@ ConnectAttempt::onHandshake (error_code ec)
beast::http::message req = makeRequest(
! overlay_.peerFinder().config().peerPrivate,
remote_endpoint_.address());
auto const hello = buildHello (sharedValue, app_);
auto const hello = buildHello (
sharedValue,
overlay_.setup().public_ip,
beast::IPAddressConversion::from_asio(remote_endpoint_),
app_);
appendHello (req, hello);
using beast::http::write;
@@ -399,7 +403,10 @@ ConnectAttempt::processResponse (beast::http::message const& m,
RippleAddress publicKey;
std::tie(publicKey, success) = verifyHello (hello,
sharedValue, journal_, app_);
sharedValue,
overlay_.setup().public_ip,
beast::IPAddressConversion::from_asio(remote_endpoint_),
journal_, app_);
if(! success)
return close(); // verifyHello logs
if(journal_.info) journal_.info <<

View File

@@ -244,7 +244,10 @@ OverlayImpl::onHandoff (std::unique_ptr <beast::asio::ssl_bundle>&& ssl_bundle,
RippleAddress publicKey;
std::tie(publicKey, success) = verifyHello (hello,
sharedValue, journal, app_);
sharedValue,
setup_.public_ip,
beast::IPAddressConversion::from_asio(
remote_endpoint), journal, app_);
if(! success)
return handoff;
@@ -256,6 +259,7 @@ OverlayImpl::onHandoff (std::unique_ptr <beast::asio::ssl_bundle>&& ssl_bundle,
publicKey.toPublicKey(), cluster);
if (result != PeerFinder::Result::success)
{
m_peerFinder->on_closed(slot);
if (journal.debug) journal.debug <<
"Peer " << remote_endpoint << " redirected, slots full";
handoff.moved = false;
@@ -1017,17 +1021,20 @@ setup_Overlay (BasicConfig const& config)
{
Overlay::Setup setup;
auto const& section = config.section("overlay");
set (setup.auto_connect, "auto_connect", section);
std::string promote;
set (promote, "become_superpeer", section);
if (promote == "never")
setup.promote = Overlay::Promote::never;
else if (promote == "always")
setup.promote = Overlay::Promote::always;
else
setup.promote = Overlay::Promote::automatic;
setup.context = make_SSLContext();
setup.expire = get<bool>(section, "expire", false);
std::string ip;
set (ip, "public_ip", section);
if (! ip.empty ())
{
bool valid;
std::tie (setup.public_ip, valid) =
beast::IP::Address::from_string (ip);
if (! valid || ! setup.public_ip.is_v4() ||
is_private (setup.public_ip))
throw std::runtime_error ("Configured public IP is invalid");
}
return setup;
}

View File

@@ -596,7 +596,7 @@ void PeerImp::doAccept()
auto resp = makeResponse(
! overlay_.peerFinder().config().peerPrivate,
http_message_, sharedValue);
http_message_, remote_address_, sharedValue);
beast::http::write (write_buffer_, resp);
auto const protocol = BuildInfo::make_protocol(hello_.protoversion());
@@ -636,7 +636,9 @@ void PeerImp::doAccept()
beast::http::message
PeerImp::makeResponse (bool crawl,
beast::http::message const& req, uint256 const& sharedValue)
beast::http::message const& req,
beast::IP::Endpoint remote,
uint256 const& sharedValue)
{
beast::http::message resp;
resp.request(false);
@@ -648,7 +650,8 @@ PeerImp::makeResponse (bool crawl,
resp.headers.append("Connect-AS", "Peer");
resp.headers.append("Server", BuildInfo::getFullVersionString());
resp.headers.append ("Crawl", crawl ? "public" : "private");
protocol::TMHello hello = buildHello(sharedValue, app_);
protocol::TMHello hello = buildHello(sharedValue,
overlay_.setup().public_ip, remote, app_);
appendHello(resp, hello);
return resp;
}
@@ -1647,22 +1650,6 @@ PeerImp::sendGetPeers ()
send (packet);
}
bool
PeerImp::sendHello()
{
bool success;
std::tie(sharedValue_, success) = makeSharedValue(
stream_.native_handle(), journal_);
if (! success)
return false;
auto const hello = buildHello (sharedValue_, app_);
auto const m = std::make_shared<Message> (
std::move(hello), protocol::mtHELLO);
send (m);
return true;
}
void
PeerImp::addLedger (uint256 const& hash)
{

View File

@@ -361,6 +361,7 @@ private:
beast::http::message
makeResponse (bool crawl, beast::http::message const& req,
beast::IP::Endpoint remoteAddress,
uint256 const& sharedValue);
void
@@ -440,15 +441,6 @@ private:
void
sendGetPeers();
/** Perform a secure handshake with the peer at the other end.
If this function returns false then we cannot guarantee that there
is no active man-in-the-middle attack taking place and the link
MUST be disconnected.
@return true if successful, false otherwise.
*/
bool
sendHello();
void
addLedger (uint256 const& hash);

View File

@@ -106,7 +106,11 @@ makeSharedValue (SSL* ssl, beast::Journal journal)
}
protocol::TMHello
buildHello (uint256 const& sharedValue, Application& app)
buildHello (
uint256 const& sharedValue,
beast::IP::Address public_ip,
beast::IP::Endpoint remote,
Application& app)
{
protocol::TMHello h;
@@ -124,6 +128,18 @@ buildHello (uint256 const& sharedValue, Application& app)
// h.set_ipv4port (portNumber); // ignored now
h.set_testnet (false);
if (remote.is_v4())
{
auto addr = remote.to_v4 ();
if (is_public (addr))
{
// Connection is to a public IP
h.set_remote_ip (addr.value);
if (public_ip != beast::IP::Address())
h.set_local_ip (public_ip.to_v4().value);
}
}
// We always advertise ourselves as private in the HELLO message. This
// suppresses the old peer advertising code and allows PeerFinder to
// take over the functionality.
@@ -168,6 +184,14 @@ appendHello (beast::http::message& m,
if (hello.has_ledgerprevious())
h.append ("Previous-Ledger", beast::base64_encode (
hello.ledgerprevious()));
if (hello.has_local_ip())
h.append ("Local-IP", beast::IP::to_string (
beast::IP::AddressV4(hello.local_ip())));
if (hello.has_remote_ip())
h.append ("Remote-IP", beast::IP::to_string (
beast::IP::AddressV4(hello.remote_ip())));
}
std::vector<ProtocolVersion>
@@ -292,13 +316,47 @@ parseHello (beast::http::message const& m, beast::Journal journal)
hello.set_ledgerprevious (beast::base64_decode (iter->second));
}
{
auto const iter = h.find ("Local-IP");
if (iter != h.end())
{
bool valid;
beast::IP::Address address;
std::tie (address, valid) =
beast::IP::Address::from_string (iter->second);
if (!valid)
return result;
if (address.is_v4())
hello.set_local_ip(address.to_v4().value);
}
}
{
auto const iter = h.find ("Remote-IP");
if (iter != h.end())
{
bool valid;
beast::IP::Address address;
std::tie (address, valid) =
beast::IP::Address::from_string (iter->second);
if (!valid)
return result;
if (address.is_v4())
hello.set_remote_ip(address.to_v4().value);
}
}
result.second = true;
return result;
}
std::pair<RippleAddress, bool>
verifyHello (protocol::TMHello const& h, uint256 const& sharedValue,
beast::Journal journal, Application& app)
verifyHello (protocol::TMHello const& h,
uint256 const& sharedValue,
beast::IP::Address public_ip,
beast::IP::Endpoint remote,
beast::Journal journal,
Application& app)
{
std::pair<RippleAddress, bool> result = { {}, false };
auto const ourTime = app.timeKeeper().now().time_since_epoch().count();
@@ -344,6 +402,11 @@ verifyHello (protocol::TMHello const& h, uint256 const& sharedValue,
journal.info <<
"Hello: Disconnect: Bad node public key.";
}
else if (result.first == app.getLocalCredentials().getNodePublic())
{
journal.info <<
"Hello: Disconnect: Self connection.";
}
else if (! result.first.verifyNodePublic (
sharedValue, h.nodeproof (), ECDSA::not_strict))
{
@@ -351,6 +414,31 @@ verifyHello (protocol::TMHello const& h, uint256 const& sharedValue,
journal.info <<
"Hello: Disconnect: Failed to verify session.";
}
else if (h.has_local_ip () &&
is_public (remote) &&
remote.is_v4 () &&
(remote.to_v4().value != h.local_ip ()))
{
// Remote asked us to confirm connection is from
// correct IP
journal.info <<
"Hello: Disconnect: Peer IP is " <<
beast::IP::to_string (remote.to_v4())
<< " not " <<
beast::IP::to_string (beast::IP::AddressV4 (h.local_ip()));
}
else if (h.has_remote_ip() && is_public (remote) &&
(public_ip != beast::IP::Address()) &&
(h.remote_ip() != public_ip.to_v4().value))
{
// We know our public IP and peer reports connection
// from some other IP
journal.info <<
"Hello: Disconnect: Our IP is " <<
beast::IP::to_string (public_ip.to_v4())
<< " not " <<
beast::IP::to_string (beast::IP::AddressV4 (h.remote_ip()));
}
else
{
// Successful connection.

View File

@@ -52,7 +52,9 @@ makeSharedValue (SSL* ssl, beast::Journal journal);
/** Build a TMHello protocol message. */
protocol::TMHello
buildHello (uint256 const& sharedValue, Application& app);
buildHello (uint256 const& sharedValue,
beast::IP::Address public_ip,
beast::IP::Endpoint remote, Application& app);
/** Insert HTTP headers based on the TMHello protocol message. */
void
@@ -70,6 +72,8 @@ parseHello (beast::http::message const& m, beast::Journal journal);
*/
std::pair<RippleAddress, bool>
verifyHello (protocol::TMHello const& h, uint256 const& sharedValue,
beast::IP::Address public_ip,
beast::IP::Endpoint remote,
beast::Journal journal, Application& app);
/** Parse a set of protocol versions.

View File

@@ -95,6 +95,8 @@ message TMHello
optional bool nodePrivate = 11; // Request to not forward IP.
optional TMProofWork proofOfWork = 12; // request/provide proof of work
optional bool testNet = 13; // Running as testnet.
optional uint32 local_ip = 14; // our public IP
optional uint32 remote_ip = 15; // IP we see connection from
}
// The status of a node in our cluster

View File

@@ -35,7 +35,7 @@ char const* getRawVersionString ()
//
// The build version number (edit this for each release)
//
"0.29.1-rc1"
"0.30.0-hf2"
//
// Must follow the format described here:
//

View File

@@ -112,9 +112,6 @@ public:
Consumer newInboundEndpoint (beast::IP::Endpoint const& address)
{
if (isWhitelisted (address))
return newAdminEndpoint (to_string (address));
Entry* entry (nullptr);
{
@@ -146,9 +143,6 @@ public:
Consumer newOutboundEndpoint (beast::IP::Endpoint const& address)
{
if (isWhitelisted (address))
return newAdminEndpoint (to_string (address));
Entry* entry (nullptr);
{
@@ -370,14 +364,6 @@ public:
//--------------------------------------------------------------------------
bool isWhitelisted (beast::IP::Endpoint const& address)
{
if (! is_public (address))
return true;
return false;
}
// Called periodically to expire entries and groom the table.
//
void periodicActivity ()

View File

@@ -22,6 +22,7 @@
#include <ripple/server/Port.h>
#include <ripple/json/json_value.h>
#include <ripple/resource/ResourceManager.h>
#include <beast/net/IPEndpoint.h>
#include <vector>
@@ -47,6 +48,11 @@ Role
requestRole (Role const& required, HTTP::Port const& port,
Json::Value const& jsonRPC, beast::IP::Endpoint const& remoteIp);
Resource::Consumer
requestInboundEndpoint (Resource::Manager& manager,
beast::IP::Endpoint const& remoteAddress,
HTTP::Port const& port);
} // ripple
#endif

View File

@@ -66,4 +66,15 @@ requestRole (Role const& required, HTTP::Port const& port,
return role;
}
Resource::Consumer
requestInboundEndpoint (Resource::Manager& manager,
beast::IP::Endpoint const& remoteAddress,
HTTP::Port const& port)
{
if (requestRole (Role::GUEST, port, Json::Value(), remoteAddress) ==
Role::ADMIN)
return manager.newAdminEndpoint (to_string (remoteAddress));
return manager.newInboundEndpoint(remoteAddress);
}
}

View File

@@ -34,6 +34,7 @@
#include <ripple/rpc/Coroutine.h>
#include <ripple/rpc/RPCHandler.h>
#include <ripple/server/Port.h>
#include <ripple/server/Role.h>
#include <ripple/json/to_string.h>
#include <ripple/rpc/RPCHandler.h>
#include <ripple/rpc/Yield.h>
@@ -133,8 +134,8 @@ ConnectionImpl <WebSocket>::ConnectionImpl (
connection_ptr const& cpConnection,
beast::IP::Endpoint const& remoteAddress,
boost::asio::io_service& io_service)
: InfoSub (source, // usage
resourceManager.newInboundEndpoint (remoteAddress))
: InfoSub (source, requestInboundEndpoint (
resourceManager, remoteAddress, handler.port()))
, app_(app)
, m_port (handler.port ())
, m_resourceManager (resourceManager)