Merge pull request #7173

d2fda6c25 restrict public node checks a little (moneromooo-monero)
This commit is contained in:
Alexander Blair 2020-12-26 13:41:41 -08:00
commit d06bae56b3
No known key found for this signature in database
GPG key ID: C64552D877C32479
7 changed files with 68 additions and 11 deletions

View file

@ -871,10 +871,19 @@ std::string get_nix_version_display_string()
return max_concurrency; 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) bool is_local_address(const std::string &address)
{ {
// always assume Tor/I2P addresses to be untrusted by default // 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"); MDEBUG("Address '" << address << "' is Tor/I2P, non local");
return false; return false;

View file

@ -228,6 +228,7 @@ namespace tools
unsigned get_max_concurrency(); unsigned get_max_concurrency();
bool is_local_address(const std::string &address); 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 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); bool sha256sum(const uint8_t *data, size_t len, crypto::hash &hash);

View file

@ -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; cryptonote::COMMAND_RPC_GET_PEER_LIST::response res;
std::string failure_message = "Couldn't retrieve peer list"; std::string failure_message = "Couldn't retrieve peer list";
req.include_blocked = true;
if (m_is_rpc) if (m_is_rpc)
{ {
if (!m_rpc_client->rpc_request(req, res, "/get_peer_list", failure_message.c_str())) 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"; std::string failure_message = "Couldn't retrieve peer list";
req.public_only = false; req.public_only = false;
req.include_blocked = true;
if (m_is_rpc) if (m_is_rpc)
{ {

View file

@ -190,6 +190,7 @@ namespace cryptonote
request.gray = true; request.gray = true;
request.white = true; request.white = true;
request.include_blocked = false;
if (!on_get_public_nodes(request, response) || response.status != CORE_RPC_STATUS_OK) if (!on_get_public_nodes(request, response) || response.status != CORE_RPC_STATUS_OK)
{ {
return {}; return {};
@ -1383,6 +1384,8 @@ namespace cryptonote
for (auto & entry : white_list) 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()) 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<epee::net_utils::ipv4_network_address>().ip(), res.white_list.emplace_back(entry.id, entry.adr.as<epee::net_utils::ipv4_network_address>().ip(),
entry.adr.as<epee::net_utils::ipv4_network_address>().port(), entry.last_seen, entry.pruning_seed, entry.rpc_port, entry.rpc_credits_per_hash); entry.adr.as<epee::net_utils::ipv4_network_address>().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) 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()) 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<epee::net_utils::ipv4_network_address>().ip(), res.gray_list.emplace_back(entry.id, entry.adr.as<epee::net_utils::ipv4_network_address>().ip(),
entry.adr.as<epee::net_utils::ipv4_network_address>().port(), entry.last_seen, entry.pruning_seed, entry.rpc_port, entry.rpc_credits_per_hash); entry.adr.as<epee::net_utils::ipv4_network_address>().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); RPC_TRACKER(get_public_nodes);
COMMAND_RPC_GET_PEER_LIST::request peer_list_req;
COMMAND_RPC_GET_PEER_LIST::response peer_list_res; 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; res.status = peer_list_res.status;
if (!success) if (!success)
{ {

View file

@ -88,7 +88,7 @@ namespace cryptonote
// advance which version they will stop working with // advance which version they will stop working with
// Don't go over 32767 for any of these // Don't go over 32767 for any of these
#define CORE_RPC_VERSION_MAJOR 3 #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 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) #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 struct request_t: public rpc_request_base
{ {
bool public_only; bool public_only;
bool include_blocked;
BEGIN_KV_SERIALIZE_MAP() BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE_PARENT(rpc_request_base) KV_SERIALIZE_PARENT(rpc_request_base)
KV_SERIALIZE_OPT(public_only, true) KV_SERIALIZE_OPT(public_only, true)
KV_SERIALIZE_OPT(include_blocked, false)
END_KV_SERIALIZE_MAP() END_KV_SERIALIZE_MAP()
}; };
typedef epee::misc_utils::struct_init<request_t> request; typedef epee::misc_utils::struct_init<request_t> request;
@ -1244,11 +1246,13 @@ namespace cryptonote
{ {
bool gray; bool gray;
bool white; bool white;
bool include_blocked;
BEGIN_KV_SERIALIZE_MAP() BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE_PARENT(rpc_request_base) KV_SERIALIZE_PARENT(rpc_request_base)
KV_SERIALIZE_OPT(gray, false) KV_SERIALIZE_OPT(gray, false)
KV_SERIALIZE_OPT(white, true) KV_SERIALIZE_OPT(white, true)
KV_SERIALIZE_OPT(include_blocked, false)
END_KV_SERIALIZE_MAP() END_KV_SERIALIZE_MAP()
}; };
typedef epee::misc_utils::struct_init<request_t> request; typedef epee::misc_utils::struct_init<request_t> request;

View file

@ -182,7 +182,7 @@ namespace
const command_line::arg_descriptor< std::vector<std::string> > arg_command = {"command", ""}; const command_line::arg_descriptor< std::vector<std::string> > arg_command = {"command", ""};
const char* USAGE_START_MINING("start_mining [<number_of_threads>] [bg_mining] [ignore_battery]"); const char* USAGE_START_MINING("start_mining [<number_of_threads>] [bg_mining] [ignore_battery]");
const char* USAGE_SET_DAEMON("set_daemon <host>[:<port>] [trusted|untrusted]"); const char* USAGE_SET_DAEMON("set_daemon <host>[:<port>] [trusted|untrusted|this-is-probably-a-spy-node]");
const char* USAGE_SHOW_BALANCE("balance [detail]"); const char* USAGE_SHOW_BALANCE("balance [detail]");
const char* USAGE_INCOMING_TRANSFERS("incoming_transfers [available|unavailable] [verbose] [uses] [index=<N1>[,<N2>[,...]]]"); const char* USAGE_INCOMING_TRANSFERS("incoming_transfers [available|unavailable] [verbose] [uses] [index=<N1>[,<N2>[,...]]]");
const char* USAGE_PAYMENTS("payments <PID_1> [<PID_2> ... <PID_N>]"); const char* USAGE_PAYMENTS("payments <PID_1> [<PID_2> ... <PID_N>]");
@ -2287,6 +2287,7 @@ bool simple_wallet::public_nodes(const std::vector<std::string> &args)
{ {
fail_msg_writer() << tr("Error retrieving public node list: ") << e.what(); 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; return true;
} }
@ -3241,7 +3242,7 @@ simple_wallet::simple_wallet()
m_cmd_binder.set_handler("set_daemon", m_cmd_binder.set_handler("set_daemon",
boost::bind(&simple_wallet::on_command, this, &simple_wallet::set_daemon, _1), boost::bind(&simple_wallet::on_command, this, &simple_wallet::set_daemon, _1),
tr(USAGE_SET_DAEMON), 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", m_cmd_binder.set_handler("save_bc",
boost::bind(&simple_wallet::on_command, this, &simple_wallet::save_bc, _1), boost::bind(&simple_wallet::on_command, this, &simple_wallet::save_bc, _1),
tr("Save the current blockchain data.")); tr("Save the current blockchain data."));
@ -5528,21 +5529,51 @@ bool simple_wallet::set_daemon(const std::vector<std::string>& args)
} else { } else {
daemon_url = args[0]; 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.size() == 2)
{ {
if (args[1] == "trusted") if (args[1] == "trusted")
m_wallet->set_trusted_daemon(true); trusted = "trusted";
else if (args[1] == "untrusted") 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 else
{ {
fail_msg_writer() << tr("Expected trusted or untrusted, got ") << args[1] << ": assuming untrusted"; fail_msg_writer() << tr("Expected trusted, untrusted or this-is-probably-a-spy-node got ") << args[1];
m_wallet->set_trusted_daemon(false); 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 else
{ {
m_wallet->set_trusted_daemon(false); m_wallet->set_trusted_daemon(false);

View file

@ -14179,6 +14179,7 @@ std::vector<cryptonote::public_node> wallet2::get_public_nodes(bool white_only)
req.white = true; req.white = true;
req.gray = !white_only; req.gray = !white_only;
req.include_blocked = false;
{ {
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex}; const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};