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
This commit is contained in:
parent
3bd6ed94d7
commit
d2fda6c25f
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -181,7 +181,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>]");
|
||||||
|
@ -2286,6 +2286,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3240,7 +3241,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."));
|
||||||
|
@ -5527,21 +5528,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);
|
||||||
|
|
|
@ -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};
|
||||||
|
|
Loading…
Reference in New Issue