aboutsummaryrefslogtreecommitdiff
path: root/src/p2p/net_node.inl
diff options
context:
space:
mode:
Diffstat (limited to 'src/p2p/net_node.inl')
-rw-r--r--src/p2p/net_node.inl214
1 files changed, 162 insertions, 52 deletions
diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl
index aa16e93d5..2f47de0f0 100644
--- a/src/p2p/net_node.inl
+++ b/src/p2p/net_node.inl
@@ -106,6 +106,7 @@ namespace nodetool
command_line::add_arg(desc, arg_p2p_seed_node);
command_line::add_arg(desc, arg_tx_proxy);
command_line::add_arg(desc, arg_anonymous_inbound);
+ command_line::add_arg(desc, arg_ban_list);
command_line::add_arg(desc, arg_p2p_hide_my_port);
command_line::add_arg(desc, arg_no_sync);
command_line::add_arg(desc, arg_no_igd);
@@ -245,6 +246,10 @@ namespace nodetool
zone.second.m_net_server.get_config_object().close(c);
conns.clear();
+
+ peerlist_entry pe{};
+ pe.adr = addr;
+ zone.second.m_peerlist.remove_from_peer_white(pe);
}
MCLOG_CYAN(el::Level::Info, "global", "Host " << addr.host_str() << " blocked.");
@@ -386,7 +391,7 @@ namespace nodetool
m_use_ipv6 = command_line::get_arg(vm, arg_p2p_use_ipv6);
m_require_ipv4 = !command_line::get_arg(vm, arg_p2p_ignore_ipv4);
public_zone.m_notifier = cryptonote::levin::notify{
- public_zone.m_net_server.get_io_service(), public_zone.m_net_server.get_config_shared(), nullptr, true, pad_txs, m_payload_handler.get_core()
+ public_zone.m_net_server.get_io_service(), public_zone.m_net_server.get_config_shared(), nullptr, epee::net_utils::zone::public_, pad_txs, m_payload_handler.get_core()
};
if (command_line::has_arg(vm, arg_p2p_add_peer))
@@ -435,12 +440,42 @@ namespace nodetool
if (command_line::has_arg(vm, arg_p2p_seed_node))
{
- boost::unique_lock<boost::shared_mutex> lock(m_seed_nodes_lock);
+ boost::unique_lock<boost::shared_mutex> lock(public_zone.m_seed_nodes_lock);
- if (!parse_peers_and_add_to_container(vm, arg_p2p_seed_node, m_seed_nodes))
+ if (!parse_peers_and_add_to_container(vm, arg_p2p_seed_node, public_zone.m_seed_nodes))
return false;
}
+ if (!command_line::is_arg_defaulted(vm, arg_ban_list))
+ {
+ const std::string ban_list = command_line::get_arg(vm, arg_ban_list);
+
+ const boost::filesystem::path ban_list_path(ban_list);
+ boost::system::error_code ec;
+ if (!boost::filesystem::exists(ban_list_path, ec))
+ {
+ throw std::runtime_error("Can't find ban list file " + ban_list + " - " + ec.message());
+ }
+
+ std::string banned_ips;
+ if (!epee::file_io_utils::load_file_to_string(ban_list_path.string(), banned_ips))
+ {
+ throw std::runtime_error("Failed to read ban list file " + ban_list);
+ }
+
+ std::istringstream iss(banned_ips);
+ for (std::string line; std::getline(iss, line); )
+ {
+ const expect<epee::net_utils::network_address> parsed_addr = net::get_network_address(line, 0);
+ if (!parsed_addr)
+ {
+ MERROR("Invalid IP address: " << line << " - " << parsed_addr.error());
+ continue;
+ }
+ block_host(*parsed_addr, std::numeric_limits<time_t>::max());
+ }
+ }
+
if(command_line::has_arg(vm, arg_p2p_hide_my_port))
m_hide_my_port = true;
@@ -499,7 +534,7 @@ namespace nodetool
}
zone.m_notifier = cryptonote::levin::notify{
- zone.m_net_server.get_io_service(), zone.m_net_server.get_config_shared(), std::move(this_noise), false, pad_txs, m_payload_handler.get_core()
+ zone.m_net_server.get_io_service(), zone.m_net_server.get_config_shared(), std::move(this_noise), proxy.zone, pad_txs, m_payload_handler.get_core()
};
}
@@ -598,21 +633,21 @@ namespace nodetool
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
- std::set<std::string> node_server<t_payload_net_handler>::get_seed_nodes(cryptonote::network_type nettype) const
+ std::set<std::string> node_server<t_payload_net_handler>::get_ip_seed_nodes() const
{
std::set<std::string> full_addrs;
- if (nettype == cryptonote::TESTNET)
+ if (m_nettype == cryptonote::TESTNET)
{
full_addrs.insert("212.83.175.67:28080");
full_addrs.insert("212.83.172.165:28080");
full_addrs.insert("192.110.160.146:28080");
}
- else if (nettype == cryptonote::STAGENET)
+ else if (m_nettype == cryptonote::STAGENET)
{
full_addrs.insert("162.210.173.150:38080");
full_addrs.insert("192.110.160.146:38080");
}
- else if (nettype == cryptonote::FAKECHAIN)
+ else if (m_nettype == cryptonote::FAKECHAIN)
{
}
else
@@ -630,7 +665,7 @@ namespace nodetool
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
- std::set<std::string> node_server<t_payload_net_handler>::get_seed_nodes()
+ std::set<std::string> node_server<t_payload_net_handler>::get_dns_seed_nodes()
{
if (!m_exclusive_peers.empty() || m_offline)
{
@@ -638,11 +673,11 @@ namespace nodetool
}
if (m_nettype == cryptonote::TESTNET)
{
- return get_seed_nodes(cryptonote::TESTNET);
+ return get_ip_seed_nodes();
}
if (m_nettype == cryptonote::STAGENET)
{
- return get_seed_nodes(cryptonote::STAGENET);
+ return get_ip_seed_nodes();
}
std::set<std::string> full_addrs;
@@ -730,7 +765,7 @@ namespace nodetool
else
MINFO("Not enough DNS seed nodes found, using fallback defaults too");
- for (const auto &peer: get_seed_nodes(cryptonote::MAINNET))
+ for (const auto &peer: get_ip_seed_nodes())
full_addrs.insert(peer);
m_fallback_seed_nodes_added.test_and_set();
}
@@ -739,6 +774,23 @@ namespace nodetool
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
+ std::set<std::string> node_server<t_payload_net_handler>::get_seed_nodes(epee::net_utils::zone zone)
+ {
+ switch (zone)
+ {
+ case epee::net_utils::zone::public_:
+ return get_dns_seed_nodes();
+ case epee::net_utils::zone::tor:
+ return {};
+ case epee::net_utils::zone::i2p:
+ return {};
+ default:
+ break;
+ }
+ throw std::logic_error{"Bad zone given to get_seed_nodes"};
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
typename node_server<t_payload_net_handler>::network_zone& node_server<t_payload_net_handler>::add_zone(const epee::net_utils::zone zone)
{
const auto zone_ = m_network_zones.lower_bound(zone);
@@ -1432,17 +1484,46 @@ namespace nodetool
const uint32_t actual_ip = na.as<const epee::net_utils::ipv4_network_address>().ip();
classB.insert(actual_ip & 0x0000ffff);
}
+#if BOOST_VERSION > 106600
+ else if (cntxt.m_remote_address.get_type_id() == epee::net_utils::ipv6_network_address::get_type_id())
+ {
+ const epee::net_utils::network_address na = cntxt.m_remote_address;
+ const boost::asio::ip::address_v6 &actual_ip = na.as<const epee::net_utils::ipv6_network_address>().ip();
+ if (actual_ip.is_v4_mapped())
+ {
+ boost::asio::ip::address_v4 v4ip = make_address_v4(boost::asio::ip::v4_mapped, actual_ip);
+ uint32_t actual_ipv4;
+ memcpy(&actual_ipv4, v4ip.to_bytes().data(), sizeof(actual_ipv4));
+ classB.insert(actual_ipv4 & ntohl(0xffff0000));
+ }
+ }
+#endif
return true;
});
}
+ auto get_host_string = [](const epee::net_utils::network_address &address) {
+#if BOOST_VERSION > 106600
+ if (address.get_type_id() == epee::net_utils::ipv6_network_address::get_type_id())
+ {
+ boost::asio::ip::address_v6 actual_ip = address.as<const epee::net_utils::ipv6_network_address>().ip();
+ if (actual_ip.is_v4_mapped())
+ {
+ boost::asio::ip::address_v4 v4ip = make_address_v4(boost::asio::ip::v4_mapped, actual_ip);
+ return epee::net_utils::ipv4_network_address(v4ip.to_uint(), 0).host_str();
+ }
+ }
+#endif
+ return address.host_str();
+ };
+ std::unordered_set<std::string> hosts_added;
std::deque<size_t> filtered;
const size_t limit = use_white_list ? 20 : std::numeric_limits<size_t>::max();
for (int step = 0; step < 2; ++step)
{
bool skip_duplicate_class_B = step == 0;
size_t idx = 0, skipped = 0;
- zone.m_peerlist.foreach (use_white_list, [&classB, &filtered, &idx, &skipped, skip_duplicate_class_B, limit, next_needed_pruning_stripe](const peerlist_entry &pe){
+ zone.m_peerlist.foreach (use_white_list, [&classB, &filtered, &idx, &skipped, skip_duplicate_class_B, limit, next_needed_pruning_stripe, &hosts_added, &get_host_string](const peerlist_entry &pe){
if (filtered.size() >= limit)
return false;
bool skip = false;
@@ -1452,6 +1533,29 @@ namespace nodetool
uint32_t actual_ip = na.as<const epee::net_utils::ipv4_network_address>().ip();
skip = classB.find(actual_ip & 0x0000ffff) != classB.end();
}
+#if BOOST_VERSION > 106600
+ else if (skip_duplicate_class_B && pe.adr.get_type_id() == epee::net_utils::ipv6_network_address::get_type_id())
+ {
+ const epee::net_utils::network_address na = pe.adr;
+ const boost::asio::ip::address_v6 &actual_ip = na.as<const epee::net_utils::ipv6_network_address>().ip();
+ if (actual_ip.is_v4_mapped())
+ {
+ boost::asio::ip::address_v4 v4ip = make_address_v4(boost::asio::ip::v4_mapped, actual_ip);
+ uint32_t actual_ipv4;
+ memcpy(&actual_ipv4, v4ip.to_bytes().data(), sizeof(actual_ipv4));
+ skip = classB.find(actual_ipv4 & ntohl(0xffff0000)) != classB.end();
+ }
+ }
+#endif
+
+ // consider each host once, to avoid giving undue inflence to hosts running several nodes
+ if (!skip)
+ {
+ const auto i = hosts_added.find(get_host_string(pe.adr));
+ if (i != hosts_added.end())
+ skip = true;
+ }
+
if (skip)
++skipped;
else if (next_needed_pruning_stripe == 0 || pe.pruning_seed == 0)
@@ -1459,16 +1563,17 @@ namespace nodetool
else if (next_needed_pruning_stripe == tools::get_pruning_stripe(pe.pruning_seed))
filtered.push_front(idx);
++idx;
+ hosts_added.insert(get_host_string(pe.adr));
return true;
});
if (skipped == 0 || !filtered.empty())
break;
if (skipped)
- MINFO("Skipping " << skipped << " possible peers as they share a class B with existing peers");
+ MDEBUG("Skipping " << skipped << " possible peers as they share a class B with existing peers");
}
if (filtered.empty())
{
- MDEBUG("No available peer in " << (use_white_list ? "white" : "gray") << " list filtered by " << next_needed_pruning_stripe);
+ MINFO("No available peer in " << (use_white_list ? "white" : "gray") << " list filtered by " << next_needed_pruning_stripe);
return false;
}
if (use_white_list)
@@ -1541,56 +1646,59 @@ namespace nodetool
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
- bool node_server<t_payload_net_handler>::connect_to_seed()
+ bool node_server<t_payload_net_handler>::connect_to_seed(epee::net_utils::zone zone)
{
- boost::upgrade_lock<boost::shared_mutex> seed_nodes_upgrade_lock(m_seed_nodes_lock);
+ network_zone& server = m_network_zones.at(zone);
+ boost::upgrade_lock<boost::shared_mutex> seed_nodes_upgrade_lock(server.m_seed_nodes_lock);
- if (!m_seed_nodes_initialized)
+ if (!server.m_seed_nodes_initialized)
{
+ const std::uint16_t default_port = cryptonote::get_config(m_nettype).P2P_DEFAULT_PORT;
boost::upgrade_to_unique_lock<boost::shared_mutex> seed_nodes_lock(seed_nodes_upgrade_lock);
- m_seed_nodes_initialized = true;
- for (const auto& full_addr : get_seed_nodes())
+ server.m_seed_nodes_initialized = true;
+ for (const auto& full_addr : get_seed_nodes(zone))
{
+ // seeds should have hostname converted to IP already
MDEBUG("Seed node: " << full_addr);
- append_net_address(m_seed_nodes, full_addr, cryptonote::get_config(m_nettype).P2P_DEFAULT_PORT);
+ server.m_seed_nodes.push_back(MONERO_UNWRAP(net::get_network_address(full_addr, default_port)));
}
- MDEBUG("Number of seed nodes: " << m_seed_nodes.size());
+ MDEBUG("Number of seed nodes: " << server.m_seed_nodes.size());
}
- if (m_seed_nodes.empty() || m_offline || !m_exclusive_peers.empty())
+ if (server.m_seed_nodes.empty() || m_offline || !m_exclusive_peers.empty())
return true;
size_t try_count = 0;
bool is_connected_to_at_least_one_seed_node = false;
- size_t current_index = crypto::rand_idx(m_seed_nodes.size());
- const net_server& server = m_network_zones.at(epee::net_utils::zone::public_).m_net_server;
+ size_t current_index = crypto::rand_idx(server.m_seed_nodes.size());
while(true)
{
- if(server.is_stop_signal_sent())
+ if(server.m_net_server.is_stop_signal_sent())
return false;
peerlist_entry pe_seed{};
- pe_seed.adr = m_seed_nodes[current_index];
+ pe_seed.adr = server.m_seed_nodes[current_index];
if (is_peer_used(pe_seed))
is_connected_to_at_least_one_seed_node = true;
- else if (try_to_connect_and_handshake_with_new_peer(m_seed_nodes[current_index], true))
+ else if (try_to_connect_and_handshake_with_new_peer(server.m_seed_nodes[current_index], true))
break;
- if(++try_count > m_seed_nodes.size())
+ if(++try_count > server.m_seed_nodes.size())
{
- if (!m_fallback_seed_nodes_added.test_and_set())
+ // only IP zone has fallback (to direct IP) seeds
+ if (zone == epee::net_utils::zone::public_ && !m_fallback_seed_nodes_added.test_and_set())
{
MWARNING("Failed to connect to any of seed peers, trying fallback seeds");
- current_index = m_seed_nodes.size() - 1;
+ current_index = server.m_seed_nodes.size() - 1;
{
boost::upgrade_to_unique_lock<boost::shared_mutex> seed_nodes_lock(seed_nodes_upgrade_lock);
- for (const auto &peer: get_seed_nodes(m_nettype))
+ for (const auto &peer: get_ip_seed_nodes())
{
MDEBUG("Fallback seed node: " << peer);
- append_net_address(m_seed_nodes, peer, cryptonote::get_config(m_nettype).P2P_DEFAULT_PORT);
+ append_net_address(server.m_seed_nodes, peer, cryptonote::get_config(m_nettype).P2P_DEFAULT_PORT);
}
}
- if (current_index == m_seed_nodes.size() - 1)
+ if (current_index == server.m_seed_nodes.size() - 1)
{
MWARNING("No fallback seeds, continuing without seeds");
break;
@@ -1604,7 +1712,7 @@ namespace nodetool
break;
}
}
- if(++current_index >= m_seed_nodes.size())
+ if(++current_index >= server.m_seed_nodes.size())
current_index = 0;
}
return true;
@@ -1620,20 +1728,21 @@ namespace nodetool
if (!m_exclusive_peers.empty()) return true;
- // Only have seeds in the public zone right now.
-
- size_t start_conn_count = get_public_outgoing_connections_count();
- if(!get_public_white_peers_count() && !connect_to_seed())
+ bool one_succeeded = false;
+ for(auto& zone : m_network_zones)
{
- return false;
- }
+ size_t start_conn_count = get_outgoing_connections_count(zone.second);
+ if(!zone.second.m_peerlist.get_white_peers_count() && !connect_to_seed(zone.first))
+ {
+ continue;
+ }
- if (!connect_to_peerlist(m_priority_peers)) return false;
+ if (zone.first == zone_type::public_ && !connect_to_peerlist(m_priority_peers)) continue;
- for(auto& zone : m_network_zones)
- {
size_t base_expected_white_connections = (zone.second.m_config.m_net_config.max_out_connection_count*P2P_DEFAULT_WHITELIST_CONNECTIONS_PERCENT)/100;
+ // carefully avoid `continue` in nested loop
+
size_t conn_count = get_outgoing_connections_count(zone.second);
while(conn_count < zone.second.m_config.m_net_config.max_out_connection_count)
{
@@ -1670,16 +1779,17 @@ namespace nodetool
}
conn_count = new_conn_count;
}
- }
- if (start_conn_count == get_public_outgoing_connections_count() && start_conn_count < m_network_zones.at(zone_type::public_).m_config.m_net_config.max_out_connection_count)
- {
- MINFO("Failed to connect to any, trying seeds");
- if (!connect_to_seed())
- return false;
+ if (start_conn_count == get_outgoing_connections_count(zone.second) && start_conn_count < zone.second.m_config.m_net_config.max_out_connection_count)
+ {
+ MINFO("Failed to connect to any, trying seeds");
+ if (!connect_to_seed(zone.first))
+ continue;
+ }
+ one_succeeded = true;
}
- return true;
+ return one_succeeded;
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
@@ -2095,7 +2205,7 @@ namespace nodetool
const epee::net_utils::network_address na = context.m_remote_address;
std::string ip;
- uint32_t ipv4_addr;
+ uint32_t ipv4_addr = 0;
boost::asio::ip::address_v6 ipv6_addr;
bool is_ipv4;
if (na.get_type_id() == epee::net_utils::ipv4_network_address::get_type_id())