Support secure RPC.

This commit is contained in:
JoelKatz
2013-06-12 12:49:27 -07:00
parent 353b0a30b5
commit 4de1dcae5e
7 changed files with 58 additions and 29 deletions

View File

@@ -7,11 +7,18 @@ SETUP_LOG (RPCDoor)
using namespace std; using namespace std;
using namespace boost::asio::ip; using namespace boost::asio::ip;
extern void initSSLContext(boost::asio::ssl::context& context,
std::string key_file, std::string cert_file, std::string chain_file);
RPCDoor::RPCDoor(boost::asio::io_service& io_service) : RPCDoor::RPCDoor(boost::asio::io_service& io_service) :
mAcceptor(io_service, tcp::endpoint(address::from_string(theConfig.RPC_IP), theConfig.RPC_PORT)), mAcceptor(io_service, tcp::endpoint(address::from_string(theConfig.RPC_IP), theConfig.RPC_PORT)),
mDelayTimer(io_service) mDelayTimer(io_service), mSSLContext(boost::asio::ssl::context::sslv23)
{ {
WriteLog (lsINFO, RPCDoor) << "RPC port: " << theConfig.RPC_IP << " " << theConfig.RPC_PORT << " allow remote: " << theConfig.RPC_ALLOW_REMOTE; WriteLog (lsINFO, RPCDoor) << "RPC port: " << theConfig.RPC_IP << " " << theConfig.RPC_PORT << " allow remote: " << theConfig.RPC_ALLOW_REMOTE;
if (theConfig.RPC_SECURE != 0)
initSSLContext(mSSLContext, theConfig.RPC_SSL_KEY, theConfig.RPC_SSL_CERT, theConfig.RPC_SSL_CHAIN);
startListening(); startListening();
} }
@@ -22,10 +29,10 @@ RPCDoor::~RPCDoor()
void RPCDoor::startListening() void RPCDoor::startListening()
{ {
RPCServer::pointer new_connection = RPCServer::create(mAcceptor.get_io_service(), &theApp->getOPs()); RPCServer::pointer new_connection = RPCServer::create(mAcceptor.get_io_service(), mSSLContext, &theApp->getOPs());
mAcceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); mAcceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
mAcceptor.async_accept(new_connection->getSocket(), mAcceptor.async_accept(new_connection->getRawSocket(),
boost::bind(&RPCDoor::handleConnect, this, new_connection, boost::bind(&RPCDoor::handleConnect, this, new_connection,
boost::asio::placeholders::error)); boost::asio::placeholders::error));
} }
@@ -41,8 +48,7 @@ bool RPCDoor::isClientAllowed(const std::string& ip)
return false; return false;
} }
void RPCDoor::handleConnect(RPCServer::pointer new_connection, void RPCDoor::handleConnect(RPCServer::pointer new_connection, const boost::system::error_code& error)
const boost::system::error_code& error)
{ {
bool delay = false; bool delay = false;
if (!error) if (!error)
@@ -50,7 +56,7 @@ void RPCDoor::handleConnect(RPCServer::pointer new_connection,
// Restrict callers by IP // Restrict callers by IP
try try
{ {
if (!isClientAllowed(new_connection->getSocket().remote_endpoint().address().to_string())) if (!isClientAllowed(new_connection->getRawSocket().remote_endpoint().address().to_string()))
{ {
startListening(); startListening();
return; return;
@@ -62,7 +68,8 @@ void RPCDoor::handleConnect(RPCServer::pointer new_connection,
return; return;
} }
new_connection->connected(); new_connection->getSocket().async_handshake(AutoSocket::ssl_socket::server,
boost::bind(&RPCServer::connected, new_connection));
} }
else else
{ {

View File

@@ -14,8 +14,9 @@ public:
~RPCDoor (); ~RPCDoor ();
private: private:
boost::asio::ip::tcp::acceptor mAcceptor; boost::asio::ip::tcp::acceptor mAcceptor;
boost::asio::deadline_timer mDelayTimer; boost::asio::deadline_timer mDelayTimer;
boost::asio::ssl::context mSSLContext;
void startListening(); void startListening();
void handleConnect(RPCServer::pointer new_connection, void handleConnect(RPCServer::pointer new_connection,

View File

@@ -18,8 +18,8 @@
SETUP_LOG (RPCServer) SETUP_LOG (RPCServer)
RPCServer::RPCServer(boost::asio::io_service& io_service , NetworkOPs* nopNetwork) RPCServer::RPCServer(boost::asio::io_service& io_service, boost::asio::ssl::context& context, NetworkOPs* nopNetwork)
: mNetOps(nopNetwork), mSocket(io_service) : mNetOps(nopNetwork), mSocket(io_service, context)
{ {
mRole = RPCHandler::GUEST; mRole = RPCHandler::GUEST;
} }
@@ -52,6 +52,11 @@ void RPCServer::handle_read_req(const boost::system::error_code& e)
boost::bind(&RPCServer::handle_write, shared_from_this(), boost::asio::placeholders::error)); boost::bind(&RPCServer::handle_write, shared_from_this(), boost::asio::placeholders::error));
} }
static void dummy_handler()
{
;
}
void RPCServer::handle_read_line(const boost::system::error_code& e) void RPCServer::handle_read_line(const boost::system::error_code& e)
{ {
if (e) if (e)
@@ -62,8 +67,7 @@ void RPCServer::handle_read_line(const boost::system::error_code& e)
if (action == haDO_REQUEST) if (action == haDO_REQUEST)
{ // request with no body { // request with no body
WriteLog (lsWARNING, RPCServer) << "RPC HTTP request with no body"; WriteLog (lsWARNING, RPCServer) << "RPC HTTP request with no body";
boost::system::error_code ignore_ec; mSocket.async_shutdown(boost::bind(&dummy_handler));
mSocket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignore_ec);
return; return;
} }
else if (action == haREAD_LINE) else if (action == haREAD_LINE)
@@ -78,8 +82,7 @@ void RPCServer::handle_read_line(const boost::system::error_code& e)
if ((rLen < 0) || (rLen > RPC_MAXIMUM_QUERY)) if ((rLen < 0) || (rLen > RPC_MAXIMUM_QUERY))
{ {
WriteLog (lsWARNING, RPCServer) << "Illegal RPC request length " << rLen; WriteLog (lsWARNING, RPCServer) << "Illegal RPC request length " << rLen;
boost::system::error_code ignore_ec; mSocket.async_shutdown(boost::bind(&dummy_handler));
mSocket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignore_ec);
return; return;
} }
@@ -99,10 +102,7 @@ void RPCServer::handle_read_line(const boost::system::error_code& e)
} }
} }
else else
{ mSocket.async_shutdown(boost::bind(&dummy_handler));
boost::system::error_code ignore_ec;
mSocket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignore_ec);
}
} }
std::string RPCServer::handleRequest(const std::string& requestStr) std::string RPCServer::handleRequest(const std::string& requestStr)
@@ -143,7 +143,7 @@ std::string RPCServer::handleRequest(const std::string& requestStr)
try try
{ {
mRole = iAdminGet(jvRequest, mSocket.remote_endpoint().address().to_string()); mRole = iAdminGet(jvRequest, mSocket.PlainSocket().remote_endpoint().address().to_string());
} }
catch (...) catch (...)
{ // endpoint already disconnected { // endpoint already disconnected
@@ -187,10 +187,7 @@ void RPCServer::handle_write(const boost::system::error_code& e)
{ {
HTTPRequestAction action = mHTTPRequest.requestDone(false); HTTPRequestAction action = mHTTPRequest.requestDone(false);
if (action == haCLOSE_CONN) if (action == haCLOSE_CONN)
{ mSocket.async_shutdown(boost::bind(&dummy_handler));
boost::system::error_code ignored_ec;
mSocket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec);
}
else else
{ {
boost::asio::async_read_until(mSocket, mLineBuffer, "\r\n", boost::asio::async_read_until(mSocket, mLineBuffer, "\r\n",

View File

@@ -15,7 +15,7 @@ private:
NetworkOPs* mNetOps; NetworkOPs* mNetOps;
boost::asio::ip::tcp::socket mSocket; AutoSocket mSocket;
boost::asio::streambuf mLineBuffer; boost::asio::streambuf mLineBuffer;
Blob mQueryVec; Blob mQueryVec;
@@ -26,7 +26,7 @@ private:
int mRole; int mRole;
RPCServer(boost::asio::io_service& io_service, NetworkOPs* nopNetwork); RPCServer(boost::asio::io_service& io_service, boost::asio::ssl::context& ssl_context, NetworkOPs* nopNetwork);
RPCServer(const RPCServer&); // no implementation RPCServer(const RPCServer&); // no implementation
RPCServer& operator=(const RPCServer&); // no implementation RPCServer& operator=(const RPCServer&); // no implementation
@@ -38,16 +38,21 @@ private:
std::string handleRequest(const std::string& requestStr); std::string handleRequest(const std::string& requestStr);
public: public:
static pointer create(boost::asio::io_service& io_service, NetworkOPs* mNetOps) static pointer create(boost::asio::io_service& io_service, boost::asio::ssl::context& context, NetworkOPs* mNetOps)
{ {
return pointer(new RPCServer(io_service, mNetOps)); return pointer(new RPCServer(io_service, context, mNetOps));
} }
boost::asio::ip::tcp::socket& getSocket() AutoSocket& getSocket()
{ {
return mSocket; return mSocket;
} }
boost::asio::ip::tcp::socket& getRawSocket()
{
return mSocket.PlainSocket();
}
void connected(); void connected();
}; };

View File

@@ -54,6 +54,8 @@ public:
bool getPublic() { return mPublic; }; bool getPublic() { return mPublic; };
boost::asio::ssl::context& getASIOContext() { return *mCtx; }
static void ssend(connection_ptr cpClient, message_ptr mpMessage) static void ssend(connection_ptr cpClient, message_ptr mpMessage)
{ {
try try

View File

@@ -38,6 +38,10 @@
#define SECTION_RPC_USER "rpc_user" #define SECTION_RPC_USER "rpc_user"
#define SECTION_RPC_PASSWORD "rpc_password" #define SECTION_RPC_PASSWORD "rpc_password"
#define SECTION_RPC_STARTUP "rpc_startup" #define SECTION_RPC_STARTUP "rpc_startup"
#define SECTION_RPC_SECURE "rpc_secure"
#define SECTION_RPC_SSL_CERT "rpc_ssl_cert"
#define SECTION_RPC_SSL_CHAIN "rpc_ssl_chain"
#define SECTION_RPC_SSL_KEY "rpc_ssl_key"
#define SECTION_SMS_FROM "sms_from" #define SECTION_SMS_FROM "sms_from"
#define SECTION_SMS_KEY "sms_key" #define SECTION_SMS_KEY "sms_key"
#define SECTION_SMS_SECRET "sms_secret" #define SECTION_SMS_SECRET "sms_secret"
@@ -198,6 +202,7 @@ Config::Config()
PEER_PORT = SYSTEM_PEER_PORT; PEER_PORT = SYSTEM_PEER_PORT;
RPC_PORT = 5001; RPC_PORT = 5001;
RPC_SECURE = 0;
WEBSOCKET_PORT = SYSTEM_WEBSOCKET_PORT; WEBSOCKET_PORT = SYSTEM_WEBSOCKET_PORT;
WEBSOCKET_PUBLIC_PORT = SYSTEM_WEBSOCKET_PUBLIC_PORT; WEBSOCKET_PUBLIC_PORT = SYSTEM_WEBSOCKET_PUBLIC_PORT;
WEBSOCKET_PUBLIC_SECURE = 1; WEBSOCKET_PUBLIC_SECURE = 1;
@@ -408,6 +413,13 @@ void Config::load()
sectionSingleB(secConfig, SECTION_WEBSOCKET_SSL_CHAIN, WEBSOCKET_SSL_CHAIN); sectionSingleB(secConfig, SECTION_WEBSOCKET_SSL_CHAIN, WEBSOCKET_SSL_CHAIN);
sectionSingleB(secConfig, SECTION_WEBSOCKET_SSL_KEY, WEBSOCKET_SSL_KEY); sectionSingleB(secConfig, SECTION_WEBSOCKET_SSL_KEY, WEBSOCKET_SSL_KEY);
if (sectionSingleB(secConfig, SECTION_RPC_SECURE, strTemp))
RPC_SECURE = boost::lexical_cast<int>(strTemp);
sectionSingleB(secConfig, SECTION_RPC_SSL_CERT, RPC_SSL_CERT);
sectionSingleB(secConfig, SECTION_RPC_SSL_CHAIN, RPC_SSL_CHAIN);
sectionSingleB(secConfig, SECTION_RPC_SSL_KEY, RPC_SSL_KEY);
sectionSingleB(secConfig, SECTION_SSL_VERIFY_FILE, SSL_VERIFY_FILE); sectionSingleB(secConfig, SECTION_SSL_VERIFY_FILE, SSL_VERIFY_FILE);
sectionSingleB(secConfig, SECTION_SSL_VERIFY_DIR, SSL_VERIFY_DIR); sectionSingleB(secConfig, SECTION_SSL_VERIFY_DIR, SSL_VERIFY_DIR);
if (sectionSingleB(secConfig, SECTION_SSL_VERIFY, strTemp)) if (sectionSingleB(secConfig, SECTION_SSL_VERIFY, strTemp))

View File

@@ -137,6 +137,11 @@ public:
bool RPC_ALLOW_REMOTE; bool RPC_ALLOW_REMOTE;
Json::Value RPC_STARTUP; Json::Value RPC_STARTUP;
int RPC_SECURE;
std::string RPC_SSL_CERT;
std::string RPC_SSL_CHAIN;
std::string RPC_SSL_KEY;
// Path searching // Path searching
int PATH_SEARCH_SIZE; int PATH_SEARCH_SIZE;