protocol: drop peers that don't reply to queries

This commit is contained in:
moneromooo 2020-12-03 13:22:52 +00:00 committed by wowario
parent f8ec114820
commit 27cfbe1a22
No known key found for this signature in database
GPG Key ID: 24DCBE762DE9C111
4 changed files with 43 additions and 19 deletions

View File

@ -94,11 +94,10 @@ namespace epee { namespace net_utils
network_address::interface const* const other_self = other.self.get(); network_address::interface const* const other_self = other.self.get();
if (self_ == other_self) return true; if (self_ == other_self) return true;
if (!self_ || !other_self) return false; if (!self_ || !other_self) return false;
const bool this_is_4 = get_type_id() == epee::net_utils::ipv4_network_address::get_type_id(); if (typeid(*self_) == typeid(*other_self))
const bool this_is_6 = get_type_id() == epee::net_utils::ipv6_network_address::get_type_id(); return self_->is_same_host(*other_self);
const bool other_is_4 = other.get_type_id() == epee::net_utils::ipv4_network_address::get_type_id(); const auto this_id = get_type_id();
const bool other_is_6 = other.get_type_id() == epee::net_utils::ipv6_network_address::get_type_id(); if (this_id == ipv4_network_address::get_type_id() && other.get_type_id() == ipv6_network_address::get_type_id())
if (this_is_4 && other_is_6)
{ {
const boost::asio::ip::address_v6 &actual_ip = other.as<const epee::net_utils::ipv6_network_address>().ip(); const boost::asio::ip::address_v6 &actual_ip = other.as<const epee::net_utils::ipv6_network_address>().ip();
if (actual_ip.is_v4_mapped()) if (actual_ip.is_v4_mapped())
@ -107,7 +106,7 @@ namespace epee { namespace net_utils
return is_same_host(ipv4_network_address(v4ip, 0)); return is_same_host(ipv4_network_address(v4ip, 0));
} }
} }
else if (this_is_6 && other_is_4) else if (this_id == ipv6_network_address::get_type_id() && other.get_type_id() == ipv4_network_address::get_type_id())
{ {
const boost::asio::ip::address_v6 &actual_ip = this->as<const epee::net_utils::ipv6_network_address>().ip(); const boost::asio::ip::address_v6 &actual_ip = this->as<const epee::net_utils::ipv6_network_address>().ip();
if (actual_ip.is_v4_mapped()) if (actual_ip.is_v4_mapped())
@ -116,8 +115,7 @@ namespace epee { namespace net_utils
return other.is_same_host(ipv4_network_address(v4ip, 0)); return other.is_same_host(ipv4_network_address(v4ip, 0));
} }
} }
if (typeid(*self_) != typeid(*other_self)) return false; return false;
return self_->is_same_host(*other_self);
} }
std::string print_connection_context(const connection_context_base& ctx) std::string print_connection_context(const connection_context_base& ctx)

View File

@ -43,7 +43,8 @@ namespace cryptonote
{ {
cryptonote_connection_context(): m_state(state_before_handshake), m_remote_blockchain_height(0), m_last_response_height(0), cryptonote_connection_context(): m_state(state_before_handshake), m_remote_blockchain_height(0), m_last_response_height(0),
m_last_request_time(boost::date_time::not_a_date_time), m_callback_request_count(0), m_last_request_time(boost::date_time::not_a_date_time), m_callback_request_count(0),
m_last_known_hash(crypto::null_hash), m_pruning_seed(0), m_rpc_port(0), m_rpc_credits_per_hash(0), m_anchor(false), m_score(0) {} m_last_known_hash(crypto::null_hash), m_pruning_seed(0), m_rpc_port(0), m_rpc_credits_per_hash(0), m_anchor(false), m_score(0),
m_expect_response(0) {}
enum state enum state
{ {
@ -67,6 +68,7 @@ namespace cryptonote
uint32_t m_rpc_credits_per_hash; uint32_t m_rpc_credits_per_hash;
bool m_anchor; bool m_anchor;
int32_t m_score; int32_t m_score;
int m_expect_response;
}; };
inline std::string get_protocol_state_string(cryptonote_connection_context::state s) inline std::string get_protocol_state_string(cryptonote_connection_context::state s)

View File

@ -161,7 +161,7 @@ namespace cryptonote
std::atomic<bool> m_ask_for_txpool_complement; std::atomic<bool> m_ask_for_txpool_complement;
boost::mutex m_sync_lock; boost::mutex m_sync_lock;
block_queue m_block_queue; block_queue m_block_queue;
epee::math_helper::once_a_time_seconds<30> m_idle_peer_kicker; epee::math_helper::once_a_time_seconds<8> m_idle_peer_kicker;
epee::math_helper::once_a_time_milliseconds<100> m_standby_checker; epee::math_helper::once_a_time_milliseconds<100> m_standby_checker;
epee::math_helper::once_a_time_seconds<101> m_sync_search_checker; epee::math_helper::once_a_time_seconds<101> m_sync_search_checker;
epee::math_helper::once_a_time_seconds<43> m_bad_peer_checker; epee::math_helper::once_a_time_seconds<43> m_bad_peer_checker;

View File

@ -69,6 +69,7 @@
#define REQUEST_NEXT_SCHEDULED_SPAN_THRESHOLD_STANDBY (5 * 1000000) // microseconds #define REQUEST_NEXT_SCHEDULED_SPAN_THRESHOLD_STANDBY (5 * 1000000) // microseconds
#define REQUEST_NEXT_SCHEDULED_SPAN_THRESHOLD (30 * 1000000) // microseconds #define REQUEST_NEXT_SCHEDULED_SPAN_THRESHOLD (30 * 1000000) // microseconds
#define IDLE_PEER_KICK_TIME (240 * 1000000) // microseconds #define IDLE_PEER_KICK_TIME (240 * 1000000) // microseconds
#define NON_RESPONSIVE_PEER_KICK_TIME (20 * 1000000) // microseconds
#define PASSIVE_PEER_KICK_TIME (60 * 1000000) // microseconds #define PASSIVE_PEER_KICK_TIME (60 * 1000000) // microseconds
#define DROP_ON_SYNC_WEDGE_THRESHOLD (30 * 1000000000ull) // nanoseconds #define DROP_ON_SYNC_WEDGE_THRESHOLD (30 * 1000000000ull) // nanoseconds
#define LAST_ACTIVITY_STALL_THRESHOLD (2.0f) // seconds #define LAST_ACTIVITY_STALL_THRESHOLD (2.0f) // seconds
@ -144,6 +145,7 @@ namespace cryptonote
handler_request_blocks_history( r.block_ids ); // change the limit(?), sleep(?) handler_request_blocks_history( r.block_ids ); // change the limit(?), sleep(?)
r.prune = m_sync_pruned_blocks; r.prune = m_sync_pruned_blocks;
context.m_last_request_time = boost::posix_time::microsec_clock::universal_time(); context.m_last_request_time = boost::posix_time::microsec_clock::universal_time();
context.m_expect_response = NOTIFY_RESPONSE_CHAIN_ENTRY::ID;
MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size() ); MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size() );
post_notify<NOTIFY_REQUEST_CHAIN>(r, context); post_notify<NOTIFY_REQUEST_CHAIN>(r, context);
MLOG_PEER_STATE("requesting chain"); MLOG_PEER_STATE("requesting chain");
@ -495,6 +497,7 @@ namespace cryptonote
r.prune = m_sync_pruned_blocks; r.prune = m_sync_pruned_blocks;
handler_request_blocks_history( r.block_ids ); // change the limit(?), sleep(?) handler_request_blocks_history( r.block_ids ); // change the limit(?), sleep(?)
context.m_last_request_time = boost::posix_time::microsec_clock::universal_time(); context.m_last_request_time = boost::posix_time::microsec_clock::universal_time();
context.m_expect_response = NOTIFY_RESPONSE_CHAIN_ENTRY::ID;
MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size() ); MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size() );
post_notify<NOTIFY_REQUEST_CHAIN>(r, context); post_notify<NOTIFY_REQUEST_CHAIN>(r, context);
MLOG_PEER_STATE("requesting chain"); MLOG_PEER_STATE("requesting chain");
@ -774,6 +777,7 @@ namespace cryptonote
handler_request_blocks_history( r.block_ids ); // change the limit(?), sleep(?) handler_request_blocks_history( r.block_ids ); // change the limit(?), sleep(?)
r.prune = m_sync_pruned_blocks; r.prune = m_sync_pruned_blocks;
context.m_last_request_time = boost::posix_time::microsec_clock::universal_time(); context.m_last_request_time = boost::posix_time::microsec_clock::universal_time();
context.m_expect_response = NOTIFY_RESPONSE_CHAIN_ENTRY::ID;
MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size() ); MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size() );
post_notify<NOTIFY_REQUEST_CHAIN>(r, context); post_notify<NOTIFY_REQUEST_CHAIN>(r, context);
MLOG_PEER_STATE("requesting chain"); MLOG_PEER_STATE("requesting chain");
@ -1072,6 +1076,14 @@ namespace cryptonote
boost::posix_time::ptime request_time = context.m_last_request_time; boost::posix_time::ptime request_time = context.m_last_request_time;
context.m_last_request_time = boost::date_time::not_a_date_time; context.m_last_request_time = boost::date_time::not_a_date_time;
if (context.m_expect_response != NOTIFY_RESPONSE_GET_OBJECTS::ID)
{
LOG_ERROR_CCONTEXT("Got NOTIFY_RESPONSE_GET_OBJECTS out of the blue, dropping connection");
drop_connection(context, true, false);
return 1;
}
context.m_expect_response = 0;
// calculate size of request // calculate size of request
size_t size = 0; size_t size = 0;
size_t blocks_size = 0; size_t blocks_size = 0;
@ -1681,41 +1693,43 @@ skip:
bool t_cryptonote_protocol_handler<t_core>::kick_idle_peers() bool t_cryptonote_protocol_handler<t_core>::kick_idle_peers()
{ {
MTRACE("Checking for idle peers..."); MTRACE("Checking for idle peers...");
std::vector<boost::uuids::uuid> idle_peers; std::vector<std::pair<boost::uuids::uuid, unsigned>> idle_peers;
m_p2p->for_each_connection([&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)->bool m_p2p->for_each_connection([&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)->bool
{ {
if (context.m_state == cryptonote_connection_context::state_synchronizing && context.m_last_request_time != boost::date_time::not_a_date_time) if (context.m_state == cryptonote_connection_context::state_synchronizing && context.m_last_request_time != boost::date_time::not_a_date_time)
{ {
const boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time(); const boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time();
const boost::posix_time::time_duration dt = now - context.m_last_request_time; const boost::posix_time::time_duration dt = now - context.m_last_request_time;
if (dt.total_microseconds() > IDLE_PEER_KICK_TIME) const auto ms = dt.total_microseconds();
if (ms > IDLE_PEER_KICK_TIME || (context.m_expect_response && ms > NON_RESPONSIVE_PEER_KICK_TIME))
{ {
if (context.m_score-- >= 0) if (context.m_score-- >= 0)
{ {
MINFO(context << " kicking idle peer, last update " << (dt.total_microseconds() / 1.e6) << " seconds ago"); MINFO(context << " kicking idle peer, last update " << (dt.total_microseconds() / 1.e6) << " seconds ago, expecting " << (int)context.m_expect_response);
LOG_PRINT_CCONTEXT_L2("requesting callback"); LOG_PRINT_CCONTEXT_L2("requesting callback");
context.m_last_request_time = boost::date_time::not_a_date_time; context.m_last_request_time = boost::date_time::not_a_date_time;
context.m_expect_response = 0;
context.m_state = cryptonote_connection_context::state_standby; // we'll go back to adding, then (if we can't), download context.m_state = cryptonote_connection_context::state_standby; // we'll go back to adding, then (if we can't), download
++context.m_callback_request_count; ++context.m_callback_request_count;
m_p2p->request_callback(context); m_p2p->request_callback(context);
} }
else else
{ {
idle_peers.push_back(context.m_connection_id); idle_peers.push_back(std::make_pair(context.m_connection_id, context.m_expect_response == 0 ? 1 : 5));
} }
} }
} }
return true; return true;
}); });
for (const auto &uuid: idle_peers) for (const auto &e: idle_peers)
{ {
if (!m_p2p->for_connection(uuid, [&](cryptonote_connection_context& ctx, nodetool::peerid_type peer_id, uint32_t f)->bool{ const auto &uuid = e.first;
m_p2p->for_connection(uuid, [&](cryptonote_connection_context& ctx, nodetool::peerid_type peer_id, uint32_t f)->bool{
MINFO(ctx << "dropping idle peer with negative score"); MINFO(ctx << "dropping idle peer with negative score");
drop_connection(ctx, true, false); drop_connection_with_score(ctx, e.second, false);
return true; return true;
})) });
MDEBUG("Failed to find peer we wanted to drop");
} }
return true; return true;
@ -2240,6 +2254,7 @@ skip:
} }
} }
context.m_last_request_time = boost::posix_time::microsec_clock::universal_time(); context.m_last_request_time = boost::posix_time::microsec_clock::universal_time();
context.m_expect_response = NOTIFY_RESPONSE_GET_OBJECTS::ID;
MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_GET_OBJECTS: blocks.size()=" << req.blocks.size() MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_GET_OBJECTS: blocks.size()=" << req.blocks.size()
<< "requested blocks count=" << count << " / " << count_limit << " from " << span.first << ", first hash " << req.blocks.front()); << "requested blocks count=" << count << " / " << count_limit << " from " << span.first << ", first hash " << req.blocks.front());
//epee::net_utils::network_throttle_manager::get_global_throttle_inreq().logger_handle_net("log/dr-monero/net/req-all.data", sec, get_avg_block_size()); //epee::net_utils::network_throttle_manager::get_global_throttle_inreq().logger_handle_net("log/dr-monero/net/req-all.data", sec, get_avg_block_size());
@ -2330,6 +2345,7 @@ skip:
//LOG_PRINT_CCONTEXT_L1("r = " << 200); //LOG_PRINT_CCONTEXT_L1("r = " << 200);
context.m_last_request_time = boost::posix_time::microsec_clock::universal_time(); context.m_last_request_time = boost::posix_time::microsec_clock::universal_time();
context.m_expect_response = NOTIFY_RESPONSE_CHAIN_ENTRY::ID;
MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size() << ", start_from_current_chain " << start_from_current_chain); MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size() << ", start_from_current_chain " << start_from_current_chain);
post_notify<NOTIFY_REQUEST_CHAIN>(r, context); post_notify<NOTIFY_REQUEST_CHAIN>(r, context);
MLOG_PEER_STATE("requesting chain"); MLOG_PEER_STATE("requesting chain");
@ -2452,6 +2468,14 @@ skip:
<< ", m_start_height=" << arg.start_height << ", m_total_height=" << arg.total_height); << ", m_start_height=" << arg.start_height << ", m_total_height=" << arg.total_height);
MLOG_PEER_STATE("received chain"); MLOG_PEER_STATE("received chain");
if (context.m_expect_response != NOTIFY_RESPONSE_CHAIN_ENTRY::ID)
{
LOG_ERROR_CCONTEXT("Got NOTIFY_RESPONSE_CHAIN_ENTRY out of the blue, dropping connection");
drop_connection(context, true, false);
return 1;
}
context.m_expect_response = 0;
context.m_last_request_time = boost::date_time::not_a_date_time; context.m_last_request_time = boost::date_time::not_a_date_time;
m_sync_download_chain_size += arg.m_block_ids.size() * sizeof(crypto::hash); m_sync_download_chain_size += arg.m_block_ids.size() * sizeof(crypto::hash);