diff --git a/contrib/epee/include/net/abstract_tcp_server2.h b/contrib/epee/include/net/abstract_tcp_server2.h index be9fc2a2..14d94728 100644 --- a/contrib/epee/include/net/abstract_tcp_server2.h +++ b/contrib/epee/include/net/abstract_tcp_server2.h @@ -54,7 +54,7 @@ namespace epee { namespace net_utils { struct i_connection_filter { - virtual bool is_remote_ip_allowed(uint32_t adress) = 0; + virtual bool is_remote_ip_allowed(uint32_t adress, bool is_incoming) = 0; protected: virtual ~i_connection_filter() diff --git a/contrib/epee/include/net/abstract_tcp_server2.inl b/contrib/epee/include/net/abstract_tcp_server2.inl index 3f5aa31b..c087b2f4 100644 --- a/contrib/epee/include/net/abstract_tcp_server2.inl +++ b/contrib/epee/include/net/abstract_tcp_server2.inl @@ -146,7 +146,7 @@ bool connection::start(bool is_income, bool is_multithreaded LOG_PRINT_L3("[sock " << socket_.native_handle() << "] new connection, remote end_point: " << print_connection_context_short(context) << " local end_point: " << local_ep.address().to_string() << ':' << local_ep.port() << ", total sockets objects " << m_ref_sockets_count); - if(is_income && m_pfilter && !m_pfilter->is_remote_ip_allowed(context.m_remote_ip)) { + if(is_income && m_pfilter && !m_pfilter->is_remote_ip_allowed(context.m_remote_ip, is_income)) { LOG_PRINT_L0("[sock " << socket_.native_handle() << "] ip denied " << string_tools::get_ip_string_from_int32(context.m_remote_ip) << ", shutdowning connection"); close(); return false; diff --git a/src/currency_core/block_chain_shortener.cpp b/src/currency_core/block_chain_shortener.cpp index 9cb53295..986658a1 100644 --- a/src/currency_core/block_chain_shortener.cpp +++ b/src/currency_core/block_chain_shortener.cpp @@ -13,7 +13,7 @@ #define SHORTENER_EVERY_100_BLOCKS_SIZE 144 #define SHORTENER_EVERY_1000_BLOCKS_SIZE 144 -static void exception_handler(){} +//static void exception_handler(){} diff --git a/src/currency_core/currency_config.h b/src/currency_core/currency_config.h index f621d83b..c5782f6e 100644 --- a/src/currency_core/currency_config.h +++ b/src/currency_core/currency_config.h @@ -239,6 +239,7 @@ #define P2P_NET_DATA_FILENAME "p2pstate.bin" +#define P2P_MANUAL_CONFIG_FILENAME "p2p_manual_config.json" #define MINER_CONFIG_FILENAME "miner_conf.json" #define GUI_SECURE_CONFIG_FILENAME "gui_secure_conf.bin" #define GUI_CONFIG_FILENAME "gui_settings.json" diff --git a/src/currency_core/currency_format_utils.h b/src/currency_core/currency_format_utils.h index b3cfbeed..4d457150 100644 --- a/src/currency_core/currency_format_utils.h +++ b/src/currency_core/currency_format_utils.h @@ -925,9 +925,9 @@ namespace currency if (crc.is_hardfork_active_for_height(2, top_block_height)) { // after hardfork 2 - tx_payer result = AUTO_VAL_INIT(result); - result.acc_addr = addr; - container.push_back(result); + //tx_payer result = AUTO_VAL_INIT(result); + //result.acc_addr = addr; + //container.push_back(result); } else { @@ -947,9 +947,9 @@ namespace currency if (crc.is_hardfork_active_for_height(2, top_block_height)) { // after hardfork 2 - tx_receiver result = AUTO_VAL_INIT(result); - result.acc_addr = addr; - container.push_back(result); + //tx_receiver result = AUTO_VAL_INIT(result); + //result.acc_addr = addr; + //container.push_back(result); } else { diff --git a/src/currency_protocol/currency_protocol_handler.inl b/src/currency_protocol/currency_protocol_handler.inl index 9de4ddf8..0d772d45 100644 --- a/src/currency_protocol/currency_protocol_handler.inl +++ b/src/currency_protocol/currency_protocol_handler.inl @@ -124,7 +124,7 @@ namespace currency for(auto it = conn_map.rbegin(); it != conn_map.rend(); ++it) ss << it->second; - LOG_PRINT_L0("Connections (" << incoming_count << " in, " << outgoing_count << " out, " << incoming_count + outgoing_count << " total):" << ENDL << ss.str()); + LOG_PRINT_L0("Connections:" << ENDL << ss.str() << ENDL << "(" << incoming_count << " in, " << outgoing_count << " out, " << incoming_count + outgoing_count << " total)"); } //------------------------------------------------------------------------------------------------------------------------ template diff --git a/src/daemon/daemon_commands_handler.h b/src/daemon/daemon_commands_handler.h index f9e7edc3..69df1340 100644 --- a/src/daemon/daemon_commands_handler.h +++ b/src/daemon/daemon_commands_handler.h @@ -81,6 +81,7 @@ public: m_cmd_binder.set_handler("debug_remote_node_mode", boost::bind(&daemon_commands_handler::debug_remote_node_mode, this, ph::_1), " - If node got connected put node into 'debug mode' i.e. no sync process of other communication except ping responses, maintenance secrete key will be requested"); m_cmd_binder.set_handler("full_db_cache_warmup", boost::bind(&daemon_commands_handler::full_db_cache_warmup, this, ph::_1), "(Experimental) Perform full DB loading to RAM cache(make sense only with big numbers passed to --db-cache-l2 option)"); m_cmd_binder.set_handler("print_cache_state", boost::bind(&daemon_commands_handler::print_cache_state, this, ph::_1), "Print db l2 cache state"); + m_cmd_binder.set_handler("reload_p2p_manual_config", boost::bind(&daemon_commands_handler::reload_p2p_manual_config, this, ph::_1), "Reload manual p2p config from '" P2P_MANUAL_CONFIG_FILENAME "'"); #ifdef _DEBUG m_cmd_binder.set_handler("debug_set_time_adj", boost::bind(&daemon_commands_handler::debug_set_time_adj, this, ph::_1), "DEBUG: set core time adjustment"); #endif @@ -226,10 +227,10 @@ private: std::map blocklist; m_srv.get_ip_block_list(blocklist); std::stringstream ss; - ss << "BLOCKED IPS:" << ENDL; + ss << "AUTO BLOCKED IPs:" << ENDL << "ip block time" << ENDL; for (const auto& e : blocklist) { - ss << string_tools::get_ip_string_from_int32(e.first) << ", time: " << std::put_time(std::localtime(&e.second), "%Y-%m-%d %H:%M:%S") << ENDL; + ss << std::left << std::setw(15) << string_tools::get_ip_string_from_int32(e.first) << " " << std::put_time(std::localtime(&e.second), "%Y-%m-%d %H:%M:%S") << ENDL; } LOG_PRINT_L0(ss.str()); return true; @@ -901,6 +902,13 @@ private: return true; } //-------------------------------------------------------------------------------- + bool reload_p2p_manual_config(const std::vector& args) + { + m_srv.reload_p2p_manual_config(false); + + return true; + } + //-------------------------------------------------------------------------------- bool print_pool(const std::vector& args) { LOG_PRINT_L0("Pool state: " << ENDL << m_srv.get_payload_object().get_core().print_pool(false)); diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h index 6cb58abb..e9367faa 100644 --- a/src/p2p/net_node.h +++ b/src/p2p/net_node.h @@ -121,10 +121,12 @@ namespace nodetool bool log_connections(); virtual uint64_t get_connections_count(); size_t get_outgoing_connections_count(); + size_t get_incoming_connections_count(); peerlist_manager& get_peerlist_manager(){return m_peerlist;} bool handle_maintainers_entry(const maintainers_entry& me); bool get_maintainers_info(maintainers_info_external& me); void get_ip_block_list(std::map& blocklist); + bool reload_p2p_manual_config(bool silent = true); typedef COMMAND_REQUEST_STAT_INFO_T COMMAND_REQUEST_STAT_INFO; private: @@ -184,9 +186,10 @@ namespace nodetool virtual bool add_ip_fail(uint32_t address); virtual bool is_stop_signal_sent(); //----------------- i_connection_filter -------------------------------------------------------- - virtual bool is_remote_ip_allowed(uint32_t adress); + virtual bool is_remote_ip_allowed(uint32_t adress, bool is_incoming); //----------------------------------------------------------------------------------------------- bool parse_peer_from_string(nodetool::net_address& pe, const std::string& node_addr); + bool parse_peerlist(const std::vector& perrs_str, std::list& peers); bool handle_command_line(const boost::program_options::variables_map& vm); bool idle_worker(); bool handle_remote_peerlist(const std::list& peerlist, time_t local_time, const net_utils::connection_context_base& context); @@ -221,7 +224,7 @@ namespace nodetool bool critical_alert_worker(); bool remove_dead_connections(); bool is_ip_good_for_adding_to_peerlist(uint32_t adress); - bool is_ip_in_blacklist(uint32_t adress); + bool is_ip_in_blacklist(uint32_t adress, bool ignore_auto_blocked_list = false); //debug functions @@ -298,9 +301,16 @@ namespace nodetool critical_section m_blocked_ips_lock; std::map m_blocked_ips; + //critical_section m_permanently_blocked_ips_lock; + std::set m_permanently_blocked_ips; + + critical_section m_ip_fails_score_lock; std::map m_ip_fails_score; + critical_section m_p2p_manual_config_lock; + p2p_config_data m_p2p_manual_config; + }; } diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index 43024815..b5623ef3 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -37,7 +37,7 @@ namespace nodetool const command_line::arg_descriptor arg_p2p_hide_my_port ("hide-my-port", "Do not announce yourself as peerlist candidate"); const command_line::arg_descriptor arg_p2p_offline_mode ( "offline-mode", "Don't connect to any node and reject any connections"); const command_line::arg_descriptor arg_p2p_disable_debug_reqs ( "disable-debug-p2p-requests", "Disable p2p debug requests"); - const command_line::arg_descriptor arg_p2p_ip_auto_blocking ( "p2p-ip-auto-blocking", "Enable (1) or disable (0) peers auto-blocking by IP <0|1>. Default: 0", 1); + const command_line::arg_descriptor arg_p2p_ip_auto_blocking ( "p2p-ip-auto-blocking", "Enable (1) or disable (0) peers auto-blocking by IP <0|1>. Default: 1", 1); const command_line::arg_descriptor arg_p2p_server_threads ( "p2p-server-threads", "Specify number of p2p server threads. Default: 10", P2P_SERVER_DEFAULT_THREADS_NUM); } @@ -106,15 +106,22 @@ namespace nodetool } //----------------------------------------------------------------------------------- template - bool node_server::is_remote_ip_allowed(uint32_t addr) + bool node_server::is_remote_ip_allowed(uint32_t addr, bool is_incoming) { if (m_offline_mode) return false; - if (!m_ip_auto_blocking_enabled) - return true; - - return !is_ip_in_blacklist(addr); + if (is_incoming) + { + if (m_p2p_manual_config.incoming_connections_limit && *m_p2p_manual_config.incoming_connections_limit >= get_incoming_connections_count()) + return false; + + if (m_use_only_priority_peers) + return false; + } + + bool ignore_auto_blocked_list = !m_ip_auto_blocking_enabled; + return !is_ip_in_blacklist(addr, ignore_auto_blocked_list); } //----------------------------------------------------------------------------------- template @@ -129,9 +136,18 @@ namespace nodetool } //----------------------------------------------------------------------------------- template - bool node_server::is_ip_in_blacklist(uint32_t addr) + bool node_server::is_ip_in_blacklist(uint32_t addr, bool ignore_auto_blocked_list /* = false */) { CRITICAL_REGION_LOCAL(m_blocked_ips_lock); + + //first check permanently blocked ip + if (m_permanently_blocked_ips.find(addr) != m_permanently_blocked_ips.end()) + return true; + + if (ignore_auto_blocked_list) + return false; + + //check temporary blocked auto it = m_blocked_ips.find(addr); if (it == m_blocked_ips.end()) return false; @@ -147,6 +163,77 @@ namespace nodetool } //----------------------------------------------------------------------------------- template + bool node_server::reload_p2p_manual_config(bool silent) + { + std::set new_block_list; + std::list new_priority_peers; + { + CRITICAL_REGION_LOCAL(m_p2p_manual_config_lock); + p2p_config_data config = AUTO_VAL_INIT(config); + std::string p2p_config_file_path = m_config_folder + "/" + P2P_MANUAL_CONFIG_FILENAME; + bool r = epee::serialization::load_t_from_json_file(config, p2p_config_file_path); + if (!r) + { + if (!silent) + { + LOG_PRINT_L0("P2P network config file is missing or not loaded"); + } + return true; + } + //loaded json, let's try to load blacklist + for (const std::string& ip_str_entry : config.ip_black_list) + { + uint32_t ip = 0; + if (!string_tools::get_ip_int32_from_string(ip, ip_str_entry)) + { + LOG_ERROR("P2P network config file loading error: failed to convert '" << ip_str_entry << "' to ip address"); + return false; + } + new_block_list.insert(ip); + } + + if (config.priority_peers_list.size()) + { + bool r = parse_peerlist(config.priority_peers_list, new_priority_peers); + CHECK_AND_ASSERT_MES(r, false, "Failed to parse priority peers"); + } + + m_p2p_manual_config = config; + + + //override some of the settings + if (m_p2p_manual_config.use_only_priority_peers) + { + m_use_only_priority_peers = *m_p2p_manual_config.use_only_priority_peers; + } + + m_priority_peers = new_priority_peers; + + + if (m_p2p_manual_config.incoming_connections_limit && *m_p2p_manual_config.incoming_connections_limit == 0) + { + m_hide_my_port = true; + } + + if (m_p2p_manual_config.outgoing_connections_limit && *m_p2p_manual_config.outgoing_connections_limit == 0) + { + //TODO: consider if need to do this + //m_offline_mode = true; + } + + } + + + //TODO: this command when passed to running daemon via command line option might be multi-thread-unsafe, subject for refactoring + //CRITICAL_REGION_LOCAL(m_permanently_blocked_ips_lock); + m_permanently_blocked_ips.clear(); + m_permanently_blocked_ips = new_block_list; + + LOG_PRINT_L0("P2P network manual config file loaded(some of the p2p cpommand line options might be overridden by '" << P2P_MANUAL_CONFIG_FILENAME << "')."); + return true; + } + //----------------------------------------------------------------------------------- + template bool node_server::block_ip(uint32_t addr) { CRITICAL_REGION_LOCAL(m_blocked_ips_lock); @@ -188,6 +275,19 @@ namespace nodetool } //----------------------------------------------------------------------------------- template + bool node_server::parse_peerlist(const std::vector& perrs_str, std::list& peers) + { + for (const std::string& pr_str : perrs_str) + { + nodetool::net_address na = AUTO_VAL_INIT(na); + bool r = parse_peer_from_string(na, pr_str); + CHECK_AND_ASSERT_MES(r, false, "Failed to parse address from string: " << pr_str); + peers.push_back(na); + } + return true; + } + //----------------------------------------------------------------------------------- + template bool node_server::handle_command_line(const boost::program_options::variables_map& vm) { m_bind_ip = command_line::get_arg(vm, arg_p2p_bind_ip); @@ -236,13 +336,8 @@ namespace nodetool if (command_line::has_arg(vm, arg_p2p_add_priority_node)) { std::vector perrs = command_line::get_arg(vm, arg_p2p_add_priority_node); - for(const std::string& pr_str: perrs) - { - nodetool::net_address na = AUTO_VAL_INIT(na); - bool r = parse_peer_from_string(na, pr_str); - CHECK_AND_ASSERT_MES(r, false, "Failed to parse address from string: " << pr_str); - m_priority_peers.push_back(na); - } + bool r = parse_peerlist(perrs, m_priority_peers); + CHECK_AND_ASSERT_MES(r, false, "Failed to parse priority peers"); } if(command_line::has_arg(vm, arg_p2p_use_only_priority_nodes)) m_use_only_priority_peers = true; @@ -383,6 +478,10 @@ namespace nodetool LOG_PRINT_GREEN("Net service binded on " << m_bind_ip << ":" << m_listenning_port, LOG_LEVEL_0); if(m_external_port) LOG_PRINT_L0("External port defined as " << m_external_port); + + + reload_p2p_manual_config(true); + return res; } //----------------------------------------------------------------------------------- @@ -842,7 +941,7 @@ namespace nodetool continue; } - if (!is_remote_ip_allowed(pe.adr.ip)) + if (!is_remote_ip_allowed(pe.adr.ip, false)) { ++peer_index; continue; @@ -912,10 +1011,22 @@ namespace nodetool size_t expected_white_connections = (m_config.m_net_config.connections_count*P2P_DEFAULT_WHITELIST_CONNECTIONS_PERCENT)/100; - size_t conn_count = get_outgoing_connections_count(); - if(conn_count < m_config.m_net_config.connections_count) + size_t out_conn_count = get_outgoing_connections_count(); + bool need_more_connections = false; + if (m_p2p_manual_config.outgoing_connections_limit) { - if(conn_count < expected_white_connections) + // m_p2p_manual_config always override default settings from m_config.m_net_config + need_more_connections = out_conn_count < *m_p2p_manual_config.outgoing_connections_limit; + } + else + { + // use default policy + need_more_connections = out_conn_count < m_config.m_net_config.connections_count; + } + + if(need_more_connections) + { + if(out_conn_count < expected_white_connections) { //start from white list if(!make_expected_connections_count(true, expected_white_connections)) @@ -966,6 +1077,20 @@ namespace nodetool return true; }); + return count; + } + //----------------------------------------------------------------------------------- + template + size_t node_server::get_incoming_connections_count() + { + size_t count = 0; + m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt) + { + if (cntxt.m_is_income) + ++count; + return true; + }); + return count; } //----------------------------------------------------------------------------------- diff --git a/src/p2p/p2p_protocol_defs.h b/src/p2p/p2p_protocol_defs.h index fe1225f4..8e3318f3 100644 --- a/src/p2p/p2p_protocol_defs.h +++ b/src/p2p/p2p_protocol_defs.h @@ -289,6 +289,29 @@ namespace nodetool }; }; + + + struct p2p_config_data + { + std::optional incoming_connections_limit; + std::optional outgoing_connections_limit; + std::vector ip_black_list; + std::optional use_only_priority_peers = false; //allow to make outgoing connections only to the peers listed in ip_priority_list + std::vector priority_peers_list; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(incoming_connections_limit) + KV_SERIALIZE(outgoing_connections_limit) + KV_SERIALIZE(ip_black_list) + KV_SERIALIZE(use_only_priority_peers) + KV_SERIALIZE(priority_peers_list) + END_KV_SERIALIZE_MAP() + }; + + + + + #ifdef ALLOW_DEBUG_COMMANDS //These commands are considered as insecure, and made in debug purposes for a limited lifetime. diff --git a/src/serialization/stl_containers.h b/src/serialization/stl_containers.h index 34981ede..f6cdbd49 100644 --- a/src/serialization/stl_containers.h +++ b/src/serialization/stl_containers.h @@ -9,6 +9,10 @@ #include #include + +#define SANITY_CHECK_MAX_RESERVATION_RAM 10000000 + + //#include "serialization.h" template