From d2fda6c25f476c45acbc875721106f965435d99f Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sun, 20 Dec 2020 12:48:34 +0000 Subject: [PATCH] restrict public node checks a little do not include blocked hosts in peer lists or public node lists by default, warn about no https on clearnet and about untrusted peers likely being spies --- src/common/util.cpp | 11 +++++- src/common/util.h | 1 + src/daemon/rpc_command_executor.cpp | 4 +++ src/rpc/core_rpc_server.cpp | 9 ++++- src/rpc/core_rpc_server_commands_defs.h | 6 +++- src/simplewallet/simplewallet.cpp | 47 ++++++++++++++++++++----- src/wallet/wallet2.cpp | 1 + 7 files changed, 68 insertions(+), 11 deletions(-) diff --git a/src/common/util.cpp b/src/common/util.cpp index f8707d65c..445a11a75 100644 --- a/src/common/util.cpp +++ b/src/common/util.cpp @@ -871,10 +871,19 @@ std::string get_nix_version_display_string() return max_concurrency; } + bool is_privacy_preserving_network(const std::string &address) + { + if (boost::ends_with(address, ".onion")) + return true; + if (boost::ends_with(address, ".i2p")) + return true; + return false; + } + bool is_local_address(const std::string &address) { // always assume Tor/I2P addresses to be untrusted by default - if (boost::ends_with(address, ".onion") || boost::ends_with(address, ".i2p")) + if (is_privacy_preserving_network(address)) { MDEBUG("Address '" << address << "' is Tor/I2P, non local"); return false; diff --git a/src/common/util.h b/src/common/util.h index 0c3409ea1..6366e5cb4 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -228,6 +228,7 @@ namespace tools unsigned get_max_concurrency(); bool is_local_address(const std::string &address); + bool is_privacy_preserving_network(const std::string &address); int vercmp(const char *v0, const char *v1); // returns < 0, 0, > 0, similar to strcmp, but more human friendly than lexical - does not attempt to validate bool sha256sum(const uint8_t *data, size_t len, crypto::hash &hash); diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp index adaa9bc0e..04feb55fd 100644 --- a/src/daemon/rpc_command_executor.cpp +++ b/src/daemon/rpc_command_executor.cpp @@ -191,6 +191,9 @@ bool t_rpc_command_executor::print_peer_list(bool white, bool gray, size_t limit cryptonote::COMMAND_RPC_GET_PEER_LIST::response res; std::string failure_message = "Couldn't retrieve peer list"; + + req.include_blocked = true; + if (m_is_rpc) { if (!m_rpc_client->rpc_request(req, res, "/get_peer_list", failure_message.c_str())) @@ -237,6 +240,7 @@ bool t_rpc_command_executor::print_peer_list_stats() { std::string failure_message = "Couldn't retrieve peer list"; req.public_only = false; + req.include_blocked = true; if (m_is_rpc) { diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 01735d62e..3970be087 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -190,6 +190,7 @@ namespace cryptonote request.gray = true; request.white = true; + request.include_blocked = false; if (!on_get_public_nodes(request, response) || response.status != CORE_RPC_STATUS_OK) { return {}; @@ -1383,6 +1384,8 @@ namespace cryptonote for (auto & entry : white_list) { + if (!req.include_blocked && m_p2p.is_host_blocked(entry.adr, NULL)) + continue; if (entry.adr.get_type_id() == epee::net_utils::ipv4_network_address::get_type_id()) res.white_list.emplace_back(entry.id, entry.adr.as().ip(), entry.adr.as().port(), entry.last_seen, entry.pruning_seed, entry.rpc_port, entry.rpc_credits_per_hash); @@ -1395,6 +1398,8 @@ namespace cryptonote for (auto & entry : gray_list) { + if (!req.include_blocked && m_p2p.is_host_blocked(entry.adr, NULL)) + continue; if (entry.adr.get_type_id() == epee::net_utils::ipv4_network_address::get_type_id()) res.gray_list.emplace_back(entry.id, entry.adr.as().ip(), entry.adr.as().port(), entry.last_seen, entry.pruning_seed, entry.rpc_port, entry.rpc_credits_per_hash); @@ -1413,8 +1418,10 @@ namespace cryptonote { RPC_TRACKER(get_public_nodes); + COMMAND_RPC_GET_PEER_LIST::request peer_list_req; COMMAND_RPC_GET_PEER_LIST::response peer_list_res; - const bool success = on_get_peer_list(COMMAND_RPC_GET_PEER_LIST::request(), peer_list_res, ctx); + peer_list_req.include_blocked = req.include_blocked; + const bool success = on_get_peer_list(peer_list_req, peer_list_res, ctx); res.status = peer_list_res.status; if (!success) { diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h index bb9005a5f..bbcb27f1c 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -88,7 +88,7 @@ namespace cryptonote // advance which version they will stop working with // Don't go over 32767 for any of these #define CORE_RPC_VERSION_MAJOR 3 -#define CORE_RPC_VERSION_MINOR 4 +#define CORE_RPC_VERSION_MINOR 5 #define MAKE_CORE_RPC_VERSION(major,minor) (((major)<<16)|(minor)) #define CORE_RPC_VERSION MAKE_CORE_RPC_VERSION(CORE_RPC_VERSION_MAJOR, CORE_RPC_VERSION_MINOR) @@ -1195,10 +1195,12 @@ namespace cryptonote struct request_t: public rpc_request_base { bool public_only; + bool include_blocked; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE_PARENT(rpc_request_base) KV_SERIALIZE_OPT(public_only, true) + KV_SERIALIZE_OPT(include_blocked, false) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init request; @@ -1244,11 +1246,13 @@ namespace cryptonote { bool gray; bool white; + bool include_blocked; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE_PARENT(rpc_request_base) KV_SERIALIZE_OPT(gray, false) KV_SERIALIZE_OPT(white, true) + KV_SERIALIZE_OPT(include_blocked, false) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init request; diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index a90bd3a39..4385394ce 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -181,7 +181,7 @@ namespace const command_line::arg_descriptor< std::vector > arg_command = {"command", ""}; const char* USAGE_START_MINING("start_mining [] [bg_mining] [ignore_battery]"); - const char* USAGE_SET_DAEMON("set_daemon [:] [trusted|untrusted]"); + const char* USAGE_SET_DAEMON("set_daemon [:] [trusted|untrusted|this-is-probably-a-spy-node]"); const char* USAGE_SHOW_BALANCE("balance [detail]"); const char* USAGE_INCOMING_TRANSFERS("incoming_transfers [available|unavailable] [verbose] [uses] [index=[,[,...]]]"); const char* USAGE_PAYMENTS("payments [ ... ]"); @@ -2286,6 +2286,7 @@ bool simple_wallet::public_nodes(const std::vector &args) { fail_msg_writer() << tr("Error retrieving public node list: ") << e.what(); } + message_writer(console_color_red, true) << tr("Most of these nodes are probably spies. You should not use them unless connecting via Tor or I2P"); return true; } @@ -3240,7 +3241,7 @@ simple_wallet::simple_wallet() m_cmd_binder.set_handler("set_daemon", boost::bind(&simple_wallet::on_command, this, &simple_wallet::set_daemon, _1), tr(USAGE_SET_DAEMON), - tr("Set another daemon to connect to.")); + tr("Set another daemon to connect to. If it's not yours, it'll probably spy on you.")); m_cmd_binder.set_handler("save_bc", boost::bind(&simple_wallet::on_command, this, &simple_wallet::save_bc, _1), tr("Save the current blockchain data.")); @@ -5527,21 +5528,51 @@ bool simple_wallet::set_daemon(const std::vector& args) } else { daemon_url = args[0]; } - LOCK_IDLE_SCOPE(); - m_wallet->init(daemon_url); + epee::net_utils::http::url_content parsed{}; + const bool r = epee::net_utils::parse_url(daemon_url, parsed); + if (!r) + { + fail_msg_writer() << tr("Failed to parse address"); + return true; + } + + std::string trusted; if (args.size() == 2) { if (args[1] == "trusted") - m_wallet->set_trusted_daemon(true); + trusted = "trusted"; else if (args[1] == "untrusted") - m_wallet->set_trusted_daemon(false); + trusted = "untrusted"; + else if (args[1] == "this-is-probably-a-spy-node") + trusted = "this-is-probably-a-spy-node"; else { - fail_msg_writer() << tr("Expected trusted or untrusted, got ") << args[1] << ": assuming untrusted"; - m_wallet->set_trusted_daemon(false); + fail_msg_writer() << tr("Expected trusted, untrusted or this-is-probably-a-spy-node got ") << args[1]; + return true; } } + + if (!tools::is_privacy_preserving_network(parsed.host) && !tools::is_local_address(parsed.host)) + { + if (trusted == "untrusted" || trusted == "") + { + fail_msg_writer() << tr("This is not Tor/I2P address, and is not a trusted daemon."); + fail_msg_writer() << tr("Either use your own trusted node, connect via Tor or I2P, or pass this-is-probably-a-spy-node and be spied on."); + return true; + } + + if (parsed.schema != "https") + message_writer(console_color_red) << tr("Warning: connecting to a non-local daemon without SSL, passive adversaries will be able to spy on you."); + } + + LOCK_IDLE_SCOPE(); + m_wallet->init(daemon_url); + + if (!trusted.empty()) + { + m_wallet->set_trusted_daemon(trusted == "trusted"); + } else { m_wallet->set_trusted_daemon(false); diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 91b3c0535..d80335db8 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -14179,6 +14179,7 @@ std::vector wallet2::get_public_nodes(bool white_only) req.white = true; req.gray = !white_only; + req.include_blocked = false; { const boost::lock_guard lock{m_daemon_rpc_mutex};