Hide RPCDoor implementation and use RippleSSLContext

This commit is contained in:
Vinnie Falco
2013-08-31 11:39:29 -07:00
parent e256716da8
commit a9f6d67bba
10 changed files with 153 additions and 280 deletions

View File

@@ -31,12 +31,6 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\modules\ripple_app\boost\ripple_SslContext.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\modules\ripple_app\consensus\ripple_DisputedTx.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
@@ -1371,7 +1365,6 @@
<ClInclude Include="..\..\BeastConfig.h" />
<ClInclude Include="..\..\modules\ripple_app\basics\ripple_RPCServerHandler.h" />
<ClInclude Include="..\..\modules\ripple_app\boost\ripple_IoService.h" />
<ClInclude Include="..\..\modules\ripple_app\boost\ripple_SslContext.h" />
<ClInclude Include="..\..\modules\ripple_app\consensus\ripple_DisputedTx.h" />
<ClInclude Include="..\..\modules\ripple_app\consensus\ripple_LedgerConsensus.h" />
<ClInclude Include="..\..\modules\ripple_app\contracts\ripple_Contract.h" />

View File

@@ -849,9 +849,6 @@
<ClCompile Include="..\..\modules\ripple_app\boost\ripple_IoService.cpp">
<Filter>[1] Ripple\ripple_app\boost</Filter>
</ClCompile>
<ClCompile Include="..\..\modules\ripple_app\boost\ripple_SslContext.cpp">
<Filter>[1] Ripple\ripple_app\boost</Filter>
</ClCompile>
<ClCompile Include="..\..\modules\ripple_asio\sockets\RippleSSLContext.cpp">
<Filter>[1] Ripple\ripple_asio\sockets</Filter>
</ClCompile>
@@ -1619,9 +1616,6 @@
<ClInclude Include="..\..\modules\ripple_app\boost\ripple_IoService.h">
<Filter>[1] Ripple\ripple_app\boost</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\ripple_app\boost\ripple_SslContext.h">
<Filter>[1] Ripple\ripple_app\boost</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\ripple_basics\utility\ripple_LoggedTimings.h">
<Filter>[1] Ripple\ripple_basics\utility</Filter>
</ClInclude>

View File

@@ -1,110 +0,0 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
namespace basio
{
SslContext* SslContext::New ()
{
return new SslContext;
}
SslContext::~SslContext ()
{
}
SslContext::operator boost::asio::ssl::context& ()
{
return *m_impl;
}
SslContext::SslContext ()
: m_impl (new boost::asio::ssl::context (boost::asio::ssl::context::sslv23))
{
}
// VFALCO TODO Can we call this function from the ctor of PeerDoor as well?
// Or can we move the common code to a new function?
//
void SslContext::initializeFromFile (
boost::asio::ssl::context& context,
std::string key_file,
std::string cert_file,
std::string chain_file)
{
SSL_CTX* sslContext = context.native_handle ();
context.set_options (boost::asio::ssl::context::default_workarounds |
boost::asio::ssl::context::no_sslv2 |
boost::asio::ssl::context::single_dh_use);
bool cert_set = false;
if (!cert_file.empty ())
{
boost::system::error_code error;
context.use_certificate_file (cert_file, boost::asio::ssl::context::pem, error);
if (error)
throw std::runtime_error ("Unable to use certificate file");
cert_set = true;
}
if (!chain_file.empty ())
{
// VFALCO Replace fopen() with RAII
FILE* f = fopen (chain_file.c_str (), "r");
if (!f)
throw std::runtime_error ("Unable to open chain file");
try
{
for (;;)
{
X509* x = PEM_read_X509 (f, NULL, NULL, NULL);
if (x == NULL)
break;
if (!cert_set)
{
if (SSL_CTX_use_certificate (sslContext, x) != 1)
throw std::runtime_error ("Unable to get certificate from chain file");
cert_set = true;
}
else if (SSL_CTX_add_extra_chain_cert (sslContext, x) != 1)
{
X509_free (x);
throw std::runtime_error ("Unable to add chain certificate");
}
}
fclose (f);
}
catch (...)
{
fclose (f);
throw;
}
}
if (!key_file.empty ())
{
boost::system::error_code error;
context.use_private_key_file (key_file, boost::asio::ssl::context::pem, error);
if (error)
throw std::runtime_error ("Unable to use private key file");
}
if (SSL_CTX_check_private_key (sslContext) != 1)
throw std::runtime_error ("Private key not valid");
}
}

View File

@@ -1,39 +0,0 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_SSLCONTEXT_H_INCLUDED
#define RIPPLE_SSLCONTEXT_H_INCLUDED
namespace basio
{
/** Hides a boost::asio::ssl::context implementation.
*/
class SslContext
{
public:
static SslContext* New ();
virtual ~SslContext ();
operator boost::asio::ssl::context& ();
static void initializeFromFile (
boost::asio::ssl::context& context,
std::string key_file,
std::string cert_file,
std::string chain_file);
private:
SslContext ();
private:
beast::ScopedPointer <boost::asio::ssl::context> m_impl;
};
}
#endif

View File

@@ -577,7 +577,7 @@ public:
}
else
{
m_wsSSLContext = RippleSSLContext::createBare ();
m_wsSSLContext = RippleSSLContext::createWebSocket ();
}
// Create private listening WebSocket socket
@@ -627,7 +627,7 @@ public:
{
try
{
mRPCDoor = new RPCDoor (m_mainService, m_rpcServerHandler);
mRPCDoor = RPCDoor::New (m_mainService, m_rpcServerHandler);
}
catch (const std::exception& e)
{

View File

@@ -158,7 +158,6 @@ namespace ripple
#include "main/ripple_LocalCredentials.h"
#include "websocket/WSDoor.h"
#include "boost/ripple_IoService.h"
#include "boost/ripple_SslContext.h"
#include "main/ripple_Application.h"
#include "rpc/RPCHandler.h"
#include "tx/TransactionQueue.h"
@@ -296,7 +295,6 @@ static const uint64 tenTo17m1 = tenTo17 - 1;
#include "data/ripple_DBInit.cpp"
#include "boost/ripple_IoService.cpp"
#include "boost/ripple_SslContext.cpp"
#endif
@@ -334,7 +332,6 @@ static const uint64 tenTo17m1 = tenTo17 - 1;
#include "tx/PaymentTransactor.cpp"
#include "tx/RegularKeySetTransactor.cpp"
#include "paths/ripple_RippleState.cpp"
#include "rpc/RPCDoor.cpp"
#include "tx/TransactionCheck.cpp"
#include "tx/TransactionMaster.cpp"
#include "tx/TransactionQueue.cpp"
@@ -354,16 +351,16 @@ static const uint64 tenTo17m1 = tenTo17 - 1;
namespace ripple
{
#include "peers/ripple_Peer.cpp"
#include "main/ripple_Application.cpp"
#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"
#include "ledger/LedgerTiming.cpp"
#include "ledger/ripple_AcceptedLedgerTx.cpp"
#include "main/ripple_Application.cpp"
#include "main/ripple_LocalCredentials.cpp"
#include "misc/ripple_FeeVote.cpp"
#include "misc/ripple_Validations.cpp"
#include "peers/ripple_Peer.cpp"
#include "rpc/RPCDoor.cpp"
#include "tx/OfferCreateTransactor.cpp"
#include "tx/WalletAddTransactor.cpp"
#endif

View File

@@ -6,96 +6,123 @@
SETUP_LOG (RPCDoor)
RPCDoor::RPCDoor (boost::asio::io_service& io_service, RPCServer::Handler& handler)
: m_rpcServerHandler (handler)
, mAcceptor (io_service,
boost::asio::ip::tcp::endpoint (boost::asio::ip::address::from_string (getConfig ().getRpcIP ()), getConfig ().getRpcPort ()))
, mDelayTimer (io_service)
, mSSLContext (boost::asio::ssl::context::sslv23)
class RPCDoorImp : public RPCDoor, public LeakChecked <RPCDoorImp>
{
WriteLog (lsINFO, RPCDoor) << "RPC port: " << getConfig ().getRpcAddress().toRawUTF8() << " allow remote: " << getConfig ().RPC_ALLOW_REMOTE;
if (getConfig ().RPC_SECURE != 0)
public:
RPCDoorImp (boost::asio::io_service& io_service, RPCServer::Handler& handler)
: m_rpcServerHandler (handler)
, mAcceptor (io_service,
boost::asio::ip::tcp::endpoint (boost::asio::ip::address::from_string (getConfig ().getRpcIP ()), getConfig ().getRpcPort ()))
, mDelayTimer (io_service)
, m_sslContext ((getConfig ().RPC_SECURE == 0) ?
RippleSSLContext::createBare () :
RippleSSLContext::createAuthenticated (
getConfig ().RPC_SSL_KEY,
getConfig ().RPC_SSL_CERT,
getConfig ().RPC_SSL_CHAIN))
{
// VFALCO TODO This could be a method of theConfig
//
basio::SslContext::initializeFromFile (
mSSLContext,
getConfig ().RPC_SSL_KEY,
getConfig ().RPC_SSL_CERT,
getConfig ().RPC_SSL_CHAIN);
WriteLog (lsINFO, RPCDoor) << "RPC port: " << getConfig ().getRpcAddress().toRawUTF8() << " allow remote: " << getConfig ().RPC_ALLOW_REMOTE;
startListening ();
}
startListening ();
}
//--------------------------------------------------------------------------
RPCDoor::~RPCDoor ()
{
WriteLog (lsINFO, RPCDoor) << "RPC port: " << getConfig ().getRpcAddress().toRawUTF8() << " allow remote: " << getConfig ().RPC_ALLOW_REMOTE;
}
void RPCDoor::startListening ()
{
RPCServer::pointer new_connection = RPCServer::New (mAcceptor.get_io_service (), mSSLContext, m_rpcServerHandler);
mAcceptor.set_option (boost::asio::ip::tcp::acceptor::reuse_address (true));
mAcceptor.async_accept (new_connection->getRawSocket (),
boost::bind (&RPCDoor::handleConnect, this, new_connection,
boost::asio::placeholders::error));
}
bool RPCDoor::isClientAllowed (const std::string& ip)
{
if (getConfig ().RPC_ALLOW_REMOTE)
return true;
// VFALCO TODO Represent ip addresses as a structure. Use isLoopback() member here
//
if (ip == "127.0.0.1")
return true;
return false;
}
void RPCDoor::handleConnect (RPCServer::pointer new_connection, const boost::system::error_code& error)
{
bool delay = false;
if (!error)
~RPCDoorImp ()
{
// Restrict callers by IP
try
WriteLog (lsINFO, RPCDoor) <<
"RPC port: " << getConfig ().getRpcAddress().toRawUTF8() <<
" allow remote: " << getConfig ().RPC_ALLOW_REMOTE;
}
//--------------------------------------------------------------------------
void startListening ()
{
RPCServer::pointer new_connection = RPCServer::New (
mAcceptor.get_io_service (), m_sslContext->get (), m_rpcServerHandler);
mAcceptor.set_option (boost::asio::ip::tcp::acceptor::reuse_address (true));
mAcceptor.async_accept (new_connection->getRawSocket (),
boost::bind (&RPCDoorImp::handleConnect, this, new_connection,
boost::asio::placeholders::error));
}
//--------------------------------------------------------------------------
bool isClientAllowed (const std::string& ip)
{
if (getConfig ().RPC_ALLOW_REMOTE)
return true;
// VFALCO TODO Represent ip addresses as a structure. Use isLoopback() member here
//
if (ip == "127.0.0.1")
return true;
return false;
}
//--------------------------------------------------------------------------
void handleConnect (RPCServer::pointer new_connection, boost::system::error_code const& error)
{
bool delay = false;
if (!error)
{
if (! isClientAllowed (new_connection->getRemoteAddressText ()))
// Restrict callers by IP
// VFALCO NOTE Prevent exceptions from being thrown at all.
try
{
if (! isClientAllowed (new_connection->getRemoteAddressText ()))
{
startListening ();
return;
}
}
catch (...)
{
// client may have disconnected
startListening ();
return;
}
new_connection->getSocket ().async_handshake (AutoSocket::ssl_socket::server,
boost::bind (&RPCServer::connected, new_connection));
}
catch (...)
else
{
// client may have disconnected
startListening ();
return;
if (error == boost::system::errc::too_many_files_open)
delay = true;
WriteLog (lsINFO, RPCDoor) << "RPCDoorImp::handleConnect Error: " << error;
}
new_connection->getSocket ().async_handshake (AutoSocket::ssl_socket::server,
boost::bind (&RPCServer::connected, new_connection));
}
else
{
if (error == boost::system::errc::too_many_files_open)
delay = true;
WriteLog (lsINFO, RPCDoor) << "RPCDoor::handleConnect Error: " << error;
if (delay)
{
mDelayTimer.expires_from_now (boost::posix_time::milliseconds (1000));
mDelayTimer.async_wait (boost::bind (&RPCDoorImp::startListening, this));
}
else
{
startListening ();
}
}
if (delay)
{
mDelayTimer.expires_from_now (boost::posix_time::milliseconds (1000));
mDelayTimer.async_wait (boost::bind (&RPCDoor::startListening, this));
}
else
startListening ();
private:
RPCServer::Handler& m_rpcServerHandler;
boost::asio::ip::tcp::acceptor mAcceptor;
boost::asio::deadline_timer mDelayTimer;
ScopedPointer <RippleSSLContext> m_sslContext;
};
//------------------------------------------------------------------------------
RPCDoor* RPCDoor::New (boost::asio::io_service& io_service, RPCServer::Handler& handler)
{
ScopedPointer <RPCDoor> result (new RPCDoorImp (io_service, handler));
return result.release ();
}
// vim:ts=4

View File

@@ -7,29 +7,14 @@
#ifndef RIPPLE_RPCDOOR_H
#define RIPPLE_RPCDOOR_H
/*
Handles incoming connections from people making RPC Requests
/** Listening socket for RPC requests.
*/
class RPCDoor : LeakChecked <RPCDoor>
class RPCDoor
{
public:
explicit RPCDoor (
boost::asio::io_service& io_service,
RPCServer::Handler& handler);
~RPCDoor ();
static RPCDoor* New (boost::asio::io_service& io_service, RPCServer::Handler& handler);
private:
RPCServer::Handler& m_rpcServerHandler;
boost::asio::ip::tcp::acceptor mAcceptor;
boost::asio::deadline_timer mDelayTimer;
boost::asio::ssl::context mSSLContext;
void startListening ();
void handleConnect (RPCServer::pointer new_connection,
const boost::system::error_code& error);
bool isClientAllowed (const std::string& ip);
virtual ~RPCDoor () { }
};
#endif

View File

@@ -14,14 +14,6 @@ public:
: 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 ()
@@ -70,8 +62,25 @@ public:
//--------------------------------------------------------------------------
// Does common initialization for all but the bare context type.
void initCommon ()
{
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);
}
//--------------------------------------------------------------------------
void initAnonymous (String const& cipherList)
{
initCommon ();
int const result = SSL_CTX_set_cipher_list (
m_context.native_handle (),
cipherList.toStdString ().c_str ());
@@ -85,6 +94,8 @@ public:
void initAuthenticated (
std::string key_file, std::string cert_file, std::string chain_file)
{
initCommon ();
SSL_CTX* const ssl = m_context.native_handle ();
bool cert_set = false;
@@ -241,6 +252,7 @@ RippleSSLContext::RippleSSLContext (ContextType& context)
: SSLContext (context)
{
}
RippleSSLContext* RippleSSLContext::createBare ()
{
ScopedPointer <RippleSSLContextImp> context (new RippleSSLContextImp ());
@@ -248,6 +260,15 @@ RippleSSLContext* RippleSSLContext::createBare ()
return context.release ();
}
RippleSSLContext* RippleSSLContext::createWebSocket ()
{
ScopedPointer <RippleSSLContextImp> context (new RippleSSLContextImp ());
context->initCommon ();
return context.release ();
}
RippleSSLContext* RippleSSLContext::createAnonymous (String const& cipherList)
{
ScopedPointer <RippleSSLContextImp> context (new RippleSSLContextImp ());

View File

@@ -25,11 +25,16 @@ public:
*/
static std::string getRawDHParams (int keySize);
/** Creates a bare context.
This is for WebSocket connections that don't use certificates.
/** Creates a bare SSL context with just sslv23 set.
This is used for RPC connections.
*/
static RippleSSLContext* createBare ();
/** Creates a suitable for WebSocket without authentication.
This is for WebSocket connections that don't use certificates.
*/
static RippleSSLContext* createWebSocket ();
/** 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.