1
0
Fork 0
forked from lthn/blockchain

p2p network manual configuration from config file

This commit is contained in:
cryptozoidberg 2025-07-20 18:41:27 +04:00
parent 0e1618c496
commit 32194f88b1
No known key found for this signature in database
GPG key ID: 2E10CC61CAC8F36D
8 changed files with 186 additions and 15 deletions

View file

@ -54,7 +54,7 @@ namespace epee {
namespace net_utils { namespace net_utils {
struct i_connection_filter { 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: protected:
virtual ~i_connection_filter() virtual ~i_connection_filter()

View file

@ -146,7 +146,7 @@ bool connection<t_protocol_handler>::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); 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"); LOG_PRINT_L0("[sock " << socket_.native_handle() << "] ip denied " << string_tools::get_ip_string_from_int32(context.m_remote_ip) << ", shutdowning connection");
close(); close();
return false; return false;

View file

@ -239,6 +239,7 @@
#define P2P_NET_DATA_FILENAME "p2pstate.bin" #define P2P_NET_DATA_FILENAME "p2pstate.bin"
#define P2P_MANUAL_CONFIG_FILENAME "p2p_manual_config.json"
#define MINER_CONFIG_FILENAME "miner_conf.json" #define MINER_CONFIG_FILENAME "miner_conf.json"
#define GUI_SECURE_CONFIG_FILENAME "gui_secure_conf.bin" #define GUI_SECURE_CONFIG_FILENAME "gui_secure_conf.bin"
#define GUI_CONFIG_FILENAME "gui_settings.json" #define GUI_CONFIG_FILENAME "gui_settings.json"

View file

@ -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), "<ip-address> - 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("debug_remote_node_mode", boost::bind(&daemon_commands_handler::debug_remote_node_mode, this, ph::_1), "<ip-address> - 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("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("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.json'");
#ifdef _DEBUG #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"); 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 #endif
@ -901,6 +902,13 @@ private:
return true; return true;
} }
//-------------------------------------------------------------------------------- //--------------------------------------------------------------------------------
bool reload_p2p_manual_config(const std::vector<std::string>& args)
{
m_srv.reload_p2p_manual_config(false);
return true;
}
//--------------------------------------------------------------------------------
bool print_pool(const std::vector<std::string>& args) bool print_pool(const std::vector<std::string>& args)
{ {
LOG_PRINT_L0("Pool state: " << ENDL << m_srv.get_payload_object().get_core().print_pool(false)); LOG_PRINT_L0("Pool state: " << ENDL << m_srv.get_payload_object().get_core().print_pool(false));

View file

@ -121,10 +121,12 @@ namespace nodetool
bool log_connections(); bool log_connections();
virtual uint64_t get_connections_count(); virtual uint64_t get_connections_count();
size_t get_outgoing_connections_count(); size_t get_outgoing_connections_count();
size_t get_incoming_connections_count();
peerlist_manager& get_peerlist_manager(){return m_peerlist;} peerlist_manager& get_peerlist_manager(){return m_peerlist;}
bool handle_maintainers_entry(const maintainers_entry& me); bool handle_maintainers_entry(const maintainers_entry& me);
bool get_maintainers_info(maintainers_info_external& me); bool get_maintainers_info(maintainers_info_external& me);
void get_ip_block_list(std::map<uint32_t, time_t>& blocklist); void get_ip_block_list(std::map<uint32_t, time_t>& blocklist);
bool reload_p2p_manual_config(bool silent = true);
typedef COMMAND_REQUEST_STAT_INFO_T<typename t_payload_net_handler::stat_info> COMMAND_REQUEST_STAT_INFO; typedef COMMAND_REQUEST_STAT_INFO_T<typename t_payload_net_handler::stat_info> COMMAND_REQUEST_STAT_INFO;
private: private:
@ -184,9 +186,10 @@ namespace nodetool
virtual bool add_ip_fail(uint32_t address); virtual bool add_ip_fail(uint32_t address);
virtual bool is_stop_signal_sent(); virtual bool is_stop_signal_sent();
//----------------- i_connection_filter -------------------------------------------------------- //----------------- 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_peer_from_string(nodetool::net_address& pe, const std::string& node_addr);
bool parse_peerlist(const std::vector<std::string>& perrs_str, std::list<nodetool::net_address>& peers);
bool handle_command_line(const boost::program_options::variables_map& vm); bool handle_command_line(const boost::program_options::variables_map& vm);
bool idle_worker(); bool idle_worker();
bool handle_remote_peerlist(const std::list<peerlist_entry>& peerlist, time_t local_time, const net_utils::connection_context_base& context); bool handle_remote_peerlist(const std::list<peerlist_entry>& peerlist, time_t local_time, const net_utils::connection_context_base& context);
@ -298,9 +301,16 @@ namespace nodetool
critical_section m_blocked_ips_lock; critical_section m_blocked_ips_lock;
std::map<uint32_t, time_t> m_blocked_ips; std::map<uint32_t, time_t> m_blocked_ips;
//critical_section m_permanently_blocked_ips_lock;
std::set<uint32_t> m_permanently_blocked_ips;
critical_section m_ip_fails_score_lock; critical_section m_ip_fails_score_lock;
std::map<uint32_t, uint64_t> m_ip_fails_score; std::map<uint32_t, uint64_t> m_ip_fails_score;
critical_section m_p2p_manual_config_lock;
p2p_config_data m_p2p_manual_config;
}; };
} }

View file

@ -106,8 +106,11 @@ namespace nodetool
} }
//----------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------
template<class t_payload_net_handler> template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::is_remote_ip_allowed(uint32_t addr) bool node_server<t_payload_net_handler>::is_remote_ip_allowed(uint32_t addr, bool is_incoming)
{ {
if (is_incoming && m_p2p_manual_config.incoming_connections_limit && *m_p2p_manual_config.incoming_connections_limit >= get_incoming_connections_count())
return false;
if (m_offline_mode) if (m_offline_mode)
return false; return false;
@ -132,6 +135,13 @@ namespace nodetool
bool node_server<t_payload_net_handler>::is_ip_in_blacklist(uint32_t addr) bool node_server<t_payload_net_handler>::is_ip_in_blacklist(uint32_t addr)
{ {
CRITICAL_REGION_LOCAL(m_blocked_ips_lock); 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;
//check temporary blocked
auto it = m_blocked_ips.find(addr); auto it = m_blocked_ips.find(addr);
if (it == m_blocked_ips.end()) if (it == m_blocked_ips.end())
return false; return false;
@ -147,6 +157,77 @@ namespace nodetool
} }
//----------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------
template<class t_payload_net_handler> template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::reload_p2p_manual_config(bool silent)
{
std::set<uint32_t> new_block_list;
std::list<net_address> 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.ip_priority_list.size())
{
bool r = parse_peerlist(config.ip_priority_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<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::block_ip(uint32_t addr) bool node_server<t_payload_net_handler>::block_ip(uint32_t addr)
{ {
CRITICAL_REGION_LOCAL(m_blocked_ips_lock); CRITICAL_REGION_LOCAL(m_blocked_ips_lock);
@ -188,6 +269,19 @@ namespace nodetool
} }
//----------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------
template<class t_payload_net_handler> template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::parse_peerlist(const std::vector<std::string>& perrs_str, std::list<net_address>& 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<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::handle_command_line(const boost::program_options::variables_map& vm) bool node_server<t_payload_net_handler>::handle_command_line(const boost::program_options::variables_map& vm)
{ {
m_bind_ip = command_line::get_arg(vm, arg_p2p_bind_ip); m_bind_ip = command_line::get_arg(vm, arg_p2p_bind_ip);
@ -236,13 +330,8 @@ namespace nodetool
if (command_line::has_arg(vm, arg_p2p_add_priority_node)) if (command_line::has_arg(vm, arg_p2p_add_priority_node))
{ {
std::vector<std::string> perrs = command_line::get_arg(vm, arg_p2p_add_priority_node); std::vector<std::string> perrs = command_line::get_arg(vm, arg_p2p_add_priority_node);
for(const std::string& pr_str: perrs) bool r = parse_peerlist(perrs, m_priority_peers);
{ CHECK_AND_ASSERT_MES(r, false, "Failed to parse priority peers");
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);
}
} }
if(command_line::has_arg(vm, arg_p2p_use_only_priority_nodes)) if(command_line::has_arg(vm, arg_p2p_use_only_priority_nodes))
m_use_only_priority_peers = true; m_use_only_priority_peers = true;
@ -383,6 +472,10 @@ namespace nodetool
LOG_PRINT_GREEN("Net service binded on " << m_bind_ip << ":" << m_listenning_port, LOG_LEVEL_0); LOG_PRINT_GREEN("Net service binded on " << m_bind_ip << ":" << m_listenning_port, LOG_LEVEL_0);
if(m_external_port) if(m_external_port)
LOG_PRINT_L0("External port defined as " << m_external_port); LOG_PRINT_L0("External port defined as " << m_external_port);
reload_p2p_manual_config(true);
return res; return res;
} }
//----------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------
@ -842,7 +935,7 @@ namespace nodetool
continue; continue;
} }
if (!is_remote_ip_allowed(pe.adr.ip)) if (!is_remote_ip_allowed(pe.adr.ip, false))
{ {
++peer_index; ++peer_index;
continue; continue;
@ -913,7 +1006,19 @@ namespace nodetool
size_t expected_white_connections = (m_config.m_net_config.connections_count*P2P_DEFAULT_WHITELIST_CONNECTIONS_PERCENT)/100; 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(); size_t conn_count = get_outgoing_connections_count();
if(conn_count < m_config.m_net_config.connections_count) bool need_more_connections = false;
if (m_p2p_manual_config.outgoing_connections_limit)
{
// m_p2p_manual_config always override default settings from m_config.m_net_config
need_more_connections = conn_count < *m_p2p_manual_config.outgoing_connections_limit;
}
else
{
// use default policy
need_more_connections = conn_count < m_config.m_net_config.connections_count;
}
if(need_more_connections)
{ {
if(conn_count < expected_white_connections) if(conn_count < expected_white_connections)
{ {
@ -966,6 +1071,20 @@ namespace nodetool
return true; return true;
}); });
return count;
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
size_t node_server<t_payload_net_handler>::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; return count;
} }
//----------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------

View file

@ -289,6 +289,29 @@ namespace nodetool
}; };
}; };
struct p2p_config_data
{
std::optional<uint64_t> incoming_connections_limit;
std::optional<uint64_t> outgoing_connections_limit;
std::vector<std::string> ip_black_list;
std::optional<bool> use_only_priority_peers = false; //allow to make outgoing connections only to the peers listed in ip_priority_list
std::vector<std::string> ip_priority_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(ip_priority_list)
END_KV_SERIALIZE_MAP()
};
#ifdef ALLOW_DEBUG_COMMANDS #ifdef ALLOW_DEBUG_COMMANDS
//These commands are considered as insecure, and made in debug purposes for a limited lifetime. //These commands are considered as insecure, and made in debug purposes for a limited lifetime.

View file

@ -9,6 +9,10 @@
#include <vector> #include <vector>
#include <list> #include <list>
#define SANITY_CHECK_MAX_RESERVATION_RAM 10000000
//#include "serialization.h" //#include "serialization.h"
template <template <bool> class Archive, class T> template <template <bool> class Archive, class T>
bool do_serialize(Archive<false> &ar, std::vector<T> &v); bool do_serialize(Archive<false> &ar, std::vector<T> &v);
@ -44,12 +48,18 @@ bool do_serialize(Archive<false> &ar, std::vector<T> &v)
v.clear(); v.clear();
// very basic sanity check // very basic sanity check
if (ar.remaining_bytes() < (cnt * sizeof(T)) ) { if (ar.remaining_bytes() < cnt) {
ar.stream().setstate(std::ios::failbit); ar.stream().setstate(std::ios::failbit);
return false; return false;
} }
v.reserve(cnt); if (sizeof(T) * cnt < SANITY_CHECK_MAX_RESERVATION_RAM)
{
v.reserve(cnt);
}
for (size_t i = 0; i < cnt; i++) { for (size_t i = 0; i < cnt; i++) {
if (i > 0) if (i > 0)
ar.delimit_array(); ar.delimit_array();