diff --git a/src/cryptonote_basic/verification_context.h b/src/cryptonote_basic/verification_context.h index 3d7200fae..f5f663464 100644 --- a/src/cryptonote_basic/verification_context.h +++ b/src/cryptonote_basic/verification_context.h @@ -58,5 +58,6 @@ namespace cryptonote bool m_marked_as_orphaned; bool m_already_exists; bool m_partial_block_reward; + bool m_bad_pow; // if bad pow, bad peer outright for DoS protection }; } diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index b672ccd6e..86bcfcc5d 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -1723,6 +1723,7 @@ bool Blockchain::handle_alternative_block(const block& b, const crypto::hash& id { MERROR_VER("Block with id: " << id << std::endl << " for alternative chain, does not have enough proof of work: " << proof_of_work << std::endl << " expected difficulty: " << current_diff); bvc.m_verifivation_failed = true; + bvc.m_bad_pow = true; return false; } @@ -3749,6 +3750,7 @@ leave: { MERROR_VER("Block with id: " << id << std::endl << "does not have enough proof of work: " << proof_of_work << " at height " << blockchain_height << ", unexpected difficulty: " << current_diffic); bvc.m_verifivation_failed = true; + bvc.m_bad_pow = true; goto leave; } } diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.h b/src/cryptonote_protocol/cryptonote_protocol_handler.h index 2666733da..b16b42564 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler.h +++ b/src/cryptonote_protocol/cryptonote_protocol_handler.h @@ -139,6 +139,7 @@ namespace cryptonote bool should_download_next_span(cryptonote_connection_context& context, bool standby); bool should_ask_for_pruned_data(cryptonote_connection_context& context, uint64_t first_block_height, uint64_t nblocks, bool check_block_weights) const; void drop_connection(cryptonote_connection_context &context, bool add_fail, bool flush_all_spans); + void drop_connection_with_score(cryptonote_connection_context &context, unsigned int score, bool flush_all_spans); bool kick_idle_peers(); bool check_standby_peers(); bool update_sync_search(); diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl index 91bcd86cc..bc5c8d6de 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl +++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl @@ -477,7 +477,7 @@ namespace cryptonote if(bvc.m_verifivation_failed) { LOG_PRINT_CCONTEXT_L0("Block verification failed, dropping connection"); - drop_connection(context, true, false); + drop_connection_with_score(context, bvc.m_bad_pow ? P2P_IP_FAILS_BEFORE_BLOCK : 1, false); return 1; } if(bvc.m_added_to_main_chain) @@ -751,7 +751,7 @@ namespace cryptonote if( bvc.m_verifivation_failed ) { LOG_PRINT_CCONTEXT_L0("Block verification failed, dropping connection"); - drop_connection(context, true, false); + drop_connection_with_score(context, bvc.m_bad_pow ? P2P_IP_FAILS_BEFORE_BLOCK : 1, false); return 1; } if( bvc.m_added_to_main_chain ) @@ -1374,7 +1374,7 @@ namespace cryptonote { if (!m_p2p->for_connection(span_connection_id, [&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t f)->bool{ LOG_PRINT_CCONTEXT_L1("Block verification failed, dropping connection"); - drop_connection(context, true, true); + drop_connection_with_score(context, bvc.m_bad_pow ? P2P_IP_FAILS_BEFORE_BLOCK : 1, true); return 1; })) LOG_ERROR_CCONTEXT("span connection id not found"); @@ -2428,14 +2428,14 @@ skip: } //------------------------------------------------------------------------------------------------------------------------ template - void t_cryptonote_protocol_handler::drop_connection(cryptonote_connection_context &context, bool add_fail, bool flush_all_spans) + void t_cryptonote_protocol_handler::drop_connection_with_score(cryptonote_connection_context &context, unsigned score, bool flush_all_spans) { LOG_DEBUG_CC(context, "dropping connection id " << context.m_connection_id << " (pruning seed " << epee::string_tools::to_string_hex(context.m_pruning_seed) << - "), add_fail " << add_fail << ", flush_all_spans " << flush_all_spans); + "), score " << score << ", flush_all_spans " << flush_all_spans); - if (add_fail) - m_p2p->add_host_fail(context.m_remote_address); + if (score > 0) + m_p2p->add_host_fail(context.m_remote_address, score); m_block_queue.flush_spans(context.m_connection_id, flush_all_spans); @@ -2443,6 +2443,12 @@ skip: } //------------------------------------------------------------------------------------------------------------------------ template + void t_cryptonote_protocol_handler::drop_connection(cryptonote_connection_context &context, bool add_fail, bool flush_all_spans) + { + return drop_connection_with_score(context, add_fail ? 1 : 0, flush_all_spans); + } + //------------------------------------------------------------------------------------------------------------------------ + template void t_cryptonote_protocol_handler::on_connection_close(cryptonote_connection_context &context) { uint64_t target = 0; diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h index d7e2e91f5..3a5d980ab 100644 --- a/src/p2p/net_node.h +++ b/src/p2p/net_node.h @@ -342,7 +342,7 @@ namespace nodetool virtual void request_callback(const epee::net_utils::connection_context_base& context); virtual void for_each_connection(std::function f); virtual bool for_connection(const boost::uuids::uuid&, std::function f); - virtual bool add_host_fail(const epee::net_utils::network_address &address); + virtual bool add_host_fail(const epee::net_utils::network_address &address, unsigned int score = 1); //----------------- i_connection_filter -------------------------------------------------------- virtual bool is_remote_host_allowed(const epee::net_utils::network_address &address, time_t *t = NULL); //----------------------------------------------------------------------------------------------- diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index bb77ea658..191efd297 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -315,13 +315,13 @@ namespace nodetool } //----------------------------------------------------------------------------------- template - bool node_server::add_host_fail(const epee::net_utils::network_address &address) + bool node_server::add_host_fail(const epee::net_utils::network_address &address, unsigned int score) { if(!address.is_blockable()) return false; CRITICAL_REGION_LOCAL(m_host_fails_score_lock); - uint64_t fails = ++m_host_fails_score[address.host_str()]; + uint64_t fails = m_host_fails_score[address.host_str()] += score; MDEBUG("Host " << address.host_str() << " fail score=" << fails); if(fails > P2P_IP_FAILS_BEFORE_BLOCK) { diff --git a/src/p2p/net_node_common.h b/src/p2p/net_node_common.h index e0046cd86..752873666 100644 --- a/src/p2p/net_node_common.h +++ b/src/p2p/net_node_common.h @@ -60,7 +60,7 @@ namespace nodetool virtual bool unblock_host(const epee::net_utils::network_address &address)=0; virtual std::map get_blocked_hosts()=0; virtual std::map get_blocked_subnets()=0; - virtual bool add_host_fail(const epee::net_utils::network_address &address)=0; + virtual bool add_host_fail(const epee::net_utils::network_address &address, unsigned int score = 1)=0; virtual void add_used_stripe_peer(const t_connection_context &context)=0; virtual void remove_used_stripe_peer(const t_connection_context &context)=0; virtual void clear_used_stripe_peers()=0; @@ -122,7 +122,7 @@ namespace nodetool { return std::map(); } - virtual bool add_host_fail(const epee::net_utils::network_address &address) + virtual bool add_host_fail(const epee::net_utils::network_address &address, unsigned int score) { return true; } diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index fef86fd34..6f5f912cd 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -217,13 +217,13 @@ namespace cryptonote return true; } //------------------------------------------------------------------------------------------------------------------------------ - bool core_rpc_server::add_host_fail(const connection_context *ctx) + bool core_rpc_server::add_host_fail(const connection_context *ctx, unsigned int score) { if(!ctx || !ctx->m_remote_address.is_blockable()) return false; CRITICAL_REGION_LOCAL(m_host_fails_score_lock); - uint64_t fails = ++m_host_fails_score[ctx->m_remote_address.host_str()]; + uint64_t fails = m_host_fails_score[ctx->m_remote_address.host_str()] += score; MDEBUG("Host " << ctx->m_remote_address.host_str() << " fail score=" << fails); if(fails > RPC_IP_FAILS_BEFORE_BLOCK) { diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h index 379f6ed28..fe03012b7 100644 --- a/src/rpc/core_rpc_server.h +++ b/src/rpc/core_rpc_server.h @@ -241,7 +241,7 @@ namespace cryptonote private: bool check_core_busy(); bool check_core_ready(); - bool add_host_fail(const connection_context *ctx); + bool add_host_fail(const connection_context *ctx, unsigned int score = 1); //utils uint64_t get_block_reward(const block& blk);