aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorluigi1111 <luigi1111w@gmail.com>2020-12-07 10:04:08 -0600
committerluigi1111 <luigi1111w@gmail.com>2020-12-07 10:04:08 -0600
commit6d35b667cf2891fcd0ab228d01b13ec9be7cb50d (patch)
tree14f6c5bfcc6ce9635afd88812e0f369531cbb70a
parentMerge pull request #7059 (diff)
parentprotocol: drop peers that don't reply to queries (diff)
downloadmonero-6d35b667cf2891fcd0ab228d01b13ec9be7cb50d.tar.xz
Merge pull request #7054
ce26c5b protocol: drop peers that don't reply to queries (moneromooo) 9427b5a keep only the last seen node on a given host in the white list (moneromooo) fa79148 protocol: drop peers that decrease claimed height (moneromooo) 1382b17 protocol: add scoring system to drop peers that don't behave (moneromooo)
-rw-r--r--contrib/epee/src/net_utils_base.cpp35
-rw-r--r--src/cryptonote_basic/connection_context.h6
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.h6
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.inl98
-rw-r--r--src/p2p/net_peerlist.cpp13
-rw-r--r--src/p2p/net_peerlist.h2
6 files changed, 144 insertions, 16 deletions
diff --git a/contrib/epee/src/net_utils_base.cpp b/contrib/epee/src/net_utils_base.cpp
index 5cc49cc71..a2ca3d3d6 100644
--- a/contrib/epee/src/net_utils_base.cpp
+++ b/contrib/epee/src/net_utils_base.cpp
@@ -6,6 +6,17 @@
#include "string_tools.h"
#include "net/local_ip.h"
+static inline uint32_t make_address_v4_from_v6(const boost::asio::ip::address_v6& a)
+{
+ const auto &bytes = a.to_bytes();
+ uint32_t v4 = 0;
+ v4 = (v4 << 8) | bytes[12];
+ v4 = (v4 << 8) | bytes[13];
+ v4 = (v4 << 8) | bytes[14];
+ v4 = (v4 << 8) | bytes[15];
+ return htonl(v4);
+}
+
namespace epee { namespace net_utils
{
bool ipv4_network_address::equal(const ipv4_network_address& other) const noexcept
@@ -83,8 +94,28 @@ namespace epee { namespace net_utils
network_address::interface const* const other_self = other.self.get();
if (self_ == other_self) return true;
if (!self_ || !other_self) return false;
- if (typeid(*self_) != typeid(*other_self)) return false;
- return self_->is_same_host(*other_self);
+ if (typeid(*self_) == typeid(*other_self))
+ return self_->is_same_host(*other_self);
+ const auto this_id = get_type_id();
+ if (this_id == ipv4_network_address::get_type_id() && other.get_type_id() == ipv6_network_address::get_type_id())
+ {
+ const boost::asio::ip::address_v6 &actual_ip = other.as<const epee::net_utils::ipv6_network_address>().ip();
+ if (actual_ip.is_v4_mapped())
+ {
+ const uint32_t v4ip = make_address_v4_from_v6(actual_ip);
+ return is_same_host(ipv4_network_address(v4ip, 0));
+ }
+ }
+ 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();
+ if (actual_ip.is_v4_mapped())
+ {
+ const uint32_t v4ip = make_address_v4_from_v6(actual_ip);
+ return other.is_same_host(ipv4_network_address(v4ip, 0));
+ }
+ }
+ return false;
}
std::string print_connection_context(const connection_context_base& ctx)
diff --git a/src/cryptonote_basic/connection_context.h b/src/cryptonote_basic/connection_context.h
index 0c3a94054..8d26e5638 100644
--- a/src/cryptonote_basic/connection_context.h
+++ b/src/cryptonote_basic/connection_context.h
@@ -43,7 +43,8 @@ namespace cryptonote
{
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_known_hash(crypto::null_hash), m_pruning_seed(0), m_rpc_port(0), m_rpc_credits_per_hash(0), m_anchor(false) {}
+ 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
{
@@ -66,7 +67,8 @@ namespace cryptonote
uint16_t m_rpc_port;
uint32_t m_rpc_credits_per_hash;
bool m_anchor;
- //size_t m_score; TODO: add score calculations
+ int32_t m_score;
+ int m_expect_response;
};
inline std::string get_protocol_state_string(cryptonote_connection_context::state s)
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.h b/src/cryptonote_protocol/cryptonote_protocol_handler.h
index 61aac6d81..ee3a67198 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.h
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.h
@@ -148,6 +148,7 @@ namespace cryptonote
void notify_new_stripe(cryptonote_connection_context &context, uint32_t stripe);
void skip_unneeded_hashes(cryptonote_connection_context& context, bool check_block_queue) const;
bool request_txpool_complement(cryptonote_connection_context &context);
+ void hit_score(cryptonote_connection_context &context, int32_t score);
t_core& m_core;
@@ -160,9 +161,10 @@ namespace cryptonote
std::atomic<bool> m_ask_for_txpool_complement;
boost::mutex m_sync_lock;
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_seconds<101> m_sync_search_checker;
+ epee::math_helper::once_a_time_seconds<43> m_bad_peer_checker;
std::atomic<unsigned int> m_max_out_peers;
tools::PerformanceTimer m_sync_timer, m_add_timer;
uint64_t m_last_add_end_time;
@@ -183,6 +185,8 @@ namespace cryptonote
double get_avg_block_size();
boost::circular_buffer<size_t> m_avg_buffer = boost::circular_buffer<size_t>(10);
+ boost::mutex m_bad_peer_check_lock;
+
template<class t_parameter>
bool post_notify(typename t_parameter::request& arg, cryptonote_connection_context& context)
{
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
index a72b7db79..25b14d903 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
@@ -68,10 +68,12 @@
#define BLOCK_QUEUE_FORCE_DOWNLOAD_NEAR_BLOCKS 1000
#define REQUEST_NEXT_SCHEDULED_SPAN_THRESHOLD_STANDBY (5 * 1000000) // microseconds
#define REQUEST_NEXT_SCHEDULED_SPAN_THRESHOLD (30 * 1000000) // microseconds
-#define IDLE_PEER_KICK_TIME (600 * 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 DROP_ON_SYNC_WEDGE_THRESHOLD (30 * 1000000000ull) // nanoseconds
#define LAST_ACTIVITY_STALL_THRESHOLD (2.0f) // seconds
+#define DROP_PEERS_ON_SCORE -2
namespace cryptonote
{
@@ -142,6 +144,8 @@ namespace cryptonote
m_core.get_short_chain_history(r.block_ids);
handler_request_blocks_history( r.block_ids ); // change the limit(?), sleep(?)
r.prune = m_sync_pruned_blocks;
+ 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() );
post_notify<NOTIFY_REQUEST_CHAIN>(r, context);
MLOG_PEER_STATE("requesting chain");
@@ -326,6 +330,11 @@ namespace cryptonote
}
}
+ if (hshd.current_height < context.m_remote_blockchain_height)
+ {
+ MINFO(context << "Claims " << hshd.current_height << ", claimed " << context.m_remote_blockchain_height << " before");
+ hit_score(context, 1);
+ }
context.m_remote_blockchain_height = hshd.current_height;
context.m_pruning_seed = hshd.pruning_seed;
#ifdef CRYPTONOTE_PRUNING_DEBUG_SPOOF_SEED
@@ -427,7 +436,7 @@ namespace cryptonote
template<class t_core>
int t_cryptonote_protocol_handler<t_core>::handle_notify_new_block(int command, NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& context)
{
- MLOGIF_P2P_MESSAGE(crypto::hash hash; cryptonote::block b; bool ret = cryptonote::parse_and_validate_block_from_blob(arg.b.block, b, &hash);, ret, "Received NOTIFY_NEW_BLOCK " << hash << " (height " << arg.current_blockchain_height << ", " << arg.b.txs.size() << " txes)");
+ MLOGIF_P2P_MESSAGE(crypto::hash hash; cryptonote::block b; bool ret = cryptonote::parse_and_validate_block_from_blob(arg.b.block, b, &hash);, ret, context << "Received NOTIFY_NEW_BLOCK " << hash << " (height " << arg.current_blockchain_height << ", " << arg.b.txs.size() << " txes)");
if(context.m_state != cryptonote_connection_context::state_normal)
return 1;
if(!is_synchronized()) // can happen if a peer connection goes to normal but another thread still hasn't finished adding queued blocks
@@ -487,6 +496,8 @@ namespace cryptonote
m_core.get_short_chain_history(r.block_ids);
r.prune = m_sync_pruned_blocks;
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_expect_response = NOTIFY_RESPONSE_CHAIN_ENTRY::ID;
MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size() );
post_notify<NOTIFY_REQUEST_CHAIN>(r, context);
MLOG_PEER_STATE("requesting chain");
@@ -498,7 +509,7 @@ namespace cryptonote
template<class t_core>
int t_cryptonote_protocol_handler<t_core>::handle_notify_new_fluffy_block(int command, NOTIFY_NEW_FLUFFY_BLOCK::request& arg, cryptonote_connection_context& context)
{
- MLOGIF_P2P_MESSAGE(crypto::hash hash; cryptonote::block b; bool ret = cryptonote::parse_and_validate_block_from_blob(arg.b.block, b, &hash);, ret, "Received NOTIFY_NEW_FLUFFY_BLOCK " << hash << " (height " << arg.current_blockchain_height << ", " << arg.b.txs.size() << " txes)");
+ MLOGIF_P2P_MESSAGE(crypto::hash hash; cryptonote::block b; bool ret = cryptonote::parse_and_validate_block_from_blob(arg.b.block, b, &hash);, ret, context << "Received NOTIFY_NEW_FLUFFY_BLOCK " << hash << " (height " << arg.current_blockchain_height << ", " << arg.b.txs.size() << " txes)");
if(context.m_state != cryptonote_connection_context::state_normal)
return 1;
if(!is_synchronized()) // can happen if a peer connection goes to normal but another thread still hasn't finished adding queued blocks
@@ -765,6 +776,8 @@ namespace cryptonote
m_core.get_short_chain_history(r.block_ids);
handler_request_blocks_history( r.block_ids ); // change the limit(?), sleep(?)
r.prune = m_sync_pruned_blocks;
+ 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() );
post_notify<NOTIFY_REQUEST_CHAIN>(r, context);
MLOG_PEER_STATE("requesting chain");
@@ -1029,6 +1042,7 @@ namespace cryptonote
drop_connection(context, false, false);
return 1;
}
+ context.m_last_request_time = boost::posix_time::microsec_clock::universal_time();
MLOG_P2P_MESSAGE("-->>NOTIFY_RESPONSE_GET_OBJECTS: blocks.size()="
<< rsp.blocks.size() << ", rsp.m_current_blockchain_height=" << rsp.current_blockchain_height
<< ", missed_ids.size()=" << rsp.missed_ids.size());
@@ -1062,6 +1076,14 @@ namespace cryptonote
boost::posix_time::ptime request_time = context.m_last_request_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
size_t size = 0;
size_t blocks_size = 0;
@@ -1107,6 +1129,11 @@ namespace cryptonote
return 1;
}
+ if (arg.current_blockchain_height < context.m_remote_blockchain_height)
+ {
+ MINFO(context << "Claims " << arg.current_blockchain_height << ", claimed " << context.m_remote_blockchain_height << " before");
+ hit_score(context, 1);
+ }
context.m_remote_blockchain_height = arg.current_blockchain_height;
if (context.m_remote_blockchain_height > m_core.get_target_blockchain_height())
m_core.set_target_blockchain_height(context.m_remote_blockchain_height);
@@ -1666,24 +1693,45 @@ skip:
bool t_cryptonote_protocol_handler<t_core>::kick_idle_peers()
{
MTRACE("Checking for 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
{
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::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))
{
- MINFO(context << " kicking idle peer, last update " << (dt.total_microseconds() / 1.e6) << " seconds ago");
- LOG_PRINT_CCONTEXT_L2("requesting callback");
- context.m_last_request_time = boost::date_time::not_a_date_time;
- 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;
- m_p2p->request_callback(context);
+ if (context.m_score-- >= 0)
+ {
+ 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");
+ 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_callback_request_count;
+ m_p2p->request_callback(context);
+ }
+ else
+ {
+ idle_peers.push_back(std::make_pair(context.m_connection_id, context.m_expect_response == 0 ? 1 : 5));
+ }
}
}
return true;
});
+
+ for (const auto &e: idle_peers)
+ {
+ 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");
+ drop_connection_with_score(ctx, e.second, false);
+ return true;
+ });
+ }
+
return true;
}
//------------------------------------------------------------------------------------------------------------------------
@@ -2206,6 +2254,7 @@ skip:
}
}
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()
<< "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());
@@ -2296,6 +2345,7 @@ skip:
//LOG_PRINT_CCONTEXT_L1("r = " << 200);
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);
post_notify<NOTIFY_REQUEST_CHAIN>(r, context);
MLOG_PEER_STATE("requesting chain");
@@ -2321,7 +2371,7 @@ skip:
}
else
{
- MINFO(context << " we've reached this peer's blockchain height");
+ MINFO(context << " we've reached this peer's blockchain height (theirs " << context.m_remote_blockchain_height << ", our target " << m_core.get_target_blockchain_height());
}
}
return true;
@@ -2418,6 +2468,14 @@ skip:
<< ", m_start_height=" << arg.start_height << ", m_total_height=" << arg.total_height);
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;
m_sync_download_chain_size += arg.m_block_ids.size() * sizeof(crypto::hash);
@@ -2448,6 +2506,11 @@ skip:
drop_connection(context, false, false);
return 1;
}
+ if (arg.total_height < context.m_remote_blockchain_height)
+ {
+ MINFO(context << "Claims " << arg.total_height << ", claimed " << context.m_remote_blockchain_height << " before");
+ hit_score(context, 1);
+ }
context.m_remote_blockchain_height = arg.total_height;
context.m_last_response_height = arg.start_height + arg.m_block_ids.size()-1;
if(context.m_last_response_height > context.m_remote_blockchain_height)
@@ -2564,6 +2627,19 @@ skip:
}
//------------------------------------------------------------------------------------------------------------------------
template<class t_core>
+ void t_cryptonote_protocol_handler<t_core>::hit_score(cryptonote_connection_context &context, int32_t score)
+ {
+ if (score <= 0)
+ {
+ MERROR("Negative score hit");
+ return;
+ }
+ context.m_score -= score;
+ if (context.m_score <= DROP_PEERS_ON_SCORE)
+ drop_connection_with_score(context, 5, false);
+ }
+ //------------------------------------------------------------------------------------------------------------------------
+ template<class t_core>
std::string t_cryptonote_protocol_handler<t_core>::get_peers_overview() const
{
std::stringstream ss;
diff --git a/src/p2p/net_peerlist.cpp b/src/p2p/net_peerlist.cpp
index ce5c67fe5..42ab9727d 100644
--- a/src/p2p/net_peerlist.cpp
+++ b/src/p2p/net_peerlist.cpp
@@ -288,6 +288,19 @@ namespace nodetool
copy_peers(peers.gray, m_peers_gray.get<by_addr>());
copy_peers(peers.anchor, m_peers_anchor.get<by_addr>());
}
+
+ void peerlist_manager::evict_host_from_white_peerlist(const peerlist_entry& pr)
+ {
+ peers_indexed::index<by_time>::type& sorted_index=m_peers_white.get<by_time>();
+ auto i = sorted_index.begin();
+ while (i != sorted_index.end())
+ {
+ if (i->adr.is_same_host(pr.adr))
+ i = sorted_index.erase(i);
+ else
+ ++i;
+ }
+ }
}
BOOST_CLASS_VERSION(nodetool::peerlist_types, nodetool::CURRENT_PEERLIST_STORAGE_ARCHIVE_VER);
diff --git a/src/p2p/net_peerlist.h b/src/p2p/net_peerlist.h
index 992462d0b..c794b0f3b 100644
--- a/src/p2p/net_peerlist.h
+++ b/src/p2p/net_peerlist.h
@@ -109,6 +109,7 @@ namespace nodetool
bool get_white_peer_by_index(peerlist_entry& p, size_t i);
bool get_gray_peer_by_index(peerlist_entry& p, size_t i);
template<typename F> bool foreach(bool white, const F &f);
+ void evict_host_from_white_peerlist(const peerlist_entry& pr);
bool append_with_peer_white(const peerlist_entry& pr);
bool append_with_peer_gray(const peerlist_entry& pr);
bool append_with_peer_anchor(const anchor_peerlist_entry& ple);
@@ -345,6 +346,7 @@ namespace nodetool
if(by_addr_it_wt == m_peers_white.get<by_addr>().end())
{
//put new record into white list
+ evict_host_from_white_peerlist(ple);
m_peers_white.insert(ple);
trim_white_peerlist();
}else