diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/blocks/checkpoints.dat | bin | 279428 -> 280452 bytes | |||
-rw-r--r-- | src/checkpoints/checkpoints.cpp | 1 | ||||
-rw-r--r-- | src/crypto/crypto.cpp | 12 | ||||
-rw-r--r-- | src/cryptonote_basic/connection_context.h | 6 | ||||
-rw-r--r-- | src/cryptonote_config.h | 1 | ||||
-rw-r--r-- | src/cryptonote_core/blockchain.cpp | 2 | ||||
-rw-r--r-- | src/cryptonote_protocol/cryptonote_protocol_handler.h | 6 | ||||
-rw-r--r-- | src/cryptonote_protocol/cryptonote_protocol_handler.inl | 101 | ||||
-rw-r--r-- | src/p2p/net_node.h | 4 | ||||
-rw-r--r-- | src/p2p/net_node.inl | 110 | ||||
-rw-r--r-- | src/p2p/net_node_common.h | 4 | ||||
-rw-r--r-- | src/p2p/net_peerlist.cpp | 13 | ||||
-rw-r--r-- | src/p2p/net_peerlist.h | 2 | ||||
-rw-r--r-- | src/version.cpp.in | 2 | ||||
-rw-r--r-- | src/wallet/wallet2.cpp | 3 |
15 files changed, 194 insertions, 73 deletions
diff --git a/src/blocks/checkpoints.dat b/src/blocks/checkpoints.dat Binary files differindex bcbfbb7ee..7f5f996cb 100644 --- a/src/blocks/checkpoints.dat +++ b/src/blocks/checkpoints.dat diff --git a/src/checkpoints/checkpoints.cpp b/src/checkpoints/checkpoints.cpp index d966eebda..d4733007b 100644 --- a/src/checkpoints/checkpoints.cpp +++ b/src/checkpoints/checkpoints.cpp @@ -242,6 +242,7 @@ namespace cryptonote ADD_CHECKPOINT2(2210500, "ed17259215ac6aabe6e8252b5b5eff613d2e69cc2111173e567109aa78301911", "0xfbcb50a9a6a433"); ADD_CHECKPOINT2(2224000, "e34bc71301600df96d08aaa6b0bde932cba1b06a3dd57076e3f664a078810a80", "0x1052fc256fceb6f"); ADD_CHECKPOINT2(2235500, "3eac1a1253495733e10d00fd5e8e1639741566d91bae38bc6d3342af6b75da53", "0x10cea232ce71d23"); + ADD_CHECKPOINT2(2244000, "f06b8a19a75070cd002414d9d3ce59cf6b11ed9db464c6b84d3f22abbff84fae", "0x112b3331539f585"); return true; } diff --git a/src/crypto/crypto.cpp b/src/crypto/crypto.cpp index 4cfe83d54..0059dd7f5 100644 --- a/src/crypto/crypto.cpp +++ b/src/crypto/crypto.cpp @@ -123,13 +123,17 @@ namespace crypto { void random32_unbiased(unsigned char *bytes) { // l = 2^252 + 27742317777372353535851937790883648493. - // it fits 15 in 32 bytes + // l fits 15 times in 32 bytes (iow, 15 l is the highest multiple of l that fits in 32 bytes) static const unsigned char limit[32] = { 0xe3, 0x6a, 0x67, 0x72, 0x8b, 0xce, 0x13, 0x29, 0x8f, 0x30, 0x82, 0x8c, 0x0b, 0xa4, 0x10, 0x39, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0 }; - do + while(1) { generate_random_bytes_thread_safe(32, bytes); - } while (!sc_isnonzero(bytes) && !less32(bytes, limit)); // should be good about 15/16 of the time - sc_reduce32(bytes); + if (!less32(bytes, limit)) + continue; + sc_reduce32(bytes); + if (sc_isnonzero(bytes)) + break; + } } /* generate a random 32-byte (256-bit) integer and copy it to res */ static inline void random_scalar(ec_scalar &res) { 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_config.h b/src/cryptonote_config.h index 826cabe17..13f0c471b 100644 --- a/src/cryptonote_config.h +++ b/src/cryptonote_config.h @@ -132,6 +132,7 @@ #define P2P_DEFAULT_HANDSHAKE_INTERVAL 60 //secondes #define P2P_DEFAULT_PACKET_MAX_SIZE 50000000 //50000000 bytes maximum packet size #define P2P_DEFAULT_PEERS_IN_HANDSHAKE 250 +#define P2P_MAX_PEERS_IN_HANDSHAKE 250 #define P2P_DEFAULT_CONNECTION_TIMEOUT 5000 //5 seconds #define P2P_DEFAULT_SOCKS_CONNECT_TIMEOUT 45 // seconds #define P2P_DEFAULT_PING_CONNECTION_TIMEOUT 2000 //2 seconds diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 89ecda2cd..78fc57967 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -5376,7 +5376,7 @@ void Blockchain::cancel() } #if defined(PER_BLOCK_CHECKPOINT) -static const char expected_block_hashes_hash[] = "3a2a0720f7ed3573d2b632f7ba127e2f97edac3af34bf924df57c13a88bf2460"; +static const char expected_block_hashes_hash[] = "6a6436850ed9df5975ca0c45513647c3d401ed8523ff5a793ad93136fa34fd3b"; void Blockchain::load_compiled_in_block_hashes(const GetCheckpointsCallback& get_checkpoints) { if (get_checkpoints == nullptr || !m_fast_sync) 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 3209fcb14..98c9468dd 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()); @@ -2260,8 +2309,7 @@ skip: uint64_t start_height; std::vector<cryptonote::block_complete_entry> blocks; boost::uuids::uuid span_connection_id; - bool filled = false; - if (m_block_queue.get_next_span(start_height, blocks, span_connection_id, filled) && filled) + if (m_block_queue.get_next_span(start_height, blocks, span_connection_id, true)) { LOG_DEBUG_CC(context, "No other thread is adding blocks, resuming"); MLOG_PEER_STATE("will try to add blocks next"); @@ -2296,6 +2344,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 +2370,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 +2467,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 +2505,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) @@ -2571,6 +2633,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_node.h b/src/p2p/net_node.h index 87fec9994..f13b36a82 100644 --- a/src/p2p/net_node.h +++ b/src/p2p/net_node.h @@ -149,7 +149,7 @@ namespace nodetool { config_t() : m_net_config(), - m_peer_id(crypto::rand<uint64_t>()), + m_peer_id(1), m_support_flags(0) {} @@ -287,7 +287,7 @@ namespace nodetool uint32_t get_max_out_public_peers() const; void change_max_in_public_peers(size_t count); uint32_t get_max_in_public_peers() const; - virtual bool block_host(const epee::net_utils::network_address &adress, time_t seconds = P2P_IP_BLOCKTIME); + virtual bool block_host(epee::net_utils::network_address address, time_t seconds = P2P_IP_BLOCKTIME); virtual bool unblock_host(const epee::net_utils::network_address &address); virtual bool block_subnet(const epee::net_utils::ipv4_network_subnet &subnet, time_t seconds = P2P_IP_BLOCKTIME); virtual bool unblock_subnet(const epee::net_utils::ipv4_network_subnet &subnet); diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index c71dfc2de..65db2615c 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -139,7 +139,9 @@ namespace nodetool if (storage) m_peerlist_storage = std::move(*storage); - m_network_zones[epee::net_utils::zone::public_].m_config.m_support_flags = P2P_SUPPORT_FLAGS; + network_zone& public_zone = m_network_zones[epee::net_utils::zone::public_]; + public_zone.m_config.m_support_flags = P2P_SUPPORT_FLAGS; + public_zone.m_config.m_peer_id = crypto::rand<uint64_t>(); m_first_connection_maker_call = true; CATCH_ENTRY_L0("node_server::init_config", false); @@ -224,7 +226,7 @@ namespace nodetool } //----------------------------------------------------------------------------------- template<class t_payload_net_handler> - bool node_server<t_payload_net_handler>::block_host(const epee::net_utils::network_address &addr, time_t seconds) + bool node_server<t_payload_net_handler>::block_host(epee::net_utils::network_address addr, time_t seconds) { if(!addr.is_blockable()) return false; @@ -237,7 +239,8 @@ namespace nodetool limit = std::numeric_limits<time_t>::max(); else limit = now + seconds; - m_blocked_hosts[addr.host_str()] = limit; + const std::string host_str = addr.host_str(); + m_blocked_hosts[host_str] = limit; // drop any connection to that address. This should only have to look into // the zone related to the connection, but really make sure everything is @@ -253,17 +256,18 @@ namespace nodetool } return true; }); - for (const auto &c: conns) - 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); + + for (const auto &c: conns) + zone.second.m_net_server.get_config_object().close(c); + + conns.clear(); } - MCLOG_CYAN(el::Level::Info, "global", "Host " << addr.host_str() << " blocked."); + MCLOG_CYAN(el::Level::Info, "global", "Host " << host_str << " blocked."); return true; } //----------------------------------------------------------------------------------- @@ -1135,11 +1139,12 @@ namespace nodetool pi = context.peer_id = rsp.node_data.peer_id; context.m_rpc_port = rsp.node_data.rpc_port; context.m_rpc_credits_per_hash = rsp.node_data.rpc_credits_per_hash; - network_zone& zone = m_network_zones.at(context.m_remote_address.get_zone()); + const auto azone = context.m_remote_address.get_zone(); + network_zone& zone = m_network_zones.at(azone); zone.m_peerlist.set_peer_just_seen(rsp.node_data.peer_id, context.m_remote_address, context.m_pruning_seed, context.m_rpc_port, context.m_rpc_credits_per_hash); // move - if(rsp.node_data.peer_id == zone.m_config.m_peer_id) + if(azone == epee::net_utils::zone::public_ && rsp.node_data.peer_id == zone.m_config.m_peer_id) { LOG_DEBUG_CC(context, "Connection to self detected, dropping connection"); hsh_result = false; @@ -1231,50 +1236,51 @@ namespace nodetool template<class t_payload_net_handler> bool node_server<t_payload_net_handler>::is_peer_used(const peerlist_entry& peer) { - for(const auto& zone : m_network_zones) - if(zone.second.m_config.m_peer_id == peer.id) - return true;//dont make connections to ourself + const auto zone = peer.adr.get_zone(); + const auto server = m_network_zones.find(zone); + if (server == m_network_zones.end()) + return false; + + const bool is_public = (zone == epee::net_utils::zone::public_); + if(is_public && server->second.m_config.m_peer_id == peer.id) + return true;//dont make connections to ourself bool used = false; - for(auto& zone : m_network_zones) + server->second.m_net_server.get_config_object().foreach_connection([&, is_public](const p2p_connection_context& cntxt) { - zone.second.m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt) + if((is_public && cntxt.peer_id == peer.id) || (!cntxt.m_is_income && peer.adr == cntxt.m_remote_address)) { - if(cntxt.peer_id == peer.id || (!cntxt.m_is_income && peer.adr == cntxt.m_remote_address)) - { - used = true; - return false;//stop enumerating - } - return true; - }); - - if(used) - return true; - } - return false; + used = true; + return false;//stop enumerating + } + return true; + }); + return used; } //----------------------------------------------------------------------------------- template<class t_payload_net_handler> bool node_server<t_payload_net_handler>::is_peer_used(const anchor_peerlist_entry& peer) { - for(auto& zone : m_network_zones) { - if(zone.second.m_config.m_peer_id == peer.id) { - return true;//dont make connections to ourself - } - bool used = false; - zone.second.m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt) + const auto zone = peer.adr.get_zone(); + const auto server = m_network_zones.find(zone); + if (server == m_network_zones.end()) + return false; + + const bool is_public = (zone == epee::net_utils::zone::public_); + if(is_public && server->second.m_config.m_peer_id == peer.id) + return true;//dont make connections to ourself + + bool used = false; + server->second.m_net_server.get_config_object().foreach_connection([&, is_public](const p2p_connection_context& cntxt) + { + if((is_public && cntxt.peer_id == peer.id) || (!cntxt.m_is_income && peer.adr == cntxt.m_remote_address)) { - if(cntxt.peer_id == peer.id || (!cntxt.m_is_income && peer.adr == cntxt.m_remote_address)) - { - used = true; - return false;//stop enumerating - } - return true; - }); - if (used) - return true; - } - return false; + used = true; + return false;//stop enumerating + } + return true; + }); + return used; } //----------------------------------------------------------------------------------- template<class t_payload_net_handler> @@ -1320,6 +1326,9 @@ namespace nodetool if (zone.m_connect == nullptr) // outgoing connections in zone not possible return false; + if (zone.m_our_address == na) + return false; + if (zone.m_current_number_of_out_peers == zone.m_config.m_net_config.max_out_connection_count) // out peers limit { return false; @@ -1647,6 +1656,9 @@ namespace nodetool peerid_to_string(pe.id) << " " << pe.adr.str() << ", pruning seed " << epee::string_tools::to_string_hex(pe.pruning_seed) << " (stripe " << next_needed_pruning_stripe << " needed)"); + if(zone.m_our_address == pe.adr) + continue; + if(is_peer_used(pe)) { _note("Peer is used"); continue; @@ -2060,6 +2072,11 @@ namespace nodetool template<class t_payload_net_handler> bool node_server<t_payload_net_handler>::handle_remote_peerlist(const std::vector<peerlist_entry>& peerlist, const epee::net_utils::connection_context_base& context) { + if (peerlist.size() > P2P_MAX_PEERS_IN_HANDSHAKE) + { + MWARNING(context << "peer sent " << peerlist.size() << " peers, considered spamming"); + return false; + } std::vector<peerlist_entry> peerlist_ = peerlist; if(!sanitize_peerlist(peerlist_)) return false; @@ -2420,11 +2437,12 @@ namespace nodetool return 1; } - network_zone& zone = m_network_zones.at(context.m_remote_address.get_zone()); + const auto azone = context.m_remote_address.get_zone(); + network_zone& zone = m_network_zones.at(azone); // test only the remote end's zone, otherwise an attacker could connect to you on clearnet // and pass in a tor connection's peer id, and deduce the two are the same if you reject it - if(arg.node_data.peer_id == zone.m_config.m_peer_id) + if(azone == epee::net_utils::zone::public_ && arg.node_data.peer_id == zone.m_config.m_peer_id) { LOG_DEBUG_CC(context, "Connection to self detected, dropping connection"); drop_connection(context); diff --git a/src/p2p/net_node_common.h b/src/p2p/net_node_common.h index 2ace5987f..f1490a0db 100644 --- a/src/p2p/net_node_common.h +++ b/src/p2p/net_node_common.h @@ -58,7 +58,7 @@ namespace nodetool virtual uint64_t get_public_connections_count()=0; virtual void for_each_connection(std::function<bool(t_connection_context&, peerid_type, uint32_t)> f)=0; virtual bool for_connection(const boost::uuids::uuid&, std::function<bool(t_connection_context&, peerid_type, uint32_t)> f)=0; - virtual bool block_host(const epee::net_utils::network_address &address, time_t seconds = 0)=0; + virtual bool block_host(epee::net_utils::network_address address, time_t seconds = 0)=0; virtual bool unblock_host(const epee::net_utils::network_address &address)=0; virtual std::map<std::string, time_t> get_blocked_hosts()=0; virtual std::map<epee::net_utils::ipv4_network_subnet, time_t> get_blocked_subnets()=0; @@ -108,7 +108,7 @@ namespace nodetool { return false; } - virtual bool block_host(const epee::net_utils::network_address &address, time_t seconds) + virtual bool block_host(epee::net_utils::network_address address, time_t seconds) { return true; } 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 diff --git a/src/version.cpp.in b/src/version.cpp.in index 6658cb3b1..00b5c5643 100644 --- a/src/version.cpp.in +++ b/src/version.cpp.in @@ -1,5 +1,5 @@ #define DEF_MONERO_VERSION_TAG "@VERSIONTAG@" -#define DEF_MONERO_VERSION "0.17.1.5" +#define DEF_MONERO_VERSION "0.17.1.6" #define DEF_MONERO_RELEASE_NAME "Oxygen Orion" #define DEF_MONERO_VERSION_FULL DEF_MONERO_VERSION "-" DEF_MONERO_VERSION_TAG #define DEF_MONERO_VERSION_IS_RELEASE @VERSION_IS_RELEASE@ diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 65411e392..299e427ce 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -2961,7 +2961,8 @@ void wallet2::update_pool_state(std::vector<std::tuple<cryptonote::transaction, MTRACE("update_pool_state got pool"); // remove any pending tx that's not in the pool - constexpr const std::chrono::seconds tx_propagation_timeout{CRYPTONOTE_DANDELIONPP_EMBARGO_AVERAGE * 3 / 2}; + // TODO: set tx_propagation_timeout to CRYPTONOTE_DANDELIONPP_EMBARGO_AVERAGE * 3 / 2 after v15 hardfork + constexpr const std::chrono::seconds tx_propagation_timeout{500}; const auto now = std::chrono::system_clock::now(); std::unordered_map<crypto::hash, wallet2::unconfirmed_transfer_details>::iterator it = m_unconfirmed_txs.begin(); while (it != m_unconfirmed_txs.end()) |