diff --git a/Builds/VisualStudio2013/RippleD.vcxproj b/Builds/VisualStudio2013/RippleD.vcxproj index 0a12ec7f98..fe68ca92c4 100644 --- a/Builds/VisualStudio2013/RippleD.vcxproj +++ b/Builds/VisualStudio2013/RippleD.vcxproj @@ -2338,9 +2338,6 @@ True - - True - True @@ -2362,8 +2359,6 @@ - - @@ -2460,8 +2455,6 @@ - - diff --git a/Builds/VisualStudio2013/RippleD.vcxproj.filters b/Builds/VisualStudio2013/RippleD.vcxproj.filters index a847291d71..12980e2272 100644 --- a/Builds/VisualStudio2013/RippleD.vcxproj.filters +++ b/Builds/VisualStudio2013/RippleD.vcxproj.filters @@ -3363,9 +3363,6 @@ ripple\basics\impl - - ripple\basics\impl - ripple\basics\impl @@ -3390,9 +3387,6 @@ ripple\basics - - ripple\basics - ripple\basics @@ -3519,9 +3513,6 @@ ripple\core - - ripple\core - ripple\core diff --git a/src/ripple/overlay/impl/PeerImp.h b/src/ripple/overlay/impl/PeerImp.h index 8fe422d82c..5e7abcf1bc 100644 --- a/src/ripple/overlay/impl/PeerImp.h +++ b/src/ripple/overlay/impl/PeerImp.h @@ -994,7 +994,6 @@ private: } } - // TODO(tom): duplicates code in handshake_analyzer::checkTransaction. static void checkTransaction ( Job&, int flags, diff --git a/src/ripple/overlay/impl/handshake_analyzer.h b/src/ripple/overlay/impl/handshake_analyzer.h deleted file mode 100644 index 048d09f3a0..0000000000 --- a/src/ripple/overlay/impl/handshake_analyzer.h +++ /dev/null @@ -1,1327 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 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. -*/ -//============================================================================== - -#ifndef RIPPLE_OVERLAY_PEERIMP_H_INCLUDED -#define RIPPLE_OVERLAY_PEERIMP_H_INCLUDED - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// VFALCO This is unfortunate. Comment this out and -// just include what is needed. -#include - -#include -#include -#include - -#include - -namespace ripple { - -typedef boost::asio::ip::tcp::socket NativeSocketType; - -class PeerImp; - -std::string to_string (Peer const& peer); -std::ostream& operator<< (std::ostream& os, Peer const& peer); - -std::string to_string (Peer const* peer); -std::ostream& operator<< (std::ostream& os, Peer const* peer); - -std::string to_string (PeerImp const& peer); -std::ostream& operator<< (std::ostream& os, PeerImp const& peer); - -std::string to_string (PeerImp const* peer); -std::ostream& operator<< (std::ostream& os, PeerImp const* peer); - -//------------------------------------------------------------------------------ - -class PeerImp - : public Peer - , public std::enable_shared_from_this - , private beast::LeakChecked - , private abstract_protocol_handler -{ -private: - /** Time alloted for a peer to send a HELLO message (DEPRECATED) */ - static const boost::posix_time::seconds nodeVerifySeconds; - - /** The clock drift we allow a remote peer to have */ - static const std::uint32_t clockToleranceDeltaSeconds = 20; - - /** The length of the smallest valid finished message */ - static const size_t sslMinimumFinishedLength = 12; - - //-------------------------------------------------------------------------- - /** We have accepted an inbound connection. - - The connection state transitions from `stateConnect` to `stateConnected` - as `stateConnect`. - */ - void accept () - { - m_journal.info << "Accepted " << m_remoteAddress; - - m_socket->set_verify_mode (boost::asio::ssl::verify_none); - m_socket->async_handshake ( - boost::asio::ssl::stream_base::server, - m_strand.wrap (std::bind ( - &PeerImp::handleStart, - std::static_pointer_cast (shared_from_this ()), - beast::asio::placeholders::error))); - } - - /** Attempt an outbound connection. - - The connection may fail (for a number of reasons) and we do not know - what will happen at this point. - - The connection state does not transition with this function and remains - as `stateConnecting`. - */ - void connect () - { - m_journal.info << "Connecting to " << m_remoteAddress; - - boost::system::error_code err; - - m_timer.expires_from_now (nodeVerifySeconds, err); - - m_timer.async_wait (m_strand.wrap (std::bind ( - &PeerImp::handleVerifyTimer, - shared_from_this (), beast::asio::placeholders::error))); - - if (err) - { - m_journal.error << "Failed to set verify timer."; - detach ("c2"); - return; - } - - m_socket->next_layer ().async_connect ( - beast::IPAddressConversion::to_asio_endpoint (m_remoteAddress), - m_strand.wrap (std::bind (&PeerImp::onConnect, - shared_from_this (), beast::asio::placeholders::error))); - } - -public: - /** Current state */ - enum State - { - /** An connection is being established (outbound) */ - stateConnecting - - /** Connection has been successfully established */ - ,stateConnected - - /** Handshake has been received from this peer */ - ,stateHandshaked - - /** Running the Ripple protocol actively */ - ,stateActive - - /** Gracefully closing */ - ,stateGracefulClose - }; - - typedef std::shared_ptr ptr; - - NativeSocketType m_owned_socket; - - beast::Journal m_journal; - - // A unique identifier (up to a restart of rippled) for this particular - // peer instance. A peer that disconnects will, upon reconnection, get a - // new ID. - ShortId m_shortId; - - // Updated at each stage of the connection process to reflect - // the current conditions as closely as possible. This includes - // the case where we learn the true IP via a PROXY handshake. - beast::IP::Endpoint m_remoteAddress; - - // These is up here to prevent warnings about order of initializations - // - Resource::Manager& m_resourceManager; - PeerFinder::Manager& m_peerFinder; - OverlayImpl& m_overlay; - bool m_inbound; - - std::unique_ptr m_socket; - boost::asio::io_service::strand m_strand; - - State m_state; // Current state - bool m_detaching; // True if detaching. - bool m_clusterNode; // True if peer is a node in our cluster - RippleAddress m_nodePublicKey; // Node public key of peer. - std::string m_nodeName; - - // Both sides of the peer calculate this value and verify that it matches - // to detect/prevent man-in-the-middle attacks. - // - uint256 m_secureCookie; - - // The indices of the smallest and largest ledgers this peer has available - // - LedgerIndex m_minLedger; - LedgerIndex m_maxLedger; - - uint256 m_closedLedgerHash; - uint256 m_previousLedgerHash; - - std::list m_recentLedgers; - std::list m_recentTxSets; - mutable std::mutex m_recentLock; - - boost::asio::deadline_timer m_timer; - - std::vector m_readBuffer; - std::list mSendQ; - Message::pointer mSendingPacket; - protocol::TMStatusChange mLastStatus; - protocol::TMHello mHello; - - Resource::Consumer m_usage; - - // The slot assigned to us by PeerFinder - PeerFinder::Slot::ptr m_slot; - - // True if close was called - bool m_was_canceled; - - boost::asio::streambuf read_buffer_; - boost::optional http_message_; - boost::optional http_parser_; - message_stream message_stream_; - std::unique_ptr load_event_; - - //-------------------------------------------------------------------------- - /** New incoming peer from the specified socket */ - PeerImp ( - NativeSocketType&& socket, - beast::IP::Endpoint remoteAddress, - OverlayImpl& overlay, - Resource::Manager& resourceManager, - PeerFinder::Manager& peerFinder, - PeerFinder::Slot::ptr const& slot, - boost::asio::ssl::context& ssl_context, - MultiSocket::Flag flags) - : m_owned_socket (std::move (socket)) - , m_journal (deprecatedLogs().journal("Peer")) - , m_shortId (0) - , m_remoteAddress (remoteAddress) - , m_resourceManager (resourceManager) - , m_peerFinder (peerFinder) - , m_overlay (overlay) - , m_inbound (true) - , m_socket (MultiSocket::New ( - m_owned_socket, ssl_context, flags.asBits ())) - , m_strand (m_owned_socket.get_io_service()) - , m_state (stateConnected) - , m_detaching (false) - , m_clusterNode (false) - , m_minLedger (0) - , m_maxLedger (0) - , m_timer (m_owned_socket.get_io_service()) - , m_slot (slot) - , m_was_canceled (false) - , message_stream_(*this) - { - } - - /** New outgoing peer - @note Construction of outbound peers is a two step process: a second - call is needed (to connect or accept) but we cannot make it from - inside the constructor because you cannot call shared_from_this - from inside constructors. - */ - PeerImp ( - beast::IP::Endpoint remoteAddress, - boost::asio::io_service& io_service, - OverlayImpl& overlay, - Resource::Manager& resourceManager, - PeerFinder::Manager& peerFinder, - PeerFinder::Slot::ptr const& slot, - boost::asio::ssl::context& ssl_context, - MultiSocket::Flag flags) - : m_owned_socket (io_service) - , m_journal (deprecatedLogs().journal("Peer")) - , m_shortId (0) - , m_remoteAddress (remoteAddress) - , m_resourceManager (resourceManager) - , m_peerFinder (peerFinder) - , m_overlay (overlay) - , m_inbound (false) - , m_socket (MultiSocket::New ( - io_service, ssl_context, flags.asBits ())) - , m_strand (io_service) - , m_state (stateConnecting) - , m_detaching (false) - , m_clusterNode (false) - , m_minLedger (0) - , m_maxLedger (0) - , m_timer (io_service) - , m_slot (slot) - , m_was_canceled (false) - , message_stream_(*this) - { - } - - virtual - ~PeerImp () - { - m_overlay.remove (m_slot); - } - - PeerImp (PeerImp const&) = delete; - PeerImp& operator= (PeerImp const&) = delete; - - MultiSocket& getStream () - { - return *m_socket; - } - - static char const* getCountedObjectName () { return "Peer"; } - - void getLedger (protocol::TMGetLedger& packet); - - // - // i/o - // - - void - start_read(); - - void - on_read_detect (error_code ec, std::size_t bytes_transferred); - - void - on_read_http (error_code ec, std::size_t bytes_transferred); - - void - on_read_protocol (error_code ec, std::size_t bytes_transferred); - - //-------------------------------------------------------------------------- - // - // abstract_protocol_handler - // - //-------------------------------------------------------------------------- - - static - error_code - invalid_argument_error() - { - return boost::system::errc::make_error_code ( - boost::system::errc::invalid_argument); - } - - error_code - on_message_unknown (std::uint16_t type) override; - - error_code - on_message_begin (std::uint16_t type, - std::shared_ptr <::google::protobuf::Message> const& m) override; - - void - on_message_end (std::uint16_t type, - std::shared_ptr <::google::protobuf::Message> const& m) override; - - error_code on_message (std::shared_ptr const& m) override; - error_code on_message (std::shared_ptr const& m) override; - error_code on_message (std::shared_ptr const& m) override; - error_code on_message (std::shared_ptr const& m) override; - error_code on_message (std::shared_ptr const& m) override; - error_code on_message (std::shared_ptr const& m) override; - error_code on_message (std::shared_ptr const& m) override; - error_code on_message (std::shared_ptr const& m) override; - error_code on_message (std::shared_ptr const& m) override; - error_code on_message (std::shared_ptr const& m) override; - error_code on_message (std::shared_ptr const& m) override; - error_code on_message (std::shared_ptr const& m) override; - error_code on_message (std::shared_ptr const& m) override; - error_code on_message (std::shared_ptr const& m) override; - error_code on_message (std::shared_ptr const& m) override; - - //-------------------------------------------------------------------------- - - State state() const - { - return m_state; - } - - void state (State new_state) - { - m_state = new_state; - } - - //-------------------------------------------------------------------------- - /** Disconnect a peer - - The peer transitions from its current state into `stateGracefulClose` - - @param rsn a code indicating why the peer was disconnected - @param onIOStrand true if called on an I/O strand. It if is not, then - a callback will be queued up. - */ - void detach (const char* rsn, bool graceful = true) - { - if (! m_strand.running_in_this_thread ()) - { - m_strand.post (std::bind (&PeerImp::detach, - shared_from_this (), rsn, graceful)); - return; - } - - if (!m_detaching) - { - // NIKB TODO No - a race is NOT ok. This needs to be fixed - // to have PeerFinder work reliably. - m_detaching = true; // Race is ok. - - if (m_was_canceled) - m_peerFinder.on_cancel (m_slot); - else - m_peerFinder.on_closed (m_slot); - - if (m_state == stateActive) - m_overlay.onPeerDisconnect (shared_from_this ()); - - m_state = stateGracefulClose; - - if (m_clusterNode && m_journal.active(beast::Journal::Severity::kWarning)) - m_journal.warning << "Cluster peer " << m_nodeName << - " detached: " << rsn; - - mSendQ.clear (); - - (void) m_timer.cancel (); - - if (graceful) - { - m_socket->async_shutdown ( - m_strand.wrap ( std::bind( - &PeerImp::handleShutdown, - std::static_pointer_cast (shared_from_this ()), - beast::asio::placeholders::error))); - } - else - { - m_socket->cancel (); - } - - // VFALCO TODO Stop doing this. - if (m_nodePublicKey.isValid ()) - m_nodePublicKey.clear (); // Be idempotent. - } - } - - /** Close the connection. */ - void close (bool graceful) - { - m_was_canceled = true; - detach ("stop", graceful); - } - - /** Outbound connection attempt has completed (not necessarily successfully) - - The connection may fail for a number of reasons. Perhaps we do not have - a route to the remote endpoint, or there is no server listening at that - address. - - If the connection succeeded, we transition to the `stateConnected` state - and move on. - - If the connection failed, we simply disconnect. - - @param ec indicates success or an error code. - */ - void onConnect (boost::system::error_code ec) - { - if (m_detaching) - return; - - NativeSocketType::endpoint_type local_endpoint; - - if (! ec) - local_endpoint = m_socket->this_layer < - NativeSocketType> ().local_endpoint (ec); - - if (ec) - { - // VFALCO NOTE This log statement looks like ass - m_journal.info << - "Connect to " << m_remoteAddress << - " failed: " << ec.message(); - // This should end up calling onPeerClosed() - detach ("hc"); - return; - } - - bassert (m_state == stateConnecting); - m_state = stateConnected; - - m_peerFinder.on_connected (m_slot, - beast::IPAddressConversion::from_asio (local_endpoint)); - - m_socket->set_verify_mode (boost::asio::ssl::verify_none); - m_socket->async_handshake ( - boost::asio::ssl::stream_base::client, - m_strand.wrap (std::bind (&PeerImp::handleStart, - std::static_pointer_cast (shared_from_this ()), - beast::asio::placeholders::error))); - } - - /** Indicates that the peer must be activated. - A peer is activated after the handshake is completed and if it is not - a second connection from a peer that we already have. Once activated - the peer transitions to `stateActive` and begins operating. - */ - void activate () - { - bassert (m_state == stateHandshaked); - m_state = stateActive; - bassert(m_shortId == 0); - m_shortId = m_overlay.next_id(); - m_overlay.onPeerActivated(shared_from_this ()); - } - - void start () - { - if (m_inbound) - accept (); - else - connect (); - } - - //-------------------------------------------------------------------------- - std::string getClusterNodeName() const - { - return m_nodeName; - } - - //-------------------------------------------------------------------------- - - void - send (Message::pointer const& m) override - { - if (m) - { - if (m_strand.running_in_this_thread()) - { - if (mSendingPacket) - mSendQ.push_back (m); - else - sendForce (m); - } - else - { - m_strand.post (std::bind (&PeerImp::send, shared_from_this(), m)); - } - - } - } - - void sendGetPeers () - { - // Ask peer for known other peers. - protocol::TMGetPeers msg; - - msg.set_doweneedthis (1); - - Message::pointer packet = std::make_shared ( - msg, protocol::mtGET_PEERS); - - send (packet); - } - - void charge (Resource::Charge const& fee) - { - if ((m_usage.charge (fee) == Resource::drop) && m_usage.disconnect ()) - detach ("resource"); - } - - static void charge (std::weak_ptr & peer, Resource::Charge const& fee) - { - Peer::ptr p (peer.lock()); - - if (p != nullptr) - p->charge (fee); - } - - Json::Value json () - { - Json::Value ret (Json::objectValue); - - ret["public_key"] = m_nodePublicKey.ToString (); - ret["address"] = m_remoteAddress.to_string(); - - if (m_inbound) - ret["inbound"] = true; - - if (m_clusterNode) - { - ret["cluster"] = true; - - if (!m_nodeName.empty ()) - ret["name"] = m_nodeName; - } - - if (mHello.has_fullversion ()) - ret["version"] = mHello.fullversion (); - - if (mHello.has_protoversion () && - (mHello.protoversion () != to_packed (BuildInfo::getCurrentProtocol()))) - { - ret["protocol"] = to_string (BuildInfo::make_protocol (mHello.protoversion ())); - } - - std::uint32_t minSeq, maxSeq; - ledgerRange(minSeq, maxSeq); - - if ((minSeq != 0) || (maxSeq != 0)) - ret["complete_ledgers"] = boost::lexical_cast(minSeq) + " - " + - boost::lexical_cast(maxSeq); - - if (!!m_closedLedgerHash) - ret["ledger"] = to_string (m_closedLedgerHash); - - if (mLastStatus.has_newstatus ()) - { - switch (mLastStatus.newstatus ()) - { - case protocol::nsCONNECTING: - ret["status"] = "connecting"; - break; - - case protocol::nsCONNECTED: - ret["status"] = "connected"; - break; - - case protocol::nsMONITORING: - ret["status"] = "monitoring"; - break; - - case protocol::nsVALIDATING: - ret["status"] = "validating"; - break; - - case protocol::nsSHUTTING: - ret["status"] = "shutting"; - break; - - default: - // FIXME: do we really want this? - m_journal.warning << "Unknown status: " << mLastStatus.newstatus (); - } - } - - return ret; - } - - bool isInCluster () const - { - return m_clusterNode; - } - - uint256 const& getClosedLedgerHash () const - { - return m_closedLedgerHash; - } - - bool hasLedger (uint256 const& hash, std::uint32_t seq) const - { - std::lock_guard sl(m_recentLock); - - if ((seq != 0) && (seq >= m_minLedger) && (seq <= m_maxLedger)) - return true; - - BOOST_FOREACH (uint256 const & ledger, m_recentLedgers) - { - if (ledger == hash) - return true; - } - - return false; - } - - void ledgerRange (std::uint32_t& minSeq, std::uint32_t& maxSeq) const - { - std::lock_guard sl(m_recentLock); - - minSeq = m_minLedger; - maxSeq = m_maxLedger; - } - - bool hasTxSet (uint256 const& hash) const - { - std::lock_guard sl(m_recentLock); - BOOST_FOREACH (uint256 const & set, m_recentTxSets) - - if (set == hash) - return true; - - return false; - } - - Peer::ShortId getShortId () const - { - return m_shortId; - } - - const RippleAddress& getNodePublic () const - { - return m_nodePublicKey; - } - - void cycleStatus () - { - m_previousLedgerHash = m_closedLedgerHash; - m_closedLedgerHash.zero (); - } - - bool supportsVersion (int version) - { - return mHello.has_protoversion () && (mHello.protoversion () >= version); - } - - bool hasRange (std::uint32_t uMin, std::uint32_t uMax) - { - return (uMin >= m_minLedger) && (uMax <= m_maxLedger); - } - - beast::IP::Endpoint getRemoteAddress() const - { - return m_remoteAddress; - } - -private: - void handleShutdown (boost::system::error_code const& ec) - { - if (m_detaching) - return; - - if (ec == boost::asio::error::operation_aborted) - return; - - if (ec) - { - m_journal.info << "Shutdown: " << ec.message (); - detach ("hsd"); - return; - } - } - - void handleWrite (boost::system::error_code const& ec, size_t bytes) - { - if (m_detaching) - return; - - // Call on IO strand - - mSendingPacket.reset (); - - if (ec == boost::asio::error::operation_aborted) - return; - - if (m_detaching) - return; - - if (ec) - { - m_journal.info << "Write: " << ec.message (); - detach ("hw"); - return; - } - - if (!mSendQ.empty ()) - { - Message::pointer packet = mSendQ.front (); - - if (packet) - { - sendForce (packet); - mSendQ.pop_front (); - } - } - } - - // We have an encrypted connection to the peer. - // Have it say who it is so we know to avoid redundant connections. - // Establish that it really who we are talking to by having it sign a - // connection detail. Also need to establish no man in the middle attack - // is in progress. - void handleStart (boost::system::error_code const& ec) - { - if (m_detaching) - return; - - if (ec == boost::asio::error::operation_aborted) - return; - - if (ec) - { - m_journal.info << "Handshake: " << ec.message (); - detach ("hs"); - return; - } - - if (m_inbound) - m_usage = m_resourceManager.newInboundEndpoint (m_remoteAddress); - else - m_usage = m_resourceManager.newOutboundEndpoint (m_remoteAddress); - - if (m_usage.disconnect ()) - { - detach ("resource"); - return; - } - - if(!sendHello ()) - { - m_journal.error << "Unable to send HELLO to " << m_remoteAddress; - detach ("hello"); - return; - } - - start_read(); - } - - void handleVerifyTimer (boost::system::error_code const& ec) - { - if (m_detaching) - return; - - if (ec == boost::asio::error::operation_aborted) - { - // Timer canceled because deadline no longer needed. - } - else if (ec) - { - m_journal.info << "Peer verify timer error"; - } - else - { - // m_journal.info << "Verify: Peer failed to verify in time."; - - detach ("hvt"); - } - } - - void sendForce (const Message::pointer& packet) - { - // must be on IO strand - if (!m_detaching) - { - mSendingPacket = packet; - - boost::asio::async_write (getStream (), - boost::asio::buffer (packet->getBuffer ()), - m_strand.wrap (std::bind ( - &PeerImp::handleWrite, - std::static_pointer_cast (shared_from_this ()), - beast::asio::placeholders::error, - beast::asio::placeholders::bytes_transferred))); - } - } - - /** Hashes the latest finished message from an SSL stream - - @param sslSession the session to get the message from. - @param hash the buffer into which the hash of the retrieved - message will be saved. The buffer MUST be at least - 64 bytes long. - @param getMessage a pointer to the function to call to retrieve the - finished message. This be either: - `SSL_get_finished` or - `SSL_get_peer_finished`. - - @return `true` if successful, `false` otherwise. - - */ - bool hashLatestFinishedMessage (const SSL *sslSession, unsigned char *hash, - size_t (*getFinishedMessage)(const SSL *, void *buf, size_t)) - { - unsigned char buf[1024]; - - // Get our finished message and hash it. - std::memset(hash, 0, 64); - - size_t len = getFinishedMessage (sslSession, buf, sizeof (buf)); - - if(len < sslMinimumFinishedLength) - return false; - - SHA512 (buf, len, hash); - - return true; - } - - /** Generates a secure cookie to protect against man-in-the-middle attacks - - This function should never fail under normal circumstances and regular - server operation. - - A failure prevents the cookie value from being calculated which is an - important component of connection security. If this function fails, a - secure connection cannot be established and the link MUST be dropped. - - @return `true` if the cookie was generated, `false` otherwise. - - @note failure is an exceptional situation - it should never happen and - will almost always indicate an active man-in-the-middle attack is - taking place. - */ - bool calculateSessionCookie () - { - SSL* ssl = m_socket->ssl_handle (); - - if (!ssl) - { - m_journal.error << "Cookie generation: No underlying connection"; - return false; - } - - unsigned char sha1[64]; - unsigned char sha2[64]; - - if (!hashLatestFinishedMessage(ssl, sha1, SSL_get_finished)) - { - m_journal.error << "Cookie generation: local setup not complete"; - return false; - } - - if (!hashLatestFinishedMessage(ssl, sha2, SSL_get_peer_finished)) - { - m_journal.error << "Cookie generation: peer setup not complete"; - return false; - } - - // If both messages hash to the same value (i.e. match) something is - // wrong. This would cause the resulting cookie to be 0. - if (memcmp (sha1, sha2, sizeof (sha1)) == 0) - { - m_journal.error << "Cookie generation: identical finished messages"; - return false; - } - - for (size_t i = 0; i < sizeof (sha1); ++i) - sha1[i] ^= sha2[i]; - - // Finally, derive the actual cookie for the values that we have - // calculated. - m_secureCookie = Serializer::getSHA512Half (sha1, sizeof(sha1)); - - return true; - } - - /** 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 () - { - if (!calculateSessionCookie()) - return false; - - Blob vchSig; - getApp().getLocalCredentials ().getNodePrivate ().signNodePrivate (m_secureCookie, vchSig); - - protocol::TMHello h; - - h.set_protoversion (to_packed (BuildInfo::getCurrentProtocol())); - h.set_protoversionmin (to_packed (BuildInfo::getMinimumProtocol())); - h.set_fullversion (BuildInfo::getFullVersionString ()); - h.set_nettime (getApp().getOPs ().getNetworkTimeNC ()); - h.set_nodepublic (getApp().getLocalCredentials ().getNodePublic ().humanNodePublic ()); - h.set_nodeproof (&vchSig[0], vchSig.size ()); - h.set_ipv4port (getConfig ().peerListeningPort); - h.set_testnet (false); - - // 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. - h.set_nodeprivate (true); - - Ledger::pointer closedLedger = getApp().getLedgerMaster ().getClosedLedger (); - - if (closedLedger && closedLedger->isClosed ()) - { - uint256 hash = closedLedger->getHash (); - h.set_ledgerclosed (hash.begin (), hash.size ()); - hash = closedLedger->getParentHash (); - h.set_ledgerprevious (hash.begin (), hash.size ()); - } - - Message::pointer packet = std::make_shared ( - h, protocol::mtHELLO); - send (packet); - - return true; - } - - void addLedger (uint256 const& hash) - { - std::lock_guard sl(m_recentLock); - BOOST_FOREACH (uint256 const & ledger, m_recentLedgers) - - if (ledger == hash) - return; - - if (m_recentLedgers.size () == 128) - m_recentLedgers.pop_front (); - - m_recentLedgers.push_back (hash); - } - - void addTxSet (uint256 const& hash) - { - std::lock_guard sl(m_recentLock); - - if(std::find (m_recentTxSets.begin (), m_recentTxSets.end (), hash) != m_recentTxSets.end ()) - return; - - if (m_recentTxSets.size () == 128) - m_recentTxSets.pop_front (); - - m_recentTxSets.push_back (hash); - } - - void doFetchPack (const std::shared_ptr& packet) - { - // VFALCO TODO Invert this dependency using an observer and shared state object. - // Don't queue fetch pack jobs if we're under load or we already have - // some queued. - if (getApp().getFeeTrack ().isLoadedLocal () || - (getApp().getLedgerMaster().getValidatedLedgerAge() > 40) || - (getApp().getJobQueue().getJobCount(jtPACK) > 10)) - { - m_journal.info << "Too busy to make fetch pack"; - return; - } - - if (packet->ledgerhash ().size () != 32) - { - m_journal.warning << "FetchPack hash size malformed"; - charge (Resource::feeInvalidRequest); - return; - } - - uint256 hash; - memcpy (hash.begin (), packet->ledgerhash ().data (), 32); - - getApp().getJobQueue ().addJob (jtPACK, "MakeFetchPack", - std::bind (&NetworkOPs::makeFetchPack, &getApp().getOPs (), std::placeholders::_1, - std::weak_ptr (shared_from_this ()), packet, - hash, UptimeTimer::getInstance ().getElapsedSeconds ())); - } - - void doProofOfWork (Job&, std::weak_ptr peer, ProofOfWork::pointer pow) - { - if (peer.expired ()) - return; - - uint256 solution = pow->solve (); - - if (solution.isZero ()) - { - m_journal.warning << "Failed to solve proof of work"; - } - else - { - Peer::ptr pptr (peer.lock ()); - - if (pptr) - { - protocol::TMProofWork reply; - reply.set_token (pow->getToken ()); - reply.set_response (solution.begin (), solution.size ()); - pptr->send (std::make_shared (reply, protocol::mtPROOFOFWORK)); - } - else - { - // WRITEME: Save solved proof of work for new connection - } - } - } - - // TODO(tom): duplicates code in PeerImp::checkTransaction. - static void checkTransaction ( - Job&, - int flags, - SerializedTransaction::pointer stx, - std::weak_ptr peer) - { - try - { - - if (stx->isFieldPresent(sfLastLedgerSequence) && - (stx->getFieldU32 (sfLastLedgerSequence) < - getApp().getLedgerMaster().getValidLedgerIndex())) - { // Transaction has expired - getApp().getHashRouter().setFlag(stx->getTransactionID(), SF_BAD); - charge (peer, Resource::feeUnwantedData); - return; - } - - auto validate = (flags & SF_SIGGOOD) ? Validate::NO : Validate::YES; - auto tx = std::make_shared (stx, validate); - - if (tx->getStatus () == INVALID) - { - getApp().getHashRouter ().setFlag ( - stx->getTransactionID (), SF_BAD); - charge (peer, Resource::feeInvalidSignature); - return; - } - else - { - getApp().getHashRouter ().setFlag ( - stx->getTransactionID (), SF_SIGGOOD); - } - - bool const trusted (flags & SF_TRUSTED); - getApp().getOPs ().processTransaction (tx, trusted, false, false); - - } - catch (...) - { - getApp().getHashRouter ().setFlag (stx->getTransactionID (), SF_BAD); - charge (peer, Resource::feeInvalidRequest); - } - } - - // Called from our JobQueue - static void checkPropose ( - Job& job, - Overlay* pPeers, - std::shared_ptr packet, - LedgerProposal::pointer proposal, - uint256 consensusLCL, - RippleAddress nodePublic, - std::weak_ptr peer, - bool fromCluster) - { - bool sigGood = false; - bool isTrusted = (job.getType () == jtPROPOSAL_t); - - WriteLog (lsTRACE, Peer) << "Checking " << - (isTrusted ? "trusted" : "UNTRUSTED") << - " proposal"; - - assert (packet); - protocol::TMProposeSet& set = *packet; - - uint256 prevLedger; - - if (set.has_previousledger ()) - { - // proposal includes a previous ledger - WriteLog(lsTRACE, Peer) << "proposal with previous ledger"; - memcpy (prevLedger.begin (), set.previousledger ().data (), 256 / 8); - - if (!fromCluster && !proposal->checkSign (set.signature ())) - { - Peer::ptr p = peer.lock (); - WriteLog(lsWARNING, Peer) << "proposal with previous ledger fails sig check: " << - *p; - charge (peer, Resource::feeInvalidSignature); - return; - } - else - sigGood = true; - } - else - { - if (consensusLCL.isNonZero () && proposal->checkSign (set.signature ())) - { - prevLedger = consensusLCL; - sigGood = true; - } - else - { - // Could be mismatched prev ledger - WriteLog(lsWARNING, Peer) << "Ledger proposal fails signature check"; - proposal->setSignature (set.signature ()); - } - } - - if (isTrusted) - { - getApp().getOPs ().processTrustedProposal (proposal, packet, nodePublic, prevLedger, sigGood); - } - else if (sigGood && (prevLedger == consensusLCL)) - { - // relay untrusted proposal - WriteLog(lsTRACE, Peer) << "relaying UNTRUSTED proposal"; - std::set peers; - - if (getApp().getHashRouter ().swapSet ( - proposal->getSuppressionID (), peers, SF_RELAYED)) - { - pPeers->foreach (send_if_not ( - std::make_shared (set, protocol::mtPROPOSE_LEDGER), - peer_in_set(peers))); - } - } - else - { - WriteLog(lsDEBUG, Peer) << "Not relaying UNTRUSTED proposal"; - } - } - - static void checkValidation (Job&, Overlay* pPeers, SerializedValidation::pointer val, bool isTrusted, bool isCluster, - std::shared_ptr packet, std::weak_ptr peer) - { - #ifndef TRUST_NETWORK - - try - #endif - { - uint256 signingHash = val->getSigningHash(); - if (!isCluster && !val->isValid (signingHash)) - { - WriteLog(lsWARNING, Peer) << "Validation is invalid"; - charge (peer, Resource::feeInvalidRequest); - return; - } - - std::string source; - Peer::ptr lp = peer.lock (); - - if (lp) - source = to_string(*lp); - else - source = "unknown"; - - std::set peers; - - //---------------------------------------------------------------------- - // - { - SerializedValidation const& sv (*val); - Validators::ReceivedValidation rv; - rv.ledgerHash = sv.getLedgerHash (); - rv.publicKey = sv.getSignerPublic(); - getApp ().getValidators ().receiveValidation (rv); - } - // - //---------------------------------------------------------------------- - - if (getApp().getOPs ().recvValidation (val, source) && - getApp().getHashRouter ().swapSet (signingHash, peers, SF_RELAYED)) - { - pPeers->foreach (send_if_not ( - std::make_shared (*packet, protocol::mtVALIDATION), - peer_in_set(peers))); - } - } - - #ifndef TRUST_NETWORK - catch (...) - { - WriteLog(lsTRACE, Peer) << "Exception processing validation"; - charge (peer, Resource::feeInvalidRequest); - } - #endif - } -}; - -//------------------------------------------------------------------------------ - -const boost::posix_time::seconds PeerImp::nodeVerifySeconds (15); - -//------------------------------------------------------------------------------ - -// to_string should not be used we should just use lexical_cast maybe - -inline std::string to_string (PeerImp const& peer) -{ - if (peer.isInCluster()) - return peer.getClusterNodeName(); - - return peer.getRemoteAddress().to_string(); -} - -inline std::string to_string (PeerImp const* peer) -{ - return to_string (*peer); -} - -inline std::ostream& operator<< (std::ostream& os, PeerImp const& peer) -{ - os << to_string (peer); - - return os; -} - -inline std::ostream& operator<< (std::ostream& os, PeerImp const* peer) -{ - os << to_string (peer); - - return os; -} - -//------------------------------------------------------------------------------ - -inline std::string to_string (Peer const& peer) -{ - if (peer.isInCluster()) - return peer.getClusterNodeName(); - - return peer.getRemoteAddress().to_string(); -} - -inline std::string to_string (Peer const* peer) -{ - return to_string (*peer); -} - -inline std::ostream& operator<< (std::ostream& os, Peer const& peer) -{ - os << to_string (peer); - - return os; -} - -inline std::ostream& operator<< (std::ostream& os, Peer const* peer) -{ - os << to_string (peer); - - return os; -} - -} - -#endif