From 4170bcd2943a365c8f78944539a3d1bfd50a5af4 Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Sun, 25 Aug 2013 00:11:04 -0700 Subject: [PATCH] Add PROXY peer listener and consolidate SSL contexts. --- Builds/VisualStudio2012/RippleD.vcxproj | 48 +-- .../VisualStudio2012/RippleD.vcxproj.filters | 60 ++-- Subtrees/websocket/src/sockets/autotls.hpp | 21 +- Subtrees/websocket/src/sockets/tls.hpp | 19 +- .../ripple_app/main/ripple_Application.cpp | 254 +++++++++------- modules/ripple_app/main/ripple_Application.h | 8 +- .../main/ripple_LocalCredentials.cpp | 26 +- .../ripple_app/main/ripple_LocalCredentials.h | 12 - modules/ripple_app/network/WSDoor.cpp | 117 -------- modules/ripple_app/network/WSDoor.h | 35 --- modules/ripple_app/peers/PeerDoor.cpp | 62 ++-- modules/ripple_app/peers/PeerDoor.h | 15 +- modules/ripple_app/peers/ripple_Peer.cpp | 58 ++-- modules/ripple_app/peers/ripple_Peer.h | 3 +- modules/ripple_app/peers/ripple_Peers.cpp | 122 ++++---- .../peers/{ripple_IPeers.h => ripple_Peers.h} | 11 +- modules/ripple_app/ripple_app.cpp | 26 +- .../{network => websocket}/WSConnection.cpp | 0 .../{network => websocket}/WSConnection.h | 0 modules/ripple_app/websocket/WSDoor.cpp | 134 +++++++++ modules/ripple_app/websocket/WSDoor.h | 18 ++ .../WSServerHandler.cpp} | 0 .../WSServerHandler.h} | 35 +-- modules/ripple_asio/ripple_asio.cpp | 5 +- modules/ripple_asio/ripple_asio.h | 1 + .../ripple_asio/sockets/RippleSSLContext.cpp | 274 ++++++++++++++++++ .../ripple_asio/sockets/RippleSSLContext.h | 51 ++++ .../sockets/ripple_MultiSocket.cpp | 72 ++--- .../ripple_asio/sockets/ripple_MultiSocket.h | 33 +-- .../sockets/ripple_MultiSocketType.h | 40 +-- .../sockets/ripple_RippleTlsContext.cpp | 151 ---------- .../sockets/ripple_RippleTlsContext.h | 32 -- .../ripple_core/functional/ripple_Config.cpp | 25 +- .../ripple_core/functional/ripple_Config.h | 11 +- 34 files changed, 947 insertions(+), 832 deletions(-) delete mode 100644 modules/ripple_app/network/WSDoor.cpp delete mode 100644 modules/ripple_app/network/WSDoor.h rename modules/ripple_app/peers/{ripple_IPeers.h => ripple_Peers.h} (92%) rename modules/ripple_app/{network => websocket}/WSConnection.cpp (100%) rename modules/ripple_app/{network => websocket}/WSConnection.h (100%) create mode 100644 modules/ripple_app/websocket/WSDoor.cpp create mode 100644 modules/ripple_app/websocket/WSDoor.h rename modules/ripple_app/{network/ripple_WSHandler.cpp => websocket/WSServerHandler.cpp} (100%) rename modules/ripple_app/{network/ripple_WSHandler.h => websocket/WSServerHandler.h} (91%) create mode 100644 modules/ripple_asio/sockets/RippleSSLContext.cpp create mode 100644 modules/ripple_asio/sockets/RippleSSLContext.h delete mode 100644 modules/ripple_asio/sockets/ripple_RippleTlsContext.cpp delete mode 100644 modules/ripple_asio/sockets/ripple_RippleTlsContext.h diff --git a/Builds/VisualStudio2012/RippleD.vcxproj b/Builds/VisualStudio2012/RippleD.vcxproj index 2a31a53f5b..28efddc0bf 100644 --- a/Builds/VisualStudio2012/RippleD.vcxproj +++ b/Builds/VisualStudio2012/RippleD.vcxproj @@ -313,24 +313,6 @@ true true - - true - true - true - true - - - true - true - true - true - - - true - true - true - true - true true @@ -683,8 +665,26 @@ true true + + true + true + true + true + + + true + true + true + true + + + true + true + true + true + - + true true true @@ -1421,9 +1421,6 @@ - - - @@ -1441,7 +1438,7 @@ - + @@ -1475,11 +1472,14 @@ + + + - + diff --git a/Builds/VisualStudio2012/RippleD.vcxproj.filters b/Builds/VisualStudio2012/RippleD.vcxproj.filters index e1c8f21a15..149d4d28e8 100644 --- a/Builds/VisualStudio2012/RippleD.vcxproj.filters +++ b/Builds/VisualStudio2012/RippleD.vcxproj.filters @@ -124,9 +124,6 @@ {29393027-f1ed-4700-bbd1-c880091ab96b} - - {7c14e9df-6d8d-4ba3-b208-f89c1d0b6b30} - {66d2d40a-72bd-41f5-9cf9-1f464a40bb04} @@ -160,6 +157,9 @@ {8476f6e8-7411-460f-bdef-68e3166078eb} + + {7c14e9df-6d8d-4ba3-b208-f89c1d0b6b30} + @@ -714,15 +714,6 @@ [1] Ripple\ripple_app\misc - - [1] Ripple\ripple_app\network - - - [1] Ripple\ripple_app\network - - - [1] Ripple\ripple_app\network - [1] Ripple\ripple_app\paths @@ -873,9 +864,6 @@ [1] Ripple\ripple_asio - - [1] Ripple\ripple_asio\sockets - [1] Ripple\ripple_app\boost @@ -885,6 +873,18 @@ [0] Subtrees\beast + + [1] Ripple\ripple_asio\sockets + + + [1] Ripple\ripple_app\websocket + + + [1] Ripple\ripple_app\websocket + + + [1] Ripple\ripple_app\websocket + @@ -1499,15 +1499,6 @@ [1] Ripple\ripple_app\misc - - [1] Ripple\ripple_app\network - - - [1] Ripple\ripple_app\network - - - [1] Ripple\ripple_app\network - [1] Ripple\ripple_app\paths @@ -1529,9 +1520,6 @@ [1] Ripple\ripple_app\peers - - [1] Ripple\ripple_app\peers - [1] Ripple\ripple_app\peers @@ -1658,9 +1646,6 @@ [1] Ripple\ripple_asio\sockets - - [1] Ripple\ripple_asio\sockets - [1] Ripple\ripple_asio\sockets @@ -1676,6 +1661,21 @@ [1] Ripple\ripple_basics\utility + + [1] Ripple\ripple_asio\sockets + + + [1] Ripple\ripple_app\websocket + + + [1] Ripple\ripple_app\websocket + + + [1] Ripple\ripple_app\websocket + + + [1] Ripple\ripple_app\peers + diff --git a/Subtrees/websocket/src/sockets/autotls.hpp b/Subtrees/websocket/src/sockets/autotls.hpp index a3c57a9a5b..803e7e65b2 100644 --- a/Subtrees/websocket/src/sockets/autotls.hpp +++ b/Subtrees/websocket/src/sockets/autotls.hpp @@ -64,15 +64,13 @@ public: return boost::asio::ssl::stream_base::client; } } - - // TLS policy adds the on_tls_init method to the handler to allow the user - // to set up their asio TLS context. + class handler_interface { public: virtual ~handler_interface() {} - + virtual void on_tcp_init() {}; - virtual boost::shared_ptr on_tls_init() = 0; + virtual boost::asio::ssl::context& get_ssl_context () = 0; }; // Connection specific details @@ -97,15 +95,12 @@ public: , m_connection(static_cast< connection_type& >(*this)) {} void init() { - m_context_ptr = m_connection.get_handler()->on_tls_init(); + boost::asio::ssl::context& ssl_context ( + m_connection.get_handler()->get_ssl_context()); - if (!m_context_ptr) { - throw "handler was unable to init autotls, connection error"; - } - - m_socket_ptr = - autotls_socket_ptr(new autotls_socket(m_endpoint.get_io_service(), *m_context_ptr, - m_endpoint.m_secure_only, m_endpoint.m_plain_only)); + m_socket_ptr = autotls_socket_ptr (new autotls_socket ( + m_endpoint.get_io_service(), ssl_context, m_endpoint.m_secure_only, + m_endpoint.m_plain_only)); } void async_init(boost::function callback) diff --git a/Subtrees/websocket/src/sockets/tls.hpp b/Subtrees/websocket/src/sockets/tls.hpp index 34e7af8caa..d43be49e3b 100644 --- a/Subtrees/websocket/src/sockets/tls.hpp +++ b/Subtrees/websocket/src/sockets/tls.hpp @@ -70,14 +70,12 @@ public: return true; } - // TLS policy adds the on_tls_init method to the handler to allow the user - // to set up their asio TLS context. class handler_interface { public: virtual ~handler_interface() {} virtual void on_tcp_init() {}; - virtual boost::shared_ptr on_tls_init() = 0; + virtual boost::asio::ssl::context& on_tls_init() = 0; }; // Connection specific details @@ -101,14 +99,13 @@ public: : m_endpoint(e) , m_connection(static_cast< connection_type& >(*this)) {} - void init() { - m_context_ptr = m_connection.get_handler()->on_tls_init(); - - if (!m_context_ptr) { - throw "handler was unable to init tls, connection error"; - } - - m_socket_ptr = tls_socket_ptr(new tls_socket(m_endpoint.get_io_service(),*m_context_ptr)); + void init() + { + boost::asio::ssl::context& ssl_context ( + m_connection.get_handler()->get_ssl_context ()); + + m_socket_ptr = tls_socket_ptr (new tls_socket ( + m_endpoint.get_io_service(), ssl_context)); } void async_init(boost::function callback) diff --git a/modules/ripple_app/main/ripple_Application.cpp b/modules/ripple_app/main/ripple_Application.cpp index 469420e42a..542fabc10c 100644 --- a/modules/ripple_app/main/ripple_Application.cpp +++ b/modules/ripple_app/main/ripple_Application.cpp @@ -175,7 +175,6 @@ public: , mValidations (IValidations::New ()) , mUNL (UniqueNodeList::New ()) , mProofOfWorkFactory (IProofOfWorkFactory::New ()) - , mPeers (IPeers::New (m_mainService)) , m_loadManager (ILoadManager::New ()) // VFALCO End new stuff // VFALCO TODO replace all NULL with nullptr @@ -183,10 +182,7 @@ public: , mTxnDB (NULL) , mLedgerDB (NULL) , mWalletDB (NULL) // VFALCO NOTE are all these 'NULL' ctor params necessary? - , mPeerDoor (NULL) , mRPCDoor (NULL) - , mWSPublicDoor (NULL) - , mWSPrivateDoor (NULL) , mSweepTimer (m_auxService) , mShutdown (false) { @@ -283,7 +279,7 @@ public: PeerDoor& getPeerDoor () { - return *mPeerDoor; + return *m_peerDoor; } OrderBookDB& getOrderBookDB () @@ -336,9 +332,9 @@ public: return *mProofOfWorkFactory; } - IPeers& getPeers () + Peers& getPeers () { - return *mPeers; + return *m_peers; } // VFALCO TODO Move these to the .cpp @@ -519,25 +515,54 @@ public: mLedgerMaster.setMinValidations (getConfig ().VALIDATION_QUORUM); + //---------------------------------------------------------------------- // - // Allow peer connections. + // + + // SSL context used for Peer connections. + { + m_peerSSLContext = RippleSSLContext::createAnonymous ( + getConfig ().PEER_SSL_CIPHER_LIST); + + // VFALCO NOTE, It seems the WebSocket context never has + // set_verify_mode called, for either setting of WEBSOCKET_SECURE + m_peerSSLContext->get().set_verify_mode (boost::asio::ssl::verify_none); + } + + // VFALCO NOTE Unfortunately, in stand-alone mode some code still + // foolishly calls getPeers(). When this is fixed we can move + // the creation of the peer SSL context and Peers object into + // the conditional. + // + m_peers = Peers::New (m_mainService, m_peerSSLContext->get ()); + + // If we're not in standalone mode, + // prepare ourselves for networking // if (!getConfig ().RUN_STANDALONE) { - try - { - mPeerDoor = PeerDoor::New ( - getConfig ().PEER_IP, - getConfig ().PEER_PORT, - getConfig ().PEER_SSL_CIPHER_LIST, - m_mainService); - } - catch (const std::exception& e) - { - // Must run as directed or exit. - WriteLog (lsFATAL, Application) << boost::str (boost::format ("Can not open peer service: %s") % e.what ()); + // Create the listening sockets for peers + // + m_peerDoor = PeerDoor::New ( + PeerDoor::sslRequired, + getConfig ().PEER_IP, + getConfig ().peerListeningPort, + m_mainService, + m_peerSSLContext->get ()); - exit (3); + if (getConfig ().peerPROXYListeningPort != 0) + { +#if RIPPLE_PEER_USES_BEAST_MULTISOCKET + // Also listen on a PROXY-only port. + m_peerProxyDoor = PeerDoor::New ( + PeerDoor::sslAndPROXYRequired, + getConfig ().PEER_IP, + getConfig ().peerPROXYListeningPort, + m_mainService, + m_peerSSLContext->get ()); +#else + WriteLog (lsWARNING, Application) << "Peer PROXY interface: configured but disabled by build configuration."; +#endif } } else @@ -545,6 +570,59 @@ public: WriteLog (lsINFO, Application) << "Peer interface: disabled"; } + // SSL context used for WebSocket connections. + if (getConfig ().WEBSOCKET_SECURE) + { + m_wsSSLContext = RippleSSLContext::createAuthenticated ( + getConfig ().WEBSOCKET_SSL_KEY, + getConfig ().WEBSOCKET_SSL_CERT, + getConfig ().WEBSOCKET_SSL_CHAIN); + } + else + { + m_wsSSLContext = RippleSSLContext::createBare (); + } + + // Create private listening WebSocket socket + // + if (!getConfig ().WEBSOCKET_IP.empty () && getConfig ().WEBSOCKET_PORT) + { + m_wsPrivateDoor = WSDoor::New (getConfig ().WEBSOCKET_IP, + getConfig ().WEBSOCKET_PORT, false, m_wsSSLContext->get ()); + + if (m_wsPrivateDoor == nullptr) + { + FatalError ("Could not open the WebSocket private interface.", + __FILE__, __LINE__); + } + } + else + { + WriteLog (lsINFO, Application) << "WebSocket private interface: disabled"; + } + + // Create public listening WebSocket socket + // + if (!getConfig ().WEBSOCKET_PUBLIC_IP.empty () && getConfig ().WEBSOCKET_PUBLIC_PORT) + { + m_wsPublicDoor = WSDoor::New (getConfig ().WEBSOCKET_PUBLIC_IP, + getConfig ().WEBSOCKET_PUBLIC_PORT, true, m_wsSSLContext->get ()); + + if (m_wsPublicDoor == nullptr) + { + FatalError ("Could not open the WebSocket public interface.", + __FILE__, __LINE__); + } + } + else + { + WriteLog (lsINFO, Application) << "WebSocket public interface: disabled"; + } + + // + // + //---------------------------------------------------------------------- + // // Allow RPC connections. // @@ -567,55 +645,11 @@ public: WriteLog (lsINFO, Application) << "RPC interface: disabled"; } - // - // Allow private WS connections. - // - if (!getConfig ().WEBSOCKET_IP.empty () && getConfig ().WEBSOCKET_PORT) - { - try - { - mWSPrivateDoor = new WSDoor (getConfig ().WEBSOCKET_IP, getConfig ().WEBSOCKET_PORT, false); - } - catch (const std::exception& e) - { - // Must run as directed or exit. - WriteLog (lsFATAL, Application) << boost::str (boost::format ("Can not open private websocket service: %s") % e.what ()); - - exit (3); - } - } - else - { - WriteLog (lsINFO, Application) << "WS private interface: disabled"; - } - - // - // Allow public WS connections. - // - if (!getConfig ().WEBSOCKET_PUBLIC_IP.empty () && getConfig ().WEBSOCKET_PUBLIC_PORT) - { - try - { - mWSPublicDoor = new WSDoor (getConfig ().WEBSOCKET_PUBLIC_IP, getConfig ().WEBSOCKET_PUBLIC_PORT, true); - } - catch (const std::exception& e) - { - // Must run as directed or exit. - WriteLog (lsFATAL, Application) << boost::str (boost::format ("Can not open public websocket service: %s") % e.what ()); - - exit (3); - } - } - else - { - WriteLog (lsINFO, Application) << "WS public interface: disabled"; - } - // // Begin connecting to network. // if (!getConfig ().RUN_STANDALONE) - mPeers->start (); + m_peers->start (); if (getConfig ().RUN_STANDALONE) { @@ -631,7 +665,6 @@ public: } } - void run (); void stop (); void sweep (); @@ -648,10 +681,6 @@ private: IoServiceThread m_mainService; IoServiceThread m_auxService; - //boost::asio::io_service mIOService; - //boost::asio::io_service mAuxService; - //boost::asio::io_service::work mIOWork; - LocalCredentials m_localCredentials; LedgerMaster mLedgerMaster; InboundLedgers m_inboundLedgers; @@ -666,6 +695,8 @@ private: OrderBookDB mOrderBookDB; // VFALCO Clean stuff + ScopedPointer m_peerSSLContext; + ScopedPointer m_wsSSLContext; ScopedPointer m_nodeStore; ScopedPointer m_validators; ScopedPointer mFeatures; @@ -675,8 +706,12 @@ private: ScopedPointer mValidations; ScopedPointer mUNL; ScopedPointer mProofOfWorkFactory; - ScopedPointer mPeers; + ScopedPointer m_peers; ScopedPointer m_loadManager; + ScopedPointer m_peerDoor; + ScopedPointer m_peerProxyDoor; + ScopedPointer m_wsPublicDoor; + ScopedPointer m_wsPrivateDoor; // VFALCO End Clean stuff DatabaseCon* mRpcDB; @@ -684,10 +719,7 @@ private: DatabaseCon* mLedgerDB; DatabaseCon* mWalletDB; - ScopedPointer mPeerDoor; ScopedPointer mRPCDoor; - ScopedPointer mWSPublicDoor; - ScopedPointer mWSPrivateDoor; boost::asio::deadline_timer mSweepTimer; @@ -700,6 +732,7 @@ private: void ApplicationImp::stop () { WriteLog (lsINFO, Application) << "Received shutdown request"; + StopSustain (); mShutdown = true; m_mainService.stop (); @@ -715,43 +748,56 @@ void ApplicationImp::stop () void ApplicationImp::run () { - // VFALCO TODO The unit tests crash if we try to - // run these threads in the IoService constructor - // so this hack makes them start later. - // - m_mainService.runExtraThreads (); - m_auxService.runExtraThreads (); - - if (!getConfig ().RUN_STANDALONE) { - // VFALCO NOTE This seems unnecessary. If we properly refactor the load - // manager then the deadlock detector can just always be "armed" + // VFALCO TODO The unit tests crash if we try to + // run these threads in the IoService constructor + // so this hack makes them start later. // - getApp().getLoadManager ().activateDeadlockDetector (); + m_mainService.runExtraThreads (); + m_auxService.runExtraThreads (); + + if (!getConfig ().RUN_STANDALONE) + { + // VFALCO NOTE This seems unnecessary. If we properly refactor the load + // manager then the deadlock detector can just always be "armed" + // + getApp().getLoadManager ().activateDeadlockDetector (); + } } - m_mainService.run (); // This blocks until the io_service is stopped. - - if (mWSPublicDoor) - mWSPublicDoor->stop (); - - if (mWSPrivateDoor) - mWSPrivateDoor->stop (); - - // VFALCO TODO Try to not have to do this early, by using observers to - // eliminate LoadManager's dependency inversions. + //-------------------------------------------------------------------------- + // // - // This deletes the object and therefore, stops the thread. - m_loadManager = nullptr; - mSweepTimer.cancel(); + // We use the main thread to call io_service::run. + // What else would we have it do? It blocks until the server + // eventually gets a stop command. + // + m_mainService.run (); - WriteLog (lsINFO, Application) << "Done."; + // + // + //-------------------------------------------------------------------------- - // VFALCO NOTE This is a sign that something is wrong somewhere, it - // shouldn't be necessary to sleep until some flag is set. - while (mShutdown) - boost::this_thread::sleep (boost::posix_time::milliseconds (100)); + { + m_wsPublicDoor = nullptr; + m_wsPrivateDoor = nullptr; + + // VFALCO TODO Try to not have to do this early, by using observers to + // eliminate LoadManager's dependency inversions. + // + // This deletes the object and therefore, stops the thread. + m_loadManager = nullptr; + + mSweepTimer.cancel(); + + WriteLog (lsINFO, Application) << "Done."; + + // VFALCO NOTE This is a sign that something is wrong somewhere, it + // shouldn't be necessary to sleep until some flag is set. + while (mShutdown) + boost::this_thread::sleep (boost::posix_time::milliseconds (100)); + } } void ApplicationImp::sweep () diff --git a/modules/ripple_app/main/ripple_Application.h b/modules/ripple_app/main/ripple_Application.h index 1b60883b85..d705082122 100644 --- a/modules/ripple_app/main/ripple_Application.h +++ b/modules/ripple_app/main/ripple_Application.h @@ -12,7 +12,7 @@ class IFeatures; class IFeeVote; class IHashRouter; class ILoadFeeTrack; -class IPeers; +class Peers; class IProofOfWorkFactory; class UniqueNodeList; class IValidations; @@ -83,12 +83,12 @@ public: virtual IHashRouter& getHashRouter () = 0; virtual ILoadFeeTrack& getFeeTrack () = 0; virtual ILoadManager& getLoadManager () = 0; - virtual IPeers& getPeers () = 0; + virtual Peers& getPeers () = 0; virtual IProofOfWorkFactory& getProofOfWorkFactory () = 0; - virtual UniqueNodeList& getUNL () = 0; + virtual UniqueNodeList& getUNL () = 0; virtual IValidations& getValidations () = 0; - virtual NodeStore& getNodeStore () = 0; + virtual NodeStore& getNodeStore () = 0; virtual JobQueue& getJobQueue () = 0; virtual InboundLedgers& getInboundLedgers () = 0; virtual LedgerMaster& getLedgerMaster () = 0; diff --git a/modules/ripple_app/main/ripple_LocalCredentials.cpp b/modules/ripple_app/main/ripple_LocalCredentials.cpp index 297a982255..797d71a4f8 100644 --- a/modules/ripple_app/main/ripple_LocalCredentials.cpp +++ b/modules/ripple_app/main/ripple_LocalCredentials.cpp @@ -4,9 +4,9 @@ */ //============================================================================== -LocalCredentials::LocalCredentials () : mDh512 (NULL), mDh1024 (NULL), mLedger (0) +LocalCredentials::LocalCredentials () + : mLedger (0) { - ; } void LocalCredentials::start () @@ -32,7 +32,6 @@ void LocalCredentials::start () // Retrieve network identity. bool LocalCredentials::nodeIdentityLoad () { - Database* db = getApp().getWalletDB ()->getDB (); DeprecatedScopedLock sl (getApp().getWalletDB ()->getDBLock ()); bool bSuccess = false; @@ -47,9 +46,6 @@ bool LocalCredentials::nodeIdentityLoad () mNodePublicKey.setNodePublic (strPublicKey); mNodePrivateKey.setNodePrivate (strPrivateKey); - mDh512 = DH_der_load (db->getStrBinary ("Dh512")); - mDh1024 = DH_der_load (db->getStrBinary ("Dh1024")); - db->endIterRows (); bSuccess = true; } @@ -77,22 +73,12 @@ bool LocalCredentials::nodeIdentityCreate () RippleAddress naNodePrivate = RippleAddress::createNodePrivate (naSeed); // Make new key. - #ifdef CREATE_NEW_DH_PARAMS - std::string strDh512 = DH_der_gen (512); -#else - static const unsigned char dh512Param[] = - { - 0x30, 0x46, 0x02, 0x41, 0x00, 0x98, 0x15, 0xd2, 0xd0, 0x08, 0x32, 0xda, - 0xaa, 0xac, 0xc4, 0x71, 0xa3, 0x1b, 0x11, 0xf0, 0x6c, 0x62, 0xb2, 0x35, - 0x8a, 0x10, 0x92, 0xc6, 0x0a, 0xa3, 0x84, 0x7e, 0xaf, 0x17, 0x29, 0x0b, - 0x70, 0xef, 0x07, 0x4f, 0xfc, 0x9d, 0x6d, 0x87, 0x99, 0x19, 0x09, 0x5b, - 0x6e, 0xdb, 0x57, 0x72, 0x4a, 0x7e, 0xcd, 0xaf, 0xbd, 0x3a, 0x97, 0x55, - 0x51, 0x77, 0x5a, 0x34, 0x7c, 0xe8, 0xc5, 0x71, 0x63, 0x02, 0x01, 0x02 - }; - std::string strDh512 (reinterpret_cast (dh512Param), sizeof (dh512Param)); -#endif + std::string strDh512 = DH_der_gen (512); +#else + std::string strDh512 (RippleSSLContext::getRawDHParams (512)); +#endif #if 1 std::string strDh1024 = strDh512; // For testing and most cases 512 is fine. diff --git a/modules/ripple_app/main/ripple_LocalCredentials.h b/modules/ripple_app/main/ripple_LocalCredentials.h index 86ebe9ac15..1eb04959fb 100644 --- a/modules/ripple_app/main/ripple_LocalCredentials.h +++ b/modules/ripple_app/main/ripple_LocalCredentials.h @@ -28,16 +28,6 @@ public: return mNodePrivateKey; } - DH* getDh512 () const - { - return DHparams_dup (mDh512); - } - - DH* getDh1024 () const - { - return DHparams_dup (mDh1024); - } - // Local persistence of RPC clients bool dataDelete (std::string const& strKey); @@ -57,8 +47,6 @@ private: RippleAddress mNodePublicKey; RippleAddress mNodePrivateKey; - DH* mDh512; - DH* mDh1024; LedgerIndex mLedger; // ledger we last synched to }; diff --git a/modules/ripple_app/network/WSDoor.cpp b/modules/ripple_app/network/WSDoor.cpp deleted file mode 100644 index 4acb9c3c53..0000000000 --- a/modules/ripple_app/network/WSDoor.cpp +++ /dev/null @@ -1,117 +0,0 @@ -//------------------------------------------------------------------------------ -/* - Copyright (c) 2011-2013, OpenCoin, Inc. -*/ -//============================================================================== - -SETUP_LOG (WSDoor) - -// -// This is a light weight, untrusted interface for web clients. -// For now we don't provide proof. Later we will. -// -// Might need to support this header for browsers: Access-Control-Allow-Origin: * -// - https://developer.mozilla.org/en-US/docs/HTTP_access_control -// - -// -// Strategy: -// - We only talk to NetworkOPs (so we will work even in thin mode) -// - NetworkOPs is smart enough to subscribe and or pass back messages -// -// VFALCO NOTE NetworkOPs isn't used here... -// - -WSDoor::WSDoor (std::string const& strIp, int iPort, bool bPublic) - : Thread ("websocket") - , m_endpointLock (this, "WSDoor", __FILE__, __LINE__) - , mPublic (bPublic) - , mIp (strIp) - , mPort (iPort) -{ - startThread (); -} - -WSDoor::~WSDoor () -{ - { - ScopedLockType lock (m_endpointLock, __FILE__, __LINE__); - - if (m_endpoint != nullptr) - m_endpoint->stop (); - } - - signalThreadShouldExit (); - waitForThreadToExit (); -} - -void WSDoor::run () -{ - WriteLog (lsINFO, WSDoor) << boost::str (boost::format ("Websocket: %s: Listening: %s %d ") - % (mPublic ? "Public" : "Private") - % mIp - % mPort); - - // Generate a single SSL context for use by all connections. - boost::shared_ptr mCtx; - mCtx = boost::make_shared (boost::asio::ssl::context::sslv23); - - mCtx->set_options ( - boost::asio::ssl::context::default_workarounds - | boost::asio::ssl::context::no_sslv2 - | boost::asio::ssl::context::single_dh_use); - - SSL_CTX_set_tmp_dh_callback (mCtx->native_handle (), handleTmpDh); - - websocketpp::server_autotls::handler::ptr handler (new WSServerHandler (mCtx, mPublic)); - - { - ScopedLockType lock (m_endpointLock, __FILE__, __LINE__); - - m_endpoint = new websocketpp::server_autotls (handler); - } - - // mEndpoint->alog().unset_level(websocketpp::log::alevel::ALL); - // mEndpoint->elog().unset_level(websocketpp::log::elevel::ALL); - - // Call the main-event-loop of the websocket server. - try - { - m_endpoint->listen ( - boost::asio::ip::tcp::endpoint ( - boost::asio::ip::address ().from_string (mIp), mPort)); - } - catch (websocketpp::exception& e) - { - WriteLog (lsWARNING, WSDoor) << "websocketpp exception: " << e.what (); - - while (1) // temporary workaround for websocketpp throwing exceptions on access/close races - { - // https://github.com/zaphoyd/websocketpp/issues/98 - try - { - m_endpoint->get_io_service ().run (); - break; - } - catch (websocketpp::exception& e) - { - WriteLog (lsWARNING, WSDoor) << "websocketpp exception: " << e.what (); - } - } - } - - delete m_endpoint; -} - -void WSDoor::stop () -{ - { - ScopedLockType lock (m_endpointLock, __FILE__, __LINE__); - - if (m_endpoint != nullptr) - m_endpoint->stop (); - } - - signalThreadShouldExit (); - waitForThreadToExit (); -} diff --git a/modules/ripple_app/network/WSDoor.h b/modules/ripple_app/network/WSDoor.h deleted file mode 100644 index 135ad577ad..0000000000 --- a/modules/ripple_app/network/WSDoor.h +++ /dev/null @@ -1,35 +0,0 @@ -//------------------------------------------------------------------------------ -/* - Copyright (c) 2011-2013, OpenCoin, Inc. -*/ -//============================================================================== - -#ifndef RIPPLE_WSDOOR_RIPPLEHEADER -#define RIPPLE_WSDOOR_RIPPLEHEADER - -class WSDoor : protected Thread, LeakChecked -{ -public: - WSDoor (std::string const& strIp, int iPort, bool bPublic); - - ~WSDoor (); - - void stop (); - -private: - void run (); - -private: - typedef RippleRecursiveMutex LockType; - typedef LockType::ScopedLockType ScopedLockType; - LockType m_endpointLock; - - ScopedPointer m_endpoint; - bool mPublic; - std::string mIp; - int mPort; -}; - -#endif - -// vim:ts=4 diff --git a/modules/ripple_app/peers/PeerDoor.cpp b/modules/ripple_app/peers/PeerDoor.cpp index 64bbe30bb2..c4f2905112 100644 --- a/modules/ripple_app/peers/PeerDoor.cpp +++ b/modules/ripple_app/peers/PeerDoor.cpp @@ -9,27 +9,14 @@ SETUP_LOG (PeerDoor) class PeerDoorImp : public PeerDoor, LeakChecked { public: - PeerDoorImp (std::string const& ip, - int port, - std::string const& sslCiphers, - boost::asio::io_service& io_service) - : mAcceptor ( - io_service, - boost::asio::ip::tcp::endpoint (boost::asio::ip::address ().from_string (ip.empty () ? "0.0.0.0" : ip), - port)) - , mCtx (boost::asio::ssl::context::sslv23) + PeerDoorImp (Kind kind, std::string const& ip, int port, + boost::asio::io_service& io_service, boost::asio::ssl::context& ssl_context) + : m_kind (kind) + , m_ssl_context (ssl_context) + , mAcceptor (io_service, boost::asio::ip::tcp::endpoint ( + boost::asio::ip::address ().from_string (ip.empty () ? "0.0.0.0" : ip), port)) , mDelayTimer (io_service) { - mCtx.set_options ( - boost::asio::ssl::context::default_workarounds | - boost::asio::ssl::context::no_sslv2 | - boost::asio::ssl::context::single_dh_use); - - SSL_CTX_set_tmp_dh_callback (mCtx.native_handle (), handleTmpDh); - - if (SSL_CTX_set_cipher_list (mCtx.native_handle (), sslCiphers.c_str ()) != 1) - std::runtime_error ("Error setting cipher list (no valid ciphers)."); - if (! ip.empty () && port != 0) { Log (lsINFO) << "Peer port: " << ip << " " << port; @@ -39,30 +26,25 @@ public: //-------------------------------------------------------------------------- - boost::asio::ssl::context& getSSLContext () - { - return mCtx; - } - - //-------------------------------------------------------------------------- - void startListening () { - Peer::pointer new_connection = Peer::New ( - mAcceptor.get_io_service (), - mCtx, - getApp().getPeers ().assignPeerId (), - true); + bool const isInbound (true); + bool const requirePROXYHandshake (m_kind == sslAndPROXYRequired); + + Peer::pointer new_connection (Peer::New ( + mAcceptor.get_io_service (), m_ssl_context, + getApp().getPeers ().assignPeerId (), + isInbound, requirePROXYHandshake)); mAcceptor.async_accept (new_connection->getNativeSocket (), - boost::bind (&PeerDoorImp::handleConnect, this, new_connection, - boost::asio::placeholders::error)); + boost::bind (&PeerDoorImp::handleConnect, this, new_connection, + boost::asio::placeholders::error)); } //-------------------------------------------------------------------------- void handleConnect (Peer::pointer new_connection, - const boost::system::error_code& error) + boost::system::error_code const& error) { bool delay = false; @@ -90,18 +72,16 @@ public: } private: + Kind m_kind; + boost::asio::ssl::context& m_ssl_context; boost::asio::ip::tcp::acceptor mAcceptor; - boost::asio::ssl::context mCtx; boost::asio::deadline_timer mDelayTimer; }; //------------------------------------------------------------------------------ -PeerDoor* PeerDoor::New ( - std::string const& ip, - int port, - std::string const& sslCiphers, - boost::asio::io_service& io_service) +PeerDoor* PeerDoor::New (Kind kind, std::string const& ip, int port, + boost::asio::io_service& io_service, boost::asio::ssl::context& ssl_context) { - return new PeerDoorImp (ip, port, sslCiphers, io_service); + return new PeerDoorImp (kind, ip, port, io_service, ssl_context); } diff --git a/modules/ripple_app/peers/PeerDoor.h b/modules/ripple_app/peers/PeerDoor.h index decaa657ea..31fbcffa2c 100644 --- a/modules/ripple_app/peers/PeerDoor.h +++ b/modules/ripple_app/peers/PeerDoor.h @@ -14,13 +14,16 @@ class PeerDoor : LeakChecked public: virtual ~PeerDoor () { } - static PeerDoor* New ( - std::string const& ip, - int port, - std::string const& sslCiphers, - boost::asio::io_service& io_service); + enum Kind + { + sslRequired, + sslAndPROXYRequired + }; - virtual boost::asio::ssl::context& getSSLContext () = 0; + static PeerDoor* New (Kind kind, std::string const& ip, int port, + boost::asio::io_service& io_service, boost::asio::ssl::context& ssl_context); + + //virtual boost::asio::ssl::context& getSSLContext () = 0; }; #endif diff --git a/modules/ripple_app/peers/ripple_Peer.cpp b/modules/ripple_app/peers/ripple_Peer.cpp index a93c51e827..051f00366f 100644 --- a/modules/ripple_app/peers/ripple_Peer.cpp +++ b/modules/ripple_app/peers/ripple_Peer.cpp @@ -33,22 +33,22 @@ public: // #if RIPPLE_PEER_USES_BEAST_MULTISOCKET - ScopedPointer m_multiSocket; + ScopedPointer m_socket; boost::asio::io_service& m_strand; NativeSocketType& getNativeSocket () { - return m_multiSocket->next_layer (); + return m_socket->next_layer (); } MultiSocket& getHandshakeStream () { - return *m_multiSocket; + return *m_socket; } MultiSocket& getStream () { - return *m_multiSocket; + return *m_socket; } //--------------------------------------------------------------------------- @@ -82,21 +82,18 @@ public: public: PeerImp (boost::asio::io_service& io_service, - boost::asio::ssl::context& ctx, + boost::asio::ssl::context& ssl_context, uint64 peerID, - bool inbound) + bool inbound, + MultiSocket::Flag flags) : m_isInbound (inbound) #if RIPPLE_PEER_USES_BEAST_MULTISOCKET - // We could optionally set Flag::client_role or Flag::server_role - // based on the inbound flag but MultiSocket can figure out out - // from the call to handshake. - // - , m_multiSocket (MultiSocket::New ( - io_service, MultiSocket::Flag::ssl | MultiSocket::Flag::ssl_required)) + , m_socket (MultiSocket::New ( + io_service, ssl_context, flags.asBits ())) , m_strand (io_service) #else , m_socket (io_service) - , m_ssl_stream (m_socket, ctx) + , m_ssl_stream (m_socket, ssl_context) , m_strand (io_service) #endif , mHelloed (false) @@ -2330,7 +2327,7 @@ void PeerImp::sendHello () h.set_nettime (getApp().getOPs ().getNetworkTimeNC ()); h.set_nodepublic (getApp().getLocalCredentials ().getNodePublic ().humanNodePublic ()); h.set_nodeproof (&vchSig[0], vchSig.size ()); - h.set_ipv4port (getConfig ().PEER_PORT); + h.set_ipv4port (getConfig ().peerListeningPort); h.set_nodeprivate (getConfig ().PEER_PRIVATE); h.set_testnet (getConfig ().TESTNET); @@ -2545,13 +2542,38 @@ Json::Value PeerImp::getJson () //------------------------------------------------------------------------------ Peer::pointer Peer::New (boost::asio::io_service& io_service, - boost::asio::ssl::context& ctx, - uint64 id, - bool inbound) + boost::asio::ssl::context& ssl_context, uint64 id, + bool inbound, bool requirePROXYHandshake) { - return Peer::pointer (new PeerImp (io_service, ctx, id, inbound)); + MultiSocket::Flag flags; + + if (inbound) + { + flags = MultiSocket::Flag::server_role | MultiSocket::Flag::ssl_required; + + if (requirePROXYHandshake) + { +#if RIPPLE_PEER_USES_BEAST_MULTISOCKET + flags = flags.with (MultiSocket::Flag::proxy); +#else + FatalError ("PROXY Handshake support disabled in this build", + __FILE__, __LINE__); +#endif + } + } + else + { + flags = MultiSocket::Flag::client_role | MultiSocket::Flag::ssl; + + bassert (! requirePROXYHandshake); + } + + return Peer::pointer (new PeerImp ( + io_service, ssl_context, id, inbound, flags)); } +//------------------------------------------------------------------------------ + void Peer::applyLoadCharge (boost::weak_ptr & peerToPunish, LoadType loadThatWasImposed) { diff --git a/modules/ripple_app/peers/ripple_Peer.h b/modules/ripple_app/peers/ripple_Peer.h index ba94073354..ee038435d4 100644 --- a/modules/ripple_app/peers/ripple_Peer.h +++ b/modules/ripple_app/peers/ripple_Peer.h @@ -24,7 +24,8 @@ public: static pointer New (boost::asio::io_service& io_service, boost::asio::ssl::context& ctx, uint64 id, - bool inbound); + bool inbound, + bool requirePROXYHandshake); // VFALCO TODO see if this and below can be private virtual void handleConnect (const boost::system::error_code& error, diff --git a/modules/ripple_app/peers/ripple_Peers.cpp b/modules/ripple_app/peers/ripple_Peers.cpp index cec9a9169e..a629a7b0f1 100644 --- a/modules/ripple_app/peers/ripple_Peers.cpp +++ b/modules/ripple_app/peers/ripple_Peers.cpp @@ -4,9 +4,11 @@ */ //============================================================================== -class Peers - : public IPeers - , LeakChecked +SETUP_LOG (Peers) + +class PeersImp + : public Peers + , LeakChecked { public: enum @@ -16,8 +18,10 @@ public: policyIntervalSeconds = 5 }; - explicit Peers (boost::asio::io_service& io_service) - : mPeerLock (this, "Peers", __FILE__, __LINE__) + PeersImp (boost::asio::io_service& io_service, boost::asio::ssl::context& ssl_context) + : m_io_service (io_service) + , m_ssl_context (ssl_context) + , mPeerLock (this, "PeersImp", __FILE__, __LINE__) , mLastPeer (0) , mPhase (0) , mScanTimer (io_service) @@ -84,16 +88,19 @@ public: private: typedef RippleRecursiveMutex LockType; typedef LockType::ScopedLockType ScopedLockType; + typedef std::pair naPeer; + typedef std::pair pipPeer; + typedef std::map::value_type vtPeer; + + boost::asio::io_service& m_io_service; + boost::asio::ssl::context& m_ssl_context; + LockType mPeerLock; uint64 mLastPeer; int mPhase; - typedef std::pair naPeer; - typedef std::pair pipPeer; - typedef std::map::value_type vtPeer; - - // Peers we are connecting with and non-thin peers we are connected to. + // PeersImp we are connecting with and non-thin peers we are connected to. // Only peers we know the connection ip for are listed. // We know the ip and port for: // - All outbound connections @@ -101,7 +108,7 @@ private: boost::unordered_map mIpMap; // Non-thin peers which we are connected to. - // Peers we have the public key for. + // PeersImp we have the public key for. typedef boost::unordered_map::value_type vtConMap; boost::unordered_map mConnectedMap; @@ -119,7 +126,7 @@ private: void policyHandler (const boost::system::error_code& ecResult); - // Peers we are establishing a connection with as a client. + // PeersImp we are establishing a connection with as a client. // int miConnectStarting; bool peerAvailable (std::string& strIp, int& iPort); @@ -137,7 +144,7 @@ void splitIpPort (const std::string& strIpPort, std::string& strIp, int& iPort) iPort = lexicalCastThrow (vIpPort[1]); } -void Peers::start () +void PeersImp::start () { if (getConfig ().RUN_STANDALONE) return; @@ -149,7 +156,7 @@ void Peers::start () scanRefresh (); } -bool Peers::getTopNAddrs (int n, std::vector& addrs) +bool PeersImp::getTopNAddrs (int n, std::vector& addrs) { // Try current connections first @@ -185,7 +192,7 @@ bool Peers::getTopNAddrs (int n, std::vector& addrs) return true; } -bool Peers::savePeer (const std::string& strIp, int iPort, char code) +bool PeersImp::savePeer (const std::string& strIp, int iPort, char code) { bool bNew = false; @@ -225,7 +232,7 @@ bool Peers::savePeer (const std::string& strIp, int iPort, char code) return bNew; } -Peer::pointer Peers::getPeerById (const uint64& id) +Peer::pointer PeersImp::getPeerById (const uint64& id) { ScopedLockType sl (mPeerLock, __FILE__, __LINE__); const boost::unordered_map::iterator& it = mPeerIdMap.find (id); @@ -236,7 +243,7 @@ Peer::pointer Peers::getPeerById (const uint64& id) return it->second; } -bool Peers::hasPeer (const uint64& id) +bool PeersImp::hasPeer (const uint64& id) { ScopedLockType sl (mPeerLock, __FILE__, __LINE__); return mPeerIdMap.find (id) != mPeerIdMap.end (); @@ -246,7 +253,7 @@ bool Peers::hasPeer (const uint64& id) // too. // // <-- true, if a peer is available to connect to -bool Peers::peerAvailable (std::string& strIp, int& iPort) +bool PeersImp::peerAvailable (std::string& strIp, int& iPort) { Database* db = getApp().getWalletDB ()->getDB (); std::vector vstrIpPort; @@ -290,7 +297,7 @@ bool Peers::peerAvailable (std::string& strIp, int& iPort) } // Make sure we have at least low water connections. -void Peers::policyLowWater () +void PeersImp::policyLowWater () { std::string strIp; int iPort; @@ -335,7 +342,7 @@ void Peers::policyLowWater () } } -void Peers::policyEnforce () +void PeersImp::policyEnforce () { // Cancel any in progress timer. (void) mPolicyTimer.cancel (); @@ -351,10 +358,10 @@ void Peers::policyEnforce () // Schedule next enforcement. mPolicyTimer.expires_at (boost::posix_time::second_clock::universal_time () + boost::posix_time::seconds (policyIntervalSeconds)); - mPolicyTimer.async_wait (BIND_TYPE (&Peers::policyHandler, this, P_1)); + mPolicyTimer.async_wait (BIND_TYPE (&PeersImp::policyHandler, this, P_1)); } -void Peers::policyHandler (const boost::system::error_code& ecResult) +void PeersImp::policyHandler (const boost::system::error_code& ecResult) { if (ecResult == boost::asio::error::operation_aborted) { @@ -372,7 +379,7 @@ void Peers::policyHandler (const boost::system::error_code& ecResult) // YYY: Should probably do this in the background. // YYY: Might end up sending to disconnected peer? -int Peers::relayMessage (Peer* fromPeer, const PackedMessage::pointer& msg) +int PeersImp::relayMessage (Peer* fromPeer, const PackedMessage::pointer& msg) { int sentTo = 0; std::vector peerVector = getPeerVector (); @@ -388,7 +395,7 @@ int Peers::relayMessage (Peer* fromPeer, const PackedMessage::pointer& msg) return sentTo; } -int Peers::relayMessageCluster (Peer* fromPeer, const PackedMessage::pointer& msg) +int PeersImp::relayMessageCluster (Peer* fromPeer, const PackedMessage::pointer& msg) { int sentTo = 0; std::vector peerVector = getPeerVector (); @@ -404,7 +411,7 @@ int Peers::relayMessageCluster (Peer* fromPeer, const PackedMessage::pointer& ms return sentTo; } -void Peers::relayMessageBut (const std::set& fromPeers, const PackedMessage::pointer& msg) +void PeersImp::relayMessageBut (const std::set& fromPeers, const PackedMessage::pointer& msg) { // Relay message to all but the specified peers std::vector peerVector = getPeerVector (); @@ -416,7 +423,7 @@ void Peers::relayMessageBut (const std::set& fromPeers, const PackedMess } -void Peers::relayMessageTo (const std::set& fromPeers, const PackedMessage::pointer& msg) +void PeersImp::relayMessageTo (const std::set& fromPeers, const PackedMessage::pointer& msg) { // Relay message to the specified peers std::vector peerVector = getPeerVector (); @@ -432,7 +439,7 @@ void Peers::relayMessageTo (const std::set& fromPeers, const PackedMessa // // Add or modify into PeerIps as a manual entry for immediate scanning. // Requires sane IP and port. -void Peers::connectTo (const std::string& strIp, int iPort) +void PeersImp::connectTo (const std::string& strIp, int iPort) { { Database* db = getApp().getWalletDB ()->getDB (); @@ -450,24 +457,23 @@ void Peers::connectTo (const std::string& strIp, int iPort) // Start a connection, if not already known connected or connecting. // // <-- true, if already connected. -Peer::pointer Peers::peerConnect (const std::string& strIp, int iPort) +Peer::pointer PeersImp::peerConnect (const std::string& strIp, int iPort) { IPAndPortNumber pipPeer = make_pair (strIp, iPort); Peer::pointer ppResult; - { ScopedLockType sl (mPeerLock, __FILE__, __LINE__); if (mIpMap.find (pipPeer) == mIpMap.end ()) { - ppResult = Peer::New (getApp().getIOService (), - getApp().getPeerDoor ().getSSLContext (), - ++mLastPeer, - false); + bool const isInbound (false); + bool const requirePROXYHandshake (false); - mIpMap[pipPeer] = ppResult; - // ++miConnectStarting; + ppResult = Peer::New (m_io_service, m_ssl_context, + ++mLastPeer, isInbound, requirePROXYHandshake); + + mIpMap [pipPeer] = ppResult; } } @@ -485,7 +491,7 @@ Peer::pointer Peers::peerConnect (const std::string& strIp, int iPort) } // Returns information on verified peers. -Json::Value Peers::getPeersJson () +Json::Value PeersImp::getPeersJson () { Json::Value ret (Json::arrayValue); std::vector vppPeers = getPeerVector (); @@ -498,14 +504,14 @@ Json::Value Peers::getPeersJson () return ret; } -int Peers::getPeerCount () +int PeersImp::getPeerCount () { ScopedLockType sl (mPeerLock, __FILE__, __LINE__); return mConnectedMap.size (); } -std::vector Peers::getPeerVector () +std::vector PeersImp::getPeerVector () { std::vector ret; @@ -522,7 +528,7 @@ std::vector Peers::getPeerVector () return ret; } -uint64 Peers::assignPeerId () +uint64 PeersImp::assignPeerId () { ScopedLockType sl (mPeerLock, __FILE__, __LINE__); return ++mLastPeer; @@ -530,7 +536,7 @@ uint64 Peers::assignPeerId () // Now know peer's node public key. Determine if we want to stay connected. // <-- bNew: false = redundant -bool Peers::peerConnected (Peer::ref peer, const RippleAddress& naPeer, +bool PeersImp::peerConnected (Peer::ref peer, const RippleAddress& naPeer, const std::string& strIP, int iPort) { bool bNew = false; @@ -592,7 +598,7 @@ bool Peers::peerConnected (Peer::ref peer, const RippleAddress& naPeer, } // We maintain a map of public key to peer for connected and verified peers. Maintain it. -void Peers::peerDisconnected (Peer::ref peer, const RippleAddress& naPeer) +void PeersImp::peerDisconnected (Peer::ref peer, const RippleAddress& naPeer) { ScopedLockType sl (mPeerLock, __FILE__, __LINE__); @@ -632,7 +638,7 @@ void Peers::peerDisconnected (Peer::ref peer, const RippleAddress& naPeer) // Schedule for immediate scanning, if not already scheduled. // // <-- true, scanRefresh needed. -bool Peers::peerScanSet (const std::string& strIp, int iPort) +bool PeersImp::peerScanSet (const std::string& strIp, int iPort) { std::string strIpPort = str (boost::format ("%s %d") % strIp % iPort); bool bScanDirty = false; @@ -682,7 +688,7 @@ bool Peers::peerScanSet (const std::string& strIp, int iPort) } // --> strIp: not empty -void Peers::peerClosed (Peer::ref peer, const std::string& strIp, int iPort) +void PeersImp::peerClosed (Peer::ref peer, const std::string& strIp, int iPort) { IPAndPortNumber ipPeer = make_pair (strIp, iPort); bool bScanRefresh = false; @@ -735,7 +741,7 @@ void Peers::peerClosed (Peer::ref peer, const std::string& strIp, int iPort) scanRefresh (); } -void Peers::peerVerified (Peer::ref peer) +void PeersImp::peerVerified (Peer::ref peer) { if (mScanning && mScanning == peer) { @@ -770,7 +776,7 @@ void Peers::peerVerified (Peer::ref peer) } } -void Peers::scanHandler (const boost::system::error_code& ecResult) +void PeersImp::scanHandler (const boost::system::error_code& ecResult) { if (ecResult == boost::asio::error::operation_aborted) { @@ -786,7 +792,7 @@ void Peers::scanHandler (const boost::system::error_code& ecResult) } } -void Peers::makeConfigured () +void PeersImp::makeConfigured () { if (getConfig ().RUN_STANDALONE) return; @@ -802,7 +808,7 @@ void Peers::makeConfigured () } // Scan ips as per db entries. -void Peers::scanRefresh () +void PeersImp::scanRefresh () { if (getConfig ().RUN_STANDALONE) { @@ -894,27 +900,15 @@ void Peers::scanRefresh () // % strIpPort % tpNext % (tpNext-tpNow).total_seconds()); mScanTimer.expires_at (tpNext); - mScanTimer.async_wait (BIND_TYPE (&Peers::scanHandler, this, P_1)); + mScanTimer.async_wait (BIND_TYPE (&PeersImp::scanHandler, this, P_1)); } } } -IPeers* IPeers::New (boost::asio::io_service& io_service) +//------------------------------------------------------------------------------ + +Peers* Peers::New (boost::asio::io_service& io_service, boost::asio::ssl::context& ssl_context) { - return new Peers (io_service); + return new PeersImp (io_service, ssl_context); } -#if 0 -bool Peers::isMessageKnown (PackedMessage::pointer msg) -{ - for (unsigned int n = 0; n < mBroadcastMessages.size (); n++) - { - if (msg == mBroadcastMessages[n].first) return (false); - } - - return (false); -} -#endif - -SETUP_LOG (Peers) - diff --git a/modules/ripple_app/peers/ripple_IPeers.h b/modules/ripple_app/peers/ripple_Peers.h similarity index 92% rename from modules/ripple_app/peers/ripple_IPeers.h rename to modules/ripple_app/peers/ripple_Peers.h index bfa44ea4bc..91a88371f5 100644 --- a/modules/ripple_app/peers/ripple_IPeers.h +++ b/modules/ripple_app/peers/ripple_Peers.h @@ -4,17 +4,18 @@ */ //============================================================================== -#ifndef RIPPLE_IPEERS_H_INCLUDED -#define RIPPLE_IPEERS_H_INCLUDED +#ifndef RIPPLE_PEERS_H_INCLUDED +#define RIPPLE_PEERS_H_INCLUDED /** Manages the set of connected peers. */ -class IPeers +class Peers { public: - static IPeers* New (boost::asio::io_service& io_service); + static Peers* New (boost::asio::io_service& io_service, + boost::asio::ssl::context& context); - virtual ~IPeers () { } + virtual ~Peers () { } // Begin enforcing connection policy. virtual void start () = 0; diff --git a/modules/ripple_app/ripple_app.cpp b/modules/ripple_app/ripple_app.cpp index 626309ef13..91f585b9a4 100644 --- a/modules/ripple_app/ripple_app.cpp +++ b/modules/ripple_app/ripple_app.cpp @@ -134,8 +134,8 @@ namespace ripple #include "misc/ripple_IFeatures.h" #include "misc/ripple_IFeeVote.h" #include "misc/ripple_IHashRouter.h" -#include "peers/ripple_Peer.h" // VFALCO TODO Rename to IPeer -#include "peers/ripple_IPeers.h" +#include "peers/ripple_Peer.h" +#include "peers/ripple_Peers.h" #include "misc/ripple_IProofOfWorkFactory.h" #include "peers/ripple_ClusterNodeStatus.h" #include "peers/ripple_UniqueNodeList.h" @@ -156,7 +156,7 @@ namespace ripple #include "misc/NetworkOPs.h" #include "tx/TransactionMaster.h" #include "main/ripple_LocalCredentials.h" -#include "network/WSDoor.h" +#include "websocket/WSDoor.h" #include "boost/ripple_IoService.h" #include "boost/ripple_SslContext.h" #include "main/ripple_Application.h" @@ -188,8 +188,8 @@ namespace ripple #include "paths/ripple_RippleState.h" #include "tx/AccountSetTransactor.h" #include "tx/TrustSetTransactor.h" -#include "network/WSConnection.h" -#include "network/ripple_WSHandler.h" +#include "websocket/WSConnection.h" +#include "websocket/WSServerHandler.h" #include "tx/WalletAddTransactor.h" #include "contracts/ripple_ScriptData.h" @@ -306,14 +306,6 @@ static const uint64 tenTo17m1 = tenTo17 - 1; #if ! defined (RIPPLE_MAIN_PART) || RIPPLE_MAIN_PART == 3 -// This is for PeerDoor and WSDoor -// Generate DH for SSL connection. -static DH* handleTmpDh (SSL* ssl, int is_export, int iKeyLength) -{ - // VFALCO TODO eliminate this horrendous dependency on theApp and LocalCredentials - return 512 == iKeyLength ? getApp().getLocalCredentials ().getDh512 () : getApp().getLocalCredentials ().getDh1024 (); -} - #include "paths/ripple_RippleCalc.cpp" #include "paths/ripple_PathState.cpp" #include "rpc/CallRPC.cpp" @@ -329,8 +321,8 @@ static DH* handleTmpDh (SSL* ssl, int is_export, int iKeyLength) #include "tx/TransactionEngine.cpp" #include "tx/TransactionMeta.cpp" #include "tx/Transactor.cpp" -#include "network/WSConnection.cpp" -#include "network/WSDoor.cpp" +#include "websocket/WSConnection.cpp" +#include "websocket/WSDoor.cpp" #endif @@ -349,7 +341,7 @@ static DH* handleTmpDh (SSL* ssl, int is_export, int iKeyLength) #include "tx/TransactionMaster.cpp" #include "tx/TransactionQueue.cpp" #include "tx/TrustSetTransactor.cpp" -#include "network/ripple_WSHandler.cpp" +#include "websocket/WSServerHandler.cpp" #endif @@ -369,6 +361,7 @@ namespace ripple #include "tx/OfferCreateTransactor.cpp" #include "misc/ripple_Validations.cpp" +#include "main/ripple_LocalCredentials.cpp" #include "tx/WalletAddTransactor.cpp" #include "ledger/ripple_AcceptedLedgerTx.cpp" #include "misc/ripple_FeeVote.cpp" @@ -384,7 +377,6 @@ namespace ripple #include "paths/ripple_Pathfinder.cpp" #include "misc/ripple_Features.cpp" -#include "main/ripple_LocalCredentials.cpp" #include "ledger/ripple_AcceptedLedger.cpp" #include "consensus/ripple_DisputedTx.cpp" #include "misc/ripple_HashRouter.cpp" diff --git a/modules/ripple_app/network/WSConnection.cpp b/modules/ripple_app/websocket/WSConnection.cpp similarity index 100% rename from modules/ripple_app/network/WSConnection.cpp rename to modules/ripple_app/websocket/WSConnection.cpp diff --git a/modules/ripple_app/network/WSConnection.h b/modules/ripple_app/websocket/WSConnection.h similarity index 100% rename from modules/ripple_app/network/WSConnection.h rename to modules/ripple_app/websocket/WSConnection.h diff --git a/modules/ripple_app/websocket/WSDoor.cpp b/modules/ripple_app/websocket/WSDoor.cpp new file mode 100644 index 0000000000..ba5e980ce1 --- /dev/null +++ b/modules/ripple_app/websocket/WSDoor.cpp @@ -0,0 +1,134 @@ +//------------------------------------------------------------------------------ +/* + Copyright (c) 2011-2013, OpenCoin, Inc. +*/ +//============================================================================== + +SETUP_LOG (WSDoor) + +// +// This is a light weight, untrusted interface for web clients. +// For now we don't provide proof. Later we will. +// +// Might need to support this header for browsers: Access-Control-Allow-Origin: * +// - https://developer.mozilla.org/en-US/docs/HTTP_access_control +// + +// +// Strategy: +// - We only talk to NetworkOPs (so we will work even in thin mode) +// - NetworkOPs is smart enough to subscribe and or pass back messages +// +// VFALCO NOTE NetworkOPs isn't used here... +// + +class WSDoorImp : public WSDoor, protected Thread, LeakChecked +{ +public: + WSDoorImp (std::string const& strIp, int iPort, bool bPublic, + boost::asio::ssl::context& ssl_context) + : Thread ("websocket") + , m_ssl_context (ssl_context) + , m_endpointLock (this, "WSDoor", __FILE__, __LINE__) + , mPublic (bPublic) + , mIp (strIp) + , mPort (iPort) + { + startThread (); + } + + ~WSDoorImp () + { + { + ScopedLockType lock (m_endpointLock, __FILE__, __LINE__); + + if (m_endpoint != nullptr) + m_endpoint->stop (); + } + + signalThreadShouldExit (); + waitForThreadToExit (); + } + +private: + void run () + { + WriteLog (lsINFO, WSDoor) << boost::str ( + boost::format ("Websocket: %s: Listening: %s %d ") % + (mPublic ? "Public" : "Private") % mIp % mPort); + + websocketpp::server_autotls::handler::ptr handler ( + new WSServerHandler ( + m_ssl_context, mPublic)); + + { + ScopedLockType lock (m_endpointLock, __FILE__, __LINE__); + + m_endpoint = new websocketpp::server_autotls (handler); + } + + // Call the main-event-loop of the websocket server. + try + { + m_endpoint->listen ( + boost::asio::ip::tcp::endpoint ( + boost::asio::ip::address ().from_string (mIp), mPort)); + } + catch (websocketpp::exception& e) + { + WriteLog (lsWARNING, WSDoor) << "websocketpp exception: " << e.what (); + + // temporary workaround for websocketpp throwing exceptions on access/close races + for (;;) + { + // https://github.com/zaphoyd/websocketpp/issues/98 + try + { + m_endpoint->get_io_service ().run (); + break; + } + catch (websocketpp::exception& e) + { + WriteLog (lsWARNING, WSDoor) << "websocketpp exception: " << e.what (); + } + } + } + + { + ScopedLockType lock (m_endpointLock, __FILE__, __LINE__); + + m_endpoint = nullptr; + } + } + +private: + typedef RippleRecursiveMutex LockType; + typedef LockType::ScopedLockType ScopedLockType; + + boost::asio::ssl::context& m_ssl_context; + LockType m_endpointLock; + + ScopedPointer m_endpoint; + bool mPublic; + std::string mIp; + int mPort; +}; + +//------------------------------------------------------------------------------ + +WSDoor* WSDoor::New (std::string const& strIp, int iPort, bool bPublic, + boost::asio::ssl::context& ssl_context) +{ + ScopedPointer door; + + try + { + door = new WSDoorImp (strIp, iPort, bPublic, ssl_context); + } + catch (...) + { + door = nullptr; + } + + return door.release (); +} diff --git a/modules/ripple_app/websocket/WSDoor.h b/modules/ripple_app/websocket/WSDoor.h new file mode 100644 index 0000000000..36aeb9002b --- /dev/null +++ b/modules/ripple_app/websocket/WSDoor.h @@ -0,0 +1,18 @@ +//------------------------------------------------------------------------------ +/* + Copyright (c) 2011-2013, OpenCoin, Inc. +*/ +//============================================================================== + +#ifndef RIPPLE_WSDOOR_RIPPLEHEADER +#define RIPPLE_WSDOOR_RIPPLEHEADER + +/** Handles accepting incoming WebSocket connections. */ +class WSDoor +{ +public: + static WSDoor* New (std::string const& strIp, int iPort, bool bPublic, + boost::asio::ssl::context& ssl_context); +}; + +#endif diff --git a/modules/ripple_app/network/ripple_WSHandler.cpp b/modules/ripple_app/websocket/WSServerHandler.cpp similarity index 100% rename from modules/ripple_app/network/ripple_WSHandler.cpp rename to modules/ripple_app/websocket/WSServerHandler.cpp diff --git a/modules/ripple_app/network/ripple_WSHandler.h b/modules/ripple_app/websocket/WSServerHandler.h similarity index 91% rename from modules/ripple_app/network/ripple_WSHandler.h rename to modules/ripple_app/websocket/WSServerHandler.h index 56a1f1b7c7..e155290bcf 100644 --- a/modules/ripple_app/network/ripple_WSHandler.h +++ b/modules/ripple_app/websocket/WSServerHandler.h @@ -4,8 +4,8 @@ */ //============================================================================== -#ifndef RIPPLE_WSHANDLER_H_INCLUDED -#define RIPPLE_WSHANDLER_H_INCLUDED +#ifndef RIPPLE_WSSERVERHANDLER_H_INCLUDED +#define RIPPLE_WSSERVERHANDLER_H_INCLUDED extern bool serverOkay (std::string& reason); @@ -47,39 +47,34 @@ protected: LockType mLock; private: - boost::shared_ptr mCtx; + boost::asio::ssl::context& m_ssl_context; protected: // For each connection maintain an associated object to track subscriptions. - boost::unordered_map > > mMap; - bool mPublic; + boost::unordered_map > > mMap; + bool mPublic; public: - WSServerHandler (boost::shared_ptr spCtx, bool bPublic) - : mLock (static_cast (this), "WSServerHandler", __FILE__, __LINE__) - , mCtx (spCtx) + WSServerHandler (boost::asio::ssl::context& ssl_context, bool bPublic) + : m_ssl_context (ssl_context) + , mLock (static_cast (this), "WSServerHandler", __FILE__, __LINE__) , mPublic (bPublic) { - if (getConfig ().WEBSOCKET_SECURE != 0) - { - basio::SslContext::initializeFromFile ( - *mCtx, - getConfig ().WEBSOCKET_SSL_KEY, - getConfig ().WEBSOCKET_SSL_CERT, - getConfig ().WEBSOCKET_SSL_CHAIN); - } } - bool getPublic () + bool getPublic () { return mPublic; }; + /* boost::asio::ssl::context& getASIOContext () { - return *mCtx; + return *m_ssl_context; } + */ static void ssend (connection_ptr cpClient, message_ptr mpMessage) { @@ -320,9 +315,9 @@ public: } } - boost::shared_ptr on_tls_init () + boost::asio::ssl::context& get_ssl_context () { - return mCtx; + return m_ssl_context; } // Respond to http requests. diff --git a/modules/ripple_asio/ripple_asio.cpp b/modules/ripple_asio/ripple_asio.cpp index 4be730a092..61012c686e 100644 --- a/modules/ripple_asio/ripple_asio.cpp +++ b/modules/ripple_asio/ripple_asio.cpp @@ -36,11 +36,8 @@ namespace ripple { -# include "sockets/ripple_RippleTlsContext.h" -# include "sockets/ripple_MultiSocket.h" #include "sockets/ripple_MultiSocketType.h" - -#include "sockets/ripple_RippleTlsContext.cpp" +#include "sockets/RippleSSLContext.cpp" #include "sockets/ripple_MultiSocket.cpp" } diff --git a/modules/ripple_asio/ripple_asio.h b/modules/ripple_asio/ripple_asio.h index 93f9be5f05..eb9de42682 100644 --- a/modules/ripple_asio/ripple_asio.h +++ b/modules/ripple_asio/ripple_asio.h @@ -14,6 +14,7 @@ namespace ripple using namespace beast; +#include "sockets/RippleSSLContext.h" #include "sockets/ripple_MultiSocket.h" } diff --git a/modules/ripple_asio/sockets/RippleSSLContext.cpp b/modules/ripple_asio/sockets/RippleSSLContext.cpp new file mode 100644 index 0000000000..0ef7159c3f --- /dev/null +++ b/modules/ripple_asio/sockets/RippleSSLContext.cpp @@ -0,0 +1,274 @@ +//------------------------------------------------------------------------------ +/* + Copyright (c) 2011-2013, OpenCoin, Inc. +*/ +//============================================================================== + +class RippleSSLContextImp : public RippleSSLContext +{ +private: + boost::asio::ssl::context m_context; + +public: + RippleSSLContextImp () + : RippleSSLContext (m_context) + , m_context (boost::asio::ssl::context::sslv23) + { + m_context.set_options ( + boost::asio::ssl::context::default_workarounds | + boost::asio::ssl::context::no_sslv2 | + boost::asio::ssl::context::single_dh_use); + + SSL_CTX_set_tmp_dh_callback ( + m_context.native_handle (), + tmp_dh_handler); + } + + ~RippleSSLContextImp () + { + } + + static DH* tmp_dh_handler (SSL*, int, int key_length) + { + return DHparams_dup (getDH (key_length)); + } + + //-------------------------------------------------------------------------- + + static std::string getRawDHParams (int keySize) + { + std::string params; + + // Original code provided the 512-bit keySize parameters + // when 1024 bits were requested so we will do the same. + if (keySize == 1024) + keySize = 512; + + switch (keySize) + { + case 512: + { + // These are the DH parameters that OpenCoin has chosen for Ripple + // + uint8 const raw [] = { + 0x30, 0x46, 0x02, 0x41, 0x00, 0x98, 0x15, 0xd2, 0xd0, 0x08, 0x32, 0xda, + 0xaa, 0xac, 0xc4, 0x71, 0xa3, 0x1b, 0x11, 0xf0, 0x6c, 0x62, 0xb2, 0x35, + 0x8a, 0x10, 0x92, 0xc6, 0x0a, 0xa3, 0x84, 0x7e, 0xaf, 0x17, 0x29, 0x0b, + 0x70, 0xef, 0x07, 0x4f, 0xfc, 0x9d, 0x6d, 0x87, 0x99, 0x19, 0x09, 0x5b, + 0x6e, 0xdb, 0x57, 0x72, 0x4a, 0x7e, 0xcd, 0xaf, 0xbd, 0x3a, 0x97, 0x55, + 0x51, 0x77, 0x5a, 0x34, 0x7c, 0xe8, 0xc5, 0x71, 0x63, 0x02, 0x01, 0x02 + }; + + params.resize (sizeof (raw)); + std::copy (raw, raw + sizeof (raw), params.begin ()); + } + break; + }; + + return params; + } + + //-------------------------------------------------------------------------- + + void initAnonymous (String const& cipherList) + { + int const result = SSL_CTX_set_cipher_list ( + m_context.native_handle (), + cipherList.toStdString ().c_str ()); + + if (result != 1) + FatalError ("invalid cipher list", __FILE__, __LINE__); + } + + //-------------------------------------------------------------------------- + + void initAuthenticated ( + std::string key_file, std::string cert_file, std::string chain_file) + { + SSL_CTX* const ssl = m_context.native_handle (); + + bool cert_set = false; + + if (! cert_file.empty ()) + { + boost::system::error_code error; + + m_context.use_certificate_file ( + cert_file, boost::asio::ssl::context::pem, error); + + if (error) + { + FatalError ("Problem with SSL certificate file.", + __FILE__, __LINE__); + } + + cert_set = true; + } + + if (! chain_file.empty ()) + { + // VFALCO Replace fopen() with RAII + FILE* f = fopen (chain_file.c_str (), "r"); + + if (!f) + { + FatalError ("Problem opening SSL chain file.", + __FILE__, __LINE__); + } + + try + { + for (;;) + { + X509* const x = PEM_read_X509 (f, NULL, NULL, NULL); + + if (x == nullptr) + break; + + if (! cert_set) + { + if (SSL_CTX_use_certificate (ssl, x) != 1) + FatalError ("Problem retrieving SSL certificate from chain file.", + __FILE__, __LINE__); + + cert_set = true; + } + else if (SSL_CTX_add_extra_chain_cert (ssl, x) != 1) + { + X509_free (x); + FatalError ("Problem adding SSL chain certificate.", + __FILE__, __LINE__); + } + } + + fclose (f); + } + catch (...) + { + fclose (f); + FatalError ("Reading the SSL chain file generated an exception.", + __FILE__, __LINE__); + } + } + + if (! key_file.empty ()) + { + boost::system::error_code error; + + m_context.use_private_key_file (key_file, + boost::asio::ssl::context::pem, error); + + if (error) + { + FatalError ("Problem using the SSL private key file.", + __FILE__, __LINE__); + } + } + + if (SSL_CTX_check_private_key (ssl) != 1) + { + FatalError ("Invalid key in SSL private key file.", + __FILE__, __LINE__); + } + } + + //-------------------------------------------------------------------------- + + // A simple RAII container for a DH + // + struct ScopedDHPointer + { + // Construct from an existing DH + // + explicit ScopedDHPointer (DH* dh) + : m_dh (dh) + { + } + + // Construct from raw DH params + // + explicit ScopedDHPointer (std::string const& params) + { + uint8 const* p (reinterpret_cast (¶ms [0])); + m_dh = d2i_DHparams (nullptr, &p, params.size ()); + if (m_dh == nullptr) + FatalError ("d2i_DHparams returned nullptr.", + __FILE__, __LINE__); + } + + ~ScopedDHPointer () + { + if (m_dh != nullptr) + DH_free (m_dh); + } + + operator DH* () const + { + return get (); + } + + DH* get () const + { + return m_dh; + } + + private: + DH* m_dh; + }; + + //-------------------------------------------------------------------------- + + static DH* getDH (int keyLength) + { + if (keyLength == 512 || keyLength == 1024) + { + static ScopedDHPointer dh512 (getRawDHParams (keyLength)); + + return dh512.get (); + } + else + { + FatalError ("unsupported key length", __FILE__, __LINE__); + } + + return nullptr; + } +}; + +//------------------------------------------------------------------------------ + +RippleSSLContext::RippleSSLContext (ContextType& context) + : SSLContext (context) +{ +} +RippleSSLContext* RippleSSLContext::createBare () +{ + ScopedPointer context (new RippleSSLContextImp ()); + + return context.release (); +} + +RippleSSLContext* RippleSSLContext::createAnonymous (String const& cipherList) +{ + ScopedPointer context (new RippleSSLContextImp ()); + + context->initAnonymous (cipherList); + + return context.release (); +} + +RippleSSLContext* RippleSSLContext::createAuthenticated ( + std::string key_file, std::string cert_file, std::string chain_file) +{ + ScopedPointer context (new RippleSSLContextImp ()); + + context->initAuthenticated (key_file, cert_file, chain_file); + + return context.release (); +} + +std::string RippleSSLContext::getRawDHParams (int keySize) +{ + return RippleSSLContextImp::getRawDHParams (keySize); +} + diff --git a/modules/ripple_asio/sockets/RippleSSLContext.h b/modules/ripple_asio/sockets/RippleSSLContext.h new file mode 100644 index 0000000000..6310450b47 --- /dev/null +++ b/modules/ripple_asio/sockets/RippleSSLContext.h @@ -0,0 +1,51 @@ +//------------------------------------------------------------------------------ +/* + Copyright (c) 2011-2013, OpenCoin, Inc. +*/ +//============================================================================== + +#ifndef RIPPLE_ASIO_RIPPLESSLCONTEXT_H_INCLUDED +#define RIPPLE_ASIO_RIPPLESSLCONTEXT_H_INCLUDED + +/** The SSL contexts used by Ripple. + + This is what Ripple uses for its secure connections. The ECDSA curve + parameters are predefined and verified to be secure. The context is set to + sslv23, Transport Layer Security / General. This is primarily used for peer to peer servers that don't care + about certificates or identity verification. +*/ +class RippleSSLContext : public SSLContext +{ +public: + /** Retrieve raw DH parameters. + This is in the format expected by the OpenSSL function d2i_DHparams. + The vector is binary. An empty vector means the key size is unsupported. + @note The string may contain nulls in the middle. Use size() to + determine the actual size. + */ + static std::string getRawDHParams (int keySize); + + /** Creates a bare context. + This is for WebSocket connections that don't use certificates. + */ + static RippleSSLContext* createBare (); + + /** Create a context that allows anonymous connections. + No certificates are required. Peers use this context. + If the cipher list is invalid, a fatal error is raised. + */ + static RippleSSLContext* createAnonymous (String const& cipherList); + + /** Create a context with authentication requirements. + This is used for WebSocket connections. + The authentication credentials are loaded from the files with + the specified names. If an error occurs, a fatal error is raised. + */ + static RippleSSLContext* createAuthenticated ( + std::string key_file, std::string cert_file, std::string chain_file); + +protected: + explicit RippleSSLContext (ContextType& context); +}; + +#endif diff --git a/modules/ripple_asio/sockets/ripple_MultiSocket.cpp b/modules/ripple_asio/sockets/ripple_MultiSocket.cpp index f65fe6eb43..dadfbda7d7 100644 --- a/modules/ripple_asio/sockets/ripple_MultiSocket.cpp +++ b/modules/ripple_asio/sockets/ripple_MultiSocket.cpp @@ -4,50 +4,13 @@ */ //============================================================================== -MultiSocket* MultiSocket::New (boost::asio::io_service& io_service, int flags) -{ - return new MultiSocketType (io_service, flags); -} - -MultiSocket* MultiSocket::New (boost::asio::ip::tcp::socket& socket, int flags) -{ - return new MultiSocketType (socket, flags); -} - MultiSocket* MultiSocket::New ( - boost::asio::ssl::stream < - boost::asio::ip::tcp::socket&>& stream, int flags) + boost::asio::io_service& io_service, + boost::asio::ssl::context& ssl_context, + int flags) { - return new MultiSocketType < - boost::asio::ssl::stream < - boost::asio::ip::tcp::socket&>& > (stream, flags); -} - -struct RippleTlsContextHolder -{ - RippleTlsContextHolder () - : m_context (RippleTlsContext::New ()) - { - } - - RippleTlsContext& get () - { - return *m_context; - } - -private: - ScopedPointer m_context; -}; - -static RippleTlsContextHolder s_context_holder; - -SslContextBase::BoostContextType &MultiSocket::getRippleTlsBoostContext () -{ - // This doesn't work because VS2012 doesn't wrap - // it with a thread-safety preamble!! - //static ScopedPointer context (RippleTlsContext::New ()); - - return s_context_holder.get ().getBoostContext (); + return new MultiSocketType ( + io_service, ssl_context, flags); } //------------------------------------------------------------------------------ @@ -92,6 +55,27 @@ public: return s; } + static boost::asio::ssl::context& getSSLContext () + { + struct ContextHolder + { + ContextHolder () + : context (RippleSSLContext::createAnonymous ( + "ALL:!LOW:!EXP:!MD5:@STRENGTH")) + { + // VFALCO NOTE Not sure if this is needed? + context->get().set_verify_mode ( + boost::asio::ssl::verify_none); + } + + ScopedPointer context; + }; + + static ContextHolder holder; + + return holder.context->get (); + } + String name () { return getArgName (m_flags); @@ -122,11 +106,11 @@ public: typedef socket_type native_socket_type; typedef acceptor_type native_acceptor_type; - explicit MultiSocketDetailsType (arg_type flags) + MultiSocketDetailsType (arg_type flags) : MultiSocketDetails (flags) , m_socket (get_io_service ()) , m_acceptor (get_io_service ()) - , m_multiSocket (m_socket, flags) + , m_multiSocket (m_socket, MultiSocketDetails::getSSLContext (), flags) , m_acceptor_wrapper (m_acceptor) { } diff --git a/modules/ripple_asio/sockets/ripple_MultiSocket.h b/modules/ripple_asio/sockets/ripple_MultiSocket.h index 888b78f4ef..48a12019c5 100644 --- a/modules/ripple_asio/sockets/ripple_MultiSocket.h +++ b/modules/ripple_asio/sockets/ripple_MultiSocket.h @@ -31,11 +31,17 @@ public: // server: will require ssl (ignores ssl flag) }; - Flag (int flags) noexcept + Flag (int flags = 0) noexcept : m_flags (flags) { } + Flag& operator= (int mask) noexcept + { + m_flags = mask; + return *this; + } + bool operator== (Flag const& other) const noexcept { return m_flags == other.m_flags; @@ -61,6 +67,11 @@ public: return Flag (m_flags & ~mask); } + int asBits () const noexcept + { + return m_flags; + } + private: int m_flags; }; @@ -76,22 +87,10 @@ public: virtual SSL* native_handle () = 0; - /* - // This would be the underlying StreamSocket template parameter - typedef boost::asio::ip::tcp::socket NativeSocketType; - typedef boost::asio::ssl::stream SslStreamType; - virtual boost::asio::ip::tcp::socket& getNativeSocket () = 0; - virtual SslStreamType& getSslStream () = 0; - */ - - static MultiSocket* New (boost::asio::io_service& io_service, int flags = 0); - static MultiSocket* New (boost::asio::ip::tcp::socket& socket, int flags = 0); - static MultiSocket* New (boost::asio::ssl::stream & stream, int flags = 0); - - // Ripple uses a SSL/TLS context with specific parameters and this returns - // a reference to the corresponding boost::asio::ssl::context object. - // - static SslContextBase::BoostContextType& getRippleTlsBoostContext (); + static MultiSocket* New ( + boost::asio::io_service& io_service, + boost::asio::ssl::context& ssl_context, + int flags = 0); }; #endif diff --git a/modules/ripple_asio/sockets/ripple_MultiSocketType.h b/modules/ripple_asio/sockets/ripple_MultiSocketType.h index bf2fb979f7..14d50ad7df 100644 --- a/modules/ripple_asio/sockets/ripple_MultiSocketType.h +++ b/modules/ripple_asio/sockets/ripple_MultiSocketType.h @@ -4,8 +4,8 @@ */ //============================================================================== -#ifndef RIPPLE_MULTISOCKETTYPE_H_INCLUDED -#define RIPPLE_MULTISOCKETTYPE_H_INCLUDED +#ifndef RIPPLE_ASIO_MULTISOCKETTYPE_H_INCLUDED +#define RIPPLE_ASIO_MULTISOCKETTYPE_H_INCLUDED /** Template for producing instances of MultiSocket */ @@ -21,10 +21,11 @@ public: typedef typename boost::add_reference ::type next_layer_type_ref; typedef typename next_layer_type::lowest_layer_type lowest_layer_type; - template - explicit MultiSocketType (Arg& arg, int flags = 0) + template + MultiSocketType (Arg& arg, boost::asio::ssl::context& ssl_context, int flags) : m_flags (flags) , m_state (stateNone) + , m_ssl_context (ssl_context) , m_verify_mode (0) , m_stream (nullptr) , m_needsShutdown (false) @@ -75,28 +76,6 @@ protected: return *m_stream; } -#if 0 - next_layer_type& next_layer () noexcept - { - return m_next_layer; - } - - next_layer_type const& next_layer () const noexcept - { - return m_next_layer; - } - - lowest_layer_type& lowest_layer () noexcept - { - return m_next_layer.lowest_layer (); - } - - lowest_layer_type const& lowest_layer () const noexcept - { - return m_next_layer.lowest_layer (); - } -#endif - //-------------------------------------------------------------------------- // // Socket @@ -609,8 +588,7 @@ protected: { typedef typename boost::asio::ssl::stream SslStream; typedef SocketWrapperStrand Wrapper; - Wrapper* const socket = new Wrapper ( - m_next_layer, MultiSocket::getRippleTlsBoostContext ()); + Wrapper* const socket = new Wrapper (m_next_layer, m_ssl_context); set_ssl_stream (socket->this_layer ()); return socket; } @@ -626,8 +604,7 @@ protected: typedef boost::asio::ssl::stream < PrefilledReadStream > SslStream; typedef SocketWrapperStrand Wrapper; - Wrapper* const socket = new Wrapper ( - m_next_layer, MultiSocket::getRippleTlsBoostContext ()); + Wrapper* const socket = new Wrapper (m_next_layer, m_ssl_context); socket->this_layer ().next_layer().fill (buffers); set_ssl_stream (socket->this_layer ()); return socket; @@ -953,13 +930,12 @@ protected: private: Flag m_flags; State m_state; + boost::asio::ssl::context& m_ssl_context; int m_verify_mode; ScopedPointer m_stream; ScopedPointer m_ssl_stream; // the ssl portion of our stream if it exists - bool m_needsShutdown; StreamSocket m_next_layer; - SSL* m_native_ssl_handle; }; diff --git a/modules/ripple_asio/sockets/ripple_RippleTlsContext.cpp b/modules/ripple_asio/sockets/ripple_RippleTlsContext.cpp deleted file mode 100644 index dacb338b54..0000000000 --- a/modules/ripple_asio/sockets/ripple_RippleTlsContext.cpp +++ /dev/null @@ -1,151 +0,0 @@ -//------------------------------------------------------------------------------ -/* - Copyright (c) 2011-2013, OpenCoin, Inc. -*/ -//============================================================================== - -//------------------------------------------------------------------------------ - -class RippleTlsContextImp : public RippleTlsContext -{ -public: - RippleTlsContextImp () - : m_context (boost::asio::ssl::context::sslv23) - { - initBoostContext (m_context); - } - - ~RippleTlsContextImp () - { - } - - BoostContextType& getBoostContext () noexcept - { - return m_context; - } - - //-------------------------------------------------------------------------- - -private: - boost::asio::ssl::context m_context; -}; - -//------------------------------------------------------------------------------ - -void RippleTlsContext::initBoostContext (BoostContextType& context) -{ - struct Helpers - { - typedef boost::array RawDHParams; - - // A simple RAII container for a DH - struct ScopedDHPointer - { - explicit ScopedDHPointer (DH* dh) - : m_dh (dh) - { - } - - ~ScopedDHPointer () - { - if (m_dh != nullptr) - DH_free (m_dh); - } - - operator DH* () const - { - return get (); - } - - DH* get () const - { - return m_dh; - } - - private: - unsigned char const* m_p; - DH* m_dh; - }; - - //---------------------------------------------------------------------- - - // These are the DH parameters that OpenCoin has chosen for Ripple - // - static RawDHParams const& getRaw512Params () noexcept - { - static RawDHParams params = - { { - 0x30, 0x46, 0x02, 0x41, 0x00, 0x98, 0x15, 0xd2, 0xd0, 0x08, 0x32, 0xda, - 0xaa, 0xac, 0xc4, 0x71, 0xa3, 0x1b, 0x11, 0xf0, 0x6c, 0x62, 0xb2, 0x35, - 0x8a, 0x10, 0x92, 0xc6, 0x0a, 0xa3, 0x84, 0x7e, 0xaf, 0x17, 0x29, 0x0b, - 0x70, 0xef, 0x07, 0x4f, 0xfc, 0x9d, 0x6d, 0x87, 0x99, 0x19, 0x09, 0x5b, - 0x6e, 0xdb, 0x57, 0x72, 0x4a, 0x7e, 0xcd, 0xaf, 0xbd, 0x3a, 0x97, 0x55, - 0x51, 0x77, 0x5a, 0x34, 0x7c, 0xe8, 0xc5, 0x71, 0x63, 0x02, 0x01, 0x02 - } }; - - return params; - } - - static DH* createDH (RawDHParams const& rawParams) - { - RawDHParams::const_iterator iter = rawParams.begin (); - return d2i_DHparams (nullptr, &iter, rawParams.size ()); - } - - //---------------------------------------------------------------------- - - static DH* getDhParameters (int keyLength) - { - if (keyLength == 512 || keyLength == 1024) - { - static ScopedDHPointer dh512 (createDH (getRaw512Params ())); - return dh512.get (); - } - else - { - FatalError ("unsupported key length", __FILE__, __LINE__); - } - - return nullptr; - } - - static DH* tmp_dh_handler (SSL*, int, int key_length) - { - return DHparams_dup (getDhParameters (key_length)); - } - - static char const* getCipherList () - { - static char const* ciphers = "ALL:!LOW:!EXP:!MD5:@STRENGTH"; - - return ciphers; - } - }; - - //-------------------------------------------------------------------------- - - context.set_options ( - boost::asio::ssl::context::default_workarounds | - boost::asio::ssl::context::no_sslv2 | - boost::asio::ssl::context::single_dh_use); - - context.set_verify_mode (boost::asio::ssl::verify_none); - - SSL_CTX_set_tmp_dh_callback ( - context.native_handle (), - Helpers::tmp_dh_handler); - - int const result = SSL_CTX_set_cipher_list ( - context.native_handle (), - Helpers::getCipherList ()); - - if (result != 1) - FatalError ("invalid cipher list", __FILE__, __LINE__); -} - -//------------------------------------------------------------------------------ - -RippleTlsContext* RippleTlsContext::New () -{ - return new RippleTlsContextImp (); -} diff --git a/modules/ripple_asio/sockets/ripple_RippleTlsContext.h b/modules/ripple_asio/sockets/ripple_RippleTlsContext.h deleted file mode 100644 index 8dc7b8ba9b..0000000000 --- a/modules/ripple_asio/sockets/ripple_RippleTlsContext.h +++ /dev/null @@ -1,32 +0,0 @@ -//------------------------------------------------------------------------------ -/* - Copyright (c) 2011-2013, OpenCoin, Inc. -*/ -//============================================================================== - -#ifndef RIPPLE_RIPPLETLSCONTEXT_H_INCLUDED -#define RIPPLE_RIPPLETLSCONTEXT_H_INCLUDED - -/** A boost SSL context which is set to Generic SSL/TLS (sslv23). - - This is what Ripple uses for its secure connections. The - curve parameters are predefined and verified to be secure. - - The context is set to sslv23, Transport Layer Security / General. - This is primarily used for peer to peer servers that don't care - about certificates or identity verification. - - Usually you don't instantiate this directly, you will need to derive - a class and initialize the context in your constructor. - - @see SslContext -*/ -class RippleTlsContext : public SslContextBase -{ -public: - static RippleTlsContext* New (); - - static void initBoostContext (BoostContextType& context); -}; - -#endif diff --git a/modules/ripple_core/functional/ripple_Config.cpp b/modules/ripple_core/functional/ripple_Config.cpp index b4d8ff27b9..fc06448ff4 100644 --- a/modules/ripple_core/functional/ripple_Config.cpp +++ b/modules/ripple_core/functional/ripple_Config.cpp @@ -35,7 +35,6 @@ Config::Config () TESTNET = false; NETWORK_START_TIME = 1319844908; - PEER_PORT = SYSTEM_PEER_PORT; RPC_SECURE = 0; WEBSOCKET_PORT = SYSTEM_WEBSOCKET_PORT; WEBSOCKET_PUBLIC_PORT = SYSTEM_WEBSOCKET_PUBLIC_PORT; @@ -90,7 +89,9 @@ Config::Config () // VFALCO NOTE Clean area // - proxyListeningPort = 0; + peerListeningPort = SYSTEM_PEER_PORT; + + peerPROXYListeningPort = 0; // // @@ -309,9 +310,6 @@ void Config::load () (void) SectionSingleB (secConfig, SECTION_PEER_IP, PEER_IP); - if (SectionSingleB (secConfig, SECTION_PEER_PORT, strTemp)) - PEER_PORT = lexicalCastThrow (strTemp); - if (SectionSingleB (secConfig, SECTION_PEER_PRIVATE, strTemp)) PEER_PRIVATE = lexicalCastThrow (strTemp); @@ -341,10 +339,21 @@ void Config::load () importNodeDatabase = parseKeyValueSection ( secConfig, ConfigSection::importNodeDatabase ()); - if (SectionSingleB (secConfig, SECTION_PEER_PROXY_PORT, strTemp) - proxyListeningPort = lexicalCastThrow (strTemp); + if (SectionSingleB (secConfig, SECTION_PEER_PORT, strTemp)) + peerListeningPort = lexicalCastThrow (strTemp); + + if (SectionSingleB (secConfig, SECTION_PEER_PROXY_PORT, strTemp)) + { + peerPROXYListeningPort = lexicalCastThrow (strTemp); + + if (peerPROXYListeningPort != 0 && peerPROXYListeningPort == peerListeningPort) + FatalError ("Peer and proxy listening ports can't be the same.", + __FILE__, __LINE__); + } else - proxyListeningPort = 0; + { + peerPROXYListeningPort = 0; + } // // VFALCO END CLEAN diff --git a/modules/ripple_core/functional/ripple_Config.h b/modules/ripple_core/functional/ripple_Config.h index 42d880c6b0..14653e56fd 100644 --- a/modules/ripple_core/functional/ripple_Config.h +++ b/modules/ripple_core/functional/ripple_Config.h @@ -85,6 +85,8 @@ public: boost::filesystem::path DEBUG_LOGFILE; boost::filesystem::path VALIDATORS_FILE; // As specifed in rippled.cfg. + //-------------------------------------------------------------------------- + /** Parameters for the main NodeStore database. This is 1 or more strings of the form = @@ -119,6 +121,10 @@ public: */ StringPairArray importNodeDatabase; + // Listening port number for peer connections. + // + int peerListeningPort; + /** PROXY listening port number If this is not zero, it indicates an additional port number on which we should accept incoming Peer connections that will also @@ -127,7 +133,9 @@ public: The PROXY Protocol: http://haproxy.1wt.eu/download/1.5/doc/proxy-protocol.txt */ - int proxyListeningPort; + int peerPROXYListeningPort; + + //-------------------------------------------------------------------------- bool ELB_SUPPORT; // Support Amazon ELB @@ -180,7 +188,6 @@ public: // Peer networking parameters std::string PEER_IP; - int PEER_PORT; int NUMBER_CONNECTIONS; std::string PEER_SSL_CIPHER_LIST; int PEER_SCAN_INTERVAL_MIN;