mirror of
https://codeberg.org/anoncontributorxmr/monero.git
synced 2024-11-30 06:43:28 +01:00
Merge pull request #4054
24569454
epee: add SSL support (moneromooo-monero)
This commit is contained in:
commit
46fd181cca
@ -46,6 +46,7 @@
|
||||
#include <memory>
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/asio/ssl.hpp>
|
||||
#include <boost/array.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
@ -102,15 +103,19 @@ namespace net_utils
|
||||
/// Construct a connection with the given io_service.
|
||||
explicit 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);
|
||||
|
||||
explicit connection( boost::asio::ip::tcp::socket&& sock,
|
||||
boost::shared_ptr<shared_state> state,
|
||||
t_connection_type connection_type);
|
||||
boost::shared_ptr<shared_state> state,
|
||||
t_connection_type connection_type,
|
||||
epee::net_utils::ssl_support_t ssl_support,
|
||||
ssl_context_t &ssl_context);
|
||||
|
||||
|
||||
|
||||
virtual ~connection() noexcept(false);
|
||||
/// Get the socket associated with the connection.
|
||||
boost::asio::ip::tcp::socket& socket();
|
||||
|
||||
/// Start the first asynchronous operation for the connection.
|
||||
bool start(bool is_income, bool is_multithreaded);
|
||||
@ -143,6 +148,10 @@ namespace net_utils
|
||||
//------------------------------------------------------
|
||||
boost::shared_ptr<connection<t_protocol_handler> > safe_shared_from_this();
|
||||
bool shutdown();
|
||||
/// Handle completion of a receive operation.
|
||||
void handle_receive(const boost::system::error_code& e,
|
||||
std::size_t bytes_transferred);
|
||||
|
||||
/// Handle completion of a read operation.
|
||||
void handle_read(const boost::system::error_code& e,
|
||||
std::size_t bytes_transferred);
|
||||
@ -160,7 +169,7 @@ namespace net_utils
|
||||
|
||||
/// Buffer for incoming data.
|
||||
boost::array<char, 8192> buffer_;
|
||||
//boost::array<char, 1024> buffer_;
|
||||
size_t buffer_ssl_init_fill;
|
||||
|
||||
t_connection_context context;
|
||||
|
||||
@ -199,6 +208,13 @@ namespace net_utils
|
||||
class boosted_tcp_server
|
||||
: private boost::noncopyable
|
||||
{
|
||||
enum try_connect_result_t
|
||||
{
|
||||
CONNECT_SUCCESS,
|
||||
CONNECT_FAILURE,
|
||||
CONNECT_NO_SSL,
|
||||
};
|
||||
|
||||
public:
|
||||
typedef boost::shared_ptr<connection<t_protocol_handler> > connection_ptr;
|
||||
typedef typename t_protocol_handler::connection_context t_connection_context;
|
||||
@ -212,8 +228,8 @@ namespace net_utils
|
||||
std::map<std::string, t_connection_type> server_type_map;
|
||||
void create_server_type_map();
|
||||
|
||||
bool init_server(uint32_t port, const std::string address = "0.0.0.0");
|
||||
bool init_server(const std::string port, const std::string& address = "0.0.0.0");
|
||||
bool init_server(uint32_t port, const std::string address = "0.0.0.0", epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_autodetect, const std::pair<std::string, std::string> &private_key_and_certificate_path = std::make_pair(std::string(), std::string()), const std::list<std::string> &allowed_certificates = {}, bool allow_any_cert = false);
|
||||
bool init_server(const std::string port, const std::string& address = "0.0.0.0", epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_autodetect, const std::pair<std::string, std::string> &private_key_and_certificate_path = std::make_pair(std::string(), std::string()), const std::list<std::string> &allowed_certificates = {}, bool allow_any_cert = false);
|
||||
|
||||
/// Run the server's io_service loop.
|
||||
bool run_server(size_t threads_count, bool wait = true, const boost::thread::attributes& attrs = boost::thread::attributes());
|
||||
@ -241,10 +257,11 @@ namespace net_utils
|
||||
default_remote = std::move(remote);
|
||||
}
|
||||
|
||||
bool add_connection(t_connection_context& out, boost::asio::ip::tcp::socket&& sock, network_address real_remote);
|
||||
bool connect(const std::string& adr, const std::string& port, uint32_t conn_timeot, t_connection_context& cn, const std::string& bind_ip = "0.0.0.0");
|
||||
bool add_connection(t_connection_context& out, boost::asio::ip::tcp::socket&& sock, network_address real_remote, epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_autodetect);
|
||||
try_connect_result_t 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);
|
||||
bool connect(const std::string& adr, const std::string& port, uint32_t conn_timeot, t_connection_context& cn, const std::string& bind_ip = "0.0.0.0", epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_autodetect);
|
||||
template<class t_callback>
|
||||
bool connect_async(const std::string& adr, const std::string& port, uint32_t conn_timeot, const t_callback &cb, const std::string& bind_ip = "0.0.0.0");
|
||||
bool connect_async(const std::string& adr, const std::string& port, uint32_t conn_timeot, const t_callback &cb, const std::string& bind_ip = "0.0.0.0", epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_autodetect);
|
||||
|
||||
typename t_protocol_handler::config_type& get_config_object()
|
||||
{
|
||||
@ -355,6 +372,9 @@ namespace net_utils
|
||||
boost::mutex connections_mutex;
|
||||
std::set<connection_ptr> connections_;
|
||||
|
||||
ssl_context_t m_ssl_context;
|
||||
std::list<std::string> m_allowed_certificates;
|
||||
|
||||
}; // class <>boosted_tcp_server
|
||||
|
||||
|
||||
|
@ -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());
|
||||
|
@ -47,8 +47,10 @@
|
||||
#include <memory>
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/asio/ssl.hpp>
|
||||
|
||||
#include "net/net_utils_base.h"
|
||||
#include "net/net_ssl.h"
|
||||
#include "syncobj.h"
|
||||
|
||||
namespace epee
|
||||
@ -95,16 +97,56 @@ class connection_basic { // not-templated base class for rapid developmet of som
|
||||
/// Strand to ensure the connection's handlers are not called concurrently.
|
||||
boost::asio::io_service::strand strand_;
|
||||
/// Socket for the connection.
|
||||
boost::asio::ip::tcp::socket socket_;
|
||||
ssl_context_t &m_ssl_context;
|
||||
ssl_support_t m_ssl_support;
|
||||
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket_;
|
||||
|
||||
public:
|
||||
// first counter is the ++/-- count of current sockets, the other socket_number is only-increasing ++ number generator
|
||||
connection_basic(boost::asio::ip::tcp::socket&& socket, boost::shared_ptr<socket_stats> stats);
|
||||
connection_basic(boost::asio::ip::tcp::socket&& socket, boost::shared_ptr<socket_stats> stats, ssl_support_t ssl_support, ssl_context_t &ssl_context);
|
||||
connection_basic(boost::asio::io_service &io_service, boost::shared_ptr<socket_stats> stats, ssl_support_t ssl_support, ssl_context_t &ssl_context);
|
||||
|
||||
virtual ~connection_basic() noexcept(false);
|
||||
|
||||
//! \return `socket_stats` object passed in construction (ptr never changes).
|
||||
socket_stats& get_stats() noexcept { return *m_stats; /* verified in constructor */ }
|
||||
connection_basic(boost::asio::io_service& io_service, std::atomic<long> &ref_sock_count, std::atomic<long> &sock_number, ssl_support_t ssl, ssl_context_t &ssl_context);
|
||||
|
||||
boost::asio::ip::tcp::socket& socket() { return socket_.next_layer(); }
|
||||
ssl_support_t get_ssl_support() const { return m_ssl_support; }
|
||||
void disable_ssl() { m_ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_disabled; }
|
||||
|
||||
bool handshake(boost::asio::ssl::stream_base::handshake_type type)
|
||||
{
|
||||
return ssl_handshake(socket_, type, m_ssl_context);
|
||||
}
|
||||
|
||||
template<typename MutableBufferSequence, typename ReadHandler>
|
||||
void async_read_some(const MutableBufferSequence &buffers, ReadHandler &&handler)
|
||||
{
|
||||
if (m_ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_enabled)
|
||||
socket_.async_read_some(buffers, std::forward<ReadHandler>(handler));
|
||||
else
|
||||
socket().async_read_some(buffers, std::forward<ReadHandler>(handler));
|
||||
}
|
||||
|
||||
template<typename ConstBufferSequence, typename WriteHandler>
|
||||
void async_write_some(const ConstBufferSequence &buffers, WriteHandler &&handler)
|
||||
{
|
||||
if (m_ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_enabled)
|
||||
socket_.async_write_some(buffers, std::forward<WriteHandler>(handler));
|
||||
else
|
||||
socket().async_write_some(buffers, std::forward<WriteHandler>(handler));
|
||||
}
|
||||
|
||||
template<typename ConstBufferSequence, typename WriteHandler>
|
||||
void async_write(const ConstBufferSequence &buffers, WriteHandler &&handler)
|
||||
{
|
||||
if (m_ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_enabled)
|
||||
boost::asio::async_write(socket_, buffers, std::forward<WriteHandler>(handler));
|
||||
else
|
||||
boost::asio::async_write(socket(), buffers, std::forward<WriteHandler>(handler));
|
||||
}
|
||||
|
||||
// various handlers to be called from connection class:
|
||||
void do_send_handler_write(const void * ptr , size_t cb);
|
||||
|
@ -275,7 +275,10 @@ namespace net_utils
|
||||
chunked_state m_chunked_state;
|
||||
std::string m_chunked_cache;
|
||||
critical_section m_lock;
|
||||
bool m_ssl;
|
||||
epee::net_utils::ssl_support_t m_ssl_support;
|
||||
std::pair<std::string, std::string> m_ssl_private_key_and_certificate_path;
|
||||
std::list<std::string> m_ssl_allowed_certificates;
|
||||
bool m_ssl_allow_any_cert;
|
||||
|
||||
public:
|
||||
explicit http_simple_client_template()
|
||||
@ -293,35 +296,39 @@ namespace net_utils
|
||||
, m_chunked_state()
|
||||
, m_chunked_cache()
|
||||
, m_lock()
|
||||
, m_ssl(false)
|
||||
, m_ssl_support(epee::net_utils::ssl_support_t::e_ssl_support_autodetect)
|
||||
{}
|
||||
|
||||
const std::string &get_host() const { return m_host_buff; };
|
||||
const std::string &get_port() const { return m_port; };
|
||||
|
||||
bool set_server(const std::string& address, boost::optional<login> user, bool ssl = false)
|
||||
bool set_server(const std::string& address, boost::optional<login> user, epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_autodetect, const std::pair<std::string, std::string> &private_key_and_certificate_path = {}, const std::list<std::string> &allowed_ssl_certificates = {}, bool allow_any_cert = false)
|
||||
{
|
||||
http::url_content parsed{};
|
||||
const bool r = parse_url(address, parsed);
|
||||
CHECK_AND_ASSERT_MES(r, false, "failed to parse url: " << address);
|
||||
set_server(std::move(parsed.host), std::to_string(parsed.port), std::move(user), ssl);
|
||||
set_server(std::move(parsed.host), std::to_string(parsed.port), std::move(user), ssl_support, private_key_and_certificate_path, allowed_ssl_certificates, allow_any_cert);
|
||||
return true;
|
||||
}
|
||||
|
||||
void set_server(std::string host, std::string port, boost::optional<login> user, bool ssl = false)
|
||||
void set_server(std::string host, std::string port, boost::optional<login> user, epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_autodetect, const std::pair<std::string, std::string> &private_key_and_certificate_path = {}, const std::list<std::string> &allowed_ssl_certificates = {}, bool allow_any_cert = false)
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_lock);
|
||||
disconnect();
|
||||
m_host_buff = std::move(host);
|
||||
m_port = std::move(port);
|
||||
m_auth = user ? http_client_auth{std::move(*user)} : http_client_auth{};
|
||||
m_ssl = ssl;
|
||||
m_ssl_support = ssl_support;
|
||||
m_ssl_private_key_and_certificate_path = private_key_and_certificate_path;
|
||||
m_ssl_allowed_certificates = allowed_ssl_certificates;
|
||||
m_ssl_allow_any_cert = allow_any_cert;
|
||||
m_net_client.set_ssl(m_ssl_support, m_ssl_private_key_and_certificate_path, m_ssl_allowed_certificates, m_ssl_allow_any_cert);
|
||||
}
|
||||
|
||||
bool connect(std::chrono::milliseconds timeout)
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_lock);
|
||||
return m_net_client.connect(m_host_buff, m_port, timeout, m_ssl);
|
||||
return m_net_client.connect(m_host_buff, m_port, timeout, "0.0.0.0");
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
bool disconnect()
|
||||
@ -330,10 +337,10 @@ namespace net_utils
|
||||
return m_net_client.disconnect();
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
bool is_connected()
|
||||
bool is_connected(bool *ssl = NULL)
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_lock);
|
||||
return m_net_client.is_connected();
|
||||
return m_net_client.is_connected(ssl);
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
virtual bool handle_target_data(std::string& piece_of_transfer)
|
||||
|
@ -58,7 +58,10 @@ namespace epee
|
||||
|
||||
bool init(std::function<void(size_t, uint8_t*)> rng, const std::string& bind_port = "0", const std::string& bind_ip = "0.0.0.0",
|
||||
std::vector<std::string> access_control_origins = std::vector<std::string>(),
|
||||
boost::optional<net_utils::http::login> user = boost::none)
|
||||
boost::optional<net_utils::http::login> user = boost::none,
|
||||
epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_autodetect,
|
||||
const std::pair<std::string, std::string> &private_key_and_certificate_path = {},
|
||||
const std::list<std::string> &allowed_certificates = std::list<std::string>(), bool allow_any_cert = false)
|
||||
{
|
||||
|
||||
//set self as callback handler
|
||||
@ -75,7 +78,7 @@ namespace epee
|
||||
m_net_server.get_config_object().m_user = std::move(user);
|
||||
|
||||
MGINFO("Binding on " << bind_ip << ":" << bind_port);
|
||||
bool res = m_net_server.init_server(bind_port, bind_ip);
|
||||
bool res = m_net_server.init_server(bind_port, bind_ip, ssl_support, private_key_and_certificate_path, allowed_certificates, allow_any_cert);
|
||||
if(!res)
|
||||
{
|
||||
LOG_ERROR("Failed to bind server");
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include <boost/lambda/lambda.hpp>
|
||||
#include <boost/interprocess/detail/atomic.hpp>
|
||||
#include "net/net_utils_base.h"
|
||||
#include "net/net_ssl.h"
|
||||
#include "misc_language.h"
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
@ -57,6 +58,13 @@ namespace net_utils
|
||||
|
||||
class blocked_mode_client
|
||||
{
|
||||
enum try_connect_result_t
|
||||
{
|
||||
CONNECT_SUCCESS,
|
||||
CONNECT_FAILURE,
|
||||
CONNECT_NO_SSL,
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct handler_obj
|
||||
@ -84,9 +92,9 @@ namespace net_utils
|
||||
m_connected(false),
|
||||
m_deadline(m_io_service),
|
||||
m_shutdowned(0),
|
||||
m_ssl(false),
|
||||
m_ctx(boost::asio::ssl::context::sslv23),
|
||||
m_ssl_socket(m_io_service,m_ctx)
|
||||
m_ssl_support(epee::net_utils::ssl_support_t::e_ssl_support_autodetect),
|
||||
m_ctx({boost::asio::ssl::context(boost::asio::ssl::context::sslv23), {}}),
|
||||
m_ssl_socket(new boost::asio::ssl::stream<boost::asio::ip::tcp::socket>(m_io_service,m_ctx.context))
|
||||
{
|
||||
|
||||
|
||||
@ -110,28 +118,92 @@ namespace net_utils
|
||||
catch(...) { /* ignore */ }
|
||||
}
|
||||
|
||||
inline void set_ssl(epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_autodetect, const std::pair<std::string, std::string> &private_key_and_certificate_path = {}, const std::list<std::string> &allowed_certificates = std::list<std::string>(), bool allow_any_cert = false)
|
||||
{
|
||||
if (ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_disabled)
|
||||
m_ctx = {boost::asio::ssl::context(boost::asio::ssl::context::sslv23), {}};
|
||||
else
|
||||
m_ctx = create_ssl_context(private_key_and_certificate_path, allowed_certificates, allow_any_cert);
|
||||
m_ssl_support = ssl_support;
|
||||
}
|
||||
|
||||
inline
|
||||
bool connect(const std::string& addr, int port, std::chrono::milliseconds timeout, bool ssl = false, const std::string& bind_ip = "0.0.0.0")
|
||||
bool connect(const std::string& addr, int port, std::chrono::milliseconds timeout, const std::string& bind_ip = "0.0.0.0")
|
||||
{
|
||||
return connect(addr, std::to_string(port), timeout, ssl, bind_ip);
|
||||
return connect(addr, std::to_string(port), timeout, bind_ip);
|
||||
}
|
||||
|
||||
inline
|
||||
bool connect(const std::string& addr, const std::string& port, std::chrono::milliseconds timeout, bool ssl = false, const std::string& bind_ip = "0.0.0.0")
|
||||
try_connect_result_t try_connect(const std::string& addr, const std::string& port, const boost::asio::ip::tcp::endpoint &remote_endpoint, std::chrono::milliseconds timeout, const std::string& bind_ip, epee::net_utils::ssl_support_t ssl_support)
|
||||
{
|
||||
m_connected = false;
|
||||
m_ssl = ssl;
|
||||
m_ssl_socket->next_layer().open(remote_endpoint.protocol());
|
||||
if(bind_ip != "0.0.0.0" && bind_ip != "0" && bind_ip != "" )
|
||||
{
|
||||
boost::asio::ip::tcp::endpoint local_endpoint(boost::asio::ip::address::from_string(addr.c_str()), 0);
|
||||
m_ssl_socket->next_layer().bind(local_endpoint);
|
||||
}
|
||||
|
||||
|
||||
m_deadline.expires_from_now(timeout);
|
||||
|
||||
boost::system::error_code ec = boost::asio::error::would_block;
|
||||
|
||||
m_ssl_socket->next_layer().async_connect(remote_endpoint, boost::lambda::var(ec) = boost::lambda::_1);
|
||||
while (ec == boost::asio::error::would_block)
|
||||
{
|
||||
m_io_service.run_one();
|
||||
}
|
||||
|
||||
if (!ec && m_ssl_socket->next_layer().is_open())
|
||||
{
|
||||
m_connected = true;
|
||||
m_deadline.expires_at(std::chrono::steady_clock::time_point::max());
|
||||
// SSL Options
|
||||
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)
|
||||
{
|
||||
if (!ssl_handshake(*m_ssl_socket, boost::asio::ssl::stream_base::client, m_ctx))
|
||||
{
|
||||
if (ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_autodetect)
|
||||
{
|
||||
boost::system::error_code ignored_ec;
|
||||
m_ssl_socket->next_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec);
|
||||
m_ssl_socket->next_layer().close();
|
||||
m_connected = false;
|
||||
return CONNECT_NO_SSL;
|
||||
}
|
||||
else
|
||||
{
|
||||
MWARNING("Failed to establish SSL connection");
|
||||
m_connected = false;
|
||||
return CONNECT_FAILURE;
|
||||
}
|
||||
}
|
||||
m_ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_enabled;
|
||||
}
|
||||
return CONNECT_SUCCESS;
|
||||
}else
|
||||
{
|
||||
MWARNING("Some problems at connect, message: " << ec.message());
|
||||
return CONNECT_FAILURE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
inline
|
||||
bool connect(const std::string& addr, const std::string& port, std::chrono::milliseconds timeout, const std::string& bind_ip = "0.0.0.0")
|
||||
{
|
||||
m_connected = false;
|
||||
try
|
||||
{
|
||||
m_ssl_socket.next_layer().close();
|
||||
m_ssl_socket->next_layer().close();
|
||||
|
||||
// Set SSL options
|
||||
// disable sslv2
|
||||
m_ctx.set_options(boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::no_sslv2);
|
||||
m_ctx.set_default_verify_paths();
|
||||
m_ctx.context.set_options(boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::no_sslv2);
|
||||
m_ctx.context.set_default_verify_paths();
|
||||
m_ssl_socket.reset(new boost::asio::ssl::stream<boost::asio::ip::tcp::socket>(m_io_service, m_ctx.context));
|
||||
|
||||
// Get a list of endpoints corresponding to the server name.
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@ -151,45 +223,20 @@ namespace net_utils
|
||||
//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);
|
||||
|
||||
|
||||
m_ssl_socket.next_layer().open(remote_endpoint.protocol());
|
||||
if(bind_ip != "0.0.0.0" && bind_ip != "0" && bind_ip != "" )
|
||||
{
|
||||
boost::asio::ip::tcp::endpoint local_endpoint(boost::asio::ip::address::from_string(addr.c_str()), 0);
|
||||
m_ssl_socket.next_layer().bind(local_endpoint);
|
||||
}
|
||||
|
||||
|
||||
m_deadline.expires_from_now(timeout);
|
||||
|
||||
|
||||
boost::system::error_code ec = boost::asio::error::would_block;
|
||||
|
||||
m_ssl_socket.next_layer().async_connect(remote_endpoint, boost::lambda::var(ec) = boost::lambda::_1);
|
||||
while (ec == boost::asio::error::would_block)
|
||||
{
|
||||
m_io_service.run_one();
|
||||
}
|
||||
|
||||
if (!ec && m_ssl_socket.next_layer().is_open())
|
||||
{
|
||||
m_connected = true;
|
||||
m_deadline.expires_at(std::chrono::steady_clock::time_point::max());
|
||||
// SSL Options
|
||||
if(m_ssl) {
|
||||
// Disable verification of host certificate
|
||||
m_ssl_socket.set_verify_mode(boost::asio::ssl::verify_peer);
|
||||
// Handshake
|
||||
m_ssl_socket.next_layer().set_option(boost::asio::ip::tcp::no_delay(true));
|
||||
m_ssl_socket.handshake(boost::asio::ssl::stream_base::client);
|
||||
}
|
||||
return true;
|
||||
}else
|
||||
{
|
||||
MWARNING("Some problems at connect, message: " << ec.message());
|
||||
try_connect_result_t try_connect_result = try_connect(addr, port, remote_endpoint, timeout, bind_ip, m_ssl_support);
|
||||
if (try_connect_result == CONNECT_FAILURE)
|
||||
return false;
|
||||
if (m_ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_autodetect)
|
||||
{
|
||||
m_ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_enabled;
|
||||
if (try_connect_result == CONNECT_NO_SSL)
|
||||
{
|
||||
MERROR("SSL handshake failed on an autodetect connection, reconnecting without SSL");
|
||||
m_ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_disabled;
|
||||
if (try_connect(addr, port, remote_endpoint, timeout, bind_ip, m_ssl_support) != CONNECT_SUCCESS)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
catch(const boost::system::system_error& er)
|
||||
{
|
||||
@ -213,9 +260,9 @@ namespace net_utils
|
||||
if(m_connected)
|
||||
{
|
||||
m_connected = false;
|
||||
if(m_ssl)
|
||||
if(m_ssl_support != epee::net_utils::ssl_support_t::e_ssl_support_disabled)
|
||||
shutdown_ssl();
|
||||
m_ssl_socket.next_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both);
|
||||
m_ssl_socket->next_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both);
|
||||
}
|
||||
}
|
||||
|
||||
@ -342,9 +389,13 @@ namespace net_utils
|
||||
return true;
|
||||
}
|
||||
|
||||
bool is_connected()
|
||||
bool is_connected(bool *ssl = NULL)
|
||||
{
|
||||
return m_connected && m_ssl_socket.next_layer().is_open();
|
||||
if (!m_connected || !m_ssl_socket->next_layer().is_open())
|
||||
return false;
|
||||
if (ssl)
|
||||
*ssl = m_ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_enabled;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline
|
||||
@ -506,15 +557,15 @@ namespace net_utils
|
||||
{
|
||||
m_deadline.cancel();
|
||||
boost::system::error_code ec;
|
||||
if(m_ssl)
|
||||
if(m_ssl_support != epee::net_utils::ssl_support_t::e_ssl_support_disabled)
|
||||
shutdown_ssl();
|
||||
m_ssl_socket.next_layer().cancel(ec);
|
||||
m_ssl_socket->next_layer().cancel(ec);
|
||||
if(ec)
|
||||
MDEBUG("Problems at cancel: " << ec.message());
|
||||
m_ssl_socket.next_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
|
||||
m_ssl_socket->next_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
|
||||
if(ec)
|
||||
MDEBUG("Problems at shutdown: " << ec.message());
|
||||
m_ssl_socket.next_layer().close(ec);
|
||||
m_ssl_socket->next_layer().close(ec);
|
||||
if(ec)
|
||||
MDEBUG("Problems at close: " << ec.message());
|
||||
boost::interprocess::ipcdetail::atomic_write32(&m_shutdowned, 1);
|
||||
@ -533,7 +584,7 @@ namespace net_utils
|
||||
|
||||
boost::asio::ip::tcp::socket& get_socket()
|
||||
{
|
||||
return m_ssl_socket.next_layer();
|
||||
return m_ssl_socket->next_layer();
|
||||
}
|
||||
|
||||
private:
|
||||
@ -550,7 +601,7 @@ namespace net_utils
|
||||
// connect(), read_line() or write_line() functions to return.
|
||||
LOG_PRINT_L3("Timed out socket");
|
||||
m_connected = false;
|
||||
m_ssl_socket.next_layer().close();
|
||||
m_ssl_socket->next_layer().close();
|
||||
|
||||
// There is no longer an active deadline. The expiry is set to positive
|
||||
// infinity so that the actor takes no action until a new deadline is set.
|
||||
@ -565,7 +616,7 @@ namespace net_utils
|
||||
// ssl socket shutdown blocks if server doesn't respond. We close after 2 secs
|
||||
boost::system::error_code ec = boost::asio::error::would_block;
|
||||
m_deadline.expires_from_now(std::chrono::milliseconds(2000));
|
||||
m_ssl_socket.async_shutdown(boost::lambda::var(ec) = boost::lambda::_1);
|
||||
m_ssl_socket->async_shutdown(boost::lambda::var(ec) = boost::lambda::_1);
|
||||
while (ec == boost::asio::error::would_block)
|
||||
{
|
||||
m_io_service.run_one();
|
||||
@ -586,35 +637,39 @@ namespace net_utils
|
||||
bool write(const void* data, size_t sz, boost::system::error_code& ec)
|
||||
{
|
||||
bool success;
|
||||
if(m_ssl)
|
||||
success = boost::asio::write(m_ssl_socket, boost::asio::buffer(data, sz), ec);
|
||||
if(m_ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_enabled)
|
||||
success = boost::asio::write(*m_ssl_socket, boost::asio::buffer(data, sz), ec);
|
||||
else
|
||||
success = boost::asio::write(m_ssl_socket.next_layer(), boost::asio::buffer(data, sz), ec);
|
||||
success = boost::asio::write(m_ssl_socket->next_layer(), boost::asio::buffer(data, sz), ec);
|
||||
return success;
|
||||
}
|
||||
|
||||
void async_write(const void* data, size_t sz, boost::system::error_code& ec)
|
||||
{
|
||||
if(m_ssl)
|
||||
boost::asio::async_write(m_ssl_socket, boost::asio::buffer(data, sz), boost::lambda::var(ec) = boost::lambda::_1);
|
||||
if(m_ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_enabled)
|
||||
boost::asio::async_write(*m_ssl_socket, boost::asio::buffer(data, sz), boost::lambda::var(ec) = boost::lambda::_1);
|
||||
else
|
||||
boost::asio::async_write(m_ssl_socket.next_layer(), boost::asio::buffer(data, sz), boost::lambda::var(ec) = boost::lambda::_1);
|
||||
boost::asio::async_write(m_ssl_socket->next_layer(), boost::asio::buffer(data, sz), boost::lambda::var(ec) = boost::lambda::_1);
|
||||
}
|
||||
|
||||
void async_read(char* buff, size_t sz, boost::asio::detail::transfer_at_least_t transfer_at_least, handler_obj& hndlr)
|
||||
{
|
||||
if(!m_ssl)
|
||||
boost::asio::async_read(m_ssl_socket.next_layer(), boost::asio::buffer(buff, sz), transfer_at_least, hndlr);
|
||||
if(m_ssl_support != epee::net_utils::ssl_support_t::e_ssl_support_enabled)
|
||||
boost::asio::async_read(m_ssl_socket->next_layer(), boost::asio::buffer(buff, sz), transfer_at_least, hndlr);
|
||||
else
|
||||
boost::asio::async_read(m_ssl_socket, boost::asio::buffer(buff, sz), transfer_at_least, hndlr);
|
||||
boost::asio::async_read(*m_ssl_socket, boost::asio::buffer(buff, sz), transfer_at_least, hndlr);
|
||||
|
||||
}
|
||||
|
||||
protected:
|
||||
boost::asio::io_service m_io_service;
|
||||
boost::asio::ssl::context m_ctx;
|
||||
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> m_ssl_socket;
|
||||
bool m_ssl;
|
||||
epee::net_utils::ssl_context_t m_ctx;
|
||||
std::shared_ptr<boost::asio::ssl::stream<boost::asio::ip::tcp::socket>> m_ssl_socket;
|
||||
epee::net_utils::ssl_support_t m_ssl_support;
|
||||
std::string m_ssl_private_key;
|
||||
std::string m_ssl_certificate;
|
||||
std::list<std::string> m_ssl_allowed_certificates;
|
||||
bool m_ssl_allow_any_cerl;
|
||||
bool m_initialized;
|
||||
bool m_connected;
|
||||
boost::asio::steady_timer m_deadline;
|
||||
@ -722,7 +777,7 @@ namespace net_utils
|
||||
// asynchronous operations are cancelled. This allows the blocked
|
||||
// connect(), read_line() or write_line() functions to return.
|
||||
LOG_PRINT_L3("Timed out socket");
|
||||
m_ssl_socket.next_layer().close();
|
||||
m_ssl_socket->next_layer().close();
|
||||
|
||||
// There is no longer an active deadline. The expiry is set to positive
|
||||
// infinity so that the actor takes no action until a new deadline is set.
|
||||
|
68
contrib/epee/include/net/net_ssl.h
Normal file
68
contrib/epee/include/net/net_ssl.h
Normal file
@ -0,0 +1,68 @@
|
||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
|
||||
|
||||
#ifndef _NET_SSL_H
|
||||
#define _NET_SSL_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <boost/asio/ssl.hpp>
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace net_utils
|
||||
{
|
||||
enum class ssl_support_t: uint8_t {
|
||||
e_ssl_support_disabled,
|
||||
e_ssl_support_enabled,
|
||||
e_ssl_support_autodetect,
|
||||
};
|
||||
|
||||
struct ssl_context_t
|
||||
{
|
||||
boost::asio::ssl::context context;
|
||||
std::list<std::string> allowed_certificates;
|
||||
bool allow_any_cert;
|
||||
};
|
||||
|
||||
// https://security.stackexchange.com/questions/34780/checking-client-hello-for-https-classification
|
||||
constexpr size_t get_ssl_magic_size() { return 9; }
|
||||
bool is_ssl(const unsigned char *data, size_t len);
|
||||
ssl_context_t create_ssl_context(const std::pair<std::string, std::string> &private_key_and_certificate_path, std::list<std::string> allowed_certificates, bool allow_any_cert);
|
||||
void use_ssl_certificate(ssl_context_t &ssl_context, const std::pair<std::string, std::string> &private_key_and_certificate_path);
|
||||
bool create_ssl_certificate(std::string &pkey_buffer, std::string &cert_buffer);
|
||||
bool is_certificate_allowed(boost::asio::ssl::verify_context &ctx, const std::list<std::string> &allowed_certificates);
|
||||
bool ssl_handshake(boost::asio::ssl::stream<boost::asio::ip::tcp::socket> &socket, boost::asio::ssl::stream_base::handshake_type type, const epee::net_utils::ssl_context_t &ssl_context);
|
||||
bool ssl_support_from_string(ssl_support_t &ssl, boost::string_ref s);
|
||||
}
|
||||
}
|
||||
|
||||
#endif //_NET_SSL_H
|
@ -241,6 +241,7 @@ namespace net_utils
|
||||
const network_address m_remote_address;
|
||||
const bool m_is_income;
|
||||
const time_t m_started;
|
||||
const time_t m_ssl;
|
||||
time_t m_last_recv;
|
||||
time_t m_last_send;
|
||||
uint64_t m_recv_cnt;
|
||||
@ -251,13 +252,14 @@ namespace net_utils
|
||||
double m_max_speed_up;
|
||||
|
||||
connection_context_base(boost::uuids::uuid connection_id,
|
||||
const network_address &remote_address, bool is_income,
|
||||
const network_address &remote_address, bool is_income, bool ssl,
|
||||
time_t last_recv = 0, time_t last_send = 0,
|
||||
uint64_t recv_cnt = 0, uint64_t send_cnt = 0):
|
||||
m_connection_id(connection_id),
|
||||
m_remote_address(remote_address),
|
||||
m_is_income(is_income),
|
||||
m_started(time(NULL)),
|
||||
m_ssl(ssl),
|
||||
m_last_recv(last_recv),
|
||||
m_last_send(last_send),
|
||||
m_recv_cnt(recv_cnt),
|
||||
@ -272,6 +274,7 @@ namespace net_utils
|
||||
m_remote_address(),
|
||||
m_is_income(false),
|
||||
m_started(time(NULL)),
|
||||
m_ssl(false),
|
||||
m_last_recv(0),
|
||||
m_last_send(0),
|
||||
m_recv_cnt(0),
|
||||
@ -284,17 +287,17 @@ namespace net_utils
|
||||
|
||||
connection_context_base& operator=(const connection_context_base& a)
|
||||
{
|
||||
set_details(a.m_connection_id, a.m_remote_address, a.m_is_income);
|
||||
set_details(a.m_connection_id, a.m_remote_address, a.m_is_income, a.m_ssl);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
template<class t_protocol_handler>
|
||||
friend class connection;
|
||||
void set_details(boost::uuids::uuid connection_id, const network_address &remote_address, bool is_income)
|
||||
void set_details(boost::uuids::uuid connection_id, const network_address &remote_address, bool is_income, bool ssl)
|
||||
{
|
||||
this->~connection_context_base();
|
||||
new(this) connection_context_base(connection_id, remote_address, is_income);
|
||||
new(this) connection_context_base(connection_id, remote_address, is_income, ssl);
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -27,7 +27,7 @@
|
||||
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
add_library(epee STATIC hex.cpp http_auth.cpp mlog.cpp net_utils_base.cpp string_tools.cpp wipeable_string.cpp memwipe.c
|
||||
connection_basic.cpp network_throttle.cpp network_throttle-detail.cpp mlocker.cpp buffer.cpp)
|
||||
connection_basic.cpp network_throttle.cpp network_throttle-detail.cpp mlocker.cpp buffer.cpp net_ssl.cpp)
|
||||
if (USE_READLINE AND GNU_READLINE_FOUND)
|
||||
add_library(epee_readline STATIC readline_buffer.cpp)
|
||||
endif()
|
||||
|
@ -48,7 +48,7 @@
|
||||
#include "net/network_throttle-detail.hpp"
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "net.p2p"
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "net.conn"
|
||||
|
||||
// ################################################################################################
|
||||
// local (TU local) headers
|
||||
@ -113,14 +113,41 @@ connection_basic_pimpl::connection_basic_pimpl(const std::string &name) : m_thro
|
||||
int connection_basic_pimpl::m_default_tos;
|
||||
|
||||
// methods:
|
||||
connection_basic::connection_basic(boost::asio::ip::tcp::socket&& socket, boost::shared_ptr<socket_stats> stats)
|
||||
connection_basic::connection_basic(boost::asio::ip::tcp::socket&& sock, boost::shared_ptr<socket_stats> stats, ssl_support_t ssl_support, ssl_context_t &ssl_context)
|
||||
:
|
||||
m_stats(std::move(stats)),
|
||||
mI( new connection_basic_pimpl("peer") ),
|
||||
strand_(socket.get_io_service()),
|
||||
socket_(std::move(socket)),
|
||||
strand_(sock.get_io_service()),
|
||||
socket_(sock.get_io_service(), ssl_context.context),
|
||||
m_want_close_connection(false),
|
||||
m_was_shutdown(false),
|
||||
m_ssl_support(ssl_support),
|
||||
m_ssl_context(ssl_context)
|
||||
{
|
||||
// add nullptr checks if removed
|
||||
CHECK_AND_ASSERT_THROW_MES(bool(m_stats), "stats shared_ptr cannot be null");
|
||||
|
||||
socket_.next_layer() = std::move(sock);
|
||||
|
||||
++(m_stats->sock_count); // increase the global counter
|
||||
mI->m_peer_number = m_stats->sock_number.fetch_add(1); // use, and increase the generated number
|
||||
|
||||
std::string remote_addr_str = "?";
|
||||
try { boost::system::error_code e; remote_addr_str = socket().remote_endpoint(e).address().to_string(); } catch(...){} ;
|
||||
|
||||
_note("Spawned connection #"<<mI->m_peer_number<<" to " << remote_addr_str << " currently we have sockets count:" << m_stats->sock_count);
|
||||
}
|
||||
|
||||
connection_basic::connection_basic(boost::asio::io_service &io_service, boost::shared_ptr<socket_stats> stats, ssl_support_t ssl_support, ssl_context_t &ssl_context)
|
||||
:
|
||||
m_stats(std::move(stats)),
|
||||
mI( new connection_basic_pimpl("peer") ),
|
||||
strand_(io_service),
|
||||
socket_(io_service, ssl_context.context),
|
||||
m_want_close_connection(false),
|
||||
m_was_shutdown(false)
|
||||
m_was_shutdown(false),
|
||||
m_ssl_support(ssl_support),
|
||||
m_ssl_context(ssl_context)
|
||||
{
|
||||
// add nullptr checks if removed
|
||||
CHECK_AND_ASSERT_THROW_MES(bool(m_stats), "stats shared_ptr cannot be null");
|
||||
@ -129,17 +156,18 @@ connection_basic::connection_basic(boost::asio::ip::tcp::socket&& socket, boost:
|
||||
mI->m_peer_number = m_stats->sock_number.fetch_add(1); // use, and increase the generated number
|
||||
|
||||
std::string remote_addr_str = "?";
|
||||
try { boost::system::error_code e; remote_addr_str = socket_.remote_endpoint(e).address().to_string(); } catch(...){} ;
|
||||
try { boost::system::error_code e; remote_addr_str = socket().remote_endpoint(e).address().to_string(); } catch(...){} ;
|
||||
|
||||
_note("Spawned connection p2p#"<<mI->m_peer_number<<" to " << remote_addr_str << " currently we have sockets count:" << m_stats->sock_count);
|
||||
_note("Spawned connection #"<<mI->m_peer_number<<" to " << remote_addr_str << " currently we have sockets count:" << m_stats->sock_count);
|
||||
}
|
||||
|
||||
connection_basic::~connection_basic() noexcept(false) {
|
||||
--(m_stats->sock_count);
|
||||
|
||||
std::string remote_addr_str = "?";
|
||||
try { boost::system::error_code e; remote_addr_str = socket_.remote_endpoint(e).address().to_string(); } catch(...){} ;
|
||||
_note("Destructing connection p2p#"<<mI->m_peer_number << " to " << remote_addr_str);
|
||||
try { boost::system::error_code e; remote_addr_str = socket().remote_endpoint(e).address().to_string(); } catch(...){} ;
|
||||
_note("Destructing connection #"<<mI->m_peer_number << " to " << remote_addr_str);
|
||||
try { throw 0; } catch(...){}
|
||||
}
|
||||
|
||||
void connection_basic::set_rate_up_limit(uint64_t limit) {
|
||||
|
319
contrib/epee/src/net_ssl.cpp
Normal file
319
contrib/epee/src/net_ssl.cpp
Normal file
@ -0,0 +1,319 @@
|
||||
// Copyright (c) 2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <string.h>
|
||||
#include <boost/asio/ssl.hpp>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/pem.h>
|
||||
#include "misc_log_ex.h"
|
||||
#include "net/net_ssl.h"
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "net.ssl"
|
||||
|
||||
// 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
|
||||
|
||||
namespace
|
||||
{
|
||||
struct openssl_bio_free
|
||||
{
|
||||
void operator()(BIO* ptr) const noexcept
|
||||
{
|
||||
if (ptr)
|
||||
BIO_free(ptr);
|
||||
}
|
||||
};
|
||||
using openssl_bio = std::unique_ptr<BIO, openssl_bio_free>;
|
||||
|
||||
struct openssl_pkey_free
|
||||
{
|
||||
void operator()(EVP_PKEY* ptr) const noexcept
|
||||
{
|
||||
if (ptr)
|
||||
EVP_PKEY_free(ptr);
|
||||
}
|
||||
};
|
||||
using openssl_pkey = std::unique_ptr<EVP_PKEY, openssl_pkey_free>;
|
||||
|
||||
}
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace net_utils
|
||||
{
|
||||
|
||||
// https://stackoverflow.com/questions/256405/programmatically-create-x509-certificate-using-openssl
|
||||
bool create_ssl_certificate(EVP_PKEY *&pkey, X509 *&cert)
|
||||
{
|
||||
MGINFO("Generating SSL certificate");
|
||||
pkey = EVP_PKEY_new();
|
||||
openssl_pkey pkey_deleter{pkey};
|
||||
if (!pkey)
|
||||
{
|
||||
MERROR("Failed to create new private key");
|
||||
return false;
|
||||
}
|
||||
RSA *rsa = RSA_generate_key(4096, RSA_F4, NULL, NULL);
|
||||
if (!rsa)
|
||||
{
|
||||
MERROR("Error generating RSA private key");
|
||||
return false;
|
||||
}
|
||||
if (EVP_PKEY_assign_RSA(pkey, rsa) <= 0)
|
||||
{
|
||||
RSA_free(rsa);
|
||||
MERROR("Error assigning RSA private key");
|
||||
return false;
|
||||
}
|
||||
|
||||
cert = X509_new();
|
||||
if (!cert)
|
||||
{
|
||||
MERROR("Failed to create new X509 certificate");
|
||||
return false;
|
||||
}
|
||||
ASN1_INTEGER_set(X509_get_serialNumber(cert), 1);
|
||||
X509_gmtime_adj(X509_get_notBefore(cert), 0);
|
||||
X509_gmtime_adj(X509_get_notAfter(cert), 3600 * 24 * 182); // half a year
|
||||
if (!X509_set_pubkey(cert, pkey))
|
||||
{
|
||||
MERROR("Error setting pubkey on certificate");
|
||||
X509_free(cert);
|
||||
return false;
|
||||
}
|
||||
X509_NAME *name = X509_get_subject_name(cert);
|
||||
X509_set_issuer_name(cert, name);
|
||||
|
||||
if (X509_sign(cert, pkey, EVP_sha256()) == 0)
|
||||
{
|
||||
MERROR("Error signing certificate");
|
||||
X509_free(cert);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool create_ssl_certificate(std::string &pkey_buffer, std::string &cert_buffer)
|
||||
{
|
||||
EVP_PKEY *pkey;
|
||||
X509 *cert;
|
||||
if (!create_ssl_certificate(pkey, cert))
|
||||
return false;
|
||||
BIO *bio_pkey = BIO_new(BIO_s_mem()), *bio_cert = BIO_new(BIO_s_mem());
|
||||
openssl_bio bio_pkey_deleter{bio_pkey};
|
||||
bool success = PEM_write_bio_PrivateKey(bio_pkey, pkey, NULL, NULL, 0, NULL, NULL) && PEM_write_bio_X509(bio_cert, cert);
|
||||
X509_free(cert);
|
||||
if (!success)
|
||||
{
|
||||
MERROR("Failed to write cert and/or pkey: " << ERR_get_error());
|
||||
return false;
|
||||
}
|
||||
BUF_MEM *buf = NULL;
|
||||
BIO_get_mem_ptr(bio_pkey, &buf);
|
||||
if (!buf || !buf->data || !buf->length)
|
||||
{
|
||||
MERROR("Failed to write pkey: " << ERR_get_error());
|
||||
return false;
|
||||
}
|
||||
pkey_buffer = std::string(buf->data, buf->length);
|
||||
buf = NULL;
|
||||
BIO_get_mem_ptr(bio_cert, &buf);
|
||||
if (!buf || !buf->data || !buf->length)
|
||||
{
|
||||
MERROR("Failed to write cert: " << ERR_get_error());
|
||||
return false;
|
||||
}
|
||||
cert_buffer = std::string(buf->data, buf->length);
|
||||
return success;
|
||||
}
|
||||
|
||||
ssl_context_t create_ssl_context(const std::pair<std::string, std::string> &private_key_and_certificate_path, std::list<std::string> allowed_certificates, bool allow_any_cert)
|
||||
{
|
||||
ssl_context_t ssl_context({boost::asio::ssl::context(boost::asio::ssl::context::sslv23), std::move(allowed_certificates)});
|
||||
|
||||
// disable sslv2
|
||||
ssl_context.context.set_options(boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::no_sslv2);
|
||||
ssl_context.context.set_default_verify_paths();
|
||||
|
||||
// set options on the SSL context for added security
|
||||
SSL_CTX *ctx = ssl_context.context.native_handle();
|
||||
CHECK_AND_ASSERT_THROW_MES(ctx, "Failed to get SSL context");
|
||||
SSL_CTX_clear_options(ctx, SSL_OP_LEGACY_SERVER_CONNECT); // SSL_CTX_SET_OPTIONS(3)
|
||||
SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF); // https://stackoverflow.com/questions/22378442
|
||||
#ifdef SSL_OP_NO_TICKET
|
||||
SSL_CTX_set_options(ctx, SSL_OP_NO_TICKET); // https://stackoverflow.com/questions/22378442
|
||||
#endif
|
||||
#ifdef SSL_OP_NO_RENEGOTIATION
|
||||
SSL_CTX_set_options(ctx, SSL_OP_NO_RENEGOTIATION);
|
||||
#endif
|
||||
#ifdef SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
|
||||
SSL_CTX_set_options(ctx, SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
|
||||
#endif
|
||||
#ifdef SSL_OP_NO_COMPRESSION
|
||||
SSL_CTX_set_options(ctx, SSL_OP_NO_COMPRESSION);
|
||||
#endif
|
||||
SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1); // https://github.com/ssllabs/research/wiki/SSL-and-TLS-Deployment-Best-Practices
|
||||
|
||||
CHECK_AND_ASSERT_THROW_MES(private_key_and_certificate_path.first.empty() == private_key_and_certificate_path.second.empty(), "private key and certificate must be either both given or both empty");
|
||||
if (private_key_and_certificate_path.second.empty())
|
||||
{
|
||||
std::string pkey, cert;
|
||||
CHECK_AND_ASSERT_THROW_MES(create_ssl_certificate(pkey, cert), "Failed to create certificate");
|
||||
ssl_context.context.use_private_key(boost::asio::buffer(pkey), boost::asio::ssl::context::pem);
|
||||
ssl_context.context.use_certificate(boost::asio::buffer(cert), boost::asio::ssl::context::pem);
|
||||
}
|
||||
else
|
||||
{
|
||||
ssl_context.context.use_private_key_file(private_key_and_certificate_path.first, boost::asio::ssl::context::pem);
|
||||
ssl_context.context.use_certificate_file(private_key_and_certificate_path.second, boost::asio::ssl::context::pem);
|
||||
}
|
||||
ssl_context.allow_any_cert = allow_any_cert;
|
||||
|
||||
return ssl_context;
|
||||
}
|
||||
|
||||
void use_ssl_certificate(ssl_context_t &ssl_context, const std::pair<std::string, std::string> &private_key_and_certificate_path)
|
||||
{
|
||||
ssl_context.context.use_private_key_file(private_key_and_certificate_path.first, boost::asio::ssl::context::pem);
|
||||
ssl_context.context.use_certificate_file(private_key_and_certificate_path.second, boost::asio::ssl::context::pem);
|
||||
}
|
||||
|
||||
bool is_ssl(const unsigned char *data, size_t len)
|
||||
{
|
||||
if (len < get_ssl_magic_size())
|
||||
return false;
|
||||
|
||||
// https://security.stackexchange.com/questions/34780/checking-client-hello-for-https-classification
|
||||
MDEBUG("SSL detection buffer, " << len << " bytes: "
|
||||
<< (unsigned)(unsigned char)data[0] << " " << (unsigned)(unsigned char)data[1] << " "
|
||||
<< (unsigned)(unsigned char)data[2] << " " << (unsigned)(unsigned char)data[3] << " "
|
||||
<< (unsigned)(unsigned char)data[4] << " " << (unsigned)(unsigned char)data[5] << " "
|
||||
<< (unsigned)(unsigned char)data[6] << " " << (unsigned)(unsigned char)data[7] << " "
|
||||
<< (unsigned)(unsigned char)data[8]);
|
||||
if (data[0] == 0x16) // record
|
||||
if (data[1] == 3) // major version
|
||||
if (data[5] == 1) // ClientHello
|
||||
if (data[6] == 0 && data[3]*256 + data[4] == data[7]*256 + data[8] + 4) // length check
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool is_certificate_allowed(boost::asio::ssl::verify_context &ctx, const std::list<std::string> &allowed_certificates)
|
||||
{
|
||||
X509_STORE_CTX *sctx = ctx.native_handle();
|
||||
if (!sctx)
|
||||
{
|
||||
MERROR("Error getting verify_context handle");
|
||||
return false;
|
||||
}
|
||||
X509 *cert =X509_STORE_CTX_get_current_cert(sctx);
|
||||
if (!cert)
|
||||
{
|
||||
MERROR("No certificate found in verify_context");
|
||||
return false;
|
||||
}
|
||||
|
||||
BIO *bio_cert = BIO_new(BIO_s_mem());
|
||||
openssl_bio bio_cert_deleter{bio_cert};
|
||||
bool success = PEM_write_bio_X509(bio_cert, cert);
|
||||
if (!success)
|
||||
{
|
||||
MERROR("Failed to print certificate");
|
||||
return false;
|
||||
}
|
||||
BUF_MEM *buf = NULL;
|
||||
BIO_get_mem_ptr(bio_cert, &buf);
|
||||
if (!buf || !buf->data || !buf->length)
|
||||
{
|
||||
MERROR("Failed to write certificate: " << ERR_get_error());
|
||||
return false;
|
||||
}
|
||||
std::string certificate(std::string(buf->data, buf->length));
|
||||
return std::find(allowed_certificates.begin(), allowed_certificates.end(), certificate) != allowed_certificates.end();
|
||||
}
|
||||
|
||||
bool ssl_handshake(boost::asio::ssl::stream<boost::asio::ip::tcp::socket> &socket, boost::asio::ssl::stream_base::handshake_type type, const epee::net_utils::ssl_context_t &ssl_context)
|
||||
{
|
||||
bool verified = false;
|
||||
socket.next_layer().set_option(boost::asio::ip::tcp::no_delay(true));
|
||||
socket.set_verify_mode(boost::asio::ssl::verify_peer);
|
||||
socket.set_verify_callback([&](bool preverified, boost::asio::ssl::verify_context &ctx)
|
||||
{
|
||||
if (!preverified)
|
||||
{
|
||||
const int err = X509_STORE_CTX_get_error(ctx.native_handle());
|
||||
const int depth = X509_STORE_CTX_get_error_depth(ctx.native_handle());
|
||||
if (err != X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT || depth != 0)
|
||||
{
|
||||
MERROR("Invalid SSL certificate, error " << err << " at depth " << depth << ", connection dropped");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!ssl_context.allow_any_cert && !ssl_context.allowed_certificates.empty() && !is_certificate_allowed(ctx, ssl_context.allowed_certificates))
|
||||
{
|
||||
MERROR("Certificate is not in the allowed list, connection droppped");
|
||||
return false;
|
||||
}
|
||||
verified = true;
|
||||
return true;
|
||||
});
|
||||
|
||||
boost::system::error_code ec;
|
||||
socket.handshake(type, ec);
|
||||
if (ec)
|
||||
{
|
||||
MERROR("handshake failed, connection dropped");
|
||||
return false;
|
||||
}
|
||||
if (!ssl_context.allow_any_cert && !verified)
|
||||
{
|
||||
MERROR("Peer did not provide a certificate in the allowed list, connection dropped");
|
||||
return false;
|
||||
}
|
||||
MDEBUG("SSL handshake success");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ssl_support_from_string(ssl_support_t &ssl, boost::string_ref s)
|
||||
{
|
||||
if (s == "enabled")
|
||||
ssl = epee::net_utils::ssl_support_t::e_ssl_support_enabled;
|
||||
else if (s == "disabled")
|
||||
ssl = epee::net_utils::ssl_support_t::e_ssl_support_disabled;
|
||||
else if (s == "autodetect")
|
||||
ssl = epee::net_utils::ssl_support_t::e_ssl_support_autodetect;
|
||||
else
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
@ -179,8 +179,8 @@ namespace tools
|
||||
|
||||
lock.unlock();
|
||||
|
||||
bool ssl = u_c.schema == "https";
|
||||
uint16_t port = u_c.port ? u_c.port : ssl ? 443 : 80;
|
||||
epee::net_utils::ssl_support_t ssl = u_c.schema == "https" ? epee::net_utils::ssl_support_t::e_ssl_support_enabled : epee::net_utils::ssl_support_t::e_ssl_support_disabled;
|
||||
uint16_t port = u_c.port ? u_c.port : ssl == epee::net_utils::ssl_support_t::e_ssl_support_enabled ? 443 : 80;
|
||||
MDEBUG("Connecting to " << u_c.host << ":" << port);
|
||||
client.set_server(u_c.host, std::to_string(port), boost::none, ssl);
|
||||
if (!client.connect(std::chrono::seconds(30)))
|
||||
|
@ -48,6 +48,7 @@ namespace cryptonote
|
||||
bool incoming;
|
||||
bool localhost;
|
||||
bool local_ip;
|
||||
bool ssl;
|
||||
|
||||
std::string address;
|
||||
std::string host;
|
||||
|
@ -268,6 +268,7 @@ namespace cryptonote
|
||||
cnx.current_upload = cntxt.m_current_speed_up / 1024;
|
||||
|
||||
cnx.connection_id = epee::string_tools::pod_to_hex(cntxt.m_connection_id);
|
||||
cnx.ssl = cntxt.m_ssl;
|
||||
|
||||
cnx.height = cntxt.m_remote_blockchain_height;
|
||||
cnx.pruning_seed = cntxt.m_pruning_seed;
|
||||
|
@ -511,6 +511,7 @@ bool t_rpc_command_executor::print_connections() {
|
||||
}
|
||||
|
||||
tools::msg_writer() << std::setw(30) << std::left << "Remote Host"
|
||||
<< std::setw(6) << "SSL"
|
||||
<< std::setw(20) << "Peer id"
|
||||
<< std::setw(20) << "Support Flags"
|
||||
<< std::setw(30) << "Recv/Sent (inactive,sec)"
|
||||
@ -530,6 +531,7 @@ bool t_rpc_command_executor::print_connections() {
|
||||
tools::msg_writer()
|
||||
//<< std::setw(30) << std::left << in_out
|
||||
<< std::setw(30) << std::left << address
|
||||
<< std::setw(6) << (info.ssl ? "yes" : "no")
|
||||
<< std::setw(20) << epee::string_tools::pad_string(info.peer_id, 16, '0', true)
|
||||
<< std::setw(20) << info.support_flags
|
||||
<< std::setw(30) << std::to_string(info.recv_count) + "(" + std::to_string(info.recv_idle_time) + ")/" + std::to_string(info.send_count) + "(" + std::to_string(info.send_idle_time) + ")"
|
||||
|
@ -162,7 +162,7 @@ namespace trezor {
|
||||
m_session(boost::none),
|
||||
m_device_info(boost::none)
|
||||
{
|
||||
m_http_client.set_server(m_bridge_host, boost::none, false);
|
||||
m_http_client.set_server(m_bridge_host, boost::none, epee::net_utils::ssl_support_t::e_ssl_support_disabled);
|
||||
}
|
||||
|
||||
virtual ~BridgeTransport() = default;
|
||||
|
@ -129,7 +129,7 @@ namespace nodetool
|
||||
typedef epee::net_utils::boosted_tcp_server<epee::levin::async_protocol_handler<p2p_connection_context>> net_server;
|
||||
|
||||
struct network_zone;
|
||||
using connect_func = boost::optional<p2p_connection_context>(network_zone&, epee::net_utils::network_address const&);
|
||||
using connect_func = boost::optional<p2p_connection_context>(network_zone&, epee::net_utils::network_address const&, epee::net_utils::ssl_support_t);
|
||||
|
||||
struct config
|
||||
{
|
||||
@ -437,8 +437,8 @@ namespace nodetool
|
||||
//keep connections to initiate some interactions
|
||||
|
||||
|
||||
static boost::optional<p2p_connection_context> public_connect(network_zone&, epee::net_utils::network_address const&);
|
||||
static boost::optional<p2p_connection_context> socks_connect(network_zone&, epee::net_utils::network_address const&);
|
||||
static boost::optional<p2p_connection_context> public_connect(network_zone&, epee::net_utils::network_address const&, epee::net_utils::ssl_support_t);
|
||||
static boost::optional<p2p_connection_context> socks_connect(network_zone&, epee::net_utils::network_address const&, epee::net_utils::ssl_support_t);
|
||||
|
||||
|
||||
/* A `std::map` provides constant iterators and key/value pointers even with
|
||||
@ -463,6 +463,8 @@ namespace nodetool
|
||||
|
||||
boost::uuids::uuid m_network_id;
|
||||
cryptonote::network_type m_nettype;
|
||||
|
||||
epee::net_utils::ssl_support_t m_ssl_support;
|
||||
};
|
||||
|
||||
const int64_t default_limit_up = P2P_DEFAULT_LIMIT_RATE_UP; // kB/s
|
||||
|
@ -650,6 +650,7 @@ namespace nodetool
|
||||
return res;
|
||||
|
||||
//try to bind
|
||||
m_ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_disabled;
|
||||
for (auto& zone : m_network_zones)
|
||||
{
|
||||
zone.second.m_net_server.get_config_object().set_handler(this);
|
||||
@ -659,7 +660,7 @@ namespace nodetool
|
||||
{
|
||||
zone.second.m_net_server.set_connection_filter(this);
|
||||
MINFO("Binding on " << zone.second.m_bind_ip << ":" << zone.second.m_port);
|
||||
res = zone.second.m_net_server.init_server(zone.second.m_port, zone.second.m_bind_ip);
|
||||
res = zone.second.m_net_server.init_server(zone.second.m_port, zone.second.m_bind_ip, epee::net_utils::ssl_support_t::e_ssl_support_disabled);
|
||||
CHECK_AND_ASSERT_MES(res, false, "Failed to bind server");
|
||||
}
|
||||
}
|
||||
@ -1057,7 +1058,7 @@ namespace nodetool
|
||||
<< (last_seen_stamp ? epee::misc_utils::get_time_interval_string(time(NULL) - last_seen_stamp):"never")
|
||||
<< ")...");
|
||||
|
||||
auto con = zone.m_connect(zone, na);
|
||||
auto con = zone.m_connect(zone, na, m_ssl_support);
|
||||
if(!con)
|
||||
{
|
||||
bool is_priority = is_priority_node(na);
|
||||
@ -1119,7 +1120,7 @@ namespace nodetool
|
||||
<< (last_seen_stamp ? epee::misc_utils::get_time_interval_string(time(NULL) - last_seen_stamp):"never")
|
||||
<< ")...");
|
||||
|
||||
auto con = zone.m_connect(zone, na);
|
||||
auto con = zone.m_connect(zone, na, m_ssl_support);
|
||||
if (!con) {
|
||||
bool is_priority = is_priority_node(na);
|
||||
|
||||
@ -2456,13 +2457,13 @@ namespace nodetool
|
||||
|
||||
template<typename t_payload_net_handler>
|
||||
boost::optional<p2p_connection_context_t<typename t_payload_net_handler::connection_context>>
|
||||
node_server<t_payload_net_handler>::socks_connect(network_zone& zone, const epee::net_utils::network_address& remote)
|
||||
node_server<t_payload_net_handler>::socks_connect(network_zone& zone, const epee::net_utils::network_address& remote, epee::net_utils::ssl_support_t ssl_support)
|
||||
{
|
||||
auto result = socks_connect_internal(zone.m_net_server.get_stop_signal(), zone.m_net_server.get_io_service(), zone.m_proxy_address, remote);
|
||||
if (result) // if no error
|
||||
{
|
||||
p2p_connection_context context{};
|
||||
if (zone.m_net_server.add_connection(context, std::move(*result), remote))
|
||||
if (zone.m_net_server.add_connection(context, std::move(*result), remote, ssl_support))
|
||||
return {std::move(context)};
|
||||
}
|
||||
return boost::none;
|
||||
@ -2470,7 +2471,7 @@ namespace nodetool
|
||||
|
||||
template<typename t_payload_net_handler>
|
||||
boost::optional<p2p_connection_context_t<typename t_payload_net_handler::connection_context>>
|
||||
node_server<t_payload_net_handler>::public_connect(network_zone& zone, epee::net_utils::network_address const& na)
|
||||
node_server<t_payload_net_handler>::public_connect(network_zone& zone, epee::net_utils::network_address const& na, epee::net_utils::ssl_support_t ssl_support)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(na.get_type_id() == epee::net_utils::ipv4_network_address::get_type_id(), boost::none,
|
||||
"Only IPv4 addresses are supported here");
|
||||
@ -2480,7 +2481,7 @@ namespace nodetool
|
||||
const bool res = zone.m_net_server.connect(epee::string_tools::get_ip_string_from_int32(ipv4.ip()),
|
||||
epee::string_tools::num_to_string_fast(ipv4.port()),
|
||||
zone.m_config.m_net_config.connection_timeout,
|
||||
con);
|
||||
con, "0.0.0.0", ssl_support);
|
||||
|
||||
if (res)
|
||||
return {std::move(con)};
|
||||
|
@ -76,6 +76,11 @@ namespace cryptonote
|
||||
command_line::add_arg(desc, arg_rpc_bind_port);
|
||||
command_line::add_arg(desc, arg_rpc_restricted_bind_port);
|
||||
command_line::add_arg(desc, arg_restricted_rpc);
|
||||
command_line::add_arg(desc, arg_rpc_ssl);
|
||||
command_line::add_arg(desc, arg_rpc_ssl_private_key);
|
||||
command_line::add_arg(desc, arg_rpc_ssl_certificate);
|
||||
command_line::add_arg(desc, arg_rpc_ssl_allowed_certificates);
|
||||
command_line::add_arg(desc, arg_rpc_ssl_allow_any_cert);
|
||||
command_line::add_arg(desc, arg_bootstrap_daemon_address);
|
||||
command_line::add_arg(desc, arg_bootstrap_daemon_login);
|
||||
cryptonote::rpc_args::init_options(desc);
|
||||
@ -112,11 +117,11 @@ namespace cryptonote
|
||||
epee::net_utils::http::login login;
|
||||
login.username = bootstrap_daemon_login.substr(0, loc);
|
||||
login.password = bootstrap_daemon_login.substr(loc + 1);
|
||||
m_http_client.set_server(m_bootstrap_daemon_address, login, false);
|
||||
m_http_client.set_server(m_bootstrap_daemon_address, login, epee::net_utils::ssl_support_t::e_ssl_support_autodetect);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_http_client.set_server(m_bootstrap_daemon_address, boost::none, false);
|
||||
m_http_client.set_server(m_bootstrap_daemon_address, boost::none, epee::net_utils::ssl_support_t::e_ssl_support_autodetect);
|
||||
}
|
||||
m_should_use_bootstrap_daemon = true;
|
||||
}
|
||||
@ -131,9 +136,32 @@ namespace cryptonote
|
||||
if (rpc_config->login)
|
||||
http_login.emplace(std::move(rpc_config->login->username), std::move(rpc_config->login->password).password());
|
||||
|
||||
epee::net_utils::ssl_support_t ssl_support;
|
||||
const std::string ssl = command_line::get_arg(vm, arg_rpc_ssl);
|
||||
if (!epee::net_utils::ssl_support_from_string(ssl_support, ssl))
|
||||
{
|
||||
MFATAL("Invalid RPC SSL support: " << ssl);
|
||||
return false;
|
||||
}
|
||||
const std::string ssl_private_key = command_line::get_arg(vm, arg_rpc_ssl_private_key);
|
||||
const std::string ssl_certificate = command_line::get_arg(vm, arg_rpc_ssl_certificate);
|
||||
const std::vector<std::string> ssl_allowed_certificate_paths = command_line::get_arg(vm, arg_rpc_ssl_allowed_certificates);
|
||||
std::list<std::string> ssl_allowed_certificates;
|
||||
for (const std::string &path: ssl_allowed_certificate_paths)
|
||||
{
|
||||
ssl_allowed_certificates.push_back({});
|
||||
if (!epee::file_io_utils::load_file_to_string(path, ssl_allowed_certificates.back()))
|
||||
{
|
||||
MERROR("Failed to load certificate: " << path);
|
||||
ssl_allowed_certificates.back() = std::string();
|
||||
}
|
||||
}
|
||||
const bool ssl_allow_any_cert = command_line::get_arg(vm, arg_rpc_ssl_allow_any_cert);
|
||||
|
||||
auto rng = [](size_t len, uint8_t *ptr){ return crypto::rand(len, ptr); };
|
||||
return epee::http_server_impl_base<core_rpc_server, connection_context>::init(
|
||||
rng, std::move(port), std::move(rpc_config->bind_ip), std::move(rpc_config->access_control_origins), std::move(http_login)
|
||||
rng, std::move(port), std::move(rpc_config->bind_ip), std::move(rpc_config->access_control_origins), std::move(http_login),
|
||||
ssl_support, std::make_pair(ssl_private_key, ssl_certificate), ssl_allowed_certificates, ssl_allow_any_cert
|
||||
);
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
@ -2318,6 +2346,35 @@ namespace cryptonote
|
||||
, false
|
||||
};
|
||||
|
||||
const command_line::arg_descriptor<std::string> core_rpc_server::arg_rpc_ssl = {
|
||||
"rpc-ssl"
|
||||
, "Enable SSL on RPC connections: enabled|disabled|autodetect"
|
||||
, "autodetect"
|
||||
};
|
||||
|
||||
const command_line::arg_descriptor<std::string> core_rpc_server::arg_rpc_ssl_private_key = {
|
||||
"rpc-ssl-private-key"
|
||||
, "Path to a PEM format private key"
|
||||
, ""
|
||||
};
|
||||
|
||||
const command_line::arg_descriptor<std::string> core_rpc_server::arg_rpc_ssl_certificate = {
|
||||
"rpc-ssl-certificate"
|
||||
, "Path to a PEM format certificate"
|
||||
, ""
|
||||
};
|
||||
|
||||
const command_line::arg_descriptor<std::vector<std::string>> core_rpc_server::arg_rpc_ssl_allowed_certificates = {
|
||||
"rpc-ssl-allowed-certificates"
|
||||
, "List of paths to PEM format certificates of allowed peers (all allowed if empty)"
|
||||
};
|
||||
|
||||
const command_line::arg_descriptor<bool> core_rpc_server::arg_rpc_ssl_allow_any_cert = {
|
||||
"rpc-ssl-allow-any-cert"
|
||||
, "Allow any peer certificate, rather than just those on the allowed list"
|
||||
, false
|
||||
};
|
||||
|
||||
const command_line::arg_descriptor<std::string> core_rpc_server::arg_bootstrap_daemon_address = {
|
||||
"bootstrap-daemon-address"
|
||||
, "URL of a 'bootstrap' remote daemon that the connected wallets can use while this daemon is still not fully synced"
|
||||
|
@ -56,6 +56,11 @@ namespace cryptonote
|
||||
static const command_line::arg_descriptor<std::string, false, true, 2> arg_rpc_bind_port;
|
||||
static const command_line::arg_descriptor<std::string> arg_rpc_restricted_bind_port;
|
||||
static const command_line::arg_descriptor<bool> arg_restricted_rpc;
|
||||
static const command_line::arg_descriptor<std::string> arg_rpc_ssl;
|
||||
static const command_line::arg_descriptor<std::string> arg_rpc_ssl_private_key;
|
||||
static const command_line::arg_descriptor<std::string> arg_rpc_ssl_certificate;
|
||||
static const command_line::arg_descriptor<std::vector<std::string>> arg_rpc_ssl_allowed_certificates;
|
||||
static const command_line::arg_descriptor<bool> arg_rpc_ssl_allow_any_cert;
|
||||
static const command_line::arg_descriptor<std::string> arg_bootstrap_daemon_address;
|
||||
static const command_line::arg_descriptor<std::string> arg_bootstrap_daemon_login;
|
||||
|
||||
|
@ -8402,7 +8402,8 @@ bool simple_wallet::status(const std::vector<std::string> &args)
|
||||
{
|
||||
uint64_t local_height = m_wallet->get_blockchain_current_height();
|
||||
uint32_t version = 0;
|
||||
if (!m_wallet->check_connection(&version))
|
||||
bool ssl = false;
|
||||
if (!m_wallet->check_connection(&version, &ssl))
|
||||
{
|
||||
success_msg_writer() << "Refreshed " << local_height << "/?, no daemon connected";
|
||||
return true;
|
||||
@ -8414,7 +8415,7 @@ bool simple_wallet::status(const std::vector<std::string> &args)
|
||||
{
|
||||
bool synced = local_height == bc_height;
|
||||
success_msg_writer() << "Refreshed " << local_height << "/" << bc_height << ", " << (synced ? "synced" : "syncing")
|
||||
<< ", daemon RPC v" << get_version_string(version);
|
||||
<< ", daemon RPC v" << get_version_string(version) << ", " << (ssl ? "SSL" : "no SSL");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1924,7 +1924,7 @@ bool WalletImpl::verifyMessageWithPublicKey(const std::string &message, const st
|
||||
|
||||
bool WalletImpl::connectToDaemon()
|
||||
{
|
||||
bool result = m_wallet->check_connection(NULL, DEFAULT_CONNECTION_TIMEOUT_MILLIS);
|
||||
bool result = m_wallet->check_connection(NULL, NULL, DEFAULT_CONNECTION_TIMEOUT_MILLIS);
|
||||
if (!result) {
|
||||
setStatusError("Error connecting to daemon at " + m_wallet->get_daemon_address());
|
||||
} else {
|
||||
@ -1937,7 +1937,7 @@ bool WalletImpl::connectToDaemon()
|
||||
Wallet::ConnectionStatus WalletImpl::connected() const
|
||||
{
|
||||
uint32_t version = 0;
|
||||
m_is_connected = m_wallet->check_connection(&version, DEFAULT_CONNECTION_TIMEOUT_MILLIS);
|
||||
m_is_connected = m_wallet->check_connection(&version, NULL, DEFAULT_CONNECTION_TIMEOUT_MILLIS);
|
||||
if (!m_is_connected)
|
||||
return Wallet::ConnectionStatus_Disconnected;
|
||||
// Version check is not implemented in light wallets nodes/wallets
|
||||
|
@ -237,6 +237,11 @@ struct options {
|
||||
const command_line::arg_descriptor<std::string> password_file = {"password-file", tools::wallet2::tr("Wallet password file"), "", true};
|
||||
const command_line::arg_descriptor<int> daemon_port = {"daemon-port", tools::wallet2::tr("Use daemon instance at port <arg> instead of 18081"), 0};
|
||||
const command_line::arg_descriptor<std::string> daemon_login = {"daemon-login", tools::wallet2::tr("Specify username[:password] for daemon RPC client"), "", true};
|
||||
const command_line::arg_descriptor<std::string> daemon_ssl = {"daemon-ssl", tools::wallet2::tr("Enable SSL on daemon RPC connections: enabled|disabled|autodetect"), "autodetect"};
|
||||
const command_line::arg_descriptor<std::string> daemon_ssl_private_key = {"daemon-ssl-private-key", tools::wallet2::tr("Path to a PEM format private key"), ""};
|
||||
const command_line::arg_descriptor<std::string> daemon_ssl_certificate = {"daemon-ssl-certificate", tools::wallet2::tr("Path to a PEM format certificate"), ""};
|
||||
const command_line::arg_descriptor<std::vector<std::string>> daemon_ssl_allowed_certificates = {"daemon-ssl-allowed-certificates", tools::wallet2::tr("List of paths to PEM format certificates of allowed RPC servers")};
|
||||
const command_line::arg_descriptor<bool> daemon_ssl_allow_any_cert = {"daemon-ssl-allow-any-cert", tools::wallet2::tr("Allow any SSL certificate from the daemon"), false};
|
||||
const command_line::arg_descriptor<bool> testnet = {"testnet", tools::wallet2::tr("For testnet. Daemon must also be launched with --testnet flag"), false};
|
||||
const command_line::arg_descriptor<bool> stagenet = {"stagenet", tools::wallet2::tr("For stagenet. Daemon must also be launched with --stagenet flag"), false};
|
||||
const command_line::arg_descriptor<std::string, false, true, 2> shared_ringdb_dir = {
|
||||
@ -308,6 +313,14 @@ std::unique_ptr<tools::wallet2> make_basic(const boost::program_options::variabl
|
||||
auto daemon_port = command_line::get_arg(vm, opts.daemon_port);
|
||||
auto device_name = command_line::get_arg(vm, opts.hw_device);
|
||||
auto device_derivation_path = command_line::get_arg(vm, opts.hw_device_derivation_path);
|
||||
auto daemon_ssl_private_key = command_line::get_arg(vm, opts.daemon_ssl_private_key);
|
||||
auto daemon_ssl_certificate = command_line::get_arg(vm, opts.daemon_ssl_certificate);
|
||||
auto daemon_ssl_allowed_certificates = command_line::get_arg(vm, opts.daemon_ssl_allowed_certificates);
|
||||
auto daemon_ssl_allow_any_cert = command_line::get_arg(vm, opts.daemon_ssl_allow_any_cert);
|
||||
auto daemon_ssl = command_line::get_arg(vm, opts.daemon_ssl);
|
||||
epee::net_utils::ssl_support_t ssl_support;
|
||||
THROW_WALLET_EXCEPTION_IF(!epee::net_utils::ssl_support_from_string(ssl_support, daemon_ssl), tools::error::wallet_internal_error,
|
||||
tools::wallet2::tr("Invalid argument for ") + std::string(opts.daemon_ssl.name));
|
||||
|
||||
THROW_WALLET_EXCEPTION_IF(!daemon_address.empty() && !daemon_host.empty() && 0 != daemon_port,
|
||||
tools::error::wallet_internal_error, tools::wallet2::tr("can't specify daemon host or port more than once"));
|
||||
@ -358,8 +371,20 @@ std::unique_ptr<tools::wallet2> make_basic(const boost::program_options::variabl
|
||||
catch (const std::exception &e) { }
|
||||
}
|
||||
|
||||
std::list<std::string> ssl_allowed_certificates;
|
||||
for (const std::string &path: daemon_ssl_allowed_certificates)
|
||||
{
|
||||
ssl_allowed_certificates.push_back({});
|
||||
if (!epee::file_io_utils::load_file_to_string(path, ssl_allowed_certificates.back()))
|
||||
{
|
||||
MERROR("Failed to load certificate: " << path);
|
||||
ssl_allowed_certificates.back() = std::string();
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<tools::wallet2> wallet(new tools::wallet2(nettype, kdf_rounds, unattended));
|
||||
wallet->init(std::move(daemon_address), std::move(login), 0, false, *trusted_daemon);
|
||||
wallet->init(std::move(daemon_address), std::move(login), 0, *trusted_daemon, ssl_support, std::make_pair(daemon_ssl_private_key, daemon_ssl_certificate), ssl_allowed_certificates, daemon_ssl_allow_any_cert);
|
||||
|
||||
boost::filesystem::path ringdb_path = command_line::get_arg(vm, opts.shared_ringdb_dir);
|
||||
wallet->set_ring_database(ringdb_path.string());
|
||||
wallet->get_message_store().set_options(vm);
|
||||
@ -1015,6 +1040,11 @@ void wallet2::init_options(boost::program_options::options_description& desc_par
|
||||
command_line::add_arg(desc_params, opts.password_file);
|
||||
command_line::add_arg(desc_params, opts.daemon_port);
|
||||
command_line::add_arg(desc_params, opts.daemon_login);
|
||||
command_line::add_arg(desc_params, opts.daemon_ssl);
|
||||
command_line::add_arg(desc_params, opts.daemon_ssl_private_key);
|
||||
command_line::add_arg(desc_params, opts.daemon_ssl_certificate);
|
||||
command_line::add_arg(desc_params, opts.daemon_ssl_allowed_certificates);
|
||||
command_line::add_arg(desc_params, opts.daemon_ssl_allow_any_cert);
|
||||
command_line::add_arg(desc_params, opts.testnet);
|
||||
command_line::add_arg(desc_params, opts.stagenet);
|
||||
command_line::add_arg(desc_params, opts.shared_ringdb_dir);
|
||||
@ -1066,7 +1096,7 @@ std::unique_ptr<wallet2> wallet2::make_dummy(const boost::program_options::varia
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool wallet2::init(std::string daemon_address, boost::optional<epee::net_utils::http::login> daemon_login, uint64_t upper_transaction_weight_limit, bool ssl, bool trusted_daemon)
|
||||
bool wallet2::init(std::string daemon_address, boost::optional<epee::net_utils::http::login> daemon_login, uint64_t upper_transaction_weight_limit, bool trusted_daemon, 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)
|
||||
{
|
||||
m_checkpoints.init_default_checkpoints(m_nettype);
|
||||
if(m_http_client.is_connected())
|
||||
@ -1076,8 +1106,7 @@ bool wallet2::init(std::string daemon_address, boost::optional<epee::net_utils::
|
||||
m_daemon_address = std::move(daemon_address);
|
||||
m_daemon_login = std::move(daemon_login);
|
||||
m_trusted_daemon = trusted_daemon;
|
||||
// When switching from light wallet to full wallet, we need to reset the height we got from lw node.
|
||||
return m_http_client.set_server(get_daemon_address(), get_daemon_login(), ssl);
|
||||
return m_http_client.set_server(get_daemon_address(), get_daemon_login(), ssl_support, private_key_and_certificate_path, allowed_certificates, allow_any_cert);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool wallet2::is_deterministic() const
|
||||
@ -4851,7 +4880,7 @@ bool wallet2::prepare_file_names(const std::string& file_path)
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool wallet2::check_connection(uint32_t *version, uint32_t timeout)
|
||||
bool wallet2::check_connection(uint32_t *version, bool *ssl, uint32_t timeout)
|
||||
{
|
||||
THROW_WALLET_EXCEPTION_IF(!m_is_initialized, error::wallet_not_initialized);
|
||||
|
||||
@ -4859,15 +4888,20 @@ bool wallet2::check_connection(uint32_t *version, uint32_t timeout)
|
||||
|
||||
// TODO: Add light wallet version check.
|
||||
if(m_light_wallet) {
|
||||
version = 0;
|
||||
if (version)
|
||||
*version = 0;
|
||||
if (ssl)
|
||||
*ssl = m_light_wallet_connected; // light wallet is always SSL
|
||||
return m_light_wallet_connected;
|
||||
}
|
||||
|
||||
if(!m_http_client.is_connected())
|
||||
if(!m_http_client.is_connected(ssl))
|
||||
{
|
||||
m_node_rpc_proxy.invalidate();
|
||||
if (!m_http_client.connect(std::chrono::milliseconds(timeout)))
|
||||
return false;
|
||||
if(!m_http_client.is_connected(ssl))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (version)
|
||||
|
@ -676,7 +676,11 @@ namespace tools
|
||||
|
||||
bool deinit();
|
||||
bool init(std::string daemon_address = "http://localhost:8080",
|
||||
boost::optional<epee::net_utils::http::login> daemon_login = boost::none, uint64_t upper_transaction_weight_limit = 0, bool ssl = false, bool trusted_daemon = false);
|
||||
boost::optional<epee::net_utils::http::login> daemon_login = boost::none, uint64_t upper_transaction_weight_limit = 0,
|
||||
bool trusted_daemon = true,
|
||||
epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_autodetect,
|
||||
const std::pair<std::string, std::string> &private_key_and_certificate_path = {},
|
||||
const std::list<std::string> &allowed_certificates = {}, bool allow_any_cert = false);
|
||||
|
||||
void stop() { m_run.store(false, std::memory_order_relaxed); m_message_store.stop(); }
|
||||
|
||||
@ -800,7 +804,7 @@ namespace tools
|
||||
bool sign_multisig_tx_to_file(multisig_tx_set &exported_txs, const std::string &filename, std::vector<crypto::hash> &txids);
|
||||
std::vector<pending_tx> create_unmixable_sweep_transactions();
|
||||
void discard_unmixable_outputs();
|
||||
bool check_connection(uint32_t *version = NULL, uint32_t timeout = 200000);
|
||||
bool check_connection(uint32_t *version = NULL, bool *ssl = NULL, uint32_t timeout = 200000);
|
||||
void get_transfers(wallet2::transfer_container& incoming_transfers) const;
|
||||
void get_payments(const crypto::hash& payment_id, std::list<wallet2::payment_details>& payments, uint64_t min_height = 0, const boost::optional<uint32_t>& subaddr_account = boost::none, const std::set<uint32_t>& subaddr_indices = {}) const;
|
||||
void get_payments(std::list<std::pair<crypto::hash,wallet2::payment_details>>& payments, uint64_t min_height, uint64_t max_height = (uint64_t)-1, const boost::optional<uint32_t>& subaddr_account = boost::none, const std::set<uint32_t>& subaddr_indices = {}) const;
|
||||
|
@ -63,6 +63,10 @@ namespace
|
||||
const command_line::arg_descriptor<bool> arg_restricted = {"restricted-rpc", "Restricts to view-only commands", false};
|
||||
const command_line::arg_descriptor<std::string> arg_wallet_dir = {"wallet-dir", "Directory for newly created wallets"};
|
||||
const command_line::arg_descriptor<bool> arg_prompt_for_password = {"prompt-for-password", "Prompts for password when not provided", false};
|
||||
const command_line::arg_descriptor<std::string> arg_rpc_ssl = {"rpc-ssl", tools::wallet2::tr("Enable SSL on wallet RPC connections: enabled|disabled|autodetect"), "autodetect"};
|
||||
const command_line::arg_descriptor<std::string> arg_rpc_ssl_private_key = {"rpc-ssl-private-key", tools::wallet2::tr("Path to a PEM format private key"), ""};
|
||||
const command_line::arg_descriptor<std::string> arg_rpc_ssl_certificate = {"rpc-ssl-certificate", tools::wallet2::tr("Path to a PEM format certificate"), ""};
|
||||
const command_line::arg_descriptor<std::vector<std::string>> arg_rpc_ssl_allowed_certificates = {"rpc-ssl-allowed-certificates", tools::wallet2::tr("List of paths to PEM format certificates of allowed RPC servers (all allowed if empty)")};
|
||||
|
||||
constexpr const char default_rpc_username[] = "monero";
|
||||
|
||||
@ -233,10 +237,32 @@ namespace tools
|
||||
assert(bool(http_login));
|
||||
} // end auth enabled
|
||||
|
||||
auto rpc_ssl_private_key = command_line::get_arg(vm, arg_rpc_ssl_private_key);
|
||||
auto rpc_ssl_certificate = command_line::get_arg(vm, arg_rpc_ssl_certificate);
|
||||
auto rpc_ssl_allowed_certificates = command_line::get_arg(vm, arg_rpc_ssl_allowed_certificates);
|
||||
auto rpc_ssl = command_line::get_arg(vm, arg_rpc_ssl);
|
||||
epee::net_utils::ssl_support_t rpc_ssl_support;
|
||||
if (!epee::net_utils::ssl_support_from_string(rpc_ssl_support, rpc_ssl))
|
||||
{
|
||||
MERROR("Invalid argument for " << std::string(arg_rpc_ssl.name));
|
||||
return false;
|
||||
}
|
||||
std::list<std::string> allowed_certificates;
|
||||
for (const std::string &path: rpc_ssl_allowed_certificates)
|
||||
{
|
||||
allowed_certificates.push_back({});
|
||||
if (!epee::file_io_utils::load_file_to_string(path, allowed_certificates.back()))
|
||||
{
|
||||
MERROR("Failed to load certificate: " << path);
|
||||
allowed_certificates.back() = std::string();
|
||||
}
|
||||
}
|
||||
|
||||
m_net_server.set_threads_prefix("RPC");
|
||||
auto rng = [](size_t len, uint8_t *ptr) { return crypto::rand(len, ptr); };
|
||||
return epee::http_server_impl_base<wallet_rpc_server, connection_context>::init(
|
||||
rng, std::move(bind_port), std::move(rpc_config->bind_ip), std::move(rpc_config->access_control_origins), std::move(http_login)
|
||||
rng, std::move(bind_port), std::move(rpc_config->bind_ip), std::move(rpc_config->access_control_origins), std::move(http_login),
|
||||
rpc_ssl_support, std::make_pair(rpc_ssl_private_key, rpc_ssl_certificate), allowed_certificates
|
||||
);
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
@ -3933,6 +3959,10 @@ int main(int argc, char** argv) {
|
||||
command_line::add_arg(desc_params, arg_from_json);
|
||||
command_line::add_arg(desc_params, arg_wallet_dir);
|
||||
command_line::add_arg(desc_params, arg_prompt_for_password);
|
||||
command_line::add_arg(desc_params, arg_rpc_ssl);
|
||||
command_line::add_arg(desc_params, arg_rpc_ssl_private_key);
|
||||
command_line::add_arg(desc_params, arg_rpc_ssl_certificate);
|
||||
command_line::add_arg(desc_params, arg_rpc_ssl_allowed_certificates);
|
||||
|
||||
daemonizer::init_options(hidden_options, desc_params);
|
||||
desc_params.add(hidden_options);
|
||||
|
Loading…
Reference in New Issue
Block a user