wownero/contrib/epee/include/net/connection_basic.hpp
moneromooo-monero 2456945408
epee: add SSL support
RPC connections now have optional tranparent SSL.

An optional private key and certificate file can be passed,
using the --{rpc,daemon}-ssl-private-key and
--{rpc,daemon}-ssl-certificate options. Those have as
argument a path to a PEM format private private key and
certificate, respectively.
If not given, a temporary self signed certificate will be used.

SSL can be enabled or disabled using --{rpc}-ssl, which
accepts autodetect (default), disabled or enabled.

Access can be restricted to particular certificates using the
--rpc-ssl-allowed-certificates, which takes a list of
paths to PEM encoded certificates. This can allow a wallet to
connect to only the daemon they think they're connected to,
by forcing SSL and listing the paths to the known good
certificates.

To generate long term certificates:

openssl genrsa -out /tmp/KEY 4096
openssl req -new -key /tmp/KEY -out /tmp/REQ
openssl x509 -req -days 999999 -sha256 -in /tmp/REQ -signkey /tmp/KEY -out /tmp/CERT

/tmp/KEY is the private key, and /tmp/CERT is the certificate,
both in PEM format. /tmp/REQ can be removed. Adjust the last
command to set expiration date, etc, as needed. It doesn't
make a whole lot of sense for monero anyway, since most servers
will run with one time temporary self signed certificates anyway.

SSL support is transparent, so all communication is done on the
existing ports, with SSL autodetection. This means you can start
using an SSL daemon now, but you should not enforce SSL yet or
nothing will talk to you.
2019-02-02 20:05:33 +00:00

183 lines
7.8 KiB
C++

/// @file
/// @author rfree (current maintainer in monero.cc project)
/// @brief base for connection, contains e.g. the ratelimit hooks
// ! This file might contain variable names same as in template class connection<>
// ! from files contrib/epee/include/net/abstract_tcp_server2.*
// ! I am not a lawyer; afaik APIs, var names etc are not copyrightable ;)
// ! (how ever if in some wonderful juristdictions that is not the case, then why not make another sub-class withat that members and licence it as epee part)
// ! Working on above premise, IF this is valid in your juristdictions, then consider this code as released as:
// Copyright (c) 2014-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.
/* rfree: place for hanlers for the non-template base, can be used by connection<> template class in abstract_tcp_server2 file */
#ifndef INCLUDED_p2p_connection_basic_hpp
#define INCLUDED_p2p_connection_basic_hpp
#include <string>
#include <atomic>
#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
{
namespace net_utils
{
struct socket_stats
{
socket_stats()
: sock_count(0), sock_number(0)
{}
std::atomic<long> sock_count;
std::atomic<long> sock_number;
};
/************************************************************************/
/* */
/************************************************************************/
/// Represents a single connection from a client.
class connection_basic_pimpl; // PIMPL for this class
enum t_connection_type { // type of the connection (of this server), e.g. so that we will know how to limit it
e_connection_type_NET = 0, // default (not used?)
e_connection_type_RPC = 1, // the rpc commands (probably not rate limited, not chunked, etc)
e_connection_type_P2P = 2 // to other p2p node (probably limited)
};
std::string to_string(t_connection_type type);
class connection_basic { // not-templated base class for rapid developmet of some code parts
// beware of removing const, net_utils::connection is sketchily doing a cast to prevent storing ptr twice
const boost::shared_ptr<socket_stats> m_stats;
public:
std::unique_ptr< connection_basic_pimpl > mI; // my Implementation
// moved here from orginal connecton<> - common member variables that do not depend on template in connection<>
volatile uint32_t m_want_close_connection;
std::atomic<bool> m_was_shutdown;
critical_section m_send_que_lock;
std::list<std::string> m_send_que;
volatile bool m_is_multithreaded;
/// Strand to ensure the connection's handlers are not called concurrently.
boost::asio::io_service::strand strand_;
/// Socket for the connection.
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, 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);
void do_send_handler_write_from_queue(const boost::system::error_code& e, size_t cb , int q_len); // from handle_write, sending next part
void logger_handle_net_write(size_t size); // network data written
void logger_handle_net_read(size_t size); // network data read
// config for rate limit
static void set_rate_up_limit(uint64_t limit);
static void set_rate_down_limit(uint64_t limit);
static uint64_t get_rate_up_limit();
static uint64_t get_rate_down_limit();
// config misc
static void set_tos_flag(int tos); // ToS / QoS flag
static int get_tos_flag();
// handlers and sleep
void sleep_before_packet(size_t packet_size, int phase, int q_len); // execute a sleep ; phase is not really used now(?)
static void save_limit_to_file(int limit); ///< for dr-monero
static double get_sleep_time(size_t cb);
static void set_save_graph(bool save_graph);
};
} // nameserver
} // nameserver
#endif