mirror of
https://github.com/monero-project/monero.git
synced 2025-05-30 06:11:34 -04:00
epee: add SSL support
RPC connections now have optional tranparent SSL. An optional private key and certificate file can be passed, using the --{rpc,daemon}-ssl-private-key and --{rpc,daemon}-ssl-certificate options. Those have as argument a path to a PEM format private private key and certificate, respectively. If not given, a temporary self signed certificate will be used. SSL can be enabled or disabled using --{rpc}-ssl, which accepts autodetect (default), disabled or enabled. Access can be restricted to particular certificates using the --rpc-ssl-allowed-certificates, which takes a list of paths to PEM encoded certificates. This can allow a wallet to connect to only the daemon they think they're connected to, by forcing SSL and listing the paths to the known good certificates. To generate long term certificates: openssl genrsa -out /tmp/KEY 4096 openssl req -new -key /tmp/KEY -out /tmp/REQ openssl x509 -req -days 999999 -sha256 -in /tmp/REQ -signkey /tmp/KEY -out /tmp/CERT /tmp/KEY is the private key, and /tmp/CERT is the certificate, both in PEM format. /tmp/REQ can be removed. Adjust the last command to set expiration date, etc, as needed. It doesn't make a whole lot of sense for monero anyway, since most servers will run with one time temporary self signed certificates anyway. SSL support is transparent, so all communication is done on the existing ports, with SSL autodetection. This means you can start using an SSL daemon now, but you should not enforce SSL yet or nothing will talk to you.
This commit is contained in:
parent
31bdf7bd11
commit
2456945408
25 changed files with 1065 additions and 239 deletions
|
@ -78,19 +78,23 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
|||
template<class t_protocol_handler>
|
||||
connection<t_protocol_handler>::connection( boost::asio::io_service& io_service,
|
||||
boost::shared_ptr<shared_state> state,
|
||||
t_connection_type connection_type
|
||||
t_connection_type connection_type,
|
||||
epee::net_utils::ssl_support_t ssl_support,
|
||||
ssl_context_t &ssl_context
|
||||
)
|
||||
: connection(boost::asio::ip::tcp::socket{io_service}, std::move(state), connection_type)
|
||||
: connection(boost::asio::ip::tcp::socket{io_service}, std::move(state), connection_type, ssl_support, ssl_context)
|
||||
{
|
||||
}
|
||||
|
||||
template<class t_protocol_handler>
|
||||
connection<t_protocol_handler>::connection( boost::asio::ip::tcp::socket&& sock,
|
||||
boost::shared_ptr<shared_state> state,
|
||||
t_connection_type connection_type
|
||||
t_connection_type connection_type,
|
||||
epee::net_utils::ssl_support_t ssl_support,
|
||||
ssl_context_t &ssl_context
|
||||
)
|
||||
:
|
||||
connection_basic(std::move(sock), state),
|
||||
connection_basic(std::move(sock), state, ssl_support, ssl_context),
|
||||
m_protocol_handler(this, check_and_get(state).config, context),
|
||||
m_connection_type( connection_type ),
|
||||
m_throttle_speed_in("speed_in", "throttle_speed_in"),
|
||||
|
@ -109,17 +113,11 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
|||
{
|
||||
if(!m_was_shutdown)
|
||||
{
|
||||
_dbg3("[sock " << socket_.native_handle() << "] Socket destroyed without shutdown.");
|
||||
_dbg3("[sock " << socket().native_handle() << "] Socket destroyed without shutdown.");
|
||||
shutdown();
|
||||
}
|
||||
|
||||
_dbg3("[sock " << socket_.native_handle() << "] Socket destroyed");
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
template<class t_protocol_handler>
|
||||
boost::asio::ip::tcp::socket& connection<t_protocol_handler>::socket()
|
||||
{
|
||||
return socket_;
|
||||
_dbg3("[sock " << socket().native_handle() << "] Socket destroyed");
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
template<class t_protocol_handler>
|
||||
|
@ -142,7 +140,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
|||
TRY_ENTRY();
|
||||
|
||||
boost::system::error_code ec;
|
||||
auto remote_ep = socket_.remote_endpoint(ec);
|
||||
auto remote_ep = socket().remote_endpoint(ec);
|
||||
CHECK_AND_NO_ASSERT_MES(!ec, false, "Failed to get remote endpoint: " << ec.message() << ':' << ec.value());
|
||||
CHECK_AND_NO_ASSERT_MES(remote_ep.address().is_v4(), false, "IPv6 not supported here");
|
||||
|
||||
|
@ -168,10 +166,11 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
|||
const boost::uuids::uuid random_uuid = boost::uuids::random_generator()();
|
||||
|
||||
context = t_connection_context{};
|
||||
context.set_details(random_uuid, std::move(real_remote), is_income);
|
||||
bool ssl = m_ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_enabled;
|
||||
context.set_details(random_uuid, std::move(real_remote), is_income, ssl);
|
||||
|
||||
boost::system::error_code ec;
|
||||
auto local_ep = socket_.local_endpoint(ec);
|
||||
auto local_ep = socket().local_endpoint(ec);
|
||||
CHECK_AND_NO_ASSERT_MES(!ec, false, "Failed to get local endpoint: " << ec.message() << ':' << ec.value());
|
||||
|
||||
_dbg3("[sock " << socket_.native_handle() << "] new connection from " << print_connection_context_short(context) <<
|
||||
|
@ -180,7 +179,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
|||
|
||||
if(static_cast<shared_state&>(get_stats()).pfilter && !static_cast<shared_state&>(get_stats()).pfilter->is_remote_host_allowed(context.m_remote_address))
|
||||
{
|
||||
_dbg2("[sock " << socket_.native_handle() << "] host denied " << context.m_remote_address.host_str() << ", shutdowning connection");
|
||||
_dbg2("[sock " << socket().native_handle() << "] host denied " << context.m_remote_address.host_str() << ", shutdowning connection");
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
|
@ -192,11 +191,21 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
|||
|
||||
reset_timer(get_default_timeout(), false);
|
||||
|
||||
socket_.async_read_some(boost::asio::buffer(buffer_),
|
||||
strand_.wrap(
|
||||
boost::bind(&connection<t_protocol_handler>::handle_read, self,
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred)));
|
||||
// first read on the raw socket to detect SSL for the server
|
||||
buffer_ssl_init_fill = 0;
|
||||
if (is_income && m_ssl_support != epee::net_utils::ssl_support_t::e_ssl_support_disabled)
|
||||
socket().async_receive(boost::asio::buffer(buffer_),
|
||||
boost::asio::socket_base::message_peek,
|
||||
strand_.wrap(
|
||||
boost::bind(&connection<t_protocol_handler>::handle_receive, self,
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred)));
|
||||
else
|
||||
async_read_some(boost::asio::buffer(buffer_),
|
||||
strand_.wrap(
|
||||
boost::bind(&connection<t_protocol_handler>::handle_read, self,
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred)));
|
||||
#if !defined(_WIN32) || !defined(__i686)
|
||||
// not supported before Windows7, too lazy for runtime check
|
||||
// Just exclude for 32bit windows builds
|
||||
|
@ -204,12 +213,12 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
|||
int tos = get_tos_flag();
|
||||
boost::asio::detail::socket_option::integer< IPPROTO_IP, IP_TOS >
|
||||
optionTos( tos );
|
||||
socket_.set_option( optionTos );
|
||||
socket().set_option( optionTos );
|
||||
//_dbg1("Set ToS flag to " << tos);
|
||||
#endif
|
||||
|
||||
boost::asio::ip::tcp::no_delay noDelayOption(false);
|
||||
socket_.set_option(noDelayOption);
|
||||
socket().set_option(noDelayOption);
|
||||
|
||||
return true;
|
||||
|
||||
|
@ -234,7 +243,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
|||
template<class t_protocol_handler>
|
||||
boost::asio::io_service& connection<t_protocol_handler>::get_io_service()
|
||||
{
|
||||
return socket_.get_io_service();
|
||||
return socket().get_io_service();
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
template<class t_protocol_handler>
|
||||
|
@ -246,9 +255,9 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
|||
auto self = safe_shared_from_this();
|
||||
if(!self)
|
||||
return false;
|
||||
//_dbg3("[sock " << socket_.native_handle() << "] add_ref, m_peer_number=" << mI->m_peer_number);
|
||||
//_dbg3("[sock " << socket().native_handle() << "] add_ref, m_peer_number=" << mI->m_peer_number);
|
||||
CRITICAL_REGION_LOCAL(self->m_self_refs_lock);
|
||||
//_dbg3("[sock " << socket_.native_handle() << "] add_ref 2, m_peer_number=" << mI->m_peer_number);
|
||||
//_dbg3("[sock " << socket().native_handle() << "] add_ref 2, m_peer_number=" << mI->m_peer_number);
|
||||
if(m_was_shutdown)
|
||||
return false;
|
||||
++m_reference_count;
|
||||
|
@ -262,9 +271,9 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
|||
{
|
||||
TRY_ENTRY();
|
||||
boost::shared_ptr<connection<t_protocol_handler> > back_connection_copy;
|
||||
LOG_TRACE_CC(context, "[sock " << socket_.native_handle() << "] release");
|
||||
LOG_TRACE_CC(context, "[sock " << socket().native_handle() << "] release");
|
||||
CRITICAL_REGION_BEGIN(m_self_refs_lock);
|
||||
CHECK_AND_ASSERT_MES(m_reference_count, false, "[sock " << socket_.native_handle() << "] m_reference_count already at 0 at connection<t_protocol_handler>::release() call");
|
||||
CHECK_AND_ASSERT_MES(m_reference_count, false, "[sock " << socket().native_handle() << "] m_reference_count already at 0 at connection<t_protocol_handler>::release() call");
|
||||
// is this the last reference?
|
||||
if (--m_reference_count == 0) {
|
||||
// move the held reference to a local variable, keeping the object alive until the function terminates
|
||||
|
@ -290,7 +299,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
|||
std::string address, port;
|
||||
boost::system::error_code e;
|
||||
|
||||
boost::asio::ip::tcp::endpoint endpoint = socket_.remote_endpoint(e);
|
||||
boost::asio::ip::tcp::endpoint endpoint = socket().remote_endpoint(e);
|
||||
if (e)
|
||||
{
|
||||
address = "<not connected>";
|
||||
|
@ -302,7 +311,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
|||
port = boost::lexical_cast<std::string>(endpoint.port());
|
||||
}
|
||||
MDEBUG(" connection type " << to_string( m_connection_type ) << " "
|
||||
<< socket_.local_endpoint().address().to_string() << ":" << socket_.local_endpoint().port()
|
||||
<< socket().local_endpoint().address().to_string() << ":" << socket().local_endpoint().port()
|
||||
<< " <--> " << context.m_remote_address.str() << " (via " << address << ":" << port << ")");
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
|
@ -311,7 +320,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
|||
std::size_t bytes_transferred)
|
||||
{
|
||||
TRY_ENTRY();
|
||||
//_info("[sock " << socket_.native_handle() << "] Async read calledback.");
|
||||
//_info("[sock " << socket().native_handle() << "] Async read calledback.");
|
||||
|
||||
if (!e)
|
||||
{
|
||||
|
@ -347,7 +356,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
|||
} while(delay > 0);
|
||||
} // any form of sleeping
|
||||
|
||||
//_info("[sock " << socket_.native_handle() << "] RECV " << bytes_transferred);
|
||||
//_info("[sock " << socket().native_handle() << "] RECV " << bytes_transferred);
|
||||
logger_handle_net_read(bytes_transferred);
|
||||
context.m_last_recv = time(NULL);
|
||||
context.m_recv_cnt += bytes_transferred;
|
||||
|
@ -355,7 +364,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
|||
bool recv_res = m_protocol_handler.handle_recv(buffer_.data(), bytes_transferred);
|
||||
if(!recv_res)
|
||||
{
|
||||
//_info("[sock " << socket_.native_handle() << "] protocol_want_close");
|
||||
//_info("[sock " << socket().native_handle() << "] protocol_want_close");
|
||||
|
||||
//some error in protocol, protocol handler ask to close connection
|
||||
boost::interprocess::ipcdetail::atomic_write32(&m_want_close_connection, 1);
|
||||
|
@ -369,24 +378,24 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
|||
}else
|
||||
{
|
||||
reset_timer(get_timeout_from_bytes_read(bytes_transferred), false);
|
||||
socket_.async_read_some(boost::asio::buffer(buffer_),
|
||||
async_read_some(boost::asio::buffer(buffer_),
|
||||
strand_.wrap(
|
||||
boost::bind(&connection<t_protocol_handler>::handle_read, connection<t_protocol_handler>::shared_from_this(),
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred)));
|
||||
//_info("[sock " << socket_.native_handle() << "]Async read requested.");
|
||||
//_info("[sock " << socket().native_handle() << "]Async read requested.");
|
||||
}
|
||||
}else
|
||||
{
|
||||
_dbg3("[sock " << socket_.native_handle() << "] Some not success at read: " << e.message() << ':' << e.value());
|
||||
_dbg3("[sock " << socket().native_handle() << "] Some not success at read: " << e.message() << ':' << e.value());
|
||||
if(e.value() != 2)
|
||||
{
|
||||
_dbg3("[sock " << socket_.native_handle() << "] Some problems at read: " << e.message() << ':' << e.value());
|
||||
_dbg3("[sock " << socket().native_handle() << "] Some problems at read: " << e.message() << ':' << e.value());
|
||||
shutdown();
|
||||
}
|
||||
else
|
||||
{
|
||||
_dbg3("[sock " << socket_.native_handle() << "] peer closed connection");
|
||||
_dbg3("[sock " << socket().native_handle() << "] peer closed connection");
|
||||
if (m_ready_to_close)
|
||||
shutdown();
|
||||
}
|
||||
|
@ -400,13 +409,85 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
|||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
template<class t_protocol_handler>
|
||||
void connection<t_protocol_handler>::handle_receive(const boost::system::error_code& e,
|
||||
std::size_t bytes_transferred)
|
||||
{
|
||||
TRY_ENTRY();
|
||||
if (e)
|
||||
{
|
||||
// offload the error case
|
||||
handle_read(e, bytes_transferred);
|
||||
return;
|
||||
}
|
||||
|
||||
reset_timer(get_timeout_from_bytes_read(bytes_transferred), false);
|
||||
|
||||
buffer_ssl_init_fill += bytes_transferred;
|
||||
if (buffer_ssl_init_fill <= get_ssl_magic_size())
|
||||
{
|
||||
socket().async_receive(boost::asio::buffer(buffer_.data() + buffer_ssl_init_fill, buffer_.size() - buffer_ssl_init_fill),
|
||||
boost::asio::socket_base::message_peek,
|
||||
strand_.wrap(
|
||||
boost::bind(&connection<t_protocol_handler>::handle_receive, connection<t_protocol_handler>::shared_from_this(),
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred)));
|
||||
return;
|
||||
}
|
||||
|
||||
// detect SSL
|
||||
if (m_ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_autodetect)
|
||||
{
|
||||
if (is_ssl((const unsigned char*)buffer_.data(), buffer_ssl_init_fill))
|
||||
{
|
||||
MDEBUG("That looks like SSL");
|
||||
m_ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_enabled; // read/write to the SSL socket
|
||||
}
|
||||
else
|
||||
{
|
||||
MDEBUG("That does not look like SSL");
|
||||
m_ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_disabled; // read/write to the raw socket
|
||||
}
|
||||
}
|
||||
|
||||
if (m_ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_enabled)
|
||||
{
|
||||
// Handshake
|
||||
if (!handshake(boost::asio::ssl::stream_base::server))
|
||||
{
|
||||
MERROR("SSL handshake failed");
|
||||
boost::interprocess::ipcdetail::atomic_write32(&m_want_close_connection, 1);
|
||||
bool do_shutdown = false;
|
||||
CRITICAL_REGION_BEGIN(m_send_que_lock);
|
||||
if(!m_send_que.size())
|
||||
do_shutdown = true;
|
||||
CRITICAL_REGION_END();
|
||||
if(do_shutdown)
|
||||
shutdown();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
async_read_some(boost::asio::buffer(buffer_),
|
||||
strand_.wrap(
|
||||
boost::bind(&connection<t_protocol_handler>::handle_read, connection<t_protocol_handler>::shared_from_this(),
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred)));
|
||||
|
||||
// If an error occurs then no new asynchronous operations are started. This
|
||||
// means that all shared_ptr references to the connection object will
|
||||
// disappear and the object will be destroyed automatically after this
|
||||
// handler returns. The connection class's destructor closes the socket.
|
||||
CATCH_ENTRY_L0("connection<t_protocol_handler>::handle_receive", void());
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
template<class t_protocol_handler>
|
||||
bool connection<t_protocol_handler>::call_run_once_service_io()
|
||||
{
|
||||
TRY_ENTRY();
|
||||
if(!m_is_multithreaded)
|
||||
{
|
||||
//single thread model, we can wait in blocked call
|
||||
size_t cnt = socket_.get_io_service().run_one();
|
||||
size_t cnt = socket().get_io_service().run_one();
|
||||
if(!cnt)//service is going to quit
|
||||
return false;
|
||||
}else
|
||||
|
@ -416,7 +497,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
|||
//if no handlers were called
|
||||
//TODO: Maybe we need to have have critical section + event + callback to upper protocol to
|
||||
//ask it inside(!) critical region if we still able to go in event wait...
|
||||
size_t cnt = socket_.get_io_service().poll_one();
|
||||
size_t cnt = socket().get_io_service().poll_one();
|
||||
if(!cnt)
|
||||
misc_utils::sleep_no_w(1);
|
||||
}
|
||||
|
@ -525,7 +606,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
|||
context.m_max_speed_up = std::max(context.m_max_speed_up, context.m_current_speed_up);
|
||||
}
|
||||
|
||||
//_info("[sock " << socket_.native_handle() << "] SEND " << cb);
|
||||
//_info("[sock " << socket().native_handle() << "] SEND " << cb);
|
||||
context.m_last_send = time(NULL);
|
||||
context.m_send_cnt += cb;
|
||||
//some data should be wrote to stream
|
||||
|
@ -570,7 +651,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
|||
MDEBUG("do_send_chunk() NOW just queues: packet="<<size_now<<" B, is added to queue-size="<<m_send_que.size());
|
||||
//do_send_handler_delayed( ptr , size_now ); // (((H))) // empty function
|
||||
|
||||
LOG_TRACE_CC(context, "[sock " << socket_.native_handle() << "] Async send requested " << m_send_que.front().size());
|
||||
LOG_TRACE_CC(context, "[sock " << socket().native_handle() << "] Async send requested " << m_send_que.front().size());
|
||||
}
|
||||
else
|
||||
{ // no active operation
|
||||
|
@ -588,14 +669,14 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
|||
|
||||
CHECK_AND_ASSERT_MES( size_now == m_send_que.front().size(), false, "Unexpected queue size");
|
||||
reset_timer(get_default_timeout(), false);
|
||||
boost::asio::async_write(socket_, boost::asio::buffer(m_send_que.front().data(), size_now ) ,
|
||||
async_write(boost::asio::buffer(m_send_que.front().data(), size_now ) ,
|
||||
//strand_.wrap(
|
||||
boost::bind(&connection<t_protocol_handler>::handle_write, self, _1, _2)
|
||||
//)
|
||||
);
|
||||
//_dbg3("(chunk): " << size_now);
|
||||
//logger_handle_net_write(size_now);
|
||||
//_info("[sock " << socket_.native_handle() << "] Async send requested " << m_send_que.front().size());
|
||||
//_info("[sock " << socket().native_handle() << "] Async send requested " << m_send_que.front().size());
|
||||
}
|
||||
|
||||
//do_send_handler_stop( ptr , cb ); // empty function
|
||||
|
@ -680,7 +761,8 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
|||
// Initiate graceful connection closure.
|
||||
m_timer.cancel();
|
||||
boost::system::error_code ignored_ec;
|
||||
socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec);
|
||||
socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec);
|
||||
socket().close();
|
||||
if (!m_host.empty())
|
||||
{
|
||||
try { host_count(m_host, -1); } catch (...) { /* ignore */ }
|
||||
|
@ -698,7 +780,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
|||
auto self = safe_shared_from_this();
|
||||
if(!self)
|
||||
return false;
|
||||
//_info("[sock " << socket_.native_handle() << "] Que Shutdown called.");
|
||||
//_info("[sock " << socket().native_handle() << "] Que Shutdown called.");
|
||||
m_timer.cancel();
|
||||
size_t send_que_size = 0;
|
||||
CRITICAL_REGION_BEGIN(m_send_que_lock);
|
||||
|
@ -733,11 +815,11 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
|||
void connection<t_protocol_handler>::handle_write(const boost::system::error_code& e, size_t cb)
|
||||
{
|
||||
TRY_ENTRY();
|
||||
LOG_TRACE_CC(context, "[sock " << socket_.native_handle() << "] Async send calledback " << cb);
|
||||
LOG_TRACE_CC(context, "[sock " << socket().native_handle() << "] Async send calledback " << cb);
|
||||
|
||||
if (e)
|
||||
{
|
||||
_dbg1("[sock " << socket_.native_handle() << "] Some problems at write: " << e.message() << ':' << e.value());
|
||||
_dbg1("[sock " << socket().native_handle() << "] Some problems at write: " << e.message() << ':' << e.value());
|
||||
shutdown();
|
||||
return;
|
||||
}
|
||||
|
@ -752,7 +834,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
|||
CRITICAL_REGION_BEGIN(m_send_que_lock);
|
||||
if(m_send_que.empty())
|
||||
{
|
||||
_erro("[sock " << socket_.native_handle() << "] m_send_que.size() == 0 at handle_write!");
|
||||
_erro("[sock " << socket().native_handle() << "] m_send_que.size() == 0 at handle_write!");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -772,11 +854,11 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
|||
if (speed_limit_is_enabled())
|
||||
do_send_handler_write_from_queue(e, m_send_que.front().size() , m_send_que.size()); // (((H)))
|
||||
CHECK_AND_ASSERT_MES( size_now == m_send_que.front().size(), void(), "Unexpected queue size");
|
||||
boost::asio::async_write(socket_, boost::asio::buffer(m_send_que.front().data(), size_now) ,
|
||||
// strand_.wrap(
|
||||
boost::bind(&connection<t_protocol_handler>::handle_write, connection<t_protocol_handler>::shared_from_this(), _1, _2)
|
||||
// )
|
||||
);
|
||||
async_write(boost::asio::buffer(m_send_que.front().data(), size_now) ,
|
||||
// strand_.wrap(
|
||||
boost::bind(&connection<t_protocol_handler>::handle_write, connection<t_protocol_handler>::shared_from_this(), _1, _2)
|
||||
// )
|
||||
);
|
||||
//_dbg3("(normal)" << size_now);
|
||||
}
|
||||
CRITICAL_REGION_END();
|
||||
|
@ -817,7 +899,8 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
|||
m_threads_count(0),
|
||||
m_thread_index(0),
|
||||
m_connection_type( connection_type ),
|
||||
new_connection_()
|
||||
new_connection_(),
|
||||
m_ssl_context({boost::asio::ssl::context(boost::asio::ssl::context::sslv23), {}})
|
||||
{
|
||||
create_server_type_map();
|
||||
m_thread_name_prefix = "NET";
|
||||
|
@ -833,7 +916,8 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
|||
m_threads_count(0),
|
||||
m_thread_index(0),
|
||||
m_connection_type(connection_type),
|
||||
new_connection_()
|
||||
new_connection_(),
|
||||
m_ssl_context({boost::asio::ssl::context(boost::asio::ssl::context::sslv23), {}})
|
||||
{
|
||||
create_server_type_map();
|
||||
m_thread_name_prefix = "NET";
|
||||
|
@ -855,12 +939,14 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
|||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
template<class t_protocol_handler>
|
||||
bool boosted_tcp_server<t_protocol_handler>::init_server(uint32_t port, const std::string address)
|
||||
bool boosted_tcp_server<t_protocol_handler>::init_server(uint32_t port, const std::string address, epee::net_utils::ssl_support_t ssl_support, const std::pair<std::string, std::string> &private_key_and_certificate_path, const std::list<std::string> &allowed_certificates, bool allow_any_cert)
|
||||
{
|
||||
TRY_ENTRY();
|
||||
m_stop_signal_sent = false;
|
||||
m_port = port;
|
||||
m_address = address;
|
||||
if (ssl_support != epee::net_utils::ssl_support_t::e_ssl_support_disabled)
|
||||
m_ssl_context = create_ssl_context(private_key_and_certificate_path, allowed_certificates, allow_any_cert);
|
||||
// Open the acceptor with the option to reuse the address (i.e. SO_REUSEADDR).
|
||||
boost::asio::ip::tcp::resolver resolver(io_service_);
|
||||
boost::asio::ip::tcp::resolver::query query(address, boost::lexical_cast<std::string>(port), boost::asio::ip::tcp::resolver::query::canonical_name);
|
||||
|
@ -872,7 +958,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
|||
boost::asio::ip::tcp::endpoint binded_endpoint = acceptor_.local_endpoint();
|
||||
m_port = binded_endpoint.port();
|
||||
MDEBUG("start accept");
|
||||
new_connection_.reset(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type));
|
||||
new_connection_.reset(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, ssl_support, m_ssl_context));
|
||||
acceptor_.async_accept(new_connection_->socket(),
|
||||
boost::bind(&boosted_tcp_server<t_protocol_handler>::handle_accept, this,
|
||||
boost::asio::placeholders::error));
|
||||
|
@ -894,7 +980,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
|||
PUSH_WARNINGS
|
||||
DISABLE_GCC_WARNING(maybe-uninitialized)
|
||||
template<class t_protocol_handler>
|
||||
bool boosted_tcp_server<t_protocol_handler>::init_server(const std::string port, const std::string& address)
|
||||
bool boosted_tcp_server<t_protocol_handler>::init_server(const std::string port, const std::string& address, epee::net_utils::ssl_support_t ssl_support, const std::pair<std::string, std::string> &private_key_and_certificate_path, const std::list<std::string> &allowed_certificates, bool allow_any_cert)
|
||||
{
|
||||
uint32_t p = 0;
|
||||
|
||||
|
@ -902,7 +988,7 @@ DISABLE_GCC_WARNING(maybe-uninitialized)
|
|||
MERROR("Failed to convert port no = " << port);
|
||||
return false;
|
||||
}
|
||||
return this->init_server(p, address);
|
||||
return this->init_server(p, address, ssl_support, private_key_and_certificate_path, allowed_certificates, allow_any_cert);
|
||||
}
|
||||
POP_WARNINGS
|
||||
//---------------------------------------------------------------------------------
|
||||
|
@ -1067,11 +1153,18 @@ POP_WARNINGS
|
|||
if (!e)
|
||||
{
|
||||
if (m_connection_type == e_connection_type_RPC) {
|
||||
MDEBUG("New server for RPC connections");
|
||||
const char *ssl_message = "unknown";
|
||||
switch (new_connection_->get_ssl_support())
|
||||
{
|
||||
case epee::net_utils::ssl_support_t::e_ssl_support_disabled: ssl_message = "disabled"; break;
|
||||
case epee::net_utils::ssl_support_t::e_ssl_support_enabled: ssl_message = "enabled"; break;
|
||||
case epee::net_utils::ssl_support_t::e_ssl_support_autodetect: ssl_message = "autodetection"; break;
|
||||
}
|
||||
MDEBUG("New server for RPC connections, SSL " << ssl_message);
|
||||
new_connection_->setRpcStation(); // hopefully this is not needed actually
|
||||
}
|
||||
connection_ptr conn(std::move(new_connection_));
|
||||
new_connection_.reset(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type));
|
||||
new_connection_.reset(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, conn->get_ssl_support(), m_ssl_context));
|
||||
acceptor_.async_accept(new_connection_->socket(),
|
||||
boost::bind(&boosted_tcp_server<t_protocol_handler>::handle_accept, this,
|
||||
boost::asio::placeholders::error));
|
||||
|
@ -1079,10 +1172,16 @@ POP_WARNINGS
|
|||
boost::asio::socket_base::keep_alive opt(true);
|
||||
conn->socket().set_option(opt);
|
||||
|
||||
bool res;
|
||||
if (default_remote.get_type_id() == net_utils::address_type::invalid)
|
||||
conn->start(true, 1 < m_threads_count);
|
||||
res = conn->start(true, 1 < m_threads_count);
|
||||
else
|
||||
conn->start(true, 1 < m_threads_count, default_remote);
|
||||
res = conn->start(true, 1 < m_threads_count, default_remote);
|
||||
if (!res)
|
||||
{
|
||||
conn->cancel();
|
||||
return;
|
||||
}
|
||||
conn->save_dbg_log();
|
||||
return;
|
||||
}
|
||||
|
@ -1100,18 +1199,18 @@ POP_WARNINGS
|
|||
assert(m_state != nullptr); // always set in constructor
|
||||
_erro("Some problems at accept: " << e.message() << ", connections_count = " << m_state->sock_count);
|
||||
misc_utils::sleep_no_w(100);
|
||||
new_connection_.reset(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type));
|
||||
new_connection_.reset(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, new_connection_->get_ssl_support(), m_ssl_context));
|
||||
acceptor_.async_accept(new_connection_->socket(),
|
||||
boost::bind(&boosted_tcp_server<t_protocol_handler>::handle_accept, this,
|
||||
boost::asio::placeholders::error));
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
template<class t_protocol_handler>
|
||||
bool boosted_tcp_server<t_protocol_handler>::add_connection(t_connection_context& out, boost::asio::ip::tcp::socket&& sock, network_address real_remote)
|
||||
bool boosted_tcp_server<t_protocol_handler>::add_connection(t_connection_context& out, boost::asio::ip::tcp::socket&& sock, network_address real_remote, epee::net_utils::ssl_support_t ssl_support)
|
||||
{
|
||||
if(std::addressof(get_io_service()) == std::addressof(sock.get_io_service()))
|
||||
{
|
||||
connection_ptr conn(new connection<t_protocol_handler>(std::move(sock), m_state, m_connection_type));
|
||||
connection_ptr conn(new connection<t_protocol_handler>(std::move(sock), m_state, m_connection_type, ssl_support, m_ssl_context));
|
||||
if(conn->start(false, 1 < m_threads_count, std::move(real_remote)))
|
||||
{
|
||||
conn->get_context(out);
|
||||
|
@ -1127,34 +1226,10 @@ POP_WARNINGS
|
|||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
template<class t_protocol_handler>
|
||||
bool boosted_tcp_server<t_protocol_handler>::connect(const std::string& adr, const std::string& port, uint32_t conn_timeout, t_connection_context& conn_context, const std::string& bind_ip)
|
||||
typename boosted_tcp_server<t_protocol_handler>::try_connect_result_t boosted_tcp_server<t_protocol_handler>::try_connect(connection_ptr new_connection_l, const std::string& adr, const std::string& port, boost::asio::ip::tcp::socket &sock_, const boost::asio::ip::tcp::endpoint &remote_endpoint, const std::string &bind_ip, uint32_t conn_timeout, epee::net_utils::ssl_support_t ssl_support)
|
||||
{
|
||||
TRY_ENTRY();
|
||||
|
||||
connection_ptr new_connection_l(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type) );
|
||||
connections_mutex.lock();
|
||||
connections_.insert(new_connection_l);
|
||||
MDEBUG("connections_ size now " << connections_.size());
|
||||
connections_mutex.unlock();
|
||||
epee::misc_utils::auto_scope_leave_caller scope_exit_handler = epee::misc_utils::create_scope_leave_handler([&](){ CRITICAL_REGION_LOCAL(connections_mutex); connections_.erase(new_connection_l); });
|
||||
boost::asio::ip::tcp::socket& sock_ = new_connection_l->socket();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
boost::asio::ip::tcp::resolver resolver(io_service_);
|
||||
boost::asio::ip::tcp::resolver::query query(boost::asio::ip::tcp::v4(), adr, port, boost::asio::ip::tcp::resolver::query::canonical_name);
|
||||
boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query);
|
||||
boost::asio::ip::tcp::resolver::iterator end;
|
||||
if(iterator == end)
|
||||
{
|
||||
_erro("Failed to resolve " << adr);
|
||||
return false;
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
//boost::asio::ip::tcp::endpoint remote_endpoint(boost::asio::ip::address::from_string(addr.c_str()), port);
|
||||
boost::asio::ip::tcp::endpoint remote_endpoint(*iterator);
|
||||
|
||||
sock_.open(remote_endpoint.protocol());
|
||||
if(bind_ip != "0.0.0.0" && bind_ip != "0" && bind_ip != "" )
|
||||
{
|
||||
|
@ -1166,7 +1241,7 @@ POP_WARNINGS
|
|||
MERROR("Error binding to " << bind_ip << ": " << ec.message());
|
||||
if (sock_.is_open())
|
||||
sock_.close();
|
||||
return false;
|
||||
return CONNECT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1200,14 +1275,14 @@ POP_WARNINGS
|
|||
{
|
||||
if (sock_.is_open())
|
||||
sock_.close();
|
||||
return false;
|
||||
return CONNECT_FAILURE;
|
||||
}
|
||||
if(local_shared_context->ec == boost::asio::error::would_block && !r)
|
||||
{
|
||||
//timeout
|
||||
sock_.close();
|
||||
_dbg3("Failed to connect to " << adr << ":" << port << ", because of timeout (" << conn_timeout << ")");
|
||||
return false;
|
||||
return CONNECT_FAILURE;
|
||||
}
|
||||
}
|
||||
ec = local_shared_context->ec;
|
||||
|
@ -1217,11 +1292,79 @@ POP_WARNINGS
|
|||
_dbg3("Some problems at connect, message: " << ec.message());
|
||||
if (sock_.is_open())
|
||||
sock_.close();
|
||||
return false;
|
||||
return CONNECT_FAILURE;
|
||||
}
|
||||
|
||||
_dbg3("Connected success to " << adr << ':' << port);
|
||||
|
||||
const epee::net_utils::ssl_support_t ssl_support = new_connection_l->get_ssl_support();
|
||||
if (ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_enabled || ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_autodetect)
|
||||
{
|
||||
// Handshake
|
||||
MDEBUG("Handshaking SSL...");
|
||||
if (!new_connection_l->handshake(boost::asio::ssl::stream_base::client))
|
||||
{
|
||||
if (ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_autodetect)
|
||||
{
|
||||
boost::system::error_code ignored_ec;
|
||||
sock_.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec);
|
||||
sock_.close();
|
||||
return CONNECT_NO_SSL;
|
||||
}
|
||||
MERROR("SSL handshake failed");
|
||||
if (sock_.is_open())
|
||||
sock_.close();
|
||||
return CONNECT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
return CONNECT_SUCCESS;
|
||||
|
||||
CATCH_ENTRY_L0("boosted_tcp_server<t_protocol_handler>::try_connect", CONNECT_FAILURE);
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
template<class t_protocol_handler>
|
||||
bool boosted_tcp_server<t_protocol_handler>::connect(const std::string& adr, const std::string& port, uint32_t conn_timeout, t_connection_context& conn_context, const std::string& bind_ip, epee::net_utils::ssl_support_t ssl_support)
|
||||
{
|
||||
TRY_ENTRY();
|
||||
|
||||
connection_ptr new_connection_l(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, ssl_support, m_ssl_context) );
|
||||
connections_mutex.lock();
|
||||
connections_.insert(new_connection_l);
|
||||
MDEBUG("connections_ size now " << connections_.size());
|
||||
connections_mutex.unlock();
|
||||
epee::misc_utils::auto_scope_leave_caller scope_exit_handler = epee::misc_utils::create_scope_leave_handler([&](){ CRITICAL_REGION_LOCAL(connections_mutex); connections_.erase(new_connection_l); });
|
||||
boost::asio::ip::tcp::socket& sock_ = new_connection_l->socket();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
boost::asio::ip::tcp::resolver resolver(io_service_);
|
||||
boost::asio::ip::tcp::resolver::query query(boost::asio::ip::tcp::v4(), adr, port, boost::asio::ip::tcp::resolver::query::canonical_name);
|
||||
boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query);
|
||||
boost::asio::ip::tcp::resolver::iterator end;
|
||||
if(iterator == end)
|
||||
{
|
||||
_erro("Failed to resolve " << adr);
|
||||
return false;
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
//boost::asio::ip::tcp::endpoint remote_endpoint(boost::asio::ip::address::from_string(addr.c_str()), port);
|
||||
boost::asio::ip::tcp::endpoint remote_endpoint(*iterator);
|
||||
|
||||
auto try_connect_result = try_connect(new_connection_l, adr, port, sock_, remote_endpoint, bind_ip, conn_timeout, ssl_support);
|
||||
if (try_connect_result == CONNECT_FAILURE)
|
||||
return false;
|
||||
if (ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_autodetect && try_connect_result == CONNECT_NO_SSL)
|
||||
{
|
||||
// we connected, but could not connect with SSL, try without
|
||||
MERROR("SSL handshake failed on an autodetect connection, reconnecting without SSL");
|
||||
new_connection_l->disable_ssl();
|
||||
try_connect_result = try_connect(new_connection_l, adr, port, sock_, remote_endpoint, bind_ip, conn_timeout, epee::net_utils::ssl_support_t::e_ssl_support_disabled);
|
||||
if (try_connect_result != CONNECT_SUCCESS)
|
||||
return false;
|
||||
}
|
||||
|
||||
// start adds the connection to the config object's list, so we don't need to have it locally anymore
|
||||
connections_mutex.lock();
|
||||
connections_.erase(new_connection_l);
|
||||
|
@ -1246,10 +1389,10 @@ POP_WARNINGS
|
|||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
template<class t_protocol_handler> template<class t_callback>
|
||||
bool boosted_tcp_server<t_protocol_handler>::connect_async(const std::string& adr, const std::string& port, uint32_t conn_timeout, const t_callback &cb, const std::string& bind_ip)
|
||||
bool boosted_tcp_server<t_protocol_handler>::connect_async(const std::string& adr, const std::string& port, uint32_t conn_timeout, const t_callback &cb, const std::string& bind_ip, epee::net_utils::ssl_support_t ssl_support)
|
||||
{
|
||||
TRY_ENTRY();
|
||||
connection_ptr new_connection_l(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type) );
|
||||
connection_ptr new_connection_l(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, ssl_support, m_ssl_context) );
|
||||
connections_mutex.lock();
|
||||
connections_.insert(new_connection_l);
|
||||
MDEBUG("connections_ size now " << connections_.size());
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue