diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/cryptonote_protocol/cryptonote_protocol_defs.h | 4 | ||||
-rw-r--r-- | src/cryptonote_protocol/cryptonote_protocol_handler.inl | 51 | ||||
-rw-r--r-- | src/p2p/net_node.h | 42 | ||||
-rw-r--r-- | src/p2p/net_node.inl | 215 | ||||
-rw-r--r-- | src/p2p/net_node_common.h | 18 | ||||
-rw-r--r-- | src/p2p/net_peerlist.h | 78 | ||||
-rw-r--r-- | src/p2p/net_peerlist_boost_serialization.h | 35 | ||||
-rw-r--r-- | src/p2p/p2p_protocol_defs.h | 121 | ||||
-rw-r--r-- | src/rpc/core_rpc_server.cpp | 40 | ||||
-rw-r--r-- | src/rpc/core_rpc_server_commands_defs.h | 13 |
10 files changed, 386 insertions, 231 deletions
diff --git a/src/cryptonote_protocol/cryptonote_protocol_defs.h b/src/cryptonote_protocol/cryptonote_protocol_defs.h index fd5b980b8..6f6c1a803 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_defs.h +++ b/src/cryptonote_protocol/cryptonote_protocol_defs.h @@ -49,6 +49,8 @@ namespace cryptonote bool localhost; bool local_ip; + std::string address; + std::string host; std::string ip; std::string port; @@ -76,6 +78,8 @@ namespace cryptonote KV_SERIALIZE(incoming) KV_SERIALIZE(localhost) KV_SERIALIZE(local_ip) + KV_SERIALIZE(address) + KV_SERIALIZE(host) KV_SERIALIZE(ip) KV_SERIALIZE(port) KV_SERIALIZE(peer_id) diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl index 79578a34e..dbb8af445 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl +++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl @@ -134,17 +134,12 @@ namespace cryptonote << std::setw(13) << "Up(now)" << ENDL; - uint32_t ip; m_p2p->for_each_connection([&](const connection_context& cntxt, nodetool::peerid_type peer_id, uint32_t support_flags) { - bool local_ip = false; - ip = ntohl(cntxt.m_remote_ip); - // TODO: local ip in calss A, B - if (ip > 3232235520 && ip < 3232301055) // 192.168.x.x - local_ip = true; + bool local_ip = cntxt.m_remote_address.is_local(); auto connection_time = time(NULL) - cntxt.m_started; ss << std::setw(30) << std::left << std::string(cntxt.m_is_income ? " [INC]":"[OUT]") + - epee::string_tools::get_ip_string_from_int32(cntxt.m_remote_ip) + ":" + std::to_string(cntxt.m_remote_port) + cntxt.m_remote_address.str() << std::setw(20) << std::hex << peer_id << std::setw(20) << std::hex << support_flags << std::setw(30) << std::to_string(cntxt.m_recv_cnt)+ "(" + std::to_string(time(NULL) - cntxt.m_last_recv) + ")" + "/" + std::to_string(cntxt.m_send_cnt) + "(" + std::to_string(time(NULL) - cntxt.m_last_send) + ")" @@ -155,7 +150,7 @@ namespace cryptonote << std::setw(10) << std::fixed << (connection_time == 0 ? 0.0 : cntxt.m_send_cnt / connection_time / 1024) << std::setw(13) << std::fixed << cntxt.m_current_speed_up / 1024 << (local_ip ? "[LAN]" : "") - << std::left << (ip == LOCALHOST_INT ? "[LOCALHOST]" : "") // 127.0.0.1 + << std::left << (cntxt.m_remote_address.is_loopback() ? "[LOCALHOST]" : "") // 127.0.0.1 << ENDL; if (connection_time > 1) @@ -193,8 +188,15 @@ namespace cryptonote cnx.incoming = cntxt.m_is_income ? true : false; - cnx.ip = epee::string_tools::get_ip_string_from_int32(cntxt.m_remote_ip); - cnx.port = std::to_string(cntxt.m_remote_port); + cnx.address = cntxt.m_remote_address.str(); + cnx.host = cntxt.m_remote_address.host_str(); + cnx.ip = ""; + cnx.port = ""; + if (cntxt.m_remote_address.type() == typeid(epee::net_utils::ipv4_network_address)) + { + cnx.ip = cnx.host; + cnx.port = std::to_string(cntxt.m_remote_address.as<epee::net_utils::ipv4_network_address>().port()); + } std::stringstream peer_id_str; peer_id_str << std::hex << peer_id; @@ -212,25 +214,8 @@ namespace cryptonote cnx.live_time = timestamp - cntxt.m_started; - uint32_t ip; - ip = ntohl(cntxt.m_remote_ip); - if (ip == LOCALHOST_INT) - { - cnx.localhost = true; - } - else - { - cnx.localhost = false; - } - - if (ip > 3232235520 && ip < 3232301055) // 192.168.x.x - { - cnx.local_ip = true; - } - else - { - cnx.local_ip = false; - } + cnx.localhost = cntxt.m_remote_address.is_loopback(); + cnx.local_ip = cntxt.m_remote_address.is_local(); auto connection_time = time(NULL) - cntxt.m_started; if (connection_time == 0) @@ -980,7 +965,7 @@ namespace cryptonote { LOG_PRINT_CCONTEXT_L1("Block verification failed, dropping connection"); m_p2p->drop_connection(context); - m_p2p->add_ip_fail(context.m_remote_ip); + m_p2p->add_host_fail(context.m_remote_address); m_core.cleanup_handle_incoming_blocks(); return 1; } @@ -988,7 +973,7 @@ namespace cryptonote { LOG_PRINT_CCONTEXT_L1("Block received at sync phase was marked as orphaned, dropping connection"); m_p2p->drop_connection(context); - m_p2p->add_ip_fail(context.m_remote_ip); + m_p2p->add_host_fail(context.m_remote_address); m_core.cleanup_handle_incoming_blocks(); return 1; } @@ -1140,7 +1125,7 @@ skip: { LOG_ERROR_CCONTEXT("sent empty m_block_ids, dropping connection"); m_p2p->drop_connection(context); - m_p2p->add_ip_fail(context.m_remote_ip); + m_p2p->add_host_fail(context.m_remote_address); return 1; } @@ -1149,7 +1134,7 @@ skip: LOG_ERROR_CCONTEXT("sent m_block_ids starting from unknown id: " << epee::string_tools::pod_to_hex(arg.m_block_ids.front()) << " , dropping connection"); m_p2p->drop_connection(context); - m_p2p->add_ip_fail(context.m_remote_ip); + m_p2p->add_host_fail(context.m_remote_address); return 1; } diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h index 13cd3f5b0..8798a52e0 100644 --- a/src/p2p/net_node.h +++ b/src/p2p/net_node.h @@ -123,9 +123,9 @@ namespace nodetool size_t get_outgoing_connections_count(); peerlist_manager& get_peerlist_manager(){return m_peerlist;} void delete_connections(size_t count); - virtual bool block_ip(uint32_t adress, time_t seconds = P2P_IP_BLOCKTIME); - virtual bool unblock_ip(uint32_t address); - virtual std::map<uint32_t, time_t> get_blocked_ips() { CRITICAL_REGION_LOCAL(m_blocked_ips_lock); return m_blocked_ips; } + virtual bool block_host(const epee::net_utils::network_address &adress, time_t seconds = P2P_IP_BLOCKTIME); + virtual bool unblock_host(const epee::net_utils::network_address &address); + virtual std::map<std::string, time_t> get_blocked_hosts() { CRITICAL_REGION_LOCAL(m_blocked_hosts_lock); return m_blocked_hosts; } private: const std::vector<std::string> m_seed_nodes_list = { "seeds.moneroseeds.se" @@ -186,11 +186,11 @@ namespace nodetool virtual bool drop_connection(const epee::net_utils::connection_context_base& context); virtual void request_callback(const epee::net_utils::connection_context_base& context); virtual void for_each_connection(std::function<bool(typename t_payload_net_handler::connection_context&, peerid_type, uint32_t)> f); - virtual bool add_ip_fail(uint32_t address); + virtual bool add_host_fail(const epee::net_utils::network_address &address); //----------------- i_connection_filter -------------------------------------------------------- - virtual bool is_remote_ip_allowed(uint32_t adress); + virtual bool is_remote_host_allowed(const epee::net_utils::network_address &address); //----------------------------------------------------------------------------------------------- - bool parse_peer_from_string(nodetool::net_address& pe, const std::string& node_addr); + bool parse_peer_from_string(epee::net_utils::network_address& pe, const std::string& node_addr, uint16_t default_port = 0); bool handle_command_line( const boost::program_options::variables_map& vm ); @@ -209,18 +209,18 @@ namespace nodetool bool make_new_connection_from_anchor_peerlist(const std::vector<anchor_peerlist_entry>& anchor_peerlist); bool make_new_connection_from_peerlist(bool use_white_list); - bool try_to_connect_and_handshake_with_new_peer(const net_address& na, bool just_take_peerlist = false, uint64_t last_seen_stamp = 0, PeerType peer_type = white, uint64_t first_seen_stamp = 0); + bool try_to_connect_and_handshake_with_new_peer(const epee::net_utils::network_address& na, bool just_take_peerlist = false, uint64_t last_seen_stamp = 0, PeerType peer_type = white, uint64_t first_seen_stamp = 0); size_t get_random_index_with_fixed_probability(size_t max_index); bool is_peer_used(const peerlist_entry& peer); bool is_peer_used(const anchor_peerlist_entry& peer); - bool is_addr_connected(const net_address& peer); + bool is_addr_connected(const epee::net_utils::network_address& peer); template<class t_callback> bool try_ping(basic_node_data& node_data, p2p_connection_context& context, t_callback cb); bool try_get_support_flags(const p2p_connection_context& context, std::function<void(p2p_connection_context&, const uint32_t&)> f); bool make_expected_connections_count(PeerType peer_type, size_t expected_connections); - void cache_connect_fail_info(const net_address& addr); - bool is_addr_recently_failed(const net_address& addr); - bool is_priority_node(const net_address& na); + void cache_connect_fail_info(const epee::net_utils::network_address& addr); + bool is_addr_recently_failed(const epee::net_utils::network_address& addr); + bool is_priority_node(const epee::net_utils::network_address& na); std::set<std::string> get_seed_nodes(bool testnet) const; template <class Container> @@ -236,9 +236,9 @@ namespace nodetool bool set_rate_down_limit(const boost::program_options::variables_map& vm, int64_t limit); bool set_rate_limit(const boost::program_options::variables_map& vm, int64_t limit); - bool has_too_many_connections(const uint32_t ip); + bool has_too_many_connections(const epee::net_utils::network_address &address); - bool check_connection_and_handshake_with_peer(const net_address& na, uint64_t last_seen_stamp); + bool check_connection_and_handshake_with_peer(const epee::net_utils::network_address& na, uint64_t last_seen_stamp); bool gray_peerlist_housekeeping(); void kill() { ///< will be called e.g. from deinit() @@ -308,23 +308,23 @@ namespace nodetool #ifdef ALLOW_DEBUG_COMMANDS uint64_t m_last_stat_request_time; #endif - std::list<net_address> m_priority_peers; - std::vector<net_address> m_exclusive_peers; - std::vector<net_address> m_seed_nodes; + std::list<epee::net_utils::network_address> m_priority_peers; + std::vector<epee::net_utils::network_address> m_exclusive_peers; + std::vector<epee::net_utils::network_address> m_seed_nodes; std::list<nodetool::peerlist_entry> m_command_line_peers; uint64_t m_peer_livetime; //keep connections to initiate some interactions net_server m_net_server; boost::uuids::uuid m_network_id; - std::map<net_address, time_t> m_conn_fails_cache; + std::map<epee::net_utils::network_address, time_t> m_conn_fails_cache; epee::critical_section m_conn_fails_cache_lock; - epee::critical_section m_blocked_ips_lock; - std::map<uint32_t, time_t> m_blocked_ips; + epee::critical_section m_blocked_hosts_lock; + std::map<std::string, time_t> m_blocked_hosts; - epee::critical_section m_ip_fails_score_lock; - std::map<uint32_t, uint64_t> m_ip_fails_score; + epee::critical_section m_host_fails_score_lock; + std::map<std::string, uint64_t> m_host_fails_score; bool m_testnet; }; diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index 5c903b1f5..47582cb96 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -200,16 +200,16 @@ namespace nodetool } //----------------------------------------------------------------------------------- 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_host_allowed(const epee::net_utils::network_address &address) { - CRITICAL_REGION_LOCAL(m_blocked_ips_lock); - auto it = m_blocked_ips.find(addr); - if(it == m_blocked_ips.end()) + CRITICAL_REGION_LOCAL(m_blocked_hosts_lock); + auto it = m_blocked_hosts.find(address.host_str()); + if(it == m_blocked_hosts.end()) return true; if(time(nullptr) >= it->second) { - m_blocked_ips.erase(it); - MCLOG_CYAN(el::Level::Info, "global", "IP " << epee::string_tools::get_ip_string_from_int32(addr) << " unblocked."); + m_blocked_hosts.erase(it); + MCLOG_CYAN(el::Level::Info, "global", "Host " << address.host_str() << " unblocked."); return true; } return false; @@ -229,16 +229,16 @@ namespace nodetool } //----------------------------------------------------------------------------------- template<class t_payload_net_handler> - bool node_server<t_payload_net_handler>::block_ip(uint32_t addr, time_t seconds) + bool node_server<t_payload_net_handler>::block_host(const epee::net_utils::network_address &addr, time_t seconds) { - CRITICAL_REGION_LOCAL(m_blocked_ips_lock); - m_blocked_ips[addr] = time(nullptr) + seconds; + CRITICAL_REGION_LOCAL(m_blocked_hosts_lock); + m_blocked_hosts[addr.host_str()] = time(nullptr) + seconds; // drop any connection to that IP std::list<boost::uuids::uuid> conns; m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt) { - if (cntxt.m_remote_ip == addr) + if (cntxt.m_remote_address.is_same_host(addr)) { conns.push_back(cntxt.m_connection_id); } @@ -247,42 +247,42 @@ namespace nodetool for (const auto &c: conns) m_net_server.get_config_object().close(c); - MCLOG_CYAN(el::Level::Info, "global", "IP " << epee::string_tools::get_ip_string_from_int32(addr) << " blocked."); + MCLOG_CYAN(el::Level::Info, "global", "Host " << addr.host_str() << " blocked."); return true; } //----------------------------------------------------------------------------------- template<class t_payload_net_handler> - bool node_server<t_payload_net_handler>::unblock_ip(uint32_t addr) + bool node_server<t_payload_net_handler>::unblock_host(const epee::net_utils::network_address &address) { - CRITICAL_REGION_LOCAL(m_blocked_ips_lock); - auto i = m_blocked_ips.find(addr); - if (i == m_blocked_ips.end()) + CRITICAL_REGION_LOCAL(m_blocked_hosts_lock); + auto i = m_blocked_hosts.find(address.host_str()); + if (i == m_blocked_hosts.end()) return false; - m_blocked_ips.erase(i); - MCLOG_CYAN(el::Level::Info, "global", "IP " << epee::string_tools::get_ip_string_from_int32(addr) << " unblocked."); + m_blocked_hosts.erase(i); + MCLOG_CYAN(el::Level::Info, "global", "Host " << address.host_str() << " unblocked."); return true; } //----------------------------------------------------------------------------------- template<class t_payload_net_handler> - bool node_server<t_payload_net_handler>::add_ip_fail(uint32_t address) + bool node_server<t_payload_net_handler>::add_host_fail(const epee::net_utils::network_address &address) { - CRITICAL_REGION_LOCAL(m_ip_fails_score_lock); - uint64_t fails = ++m_ip_fails_score[address]; - MDEBUG("IP " << epee::string_tools::get_ip_string_from_int32(address) << " fail score=" << fails); + CRITICAL_REGION_LOCAL(m_host_fails_score_lock); + uint64_t fails = ++m_host_fails_score[address.host_str()]; + MDEBUG("Host " << address.host_str() << " fail score=" << fails); if(fails > P2P_IP_FAILS_BEFORE_BLOCK) { - auto it = m_ip_fails_score.find(address); - CHECK_AND_ASSERT_MES(it != m_ip_fails_score.end(), false, "internal error"); + auto it = m_host_fails_score.find(address.host_str()); + CHECK_AND_ASSERT_MES(it != m_host_fails_score.end(), false, "internal error"); it->second = P2P_IP_FAILS_BEFORE_BLOCK/2; - block_ip(address); + block_host(address); } return true; } //----------------------------------------------------------------------------------- template<class t_payload_net_handler> - bool node_server<t_payload_net_handler>::parse_peer_from_string(nodetool::net_address& pe, const std::string& node_addr) + bool node_server<t_payload_net_handler>::parse_peer_from_string(epee::net_utils::network_address& pe, const std::string& node_addr, uint16_t default_port) { - return epee::string_tools::parse_peer_from_string(pe.ip, pe.port, node_addr); + return epee::net_utils::create_network_address(pe, node_addr, default_port); } //----------------------------------------------------------------------------------- template<class t_payload_net_handler> @@ -306,10 +306,9 @@ namespace nodetool { nodetool::peerlist_entry pe = AUTO_VAL_INIT(pe); pe.id = crypto::rand<uint64_t>(); - bool r = parse_peer_from_string(pe.adr, pr_str); + const uint16_t default_port = m_testnet ? ::config::testnet::P2P_DEFAULT_PORT : ::config::P2P_DEFAULT_PORT; + bool r = parse_peer_from_string(pe.adr, pr_str, default_port); CHECK_AND_ASSERT_MES(r, false, "Failed to parse address from string: " << pr_str); - if (pe.adr.port == 0) - pe.adr.port = m_testnet ? ::config::testnet::P2P_DEFAULT_PORT : ::config::P2P_DEFAULT_PORT; m_command_line_peers.push_back(pe); } } @@ -359,7 +358,7 @@ namespace nodetool } //----------------------------------------------------------------------------------- inline void append_net_address( - std::vector<net_address> & seed_nodes + std::vector<epee::net_utils::network_address> & seed_nodes , std::string const & addr ) { @@ -383,15 +382,14 @@ namespace nodetool ip::tcp::endpoint endpoint = *i; if (endpoint.address().is_v4()) { - nodetool::net_address na; - na.ip = boost::asio::detail::socket_ops::host_to_network_long(endpoint.address().to_v4().to_ulong()); - na.port = endpoint.port(); + epee::net_utils::network_address na(new epee::net_utils::ipv4_network_address(boost::asio::detail::socket_ops::host_to_network_long(endpoint.address().to_v4().to_ulong()), endpoint.port())); seed_nodes.push_back(na); - MINFO("Added seed node: " << endpoint.address().to_v4().to_string(ec) << ':' << na.port); + MINFO("Added seed node: " << na.str()); } else { - MDEBUG("IPv6 doesn't supported, skip '" << host << "' -> " << endpoint.address().to_v6().to_string(ec)); + MERROR("IPv6 unsupported, skip '" << host << "' -> " << endpoint.address().to_v6().to_string(ec)); + throw std::runtime_error("IPv6 unsupported"); } } } @@ -752,10 +750,10 @@ namespace nodetool return; } - if(!handle_remote_peerlist(rsp.local_peerlist, rsp.node_data.local_time, context)) + if(!handle_remote_peerlist(rsp.local_peerlist_new, rsp.node_data.local_time, context)) { LOG_ERROR_CC(context, "COMMAND_HANDSHAKE: failed to handle_remote_peerlist(...), closing connection."); - add_ip_fail(context.m_remote_ip); + add_host_fail(context.m_remote_address); return; } hsh_result = true; @@ -769,7 +767,7 @@ namespace nodetool } pi = context.peer_id = rsp.node_data.peer_id; - m_peerlist.set_peer_just_seen(rsp.node_data.peer_id, context.m_remote_ip, context.m_remote_port); + m_peerlist.set_peer_just_seen(rsp.node_data.peer_id, context.m_remote_address); if(rsp.node_data.peer_id == m_config.m_peer_id) { @@ -820,14 +818,14 @@ namespace nodetool return; } - if(!handle_remote_peerlist(rsp.local_peerlist, rsp.local_time, context)) + if(!handle_remote_peerlist(rsp.local_peerlist_new, rsp.local_time, context)) { LOG_WARNING_CC(context, "COMMAND_TIMED_SYNC: failed to handle_remote_peerlist(...), closing connection."); m_net_server.get_config_object().close(context.m_connection_id ); - add_ip_fail(context.m_remote_ip); + add_host_fail(context.m_remote_address); } if(!context.m_is_income) - m_peerlist.set_peer_just_seen(context.peer_id, context.m_remote_ip, context.m_remote_port); + m_peerlist.set_peer_just_seen(context.peer_id, context.m_remote_address); m_payload_handler.process_payload_sync_data(rsp.payload_data, context, false); }); @@ -862,7 +860,7 @@ namespace nodetool bool used = false; m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt) { - if(cntxt.peer_id == peer.id || (!cntxt.m_is_income && peer.adr.ip == cntxt.m_remote_ip && peer.adr.port == cntxt.m_remote_port)) + if(cntxt.peer_id == peer.id || (!cntxt.m_is_income && peer.adr == cntxt.m_remote_address)) { used = true; return false;//stop enumerating @@ -884,7 +882,7 @@ namespace nodetool m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt) { - if(cntxt.peer_id == peer.id || (!cntxt.m_is_income && peer.adr.ip == cntxt.m_remote_ip && peer.adr.port == cntxt.m_remote_port)) + if(cntxt.peer_id == peer.id || (!cntxt.m_is_income && peer.adr == cntxt.m_remote_address)) { used = true; @@ -898,12 +896,12 @@ namespace nodetool } //----------------------------------------------------------------------------------- template<class t_payload_net_handler> - bool node_server<t_payload_net_handler>::is_addr_connected(const net_address& peer) + bool node_server<t_payload_net_handler>::is_addr_connected(const epee::net_utils::network_address& peer) { bool connected = false; m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt) { - if(!cntxt.m_is_income && peer.ip == cntxt.m_remote_ip && peer.port == cntxt.m_remote_port) + if(!cntxt.m_is_income && peer == cntxt.m_remote_address) { connected = true; return false;//stop enumerating @@ -924,7 +922,7 @@ namespace nodetool } while(0) template<class t_payload_net_handler> - bool node_server<t_payload_net_handler>::try_to_connect_and_handshake_with_new_peer(const net_address& na, bool just_take_peerlist, uint64_t last_seen_stamp, PeerType peer_type, uint64_t first_seen_stamp) + bool node_server<t_payload_net_handler>::try_to_connect_and_handshake_with_new_peer(const epee::net_utils::network_address& na, bool just_take_peerlist, uint64_t last_seen_stamp, PeerType peer_type, uint64_t first_seen_stamp) { if (m_current_number_of_out_peers == m_config.m_net_config.connections_count) // out peers limit { @@ -936,23 +934,24 @@ namespace nodetool m_current_number_of_out_peers --; // atomic variable, update time = 1s return false; } - MDEBUG("Connecting to " << epee::string_tools::get_ip_string_from_int32(na.ip) << ":" - << epee::string_tools::num_to_string_fast(na.port) << "(peer_type=" << peer_type << ", last_seen: " + MDEBUG("Connecting to " << na.str() << "(peer_type=" << peer_type << ", last_seen: " << (last_seen_stamp ? epee::misc_utils::get_time_interval_string(time(NULL) - last_seen_stamp):"never") << ")..."); + CHECK_AND_ASSERT_MES(na.type() == typeid(epee::net_utils::ipv4_network_address), false, + "Only IPv4 addresses are supported here, got " << na.type().name()); + const epee::net_utils::ipv4_network_address &ipv4 = na.as<const epee::net_utils::ipv4_network_address>(); + typename net_server::t_connection_context con = AUTO_VAL_INIT(con); - bool res = m_net_server.connect(epee::string_tools::get_ip_string_from_int32(na.ip), - epee::string_tools::num_to_string_fast(na.port), + bool res = m_net_server.connect(epee::string_tools::get_ip_string_from_int32(ipv4.ip()), + epee::string_tools::num_to_string_fast(ipv4.port()), m_config.m_net_config.connection_timeout, con); if(!res) { bool is_priority = is_priority_node(na); - LOG_PRINT_CC_PRIORITY_NODE(is_priority, con, "Connect failed to " - << epee::string_tools::get_ip_string_from_int32(na.ip) - << ":" << epee::string_tools::num_to_string_fast(na.port) + LOG_PRINT_CC_PRIORITY_NODE(is_priority, con, "Connect failed to " << na.str() /*<< ", try " << try_count*/); //m_peerlist.set_peer_unreachable(pe); return false; @@ -965,8 +964,7 @@ namespace nodetool { bool is_priority = is_priority_node(na); LOG_PRINT_CC_PRIORITY_NODE(is_priority, con, "Failed to HANDSHAKE with peer " - << epee::string_tools::get_ip_string_from_int32(na.ip) - << ":" << epee::string_tools::num_to_string_fast(na.port) + << na.str() /*<< ", try " << try_count*/); return false; } @@ -999,25 +997,26 @@ namespace nodetool } template<class t_payload_net_handler> - bool node_server<t_payload_net_handler>::check_connection_and_handshake_with_peer(const net_address& na, uint64_t last_seen_stamp) + bool node_server<t_payload_net_handler>::check_connection_and_handshake_with_peer(const epee::net_utils::network_address& na, uint64_t last_seen_stamp) { - LOG_PRINT_L1("Connecting to " << epee::string_tools::get_ip_string_from_int32(na.ip) << ":" - << epee::string_tools::num_to_string_fast(na.port) << "(last_seen: " + LOG_PRINT_L1("Connecting to " << na.str() << "(last_seen: " << (last_seen_stamp ? epee::misc_utils::get_time_interval_string(time(NULL) - last_seen_stamp):"never") << ")..."); + CHECK_AND_ASSERT_MES(na.type() == typeid(epee::net_utils::ipv4_network_address), false, + "Only IPv4 addresses are supported here, got " << na.type().name()); + const epee::net_utils::ipv4_network_address &ipv4 = na.as<epee::net_utils::ipv4_network_address>(); + typename net_server::t_connection_context con = AUTO_VAL_INIT(con); - bool res = m_net_server.connect(epee::string_tools::get_ip_string_from_int32(na.ip), - epee::string_tools::num_to_string_fast(na.port), + bool res = m_net_server.connect(epee::string_tools::get_ip_string_from_int32(ipv4.ip()), + epee::string_tools::num_to_string_fast(ipv4.port()), m_config.m_net_config.connection_timeout, con); if (!res) { bool is_priority = is_priority_node(na); - LOG_PRINT_CC_PRIORITY_NODE(is_priority, con, "Connect failed to " - << epee::string_tools::get_ip_string_from_int32(na.ip) - << ":" << epee::string_tools::num_to_string_fast(na.port)); + LOG_PRINT_CC_PRIORITY_NODE(is_priority, con, "Connect failed to " << na.str()); return false; } @@ -1028,9 +1027,7 @@ namespace nodetool if (!res) { bool is_priority = is_priority_node(na); - LOG_PRINT_CC_PRIORITY_NODE(is_priority, con, "Failed to HANDSHAKE with peer " - << epee::string_tools::get_ip_string_from_int32(na.ip) - << ":" << epee::string_tools::num_to_string_fast(na.port)); + LOG_PRINT_CC_PRIORITY_NODE(is_priority, con, "Failed to HANDSHAKE with peer " << na.str()); return false; } @@ -1046,7 +1043,7 @@ namespace nodetool //----------------------------------------------------------------------------------- template<class t_payload_net_handler> - bool node_server<t_payload_net_handler>::is_addr_recently_failed(const net_address& addr) + bool node_server<t_payload_net_handler>::is_addr_recently_failed(const epee::net_utils::network_address& addr) { CRITICAL_REGION_LOCAL(m_conn_fails_cache_lock); auto it = m_conn_fails_cache.find(addr); @@ -1063,14 +1060,14 @@ namespace nodetool bool node_server<t_payload_net_handler>::make_new_connection_from_anchor_peerlist(const std::vector<anchor_peerlist_entry>& anchor_peerlist) { for (const auto& pe: anchor_peerlist) { - _note("Considering connecting (out) to peer: " << pe.id << " " << epee::string_tools::get_ip_string_from_int32(pe.adr.ip) << ":" << boost::lexical_cast<std::string>(pe.adr.port)); + _note("Considering connecting (out) to peer: " << pe.id << " " << pe.adr.str()); if(is_peer_used(pe)) { _note("Peer is used"); continue; } - if(!is_remote_ip_allowed(pe.adr.ip)) { + if(!is_remote_host_allowed(pe.adr)) { continue; } @@ -1078,8 +1075,7 @@ namespace nodetool continue; } - MDEBUG("Selected peer: " << pe.id << " " << epee::string_tools::get_ip_string_from_int32(pe.adr.ip) - << ":" << boost::lexical_cast<std::string>(pe.adr.port) + MDEBUG("Selected peer: " << pe.id << " " << pe.adr.str() << "[peer_type=" << anchor << "] first_seen: " << epee::misc_utils::get_time_interval_string(time(NULL) - pe.first_seen)); @@ -1130,21 +1126,20 @@ namespace nodetool ++try_count; - _note("Considering connecting (out) to peer: " << pe.id << " " << epee::string_tools::get_ip_string_from_int32(pe.adr.ip) << ":" << boost::lexical_cast<std::string>(pe.adr.port)); + _note("Considering connecting (out) to peer: " << pe.id << " " << pe.adr.str()); if(is_peer_used(pe)) { _note("Peer is used"); continue; } - if(!is_remote_ip_allowed(pe.adr.ip)) + if(!is_remote_host_allowed(pe.adr)) continue; if(is_addr_recently_failed(pe.adr)) continue; - MDEBUG("Selected peer: " << pe.id << " " << epee::string_tools::get_ip_string_from_int32(pe.adr.ip) - << ":" << boost::lexical_cast<std::string>(pe.adr.port) + MDEBUG("Selected peer: " << pe.id << " " << pe.adr.str() << "[peer_list=" << (use_white_list ? white : gray) << "] last_seen: " << (pe.last_seen ? epee::misc_utils::get_time_interval_string(time(NULL) - pe.last_seen) : "never")); @@ -1325,7 +1320,7 @@ namespace nodetool { if(be.last_seen > local_time) { - MWARNING("FOUND FUTURE peerlist for entry " << epee::string_tools::get_ip_string_from_int32(be.adr.ip) << ":" << be.adr.port << " last_seen: " << be.last_seen << ", local_time(on remote node):" << local_time); + MWARNING("FOUND FUTURE peerlist for entry " << be.adr.str() << " last_seen: " << be.last_seen << ", local_time(on remote node):" << local_time); return false; } be.last_seen += delta; @@ -1421,8 +1416,7 @@ namespace nodetool m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt) { connection_entry ce; - ce.adr.ip = cntxt.m_remote_ip; - ce.adr.port = cntxt.m_remote_port; + ce.adr = cntxt.m_remote_address; ce.id = cntxt.peer_id; ce.is_income = cntxt.m_is_income; rsp.connections_list.push_back(ce); @@ -1512,19 +1506,24 @@ namespace nodetool if(!node_data.my_port) return false; - uint32_t actual_ip = context.m_remote_ip; - if(!m_peerlist.is_ip_allowed(actual_ip)) + CHECK_AND_ASSERT_MES(context.m_remote_address.type() == typeid(epee::net_utils::ipv4_network_address), false, + "Only IPv4 addresses are supported here, got " << context.m_remote_address.type().name()); + + const epee::net_utils::network_address na = context.m_remote_address; + uint32_t actual_ip = na.as<const epee::net_utils::ipv4_network_address>().ip(); + if(!m_peerlist.is_host_allowed(context.m_remote_address)) return false; std::string ip = epee::string_tools::get_ip_string_from_int32(actual_ip); std::string port = epee::string_tools::num_to_string_fast(node_data.my_port); + epee::net_utils::network_address address(new epee::net_utils::ipv4_network_address(actual_ip, node_data.my_port)); peerid_type pr = node_data.peer_id; - bool r = m_net_server.connect_async(ip, port, m_config.m_net_config.ping_connection_timeout, [cb, /*context,*/ ip, port, pr, this]( + bool r = m_net_server.connect_async(ip, port, m_config.m_net_config.ping_connection_timeout, [cb, /*context,*/ address, pr, this]( const typename net_server::t_connection_context& ping_context, const boost::system::error_code& ec)->bool { if(ec) { - LOG_WARNING_CC(ping_context, "back ping connect failed to " << ip << ":" << port); + LOG_WARNING_CC(ping_context, "back ping connect failed to " << address.str()); return false; } COMMAND_PING::request req; @@ -1543,13 +1542,13 @@ namespace nodetool { if(code <= 0) { - LOG_ERROR_CC(ping_context, "Failed to invoke COMMAND_PING to " << ip << ":" << port << "(" << code << ", " << epee::levin::get_err_descr(code) << ")"); + LOG_ERROR_CC(ping_context, "Failed to invoke COMMAND_PING to " << address.str() << "(" << code << ", " << epee::levin::get_err_descr(code) << ")"); return; } if(rsp.status != PING_OK_RESPONSE_STATUS_TEXT || pr != rsp.peer_id) { - LOG_ERROR_CC(ping_context, "back ping invoke wrong response \"" << rsp.status << "\" from" << ip << ":" << port << ", hsh_peer_id=" << pr_ << ", rsp.peer_id=" << rsp.peer_id); + LOG_ERROR_CC(ping_context, "back ping invoke wrong response \"" << rsp.status << "\" from" << address.str() << ", hsh_peer_id=" << pr_ << ", rsp.peer_id=" << rsp.peer_id); m_net_server.get_config_object().close(ping_context.m_connection_id); return; } @@ -1559,7 +1558,7 @@ namespace nodetool if(!inv_call_res) { - LOG_ERROR_CC(ping_context, "back ping invoke failed to " << ip << ":" << port); + LOG_ERROR_CC(ping_context, "back ping invoke failed to " << address.str()); m_net_server.get_config_object().close(ping_context.m_connection_id); return false; } @@ -1610,7 +1609,7 @@ namespace nodetool //fill response rsp.local_time = time(NULL); - m_peerlist.get_peerlist_head(rsp.local_peerlist); + m_peerlist.get_peerlist_head(rsp.local_peerlist_new); m_payload_handler.get_payload_sync_data(rsp.payload_data); LOG_DEBUG_CC(context, "COMMAND_TIMED_SYNC"); return 1; @@ -1624,7 +1623,7 @@ namespace nodetool LOG_INFO_CC(context, "WRONG NETWORK AGENT CONNECTED! id=" << epee::string_tools::get_str_from_guid_a(arg.node_data.network_id)); drop_connection(context); - add_ip_fail(context.m_remote_ip); + add_host_fail(context.m_remote_address); return 1; } @@ -1632,7 +1631,7 @@ namespace nodetool { LOG_ERROR_CC(context, "COMMAND_HANDSHAKE came not from incoming connection"); drop_connection(context); - add_ip_fail(context.m_remote_ip); + add_host_fail(context.m_remote_address); return 1; } @@ -1650,9 +1649,9 @@ namespace nodetool return 1; } - if(has_too_many_connections(context.m_remote_ip)) + if(has_too_many_connections(context.m_remote_address)) { - LOG_PRINT_CCONTEXT_L1("CONNECTION FROM " << epee::string_tools::get_ip_string_from_int32(context.m_remote_ip) << " REFUSED, too many connections from the same address"); + LOG_PRINT_CCONTEXT_L1("CONNECTION FROM " << context.m_remote_address.host_str() << " REFUSED, too many connections from the same address"); drop_connection(context); return 1; } @@ -1667,16 +1666,18 @@ namespace nodetool //try ping to be sure that we can add this peer to peer_list try_ping(arg.node_data, context, [peer_id_l, port_l, context, this]() { + CHECK_AND_ASSERT_MES(context.m_remote_address.type() == typeid(epee::net_utils::ipv4_network_address), void(), + "Only IPv4 addresses are supported here, got " << context.m_remote_address.type().name()); //called only(!) if success pinged, update local peerlist peerlist_entry pe; - pe.adr.ip = context.m_remote_ip; - pe.adr.port = port_l; + const epee::net_utils::network_address na = context.m_remote_address; + pe.adr.reset(new epee::net_utils::ipv4_network_address(na.as<epee::net_utils::ipv4_network_address>().ip(), port_l)); time_t last_seen; time(&last_seen); pe.last_seen = static_cast<int64_t>(last_seen); pe.id = peer_id_l; this->m_peerlist.append_with_peer_white(pe); - LOG_DEBUG_CC(context, "PING SUCCESS " << epee::string_tools::get_ip_string_from_int32(context.m_remote_ip) << ":" << port_l); + LOG_DEBUG_CC(context, "PING SUCCESS " << context.m_remote_address.host_str() << ":" << port_l); }); } @@ -1686,7 +1687,7 @@ namespace nodetool }); //fill response - m_peerlist.get_peerlist_head(rsp.local_peerlist); + m_peerlist.get_peerlist_head(rsp.local_peerlist_new); get_local_node_data(rsp.node_data); m_payload_handler.get_payload_sync_data(rsp.payload_data); LOG_DEBUG_CC(context, "COMMAND_HANDSHAKE"); @@ -1726,7 +1727,7 @@ namespace nodetool std::stringstream ss; m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt) { - ss << epee::string_tools::get_ip_string_from_int32(cntxt.m_remote_ip) << ":" << cntxt.m_remote_port + ss << cntxt.m_remote_address.str() << " \t\tpeer_id " << cntxt.peer_id << " \t\tconn_id " << epee::string_tools::get_str_from_guid_a(cntxt.m_connection_id) << (cntxt.m_is_income ? " INC":" OUT") << std::endl; @@ -1746,9 +1747,8 @@ namespace nodetool void node_server<t_payload_net_handler>::on_connection_close(p2p_connection_context& context) { if (!m_net_server.is_stop_signal_sent() && !context.m_is_income) { - nodetool::net_address na = AUTO_VAL_INIT(na); - na.ip = context.m_remote_ip; - na.port = context.m_remote_port; + epee::net_utils::network_address na = AUTO_VAL_INIT(na); + na = context.m_remote_address; m_peerlist.remove_from_peer_anchor(na); } @@ -1757,7 +1757,7 @@ namespace nodetool } template<class t_payload_net_handler> - bool node_server<t_payload_net_handler>::is_priority_node(const net_address& na) + bool node_server<t_payload_net_handler>::is_priority_node(const epee::net_utils::network_address& na) { return (std::find(m_priority_peers.begin(), m_priority_peers.end(), na) != m_priority_peers.end()) || (std::find(m_exclusive_peers.begin(), m_exclusive_peers.end(), na) != m_exclusive_peers.end()); } @@ -1765,7 +1765,7 @@ namespace nodetool template<class t_payload_net_handler> template <class Container> bool node_server<t_payload_net_handler>::connect_to_peerlist(const Container& peers) { - for(const net_address& na: peers) + for(const epee::net_utils::network_address& na: peers) { if(m_net_server.is_stop_signal_sent()) return false; @@ -1786,11 +1786,10 @@ namespace nodetool for(const std::string& pr_str: perrs) { - nodetool::net_address na = AUTO_VAL_INIT(na); - bool r = parse_peer_from_string(na, pr_str); + epee::net_utils::network_address na = AUTO_VAL_INIT(na); + const uint16_t default_port = m_testnet ? ::config::testnet::P2P_DEFAULT_PORT : ::config::P2P_DEFAULT_PORT; + bool r = parse_peer_from_string(na, pr_str, default_port); CHECK_AND_ASSERT_MES(r, false, "Failed to parse address from string: " << pr_str); - if (na.port == 0) - na.port = m_testnet ? ::config::testnet::P2P_DEFAULT_PORT : ::config::P2P_DEFAULT_PORT; container.push_back(na); } @@ -1884,14 +1883,14 @@ namespace nodetool } template<class t_payload_net_handler> - bool node_server<t_payload_net_handler>::has_too_many_connections(const uint32_t ip) + bool node_server<t_payload_net_handler>::has_too_many_connections(const epee::net_utils::network_address &address) { const uint8_t max_connections = 1; uint8_t count = 0; m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt) { - if (cntxt.m_is_income && cntxt.m_remote_ip == ip) { + if (cntxt.m_is_income && cntxt.m_remote_address.is_same_host(address)) { count++; if (count > max_connections) { @@ -1919,14 +1918,14 @@ namespace nodetool if (!success) { m_peerlist.remove_from_peer_gray(pe); - LOG_PRINT_L2("PEER EVICTED FROM GRAY PEER LIST IP address: " << epee::string_tools::get_ip_string_from_int32(pe.adr.ip) << " Peer ID: " << std::hex << pe.id); + LOG_PRINT_L2("PEER EVICTED FROM GRAY PEER LIST IP address: " << pe.adr.host_str() << " Peer ID: " << std::hex << pe.id); return true; } m_peerlist.set_peer_just_seen(pe.id, pe.adr); - LOG_PRINT_L2("PEER PROMOTED TO WHITE PEER LIST IP address: " << epee::string_tools::get_ip_string_from_int32(pe.adr.ip) << " Peer ID: " << std::hex << pe.id); + LOG_PRINT_L2("PEER PROMOTED TO WHITE PEER LIST IP address: " << pe.adr.host_str() << " Peer ID: " << std::hex << pe.id); return true; } diff --git a/src/p2p/net_node_common.h b/src/p2p/net_node_common.h index 6aba7aa24..42de2655d 100644 --- a/src/p2p/net_node_common.h +++ b/src/p2p/net_node_common.h @@ -51,10 +51,10 @@ namespace nodetool virtual void request_callback(const epee::net_utils::connection_context_base& context)=0; virtual uint64_t get_connections_count()=0; virtual void for_each_connection(std::function<bool(t_connection_context&, peerid_type, uint32_t)> f)=0; - virtual bool block_ip(uint32_t adress, time_t seconds = 0)=0; - virtual bool unblock_ip(uint32_t adress)=0; - virtual std::map<uint32_t, time_t> get_blocked_ips()=0; - virtual bool add_ip_fail(uint32_t adress)=0; + virtual bool block_host(const 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 bool add_host_fail(const epee::net_utils::network_address &address)=0; }; template<class t_connection_context> @@ -93,19 +93,19 @@ namespace nodetool { return false; } - virtual bool block_ip(uint32_t adress, time_t seconds) + virtual bool block_host(const epee::net_utils::network_address &address, time_t seconds) { return true; } - virtual bool unblock_ip(uint32_t adress) + virtual bool unblock_host(const epee::net_utils::network_address &address) { return true; } - virtual std::map<uint32_t, time_t> get_blocked_ips() + virtual std::map<std::string, time_t> get_blocked_hosts() { - return std::map<uint32_t, time_t>(); + return std::map<std::string, time_t>(); } - virtual bool add_ip_fail(uint32_t adress) + virtual bool add_host_fail(const epee::net_utils::network_address &address) { return true; } diff --git a/src/p2p/net_peerlist.h b/src/p2p/net_peerlist.h index de0f51cc3..a30a05422 100644 --- a/src/p2p/net_peerlist.h +++ b/src/p2p/net_peerlist.h @@ -54,7 +54,7 @@ #include "net_peerlist_boost_serialization.h" -#define CURRENT_PEERLIST_STORAGE_ARCHIVE_VER 5 +#define CURRENT_PEERLIST_STORAGE_ARCHIVE_VER 6 namespace nodetool { @@ -78,14 +78,13 @@ namespace nodetool 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); - bool set_peer_just_seen(peerid_type peer, uint32_t ip, uint32_t port); - bool set_peer_just_seen(peerid_type peer, const net_address& addr); + bool set_peer_just_seen(peerid_type peer, const epee::net_utils::network_address& addr); bool set_peer_unreachable(const peerlist_entry& pr); - bool is_ip_allowed(uint32_t ip); + bool is_host_allowed(const epee::net_utils::network_address &address); bool get_random_gray_peer(peerlist_entry& pe); bool remove_from_peer_gray(const peerlist_entry& pe); bool get_and_empty_anchor_peerlist(std::vector<anchor_peerlist_entry>& apl); - bool remove_from_peer_anchor(const net_address& addr); + bool remove_from_peer_anchor(const epee::net_utils::network_address& addr); private: struct by_time{}; @@ -130,7 +129,7 @@ namespace nodetool peerlist_entry, boost::multi_index::indexed_by< // access by peerlist_entry::net_adress - boost::multi_index::ordered_unique<boost::multi_index::tag<by_addr>, boost::multi_index::member<peerlist_entry,net_address,&peerlist_entry::adr> >, + boost::multi_index::ordered_unique<boost::multi_index::tag<by_addr>, boost::multi_index::member<peerlist_entry,epee::net_utils::network_address,&peerlist_entry::adr> >, // sort by peerlist_entry::last_seen< boost::multi_index::ordered_non_unique<boost::multi_index::tag<by_time>, boost::multi_index::member<peerlist_entry,int64_t,&peerlist_entry::last_seen> > > @@ -142,7 +141,7 @@ namespace nodetool // access by peerlist_entry::id< boost::multi_index::ordered_unique<boost::multi_index::tag<by_id>, boost::multi_index::member<peerlist_entry,uint64_t,&peerlist_entry::id> >, // access by peerlist_entry::net_adress - boost::multi_index::ordered_unique<boost::multi_index::tag<by_addr>, boost::multi_index::member<peerlist_entry,net_address,&peerlist_entry::adr> >, + boost::multi_index::ordered_unique<boost::multi_index::tag<by_addr>, boost::multi_index::member<peerlist_entry,epee::net_utils::network_address,&peerlist_entry::adr> >, // sort by peerlist_entry::last_seen< boost::multi_index::ordered_non_unique<boost::multi_index::tag<by_time>, boost::multi_index::member<peerlist_entry,int64_t,&peerlist_entry::last_seen> > > @@ -152,16 +151,45 @@ namespace nodetool anchor_peerlist_entry, boost::multi_index::indexed_by< // access by anchor_peerlist_entry::net_adress - boost::multi_index::ordered_unique<boost::multi_index::tag<by_addr>, boost::multi_index::member<anchor_peerlist_entry,net_address,&anchor_peerlist_entry::adr> >, + boost::multi_index::ordered_unique<boost::multi_index::tag<by_addr>, boost::multi_index::member<anchor_peerlist_entry,epee::net_utils::network_address,&anchor_peerlist_entry::adr> >, // sort by anchor_peerlist_entry::first_seen boost::multi_index::ordered_non_unique<boost::multi_index::tag<by_time>, boost::multi_index::member<anchor_peerlist_entry,int64_t,&anchor_peerlist_entry::first_seen> > > > anchor_peers_indexed; public: + template <class Archive, class List, class Element, class t_version_type> + void serialize_peers(Archive &a, List &list, Element ple, const t_version_type ver) + { + if (typename Archive::is_saving()) + { + uint64_t size = list.size(); + a & size; + for (auto p: list) + { + a & p; + } + } + else + { + uint64_t size; + a & size; + list.clear(); + while (size--) + { + a & ple; + list.insert(ple); + } + } + } + template <class Archive, class t_version_type> void serialize(Archive &a, const t_version_type ver) { + // at v6, we drop existing peerlists, because annoying change + if (ver < 6) + return; + if(ver < 3) return; CRITICAL_REGION_LOCAL(m_peerlist_lock); @@ -174,14 +202,25 @@ namespace nodetool return; } +#if 0 + // trouble loading more than one peer, can't find why a & m_peers_white; a & m_peers_gray; +#else + serialize_peers(a, m_peers_white, peerlist_entry(), ver); + serialize_peers(a, m_peers_gray, peerlist_entry(), ver); +#endif if(ver < 5) { return; } +#if 0 + // trouble loading more than one peer, can't find why a & m_peers_anchor; +#else + serialize_peers(a, m_peers_anchor, anchor_peerlist_entry(), ver); +#endif } private: @@ -284,13 +323,13 @@ namespace nodetool } //-------------------------------------------------------------------------------------------------- inline - bool peerlist_manager::is_ip_allowed(uint32_t ip) + bool peerlist_manager::is_host_allowed(const epee::net_utils::network_address &address) { //never allow loopback ip - if(epee::net_utils::is_ip_loopback(ip)) + if(address.is_loopback()) return false; - if(!m_allow_local_ip && epee::net_utils::is_ip_local(ip)) + if(!m_allow_local_ip && address.is_local()) return false; return true; @@ -336,16 +375,7 @@ namespace nodetool } //-------------------------------------------------------------------------------------------------- inline - bool peerlist_manager::set_peer_just_seen(peerid_type peer, uint32_t ip, uint32_t port) - { - net_address addr; - addr.ip = ip; - addr.port = port; - return set_peer_just_seen(peer, addr); - } - //-------------------------------------------------------------------------------------------------- - inline - bool peerlist_manager::set_peer_just_seen(peerid_type peer, const net_address& addr) + bool peerlist_manager::set_peer_just_seen(peerid_type peer, const epee::net_utils::network_address& addr) { TRY_ENTRY(); CRITICAL_REGION_LOCAL(m_peerlist_lock); @@ -362,7 +392,7 @@ namespace nodetool bool peerlist_manager::append_with_peer_white(const peerlist_entry& ple) { TRY_ENTRY(); - if(!is_ip_allowed(ple.adr.ip)) + if(!is_host_allowed(ple.adr)) return true; CRITICAL_REGION_LOCAL(m_peerlist_lock); @@ -392,7 +422,7 @@ namespace nodetool bool peerlist_manager::append_with_peer_gray(const peerlist_entry& ple) { TRY_ENTRY(); - if(!is_ip_allowed(ple.adr.ip)) + if(!is_host_allowed(ple.adr)) return true; CRITICAL_REGION_LOCAL(m_peerlist_lock); @@ -496,7 +526,7 @@ namespace nodetool } //-------------------------------------------------------------------------------------------------- inline - bool peerlist_manager::remove_from_peer_anchor(const net_address& addr) + bool peerlist_manager::remove_from_peer_anchor(const epee::net_utils::network_address& addr) { TRY_ENTRY(); diff --git a/src/p2p/net_peerlist_boost_serialization.h b/src/p2p/net_peerlist_boost_serialization.h index 6891ac80c..0a21895cf 100644 --- a/src/p2p/net_peerlist_boost_serialization.h +++ b/src/p2p/net_peerlist_boost_serialization.h @@ -30,16 +30,43 @@ #pragma once +#include "net/net_utils_base.h" + namespace boost { namespace serialization { - //BOOST_CLASS_VERSION(odetool::net_adress, 1) + enum { sertype_ipv4_address }; + static inline uint8_t get_type(const epee::net_utils::network_address &na) + { + if (na.type() == typeid(epee::net_utils::ipv4_network_address)) + return sertype_ipv4_address; + throw std::runtime_error("Unsupported network address type"); + return 0; + } + template <class Archive, class ver_type> + inline void serialize(Archive &a, epee::net_utils::network_address& na, const ver_type ver) + { + uint8_t type; + if (typename Archive::is_saving()) + type = get_type(na); + a & type; + switch (type) + { + case sertype_ipv4_address: + if (!typename Archive::is_saving()) + na.reset(new epee::net_utils::ipv4_network_address(0, 0)); + a & na.as<epee::net_utils::ipv4_network_address>(); + break; + default: + throw std::runtime_error("Unsupported network address type"); + } + } template <class Archive, class ver_type> - inline void serialize(Archive &a, nodetool::net_address& na, const ver_type ver) + inline void serialize(Archive &a, epee::net_utils::ipv4_network_address& na, const ver_type ver) { - a & na.ip; - a & na.port; + a & na.m_ip; + a & na.m_port; } diff --git a/src/p2p/p2p_protocol_defs.h b/src/p2p/p2p_protocol_defs.h index 5ec012714..d60990f8a 100644 --- a/src/p2p/p2p_protocol_defs.h +++ b/src/p2p/p2p_protocol_defs.h @@ -32,6 +32,7 @@ #include <boost/uuid/uuid.hpp> #include "serialization/keyvalue_serialization.h" +#include "net/net_utils_base.h" #include "misc_language.h" #include "cryptonote_config.h" #include "crypto/crypto.h" @@ -43,46 +44,64 @@ namespace nodetool #pragma pack (push, 1) - struct net_address + struct network_address_old { uint32_t ip; uint32_t port; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(ip) + KV_SERIALIZE(port) + END_KV_SERIALIZE_MAP() }; - struct peerlist_entry + template<typename AddressType> + struct peerlist_entry_base { - net_address adr; + AddressType adr; peerid_type id; int64_t last_seen; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(adr) + KV_SERIALIZE(id) + KV_SERIALIZE(last_seen) + END_KV_SERIALIZE_MAP() }; + typedef peerlist_entry_base<epee::net_utils::network_address> peerlist_entry; - struct anchor_peerlist_entry + template<typename AddressType> + struct anchor_peerlist_entry_base { - net_address adr; + AddressType adr; peerid_type id; int64_t first_seen; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(adr) + KV_SERIALIZE(id) + KV_SERIALIZE(first_seen) + END_KV_SERIALIZE_MAP() }; + typedef anchor_peerlist_entry_base<epee::net_utils::network_address> anchor_peerlist_entry; - struct connection_entry + template<typename AddressType> + struct connection_entry_base { - net_address adr; + AddressType adr; peerid_type id; bool is_income; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(adr) + KV_SERIALIZE(id) + KV_SERIALIZE(is_income) + END_KV_SERIALIZE_MAP() }; + typedef connection_entry_base<epee::net_utils::network_address> connection_entry; #pragma pack(pop) - inline - bool operator < (const net_address& a, const net_address& b) - { - return epee::misc_utils::is_less_as_pod(a, b); - } - - inline - bool operator == (const net_address& a, const net_address& b) - { - return memcmp(&a, &b, sizeof(a)) == 0; - } inline std::string print_peerlist_to_string(const std::list<peerlist_entry>& pl) { @@ -92,7 +111,7 @@ namespace nodetool ss << std::setfill ('0') << std::setw (8) << std::hex << std::noshowbase; for(const peerlist_entry& pe: pl) { - ss << pe.id << "\t" << epee::string_tools::get_ip_string_from_int32(pe.adr.ip) << ":" << boost::lexical_cast<std::string>(pe.adr.port) << " \tlast_seen: " << epee::misc_utils::get_time_interval_string(now_time - pe.last_seen) << std::endl; + ss << pe.id << "\t" << pe.adr->str() << " \tlast_seen: " << epee::misc_utils::get_time_interval_string(now_time - pe.last_seen) << std::endl; } return ss.str(); } @@ -157,12 +176,40 @@ namespace nodetool { basic_node_data node_data; t_playload_type payload_data; - std::list<peerlist_entry> local_peerlist; + std::list<peerlist_entry> local_peerlist_new; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(node_data) KV_SERIALIZE(payload_data) - KV_SERIALIZE_CONTAINER_POD_AS_BLOB(local_peerlist) + if (is_store) + { + // saving: save both, so old and new peers can understand it + KV_SERIALIZE(local_peerlist_new) + std::list<peerlist_entry_base<network_address_old>> local_peerlist; + for (const auto &p: this_ref.local_peerlist_new) + { + if (p.adr.type() == typeid(epee::net_utils::ipv4_network_address)) + { + const epee::net_utils::network_address &na = p.adr; + const epee::net_utils::ipv4_network_address &ipv4 = na.as<const epee::net_utils::ipv4_network_address>(); + local_peerlist.push_back(peerlist_entry_base<network_address_old>({{ipv4.ip(), ipv4.port()}, p.id, p.last_seen})); + } + else + MDEBUG("Not including in legacy peer list: " << p.adr.str()); + } + epee::serialization::selector<is_store>::serialize_stl_container_pod_val_as_blob(local_peerlist, stg, hparent_section, "local_peerlist"); + } + else + { + // loading: load old list only if there is no new one + if (!epee::serialization::selector<is_store>::serialize(this_ref.local_peerlist_new, stg, hparent_section, "local_peerlist_new")) + { + std::list<peerlist_entry_base<network_address_old>> local_peerlist; + epee::serialization::selector<is_store>::serialize_stl_container_pod_val_as_blob(local_peerlist, stg, hparent_section, "local_peerlist"); + for (const auto &p: local_peerlist) + ((response&)this_ref).local_peerlist_new.push_back(peerlist_entry({new epee::net_utils::ipv4_network_address(p.adr.ip, p.adr.port), p.id, p.last_seen})); + } + } END_KV_SERIALIZE_MAP() }; }; @@ -188,12 +235,40 @@ namespace nodetool { uint64_t local_time; t_playload_type payload_data; - std::list<peerlist_entry> local_peerlist; + std::list<peerlist_entry> local_peerlist_new; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(local_time) KV_SERIALIZE(payload_data) - KV_SERIALIZE_CONTAINER_POD_AS_BLOB(local_peerlist) + if (is_store) + { + // saving: save both, so old and new peers can understand it + KV_SERIALIZE(local_peerlist_new) + std::list<peerlist_entry_base<network_address_old>> local_peerlist; + for (const auto &p: this_ref.local_peerlist_new) + { + if (p.adr.type() == typeid(epee::net_utils::ipv4_network_address)) + { + const epee::net_utils::network_address &na = p.adr; + const epee::net_utils::ipv4_network_address &ipv4 = na.as<const epee::net_utils::ipv4_network_address>(); + local_peerlist.push_back(peerlist_entry_base<network_address_old>({{ipv4.ip(), ipv4.port()}, p.id, p.last_seen})); + } + else + MDEBUG("Not including in legacy peer list: " << p.adr.str()); + } + epee::serialization::selector<is_store>::serialize_stl_container_pod_val_as_blob(local_peerlist, stg, hparent_section, "local_peerlist"); + } + else + { + // loading: load old list only if there is no new one + if (!epee::serialization::selector<is_store>::serialize(this_ref.local_peerlist_new, stg, hparent_section, "local_peerlist_new")) + { + std::list<peerlist_entry_base<network_address_old>> local_peerlist; + epee::serialization::selector<is_store>::serialize_stl_container_pod_val_as_blob(local_peerlist, stg, hparent_section, "local_peerlist"); + for (const auto &p: local_peerlist) + ((response&)this_ref).local_peerlist_new.push_back(peerlist_entry({new epee::net_utils::ipv4_network_address(p.adr.ip, p.adr.port), p.id, p.last_seen})); + } + } END_KV_SERIALIZE_MAP() }; }; diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 76a69fbf6..640c53522 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -736,12 +736,20 @@ namespace cryptonote for (auto & entry : white_list) { - res.white_list.emplace_back(entry.id, entry.adr.ip, entry.adr.port, entry.last_seen); + if (entry.adr.type() == typeid(epee::net_utils::ipv4_network_address)) + res.white_list.emplace_back(entry.id, entry.adr.as<epee::net_utils::ipv4_network_address>().ip(), + entry.adr.as<epee::net_utils::ipv4_network_address>().port(), entry.last_seen); + else + res.white_list.emplace_back(entry.id, entry.adr.str(), entry.last_seen); } for (auto & entry : gray_list) { - res.gray_list.emplace_back(entry.id, entry.adr.ip, entry.adr.port, entry.last_seen); + if (entry.adr.type() == typeid(epee::net_utils::ipv4_network_address)) + res.gray_list.emplace_back(entry.id, entry.adr.as<epee::net_utils::ipv4_network_address>().ip(), + entry.adr.as<epee::net_utils::ipv4_network_address>().port(), entry.last_seen); + else + res.gray_list.emplace_back(entry.id, entry.adr.str(), entry.last_seen); } res.status = CORE_RPC_STATUS_OK; @@ -1300,12 +1308,16 @@ namespace cryptonote } auto now = time(nullptr); - std::map<uint32_t, time_t> blocked_ips = m_p2p.get_blocked_ips(); - for (std::map<uint32_t, time_t>::const_iterator i = blocked_ips.begin(); i != blocked_ips.end(); ++i) + std::map<std::string, time_t> blocked_hosts = m_p2p.get_blocked_hosts(); + for (std::map<std::string, time_t>::const_iterator i = blocked_hosts.begin(); i != blocked_hosts.end(); ++i) { if (i->second > now) { COMMAND_RPC_GETBANS::ban b; - b.ip = i->first; + b.host = i->first; + b.ip = 0; + uint32_t ip; + if (epee::string_tools::get_ip_int32_from_string(ip, i->first)) + b.ip = ip; b.seconds = i->second - now; res.bans.push_back(b); } @@ -1326,10 +1338,24 @@ namespace cryptonote for (auto i = req.bans.begin(); i != req.bans.end(); ++i) { + epee::net_utils::network_address na; + if (!i->host.empty()) + { + if (!epee::net_utils::create_network_address(na, i->host)) + { + error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM; + error_resp.message = "Unsupported host type"; + return false; + } + } + else + { + na.reset(new epee::net_utils::ipv4_network_address(i->ip, 0)); + } if (i->ban) - m_p2p.block_ip(i->ip, i->seconds); + m_p2p.block_host(na, i->seconds); else - m_p2p.unblock_ip(i->ip); + m_p2p.unblock_host(na); } res.status = CORE_RPC_STATUS_OK; diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h index 9bdadf0d1..28be288c4 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -49,7 +49,7 @@ namespace cryptonote // advance which version they will stop working with // Don't go over 32767 for any of these #define CORE_RPC_VERSION_MAJOR 1 -#define CORE_RPC_VERSION_MINOR 10 +#define CORE_RPC_VERSION_MINOR 11 #define MAKE_CORE_RPC_VERSION(major,minor) (((major)<<16)|(minor)) #define CORE_RPC_VERSION MAKE_CORE_RPC_VERSION(CORE_RPC_VERSION_MAJOR, CORE_RPC_VERSION_MINOR) @@ -861,18 +861,23 @@ namespace cryptonote struct peer { uint64_t id; + std::string host; uint32_t ip; uint16_t port; uint64_t last_seen; peer() = default; + peer(uint64_t id, const std::string &host, uint64_t last_seen) + : id(id), host(host), ip(0), port(0), last_seen(last_seen) + {} peer(uint64_t id, uint32_t ip, uint16_t port, uint64_t last_seen) - : id(id), ip(ip), port(port), last_seen(last_seen) + : id(id), host(std::to_string(ip)), ip(ip), port(port), last_seen(last_seen) {} BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(id) + KV_SERIALIZE(host) KV_SERIALIZE(ip) KV_SERIALIZE(port) KV_SERIALIZE(last_seen) @@ -1226,10 +1231,12 @@ namespace cryptonote { struct ban { + std::string host; uint32_t ip; uint32_t seconds; BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(host) KV_SERIALIZE(ip) KV_SERIALIZE(seconds) END_KV_SERIALIZE_MAP() @@ -1257,11 +1264,13 @@ namespace cryptonote { struct ban { + std::string host; uint32_t ip; bool ban; uint32_t seconds; BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(host) KV_SERIALIZE(ip) KV_SERIALIZE(ban) KV_SERIALIZE(seconds) |