diff --git a/nano/core_test/toml.cpp b/nano/core_test/toml.cpp index 35e53d9572..43a950e7d2 100644 --- a/nano/core_test/toml.cpp +++ b/nano/core_test/toml.cpp @@ -1,6 +1,5 @@ #include #include -#include #include #include #include @@ -943,64 +942,6 @@ TEST (toml, daemon_read_config) } } -/** Deserialize an tls config with non-default values */ -TEST (toml, tls_config_deserialize_no_defaults) -{ - std::stringstream ss; - - // A config file with values that differs from devnet defaults - ss << R"toml( - enable_https=true - enable_wss=true - verbose_logging=true - server_cert_path="xyz.cert.pem" - server_key_path="xyz.key.pem" - server_key_passphrase="xyz" - server_dh_path="xyz.pem" - )toml"; - - nano::tomlconfig toml; - toml.read (ss); - nano::tls_config conf; - nano::tls_config defaults; - conf.deserialize_toml (toml); - - ASSERT_FALSE (toml.get_error ()) << toml.get_error ().get_message (); - - ASSERT_NE (conf.enable_https, defaults.enable_https); - ASSERT_NE (conf.enable_wss, defaults.enable_wss); - ASSERT_NE (conf.verbose_logging, defaults.verbose_logging); - ASSERT_NE (conf.server_cert_path, defaults.server_cert_path); - ASSERT_NE (conf.server_key_path, defaults.server_key_path); - ASSERT_NE (conf.server_key_passphrase, defaults.server_key_passphrase); - ASSERT_NE (conf.server_dh_path, defaults.server_dh_path); -} - -/** Empty tls config file should match a default config object, and there should be no required values. */ -TEST (toml, tls_config_defaults) -{ - std::stringstream ss; - - // A config with no values - ss << R"toml()toml"; - - nano::tomlconfig toml; - toml.read (ss); - nano::tls_config conf; - nano::tls_config defaults; - conf.deserialize_toml (toml); - - ASSERT_FALSE (toml.get_error ()) << toml.get_error ().get_message (); - - ASSERT_EQ (conf.enable_https, defaults.enable_wss); - ASSERT_EQ (conf.enable_wss, defaults.enable_wss); - ASSERT_EQ (conf.verbose_logging, defaults.verbose_logging); - ASSERT_EQ (conf.server_cert_path, defaults.server_cert_path); - ASSERT_EQ (conf.server_key_path, defaults.server_key_path); - ASSERT_EQ (conf.server_key_passphrase, defaults.server_key_passphrase); - ASSERT_EQ (conf.server_dh_path, defaults.server_dh_path); -} - TEST (toml, log_config_defaults) { std::stringstream ss; diff --git a/nano/lib/CMakeLists.txt b/nano/lib/CMakeLists.txt index 5643ed9808..144e1adfd4 100644 --- a/nano/lib/CMakeLists.txt +++ b/nano/lib/CMakeLists.txt @@ -99,8 +99,6 @@ add_library( threading.cpp timer.hpp timer.cpp - tlsconfig.hpp - tlsconfig.cpp tomlconfig.hpp tomlconfig.cpp uniquer.hpp diff --git a/nano/lib/rpcconfig.cpp b/nano/lib/rpcconfig.cpp index 8635a8867e..9c67617772 100644 --- a/nano/lib/rpcconfig.cpp +++ b/nano/lib/rpcconfig.cpp @@ -5,30 +5,6 @@ #include -nano::error nano::rpc_secure_config::serialize_toml (nano::tomlconfig & toml) const -{ - toml.put ("enable", enable, "Enable or disable TLS support.\ntype:bool"); - toml.put ("verbose_logging", verbose_logging, "Enable or disable verbose logging.\ntype:bool"); - toml.put ("server_key_passphrase", server_key_passphrase, "Server key passphrase.\ntype:string"); - toml.put ("server_cert_path", server_cert_path, "Directory containing certificates.\ntype:string,path"); - toml.put ("server_key_path", server_key_path, "Path to server key PEM file.\ntype:string,path"); - toml.put ("server_dh_path", server_dh_path, "Path to Diffie-Hellman params file.\ntype:string,path"); - toml.put ("client_certs_path", client_certs_path, "Directory containing client certificates.\ntype:string"); - return toml.get_error (); -} - -nano::error nano::rpc_secure_config::deserialize_toml (nano::tomlconfig & toml) -{ - toml.get ("enable", enable); - toml.get ("verbose_logging", verbose_logging); - toml.get ("server_key_passphrase", server_key_passphrase); - toml.get ("server_cert_path", server_cert_path); - toml.get ("server_key_path", server_key_path); - toml.get ("server_dh_path", server_dh_path); - toml.get ("client_certs_path", client_certs_path); - return toml.get_error (); -} - nano::rpc_config::rpc_config (nano::network_constants & network_constants) : rpc_process{ network_constants }, address{ boost::asio::ip::address_v6::loopback ().to_string () } @@ -68,12 +44,6 @@ nano::error nano::rpc_config::deserialize_toml (nano::tomlconfig & toml) { if (!toml.empty ()) { - auto rpc_secure_l (toml.get_optional_child ("secure")); - if (rpc_secure_l) - { - return nano::error ("The RPC secure configuration has moved to config-tls.toml. Please update the configuration."); - } - boost::asio::ip::address_v6 address_l; toml.get_optional ("address", address_l, boost::asio::ip::address_v6::loopback ()); address = address_l.to_string (); diff --git a/nano/lib/rpcconfig.hpp b/nano/lib/rpcconfig.hpp index d07b2ead3a..230cbd197e 100644 --- a/nano/lib/rpcconfig.hpp +++ b/nano/lib/rpcconfig.hpp @@ -13,34 +13,6 @@ namespace nano { class tomlconfig; -class tls_config; - -/** - * Configuration options for RPC TLS. - * @note This is deprecated, but kept for a few versions in order to yield a config error message on startup if it's used. - */ -class rpc_secure_config final -{ -public: - nano::error serialize_toml (nano::tomlconfig &) const; - nano::error deserialize_toml (nano::tomlconfig &); - -private: - /** If true, enable TLS */ - bool enable{ false }; - /** If true, log certificate verification details */ - bool verbose_logging{ false }; - /** Must be set if the private key PEM is password protected */ - std::string server_key_passphrase; - /** Path to certificate- or chain file. Must be PEM formatted. */ - std::string server_cert_path; - /** Path to private key file. Must be PEM formatted.*/ - std::string server_key_path; - /** Path to dhparam file */ - std::string server_dh_path; - /** Optional path to directory containing client certificates */ - std::string client_certs_path; -}; class rpc_process_config final { @@ -72,12 +44,9 @@ class rpc_config final std::string address; uint16_t port{ rpc_process.network_constants.default_rpc_port }; bool enable_control{ false }; - rpc_secure_config secure; uint8_t max_json_depth{ 20 }; uint64_t max_request_size{ 32 * 1024 * 1024 }; nano::rpc_logging_config rpc_logging; - /** Optional TLS config */ - std::shared_ptr tls_config; }; nano::error read_rpc_config_toml (std::filesystem::path const & data_path_a, nano::rpc_config & config_a, std::vector const & config_overrides = std::vector ()); diff --git a/nano/lib/tlsconfig.cpp b/nano/lib/tlsconfig.cpp deleted file mode 100644 index 9af33384b4..0000000000 --- a/nano/lib/tlsconfig.cpp +++ /dev/null @@ -1,186 +0,0 @@ -#include -#include -#include -#include - -#include - -#include - -namespace nano -{ -nano::error nano::tls_config::serialize_toml (nano::tomlconfig & toml) const -{ - toml.put ("enable_https", enable_https, "Enable or disable https:// support.\ntype:bool"); - toml.put ("enable_wss", enable_wss, "Enable or disable wss:// support.\ntype:bool"); - toml.put ("verbose_logging", verbose_logging, "Enable or disable verbose TLS logging.\ntype:bool"); - toml.put ("server_key_passphrase", server_key_passphrase, "Server key passphrase.\ntype:string"); - toml.put ("server_cert_path", server_cert_path, "Directory containing certificates.\ntype:string,path"); - toml.put ("server_key_path", server_key_path, "Path to server key PEM file.\ntype:string,path"); - toml.put ("server_dh_path", server_dh_path, "Path to Diffie-Hellman params file.\ntype:string,path"); - toml.put ("client_certs_path", client_certs_path, "Directory containing optional client certificates.\ntype:string,path"); - return toml.get_error (); -} - -nano::error nano::tls_config::deserialize_toml (nano::tomlconfig & toml) -{ - toml.get ("enable_https", enable_https); - toml.get ("enable_wss", enable_wss); - toml.get ("verbose_logging", verbose_logging); - toml.get ("server_key_passphrase", server_key_passphrase); - toml.get ("server_cert_path", server_cert_path); - toml.get ("server_key_path", server_key_path); - toml.get ("server_dh_path", server_dh_path); - toml.get ("client_certs_path", client_certs_path); - return toml.get_error (); -} - -#ifdef NANO_SECURE_RPC -namespace -{ - bool on_verify_certificate (bool preverified, boost::asio::ssl::verify_context & ctx, nano::tls_config & config_a, nano::logger_mt & logger_a) - { - X509_STORE_CTX * cts = ctx.native_handle (); - auto error (X509_STORE_CTX_get_error (cts)); - switch (error) - { - case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: - logger_a.always_log ("TLS: Unable to get issuer"); - break; - case X509_V_ERR_CERT_NOT_YET_VALID: - case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: - logger_a.always_log ("TLS: Certificate not yet valid"); - break; - case X509_V_ERR_CERT_HAS_EXPIRED: - case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: - logger_a.always_log ("TLS: Certificate expired"); - break; - case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: - if (config_a.verbose_logging) - { - logger_a.always_log ("TLS: Self-signed certificate in chain"); - } - - // Allow self-signed certificates - preverified = true; - break; - case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: - logger_a.always_log ("TLS: Self-signed certificate not in the list of trusted certs (forgot to subject-hash certificate filename?)"); - break; - default: - break; - } - - if (config_a.verbose_logging) - { - if (error != 0) - { - logger_a.always_log ("TLS: Error: ", X509_verify_cert_error_string (error)); - logger_a.always_log ("TLS: Error chain depth : ", X509_STORE_CTX_get_error_depth (cts)); - } - - X509 * cert = X509_STORE_CTX_get_current_cert (cts); - char subject_name[512]; - X509_NAME_oneline (X509_get_subject_name (cert), subject_name, sizeof (subject_name) - 1); - logger_a.always_log ("TLS: Verifying: ", subject_name); - logger_a.always_log ("TLS: Verification: ", preverified); - } - else if (!preverified) - { - logger_a.always_log ("TLS: Pre-verification failed. Turn on verbose logging for more information."); - } - - return preverified; - } - - void load_certs (nano::tls_config & config_a, nano::logger_mt & logger_a) - { - try - { - // This is called if the key is password protected - config_a.ssl_context.set_password_callback ( - [&config_a] (std::size_t, - boost::asio::ssl::context_base::password_purpose) { - return config_a.server_key_passphrase; - }); - - // The following two options disables the session cache and enables stateless session resumption. - // This is necessary because of the way the RPC server abruptly terminate connections. - SSL_CTX_set_session_cache_mode (config_a.ssl_context.native_handle (), SSL_SESS_CACHE_OFF); - SSL_CTX_set_options (config_a.ssl_context.native_handle (), SSL_OP_NO_TICKET); - - config_a.ssl_context.set_options ( - boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::no_sslv2 | boost::asio::ssl::context::no_sslv3 | boost::asio::ssl::context::single_dh_use); - - config_a.ssl_context.use_certificate_chain_file (config_a.server_cert_path); - config_a.ssl_context.use_private_key_file (config_a.server_key_path, boost::asio::ssl::context::pem); - config_a.ssl_context.use_tmp_dh_file (config_a.server_dh_path); - - // Verify client certificates? - if (!config_a.client_certs_path.empty ()) - { - config_a.ssl_context.set_verify_mode (boost::asio::ssl::verify_fail_if_no_peer_cert | boost::asio::ssl::verify_peer); - config_a.ssl_context.add_verify_path (config_a.client_certs_path); - config_a.ssl_context.set_verify_callback ([&config_a, &logger_a] (auto preverified, auto & ctx) { - return on_verify_certificate (preverified, ctx, config_a, logger_a); - }); - } - - logger_a.always_log ("TLS: successfully configured"); - } - catch (boost::system::system_error const & err) - { - auto error (boost::str (boost::format ("Could not load certificate information: %1%. Make sure the paths and the passphrase in config-tls.toml are correct.") % err.what ())); - std::cerr << error << std::endl; - logger_a.always_log (error); - } - } -} -#endif - -nano::error read_tls_config_toml (std::filesystem::path const & data_path_a, nano::tls_config & config_a, nano::logger & logger, std::vector const & config_overrides) -{ - nano::error error; - auto toml_config_path = nano::get_tls_toml_config_path (data_path_a); - - // Parse and deserialize - nano::tomlconfig toml; - - std::stringstream config_overrides_stream; - for (auto const & entry : config_overrides) - { - config_overrides_stream << entry << std::endl; - } - config_overrides_stream << std::endl; - - // Make sure we don't create an empty toml file if it doesn't exist. Running without a tls toml file is the default. - if (!error) - { - if (std::filesystem::exists (toml_config_path)) - { - error = toml.read (config_overrides_stream, toml_config_path); - } - else - { - error = toml.read (config_overrides_stream); - } - } - - if (!error) - { - error = config_a.deserialize_toml (toml); - } - - if (!error && (config_a.enable_https || config_a.enable_wss)) - { -#ifdef NANO_SECURE_RPC - load_certs (config_a, logger_a); -#else - logger.critical (nano::log::type::tls, "HTTPS or WSS is enabled in the TLS configuration, but the node is not built with NANO_SECURE_RPC"); - std::exit (1); -#endif - } - - return error; -} -} diff --git a/nano/lib/tlsconfig.hpp b/nano/lib/tlsconfig.hpp deleted file mode 100644 index bae2a9f9b2..0000000000 --- a/nano/lib/tlsconfig.hpp +++ /dev/null @@ -1,58 +0,0 @@ -#pragma once - -#include -#include - -#include -#include -#include - -#ifdef NANO_SECURE_RPC -#include -#endif - -namespace nano -{ -class logger; -class jsonconfig; -class tomlconfig; - -/** Configuration options for secure RPC and WebSocket connections */ -class tls_config final -{ -public: - nano::error serialize_toml (nano::tomlconfig &) const; - nano::error deserialize_toml (nano::tomlconfig &); - - /** If true, enable TLS for RPC (only allow https, otherwise only allow http) */ - bool enable_https{ false }; - - /** If true, enable TLS for WebSocket (only allow wss, otherwise only allow ws) */ - bool enable_wss{ false }; - - /** If true, log certificate verification details */ - bool verbose_logging{ false }; - - /** Must be set if the private key PEM is password protected */ - std::string server_key_passphrase; - - /** Path to certificate- or chain file. Must be PEM formatted. */ - std::string server_cert_path; - - /** Path to private key file. Must be PEM formatted.*/ - std::string server_key_path; - - /** Path to dhparam file */ - std::string server_dh_path; - - /** Optional path to directory containing client certificates */ - std::string client_certs_path; - -#ifdef NANO_SECURE_RPC - /** The context needs to be shared between sessions to make resumption work */ - boost::asio::ssl::context ssl_context{ boost::asio::ssl::context::tlsv12_server }; -#endif -}; - -nano::error read_tls_config_toml (std::filesystem::path const & data_path_a, nano::tls_config & config_a, nano::logger &, std::vector const & config_overrides = std::vector ()); -} diff --git a/nano/nano_node/daemon.cpp b/nano/nano_node/daemon.cpp index e172e18f72..6752bde692 100644 --- a/nano/nano_node/daemon.cpp +++ b/nano/nano_node/daemon.cpp @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include @@ -75,171 +74,156 @@ void nano::daemon::run (std::filesystem::path const & data_path, nano::node_flag nano::network_params network_params{ nano::network_constants::active_network }; nano::daemon_config config{ data_path, network_params }; - auto error = nano::read_node_config_toml (data_path, config, flags.config_overrides); + if (auto error = nano::read_node_config_toml (data_path, config, flags.config_overrides)) + { + logger.critical (nano::log::type::daemon, "Error deserializing node config: {}", error.get_message ()); + std::exit (1); + } + if (auto error = nano::flags_config_conflicts (flags, config.node)) + { + logger.critical (nano::log::type::daemon, "Error parsing command line options: {}", error.message ()); + std::exit (1); + } nano::set_use_memory_pools (config.node.use_memory_pools); - if (!error) + std::shared_ptr io_ctx = std::make_shared (); + + auto opencl = nano::opencl_work::create (config.opencl_enable, config.opencl, logger, config.node.network_params.work); + nano::opencl_work_func_t opencl_work_func; + if (opencl) { - error = nano::flags_config_conflicts (flags, config.node); + opencl_work_func = [&opencl] (nano::work_version const version_a, nano::root const & root_a, uint64_t difficulty_a, std::atomic & ticket_a) { + return opencl->generate_work (version_a, root_a, difficulty_a, ticket_a); + }; } - if (!error) + nano::work_pool opencl_work (config.node.network_params.network, config.node.work_threads, config.node.pow_sleep_interval, opencl_work_func); + try { - auto tls_config (std::make_shared ()); - error = nano::read_tls_config_toml (data_path, *tls_config, logger); - if (error) - { - std::cerr << error.get_message () << std::endl; - std::exit (1); - } - else - { - config.node.websocket_config.tls_config = tls_config; - } + // This avoids a blank prompt during any node initialization delays + logger.info (nano::log::type::daemon, "Starting up Nano node..."); - std::shared_ptr io_ctx = std::make_shared (); + // Print info about number of logical cores detected, those are used to decide how many IO, worker and signature checker threads to spawn + logger.info (nano::log::type::daemon, "Hardware concurrency: {} ( configured: {} )", std::thread::hardware_concurrency (), nano::hardware_concurrency ()); - auto opencl = nano::opencl_work::create (config.opencl_enable, config.opencl, logger, config.node.network_params.work); - nano::opencl_work_func_t opencl_work_func; - if (opencl) + nano::set_file_descriptor_limit (OPEN_FILE_DESCRIPTORS_LIMIT); + auto const file_descriptor_limit = nano::get_file_descriptor_limit (); + logger.info (nano::log::type::daemon, "File descriptors limit: {}", file_descriptor_limit); + if (file_descriptor_limit < OPEN_FILE_DESCRIPTORS_LIMIT) { - opencl_work_func = [&opencl] (nano::work_version const version_a, nano::root const & root_a, uint64_t difficulty_a, std::atomic & ticket_a) { - return opencl->generate_work (version_a, root_a, difficulty_a, ticket_a); - }; + logger.warn (nano::log::type::daemon, "File descriptors limit is lower than the {} recommended. Node was unable to change it.", OPEN_FILE_DESCRIPTORS_LIMIT); } - nano::work_pool opencl_work (config.node.network_params.network, config.node.work_threads, config.node.pow_sleep_interval, opencl_work_func); - try - { - // This avoids a blank prompt during any node initialization delays - logger.info (nano::log::type::daemon, "Starting up Nano node..."); - - // Print info about number of logical cores detected, those are used to decide how many IO, worker and signature checker threads to spawn - logger.info (nano::log::type::daemon, "Hardware concurrency: {} ( configured: {} )", std::thread::hardware_concurrency (), nano::hardware_concurrency ()); - nano::set_file_descriptor_limit (OPEN_FILE_DESCRIPTORS_LIMIT); - auto const file_descriptor_limit = nano::get_file_descriptor_limit (); - logger.info (nano::log::type::daemon, "File descriptors limit: {}", file_descriptor_limit); - if (file_descriptor_limit < OPEN_FILE_DESCRIPTORS_LIMIT) - { - logger.warn (nano::log::type::daemon, "File descriptors limit is lower than the {} recommended. Node was unable to change it.", OPEN_FILE_DESCRIPTORS_LIMIT); - } - - // for the daemon start up, if the user hasn't specified a port in - // the config, we must use the default peering port for the network - // - if (!config.node.peering_port.has_value ()) - { - config.node.peering_port = network_params.network.default_node_port; - } + // for the daemon start up, if the user hasn't specified a port in + // the config, we must use the default peering port for the network + // + if (!config.node.peering_port.has_value ()) + { + config.node.peering_port = network_params.network.default_node_port; + } - auto node = std::make_shared (io_ctx, data_path, config.node, opencl_work, flags); - if (!node->init_error ()) - { - auto network_label = node->network_params.network.get_current_network_as_string (); - std::time_t dateTime = std::time (nullptr); + auto node = std::make_shared (io_ctx, data_path, config.node, opencl_work, flags); + if (!node->init_error ()) + { + auto network_label = node->network_params.network.get_current_network_as_string (); + std::time_t dateTime = std::time (nullptr); - logger.info (nano::log::type::daemon, "Network: {}", network_label); - logger.info (nano::log::type::daemon, "Version: {}", NANO_VERSION_STRING); - logger.info (nano::log::type::daemon, "Data path: '{}'", node->application_path.string ()); - logger.info (nano::log::type::daemon, "Build info: {}", BUILD_INFO); - logger.info (nano::log::type::daemon, "Database backend: {}", node->store.vendor_get ()); - logger.info (nano::log::type::daemon, "Start time: {:%c} UTC", fmt::gmtime (dateTime)); + logger.info (nano::log::type::daemon, "Network: {}", network_label); + logger.info (nano::log::type::daemon, "Version: {}", NANO_VERSION_STRING); + logger.info (nano::log::type::daemon, "Data path: '{}'", node->application_path.string ()); + logger.info (nano::log::type::daemon, "Build info: {}", BUILD_INFO); + logger.info (nano::log::type::daemon, "Database backend: {}", node->store.vendor_get ()); + logger.info (nano::log::type::daemon, "Start time: {:%c} UTC", fmt::gmtime (dateTime)); - // IO context runner should be started first and stopped last to allow asio handlers to execute during node start/stop - runner = std::make_unique (io_ctx, logger, node->config.io_threads, nano::thread_role::name::io_daemon); + // IO context runner should be started first and stopped last to allow asio handlers to execute during node start/stop + runner = std::make_unique (io_ctx, logger, node->config.io_threads, nano::thread_role::name::io_daemon); - node->start (); + node->start (); - std::atomic stopped{ false }; + std::atomic stopped{ false }; - std::unique_ptr ipc_server = std::make_unique (*node, config.rpc); - std::unique_ptr rpc_process; - std::unique_ptr rpc_handler; - std::shared_ptr rpc; + std::unique_ptr ipc_server = std::make_unique (*node, config.rpc); + std::unique_ptr rpc_process; + std::unique_ptr rpc_handler; + std::shared_ptr rpc; - if (config.rpc_enable) + if (config.rpc_enable) + { + // In process RPC + if (!config.rpc.child_process.enable) { - if (!config.rpc.child_process.enable) + auto stop_callback = [this, &stopped] () { + logger.warn (nano::log::type::daemon, "RPC stop request received, stopping..."); + stopped = true; + stopped.notify_all (); + }; + + // Launch rpc in-process + nano::rpc_config rpc_config{ config.node.network_params.network }; + if (auto error = nano::read_rpc_config_toml (data_path, rpc_config, flags.rpc_config_overrides)) { - auto stop_callback = [this, &stopped] () { - logger.warn (nano::log::type::daemon, "RPC stop request received, stopping..."); - stopped = true; - stopped.notify_all (); - }; - - // Launch rpc in-process - nano::rpc_config rpc_config{ config.node.network_params.network }; - auto error = nano::read_rpc_config_toml (data_path, rpc_config, flags.rpc_config_overrides); - if (error) - { - std::cout << error.get_message () << std::endl; - std::exit (1); - } - - rpc_config.tls_config = tls_config; - rpc_handler = std::make_unique (*node, *ipc_server, config.rpc, stop_callback); - rpc = nano::get_rpc (io_ctx, rpc_config, *rpc_handler); - rpc->start (); + logger.critical (nano::log::type::daemon, "Error deserializing RPC config: {}", error.get_message ()); + std::exit (1); } - else + + rpc_handler = std::make_unique (*node, *ipc_server, config.rpc, stop_callback); + rpc = nano::get_rpc (io_ctx, rpc_config, *rpc_handler); + rpc->start (); + } + else + { + // Spawn a child rpc process + if (!std::filesystem::exists (config.rpc.child_process.rpc_path)) { - // Spawn a child rpc process - if (!std::filesystem::exists (config.rpc.child_process.rpc_path)) - { - throw std::runtime_error (std::string ("RPC is configured to spawn a new process however the file cannot be found at: ") + config.rpc.child_process.rpc_path); - } + throw std::runtime_error (std::string ("RPC is configured to spawn a new process however the file cannot be found at: ") + config.rpc.child_process.rpc_path); + } - auto network = node->network_params.network.get_current_network_as_string (); + auto network = node->network_params.network.get_current_network_as_string (); - rpc_process = std::make_unique (config.rpc.child_process.rpc_path, "--daemon", "--data_path", data_path.string (), "--network", network); - } - debug_assert (rpc || rpc_process); + rpc_process = std::make_unique (config.rpc.child_process.rpc_path, "--daemon", "--data_path", data_path.string (), "--network", network); } + debug_assert (rpc || rpc_process); + } - auto signal_handler = [this, &stopped] (int signum) { - logger.warn (nano::log::type::daemon, "Interrupt signal received ({}), stopping...", to_signal_name (signum)); - stopped = true; - stopped.notify_all (); - }; - - nano::signal_manager sigman; - // keep trapping Ctrl-C to avoid a second Ctrl-C interrupting tasks started by the first - sigman.register_signal_handler (SIGINT, signal_handler, true); - // sigterm is less likely to come in bunches so only trap it once - sigman.register_signal_handler (SIGTERM, signal_handler, false); + auto signal_handler = [this, &stopped] (int signum) { + logger.warn (nano::log::type::daemon, "Interrupt signal received ({}), stopping...", to_signal_name (signum)); + stopped = true; + stopped.notify_all (); + }; - // Keep running until stopped flag is set - stopped.wait (false); + nano::signal_manager sigman; + // keep trapping Ctrl-C to avoid a second Ctrl-C interrupting tasks started by the first + sigman.register_signal_handler (SIGINT, signal_handler, true); + // sigterm is less likely to come in bunches so only trap it once + sigman.register_signal_handler (SIGTERM, signal_handler, false); - logger.info (nano::log::type::daemon, "Stopping..."); + // Keep running until stopped flag is set + stopped.wait (false); - if (rpc) - { - rpc->stop (); - } - ipc_server->stop (); - node->stop (); - io_ctx->stop (); - runner->join (); + logger.info (nano::log::type::daemon, "Stopping..."); - if (rpc_process) - { - rpc_process->wait (); - } + if (rpc) + { + rpc->stop (); } - else + ipc_server->stop (); + node->stop (); + io_ctx->stop (); + runner->join (); + + if (rpc_process) { - logger.critical (nano::log::type::daemon, "Error initializing node"); + rpc_process->wait (); } } - catch (std::runtime_error const & e) + else { - logger.critical (nano::log::type::daemon, "Error while running node: {}", e.what ()); + logger.critical (nano::log::type::daemon, "Error initializing node"); } } - else + catch (std::runtime_error const & e) { - logger.critical (nano::log::type::daemon, "Error deserializing config: {}", error.get_message ()); + logger.critical (nano::log::type::daemon, "Error while running node: {}", e.what ()); } logger.info (nano::log::type::daemon, "Daemon stopped"); diff --git a/nano/nano_rpc/entry.cpp b/nano/nano_rpc/entry.cpp index 9e062fb684..11cea70432 100644 --- a/nano/nano_rpc/entry.cpp +++ b/nano/nano_rpc/entry.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include @@ -37,18 +36,6 @@ void run (std::filesystem::path const & data_path, std::vector cons auto error = nano::read_rpc_config_toml (data_path, rpc_config, config_overrides); if (!error) { - auto tls_config (std::make_shared ()); - error = nano::read_tls_config_toml (data_path, *tls_config, logger); - if (error) - { - logger.critical (nano::log::type::daemon_rpc, "Error reading RPC TLS config: {}", error.get_message ()); - std::exit (1); - } - else - { - rpc_config.tls_config = tls_config; - } - std::shared_ptr io_ctx = std::make_shared (); runner = std::make_unique (io_ctx, logger, rpc_config.rpc_process.io_threads, nano::thread_role::name::io_daemon); diff --git a/nano/nano_wallet/entry.cpp b/nano/nano_wallet/entry.cpp index 3fa835b749..65be63a226 100644 --- a/nano/nano_wallet/entry.cpp +++ b/nano/nano_wallet/entry.cpp @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include @@ -109,19 +108,6 @@ int run_wallet (QApplication & application, int argc, char * const * argv, std:: { nano::set_use_memory_pools (config.node.use_memory_pools); - auto tls_config (std::make_shared ()); - error = nano::read_tls_config_toml (data_path, *tls_config, logger); - if (error) - { - splash->hide (); - show_error (error.get_message ()); - std::exit (1); - } - else - { - config.node.websocket_config.tls_config = tls_config; - } - std::shared_ptr io_ctx = std::make_shared (); nano::thread_runner runner (io_ctx, logger, config.node.io_threads, nano::thread_role::name::io_daemon); @@ -190,7 +176,6 @@ int run_wallet (QApplication & application, int argc, char * const * argv, std:: show_error (error.get_message ()); std::exit (1); } - rpc_config.tls_config = tls_config; rpc_handler = std::make_unique (*node, ipc, config.rpc); rpc = nano::get_rpc (io_ctx, rpc_config, *rpc_handler); rpc->start (); diff --git a/nano/node/cli.cpp b/nano/node/cli.cpp index 41e236bf9a..2e1e4df4a4 100644 --- a/nano/node/cli.cpp +++ b/nano/node/cli.cpp @@ -1,6 +1,5 @@ #include #include -#include #include #include #include @@ -700,12 +699,6 @@ std::error_code nano::handle_node_options (boost::program_options::variables_map nano::log_config config = nano::log_config::sample_config (); config.serialize_toml (toml); } - else if (type == "tls") - { - valid_type = true; - nano::tls_config config; - config.serialize_toml (toml); - } else { std::cerr << "Invalid configuration type " << type << ". Must be node or rpc." << std::endl; diff --git a/nano/node/websocket.cpp b/nano/node/websocket.cpp index 0d15ca1367..698f0075e0 100644 --- a/nano/node/websocket.cpp +++ b/nano/node/websocket.cpp @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include @@ -578,8 +577,7 @@ void nano::websocket::listener::stop () sessions.clear (); } -nano::websocket::listener::listener (std::shared_ptr const & tls_config_a, nano::logger & logger_a, nano::wallets & wallets_a, boost::asio::io_context & io_ctx_a, boost::asio::ip::tcp::endpoint endpoint_a) : - tls_config (tls_config_a), +nano::websocket::listener::listener (nano::logger & logger_a, nano::wallets & wallets_a, boost::asio::io_context & io_ctx_a, boost::asio::ip::tcp::endpoint endpoint_a) : logger (logger_a), wallets (wallets_a), acceptor (io_ctx_a), @@ -629,22 +627,15 @@ void nano::websocket::listener::on_accept (boost::system::error_code ec) { // Create the session and initiate websocket handshake std::shared_ptr session; - if (tls_config && tls_config->enable_wss) - { -#ifdef NANO_SECURE_RPC - session = std::make_shared (*this, std::move (socket), tls_config->ssl_context); -#endif - } - else - { - session = std::make_shared (*this, std::move (socket), logger); - } + session = std::make_shared (*this, std::move (socket), logger); + // TODO: Why is this locking and unlocking mutex manually?? sessions_mutex.lock (); sessions.push_back (session); // Clean up expired sessions sessions.erase (std::remove_if (sessions.begin (), sessions.end (), [] (auto & elem) { return elem.expired (); }), sessions.end ()); sessions_mutex.unlock (); + session->handshake (); } @@ -1003,7 +994,7 @@ nano::websocket_server::websocket_server (nano::websocket::config & config_a, na } auto endpoint = nano::tcp_endpoint{ boost::asio::ip::make_address_v6 (config.address), config.port }; - server = std::make_shared (config.tls_config, logger, wallets, io_ctx, endpoint); + server = std::make_shared (logger, wallets, io_ctx, endpoint); observers.blocks.add ([this] (nano::election_status const & status_a, std::vector const & votes_a, nano::account const & account_a, nano::amount const & amount_a, bool is_state_send_a, bool is_state_epoch_a) { debug_assert (status_a.type != nano::election_status_type::ongoing); diff --git a/nano/node/websocket.hpp b/nano/node/websocket.hpp index 560530392c..19e1645970 100644 --- a/nano/node/websocket.hpp +++ b/nano/node/websocket.hpp @@ -26,7 +26,6 @@ class ledger; class logger; class node_observers; class telemetry_data; -class tls_config; class vote; enum class vote_code; class wallets; @@ -303,7 +302,7 @@ namespace websocket class listener final : public std::enable_shared_from_this { public: - listener (std::shared_ptr const & tls_config_a, nano::logger &, nano::wallets & wallets_a, boost::asio::io_context & io_ctx_a, boost::asio::ip::tcp::endpoint endpoint_a); + listener (nano::logger &, nano::wallets & wallets_a, boost::asio::io_context & io_ctx_a, boost::asio::ip::tcp::endpoint endpoint_a); /** Start accepting connections */ void run (); @@ -352,7 +351,6 @@ namespace websocket /** Removes from subscription count of a specific topic*/ void decrease_subscriber_count (nano::websocket::topic const & topic_a); - std::shared_ptr tls_config; nano::logger & logger; nano::wallets & wallets; boost::asio::ip::tcp::acceptor acceptor; diff --git a/nano/node/websocketconfig.hpp b/nano/node/websocketconfig.hpp index 7ece6ca74c..5dc0e6acd9 100644 --- a/nano/node/websocketconfig.hpp +++ b/nano/node/websocketconfig.hpp @@ -8,7 +8,6 @@ namespace nano { class tomlconfig; -class tls_config; namespace websocket { /** websocket configuration */ @@ -22,8 +21,6 @@ namespace websocket bool enabled{ false }; uint16_t port; std::string address; - /** Optional TLS config */ - std::shared_ptr tls_config; }; } } diff --git a/nano/rpc/CMakeLists.txt b/nano/rpc/CMakeLists.txt index c3e8cafc04..6b62ad6111 100644 --- a/nano/rpc/CMakeLists.txt +++ b/nano/rpc/CMakeLists.txt @@ -1,11 +1,5 @@ -if(NANO_SECURE_RPC OR RAIBLOCKS_SECURE_RPC) - set(secure_rpc_sources rpc_secure.hpp rpc_secure.cpp - rpc_connection_secure.hpp rpc_connection_secure.cpp) -endif() - add_library( rpc - ${secure_rpc_sources} rpc.hpp rpc.cpp rpc_connection.hpp @@ -15,4 +9,4 @@ add_library( rpc_request_processor.hpp rpc_request_processor.cpp) -target_link_libraries(rpc nano_lib Boost::beast ${OPENSSL_LIBRARIES}) +target_link_libraries(rpc nano_lib Boost::beast) diff --git a/nano/rpc/rpc.cpp b/nano/rpc/rpc.cpp index 5b5d84ecde..a2c1e33202 100644 --- a/nano/rpc/rpc.cpp +++ b/nano/rpc/rpc.cpp @@ -1,6 +1,5 @@ #include #include -#include #include #include @@ -8,10 +7,6 @@ #include -#ifdef NANO_SECURE_RPC -#include -#endif - nano::rpc::rpc (std::shared_ptr io_ctx_a, nano::rpc_config config_a, nano::rpc_handler_interface & rpc_handler_interface_a) : config (std::move (config_a)), io_ctx_shared (io_ctx_a), @@ -88,15 +83,5 @@ void nano::rpc::stop () std::shared_ptr nano::get_rpc (std::shared_ptr io_ctx_a, nano::rpc_config const & config_a, nano::rpc_handler_interface & rpc_handler_interface_a) { - if (config_a.tls_config && config_a.tls_config->enable_https) - { -#ifdef NANO_SECURE_RPC - return std::make_shared (io_ctx_a, config_a, rpc_handler_interface_a); -#endif - } - else - { - return std::make_shared (io_ctx_a, config_a, rpc_handler_interface_a); - } - return nullptr; + return std::make_shared (io_ctx_a, config_a, rpc_handler_interface_a); } diff --git a/nano/rpc/rpc_connection_secure.cpp b/nano/rpc/rpc_connection_secure.cpp deleted file mode 100644 index 6287ed9931..0000000000 --- a/nano/rpc/rpc_connection_secure.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include -#include -#include - -#include - -nano::rpc_connection_secure::rpc_connection_secure (nano::rpc_config const & rpc_config, boost::asio::io_context & io_ctx, nano::logger_mt & logger, nano::rpc_handler_interface & rpc_handler_interface, boost::asio::ssl::context & ssl_context) : - nano::rpc_connection (rpc_config, io_ctx, logger, rpc_handler_interface), - stream (socket, ssl_context) -{ -} - -void nano::rpc_connection_secure::parse_connection () -{ - // Perform the SSL handshake - auto this_l = std::static_pointer_cast (shared_from_this ()); - stream.async_handshake (boost::asio::ssl::stream_base::server, - boost::asio::bind_executor (this_l->strand, [this_l] (auto & ec) { - this_l->handle_handshake (ec); - })); -} - -void nano::rpc_connection_secure::on_shutdown (boost::system::error_code const & error) -{ - // No-op. We initiate the shutdown (since the RPC server kills the connection after each request) - // and we'll thus get an expected EOF error. If the client disconnects, a short-read error will be expected. -} - -void nano::rpc_connection_secure::handle_handshake (boost::system::error_code const & error) -{ - if (!error) - { - read (stream); - } - else - { - logger.always_log ("TLS: Handshake error: ", error.message ()); - } -} - -void nano::rpc_connection_secure::write_completion_handler (std::shared_ptr const & rpc) -{ - auto rpc_connection_secure = boost::polymorphic_pointer_downcast (rpc); - rpc_connection_secure->stream.async_shutdown (boost::asio::bind_executor (rpc->strand, [rpc_connection_secure] (auto const & ec_shutdown) { - rpc_connection_secure->on_shutdown (ec_shutdown); - })); -} diff --git a/nano/rpc/rpc_connection_secure.hpp b/nano/rpc/rpc_connection_secure.hpp deleted file mode 100644 index 13e9287d20..0000000000 --- a/nano/rpc/rpc_connection_secure.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -#include - -#include - -namespace nano -{ -/** - * Specialization of nano::rpc_connection for establishing TLS connections. - * Handshakes with client certificates are supported. - */ -class rpc_connection_secure : public rpc_connection -{ -public: - rpc_connection_secure (nano::rpc_config const & rpc_config, boost::asio::io_context & io_ctx, nano::logger_mt & logger, nano::rpc_handler_interface & rpc_handler_interface_a, boost::asio::ssl::context & ssl_context); - void parse_connection () override; - void write_completion_handler (std::shared_ptr const & rpc) override; - /** The TLS handshake callback */ - void handle_handshake (boost::system::error_code const & error); - /** The TLS async shutdown callback */ - void on_shutdown (boost::system::error_code const & error); - -private: - boost::asio::ssl::stream stream; -}; -} diff --git a/nano/rpc/rpc_secure.cpp b/nano/rpc/rpc_secure.cpp deleted file mode 100644 index 9640e28c2f..0000000000 --- a/nano/rpc/rpc_secure.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include -#include -#include -#include - -#include -#include - -#include - -nano::rpc_secure::rpc_secure (boost::asio::io_context & context_a, nano::rpc_config const & config_a, nano::rpc_handler_interface & rpc_handler_interface_a) : - rpc (context_a, config_a, rpc_handler_interface_a) -{ -} - -void nano::rpc_secure::accept () -{ - auto connection (std::make_shared (config, io_ctx, logger, rpc_handler_interface, config.tls_config->ssl_context)); - acceptor.async_accept (connection->socket, boost::asio::bind_executor (connection->strand, [this, connection] (boost::system::error_code const & ec) { - if (ec != boost::asio::error::operation_aborted && acceptor.is_open ()) - { - accept (); - } - if (!ec) - { - connection->parse_connection (); - } - else - { - logger.error (nano::log::type::rpc, "Error accepting RPC connection: {}", ec.message ()); - } - })); -} diff --git a/nano/rpc/rpc_secure.hpp b/nano/rpc/rpc_secure.hpp deleted file mode 100644 index 44ea22a9e0..0000000000 --- a/nano/rpc/rpc_secure.hpp +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once -#include - -namespace boost -{ -namespace asio -{ - class io_context; -} -} - -namespace nano -{ -/** - * Specialization of nano::rpc with TLS support - */ -class rpc_secure : public rpc -{ -public: - rpc_secure (boost::asio::io_context & context_a, nano::rpc_config const & config_a, nano::rpc_handler_interface & rpc_handler_interface_a); - - /** Starts accepting connections */ - void accept () override; -}; -}