From 2a38ee251a22d100119b6aa06e9aa31f9b6fb50e Mon Sep 17 00:00:00 2001 From: selsta Date: Mon, 19 Oct 2020 21:02:59 +0200 Subject: [PATCH 01/14] net_node: add --ban-list option --- src/p2p/net_node.cpp | 1 + src/p2p/net_node.h | 1 + src/p2p/net_node.inl | 31 +++++++++++++++++++++++++++++++ 3 files changed, 33 insertions(+) diff --git a/src/p2p/net_node.cpp b/src/p2p/net_node.cpp index 1c5dca0d7..aee1fa593 100644 --- a/src/p2p/net_node.cpp +++ b/src/p2p/net_node.cpp @@ -146,6 +146,7 @@ namespace nodetool const command_line::arg_descriptor > arg_p2p_seed_node = {"seed-node", "Connect to a node to retrieve peer addresses, and disconnect"}; const command_line::arg_descriptor > arg_tx_proxy = {"tx-proxy", "Send local txes through proxy: ,[,max_connections][,disable_noise] i.e. \"tor,127.0.0.1:9050,100,disable_noise\""}; const command_line::arg_descriptor > arg_anonymous_inbound = {"anonymous-inbound", ",<[bind-ip:]port>[,max_connections] i.e. \"x.onion,127.0.0.1:18083,100\""}; + const command_line::arg_descriptor arg_ban_list = {"ban-list", "Specify ban list file, one IP address per line"}; const command_line::arg_descriptor arg_p2p_hide_my_port = {"hide-my-port", "Do not announce yourself as peerlist candidate", false, true}; const command_line::arg_descriptor arg_no_sync = {"no-sync", "Don't synchronize the blockchain with other peers", false}; diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h index 001559313..fb9f5c88e 100644 --- a/src/p2p/net_node.h +++ b/src/p2p/net_node.h @@ -520,6 +520,7 @@ namespace nodetool extern const command_line::arg_descriptor > arg_p2p_seed_node; extern const command_line::arg_descriptor > arg_tx_proxy; extern const command_line::arg_descriptor > arg_anonymous_inbound; + extern const command_line::arg_descriptor arg_ban_list; extern const command_line::arg_descriptor arg_p2p_hide_my_port; extern const command_line::arg_descriptor arg_no_sync; diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index 8a36147ad..5a213f7c5 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -106,6 +106,7 @@ namespace nodetool command_line::add_arg(desc, arg_p2p_seed_node); command_line::add_arg(desc, arg_tx_proxy); command_line::add_arg(desc, arg_anonymous_inbound); + command_line::add_arg(desc, arg_ban_list); command_line::add_arg(desc, arg_p2p_hide_my_port); command_line::add_arg(desc, arg_no_sync); command_line::add_arg(desc, arg_no_igd); @@ -441,6 +442,36 @@ namespace nodetool return false; } + if (!command_line::is_arg_defaulted(vm, arg_ban_list)) + { + const std::string ban_list = command_line::get_arg(vm, arg_ban_list); + + const boost::filesystem::path ban_list_path(ban_list); + boost::system::error_code ec; + if (!boost::filesystem::exists(ban_list_path, ec)) + { + throw std::runtime_error("Can't find ban list file " + ban_list + " - " + ec.message()); + } + + std::string banned_ips; + if (!epee::file_io_utils::load_file_to_string(ban_list_path.string(), banned_ips)) + { + throw std::runtime_error("Failed to read ban list file " + ban_list); + } + + std::istringstream iss(banned_ips); + for (std::string line; std::getline(iss, line); ) + { + const expect parsed_addr = net::get_network_address(line, 0); + if (!parsed_addr) + { + MERROR("Invalid IP address: " << line << " - " << parsed_addr.error()); + continue; + } + block_host(*parsed_addr, std::numeric_limits::max()); + } + } + if(command_line::has_arg(vm, arg_p2p_hide_my_port)) m_hide_my_port = true; From d37785db0c2fc1e94a2d707c7e8ce5674570f668 Mon Sep 17 00:00:00 2001 From: Lee Clagett Date: Sat, 31 Oct 2020 15:51:46 -0400 Subject: [PATCH 02/14] Fix tx flush callback queueing --- src/cryptonote_protocol/levin_notify.cpp | 33 +++++++----------------- 1 file changed, 10 insertions(+), 23 deletions(-) diff --git a/src/cryptonote_protocol/levin_notify.cpp b/src/cryptonote_protocol/levin_notify.cpp index dbd11e7d0..9dfefe957 100644 --- a/src/cryptonote_protocol/levin_notify.cpp +++ b/src/cryptonote_protocol/levin_notify.cpp @@ -241,8 +241,8 @@ namespace levin strand(io_service), map(), channels(), - flush_time(std::chrono::steady_clock::time_point::max()), connection_count(0), + flush_callbacks(0), is_public(is_public), pad_txs(pad_txs), fluffing(false) @@ -258,8 +258,8 @@ namespace levin boost::asio::io_service::strand strand; net::dandelionpp::connection_map map;//!< Tracks outgoing uuid's for noise channels or Dandelion++ stems std::deque channels; //!< Never touch after init; only update elements on `noise_channel.strand` - std::chrono::steady_clock::time_point flush_time; //!< Next expected Dandelion++ fluff flush std::atomic connection_count; //!< Only update in strand, can be read at any time + std::uint32_t flush_callbacks; //!< Number of active fluff flush callbacks queued const bool is_public; //!< Zone is public ipv4/ipv6 connections const bool pad_txs; //!< Pad txs to the next boundary for privacy bool fluffing; //!< Zone is in Dandelion++ fluff epoch @@ -305,7 +305,6 @@ namespace levin struct fluff_flush { std::shared_ptr zone_; - std::chrono::steady_clock::time_point flush_time_; static void queue(std::shared_ptr zone, const std::chrono::steady_clock::time_point flush_time) { @@ -313,28 +312,21 @@ namespace levin assert(zone->strand.running_in_this_thread()); detail::zone& this_zone = *zone; - this_zone.flush_time = flush_time; + ++this_zone.flush_callbacks; this_zone.flush_txs.expires_at(flush_time); - this_zone.flush_txs.async_wait(this_zone.strand.wrap(fluff_flush{std::move(zone), flush_time})); + this_zone.flush_txs.async_wait(this_zone.strand.wrap(fluff_flush{std::move(zone)})); } void operator()(const boost::system::error_code error) { - if (!zone_ || !zone_->p2p) + if (!zone_ || !zone_->flush_callbacks || --zone_->flush_callbacks || !zone_->p2p) return; assert(zone_->strand.running_in_this_thread()); const bool timer_error = bool(error); - if (timer_error) - { - if (error != boost::system::errc::operation_canceled) - throw boost::system::system_error{error, "fluff_flush timer failed"}; - - // new timer canceled this one set in future - if (zone_->flush_time < flush_time_) - return; - } + if (timer_error && error != boost::system::errc::operation_canceled) + throw boost::system::system_error{error, "fluff_flush timer failed"}; const auto now = std::chrono::steady_clock::now(); auto next_flush = std::chrono::steady_clock::time_point::max(); @@ -370,8 +362,6 @@ namespace levin if (next_flush != std::chrono::steady_clock::time_point::max()) fluff_flush::queue(std::move(zone_), next_flush); - else - zone_->flush_time = next_flush; // signal that no timer is set } }; @@ -406,13 +396,11 @@ namespace levin MDEBUG("Queueing " << txs.size() << " transaction(s) for Dandelion++ fluffing"); - bool available = false; - zone->p2p->foreach_connection([txs, now, &zone, &source, &in_duration, &out_duration, &next_flush, &available] (detail::p2p_context& context) + zone->p2p->foreach_connection([txs, now, &zone, &source, &in_duration, &out_duration, &next_flush] (detail::p2p_context& context) { // When i2p/tor, only fluff to outbound connections if (source != context.m_connection_id && (zone->is_public || !context.m_is_income)) { - available = true; if (context.fluff_txs.empty()) context.flush_time = now + (context.m_is_income ? in_duration() : out_duration()); @@ -424,10 +412,9 @@ namespace levin return true; }); - if (!available) + if (next_flush == std::chrono::steady_clock::time_point::max()) MWARNING("Unable to send transaction(s), no available connections"); - - if (next_flush < zone->flush_time) + else if (!zone->flush_callbacks || next_flush < zone->flush_txs.expires_at()) fluff_flush::queue(std::move(zone), next_flush); } }; From aae4bf32aa0f2d64223b59363ea43c448ded0d41 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Tue, 3 Nov 2020 12:59:36 +0000 Subject: [PATCH 03/14] protocol: reject empty incoming block messages --- src/cryptonote_protocol/cryptonote_protocol_handler.inl | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl index c0a18789a..6027d3cab 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl +++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl @@ -1091,6 +1091,13 @@ namespace cryptonote //epee::net_utils::network_throttle_manager::get_global_throttle_inreq().logger_handle_net("log/dr-monero/net/req-all.data", sec, get_avg_block_size()); + if(arg.blocks.empty()) + { + LOG_ERROR_CCONTEXT("sent wrong NOTIFY_HAVE_OBJECTS: no blocks"); + drop_connection(context, true, false); + ++m_sync_bad_spans_downloaded; + return 1; + } if(context.m_last_response_height > arg.current_blockchain_height) { LOG_ERROR_CCONTEXT("sent wrong NOTIFY_HAVE_OBJECTS: arg.m_current_blockchain_height=" << arg.current_blockchain_height From df5779790c3b1c5f2dfdf99bd7616beb6436f340 Mon Sep 17 00:00:00 2001 From: Lee Clagett Date: Tue, 3 Nov 2020 13:58:14 -0500 Subject: [PATCH 04/14] Switch to Dandelion++ fluff mode if no out connections for stem mode --- src/cryptonote_protocol/levin_notify.cpp | 10 +-- tests/unit_tests/levin.cpp | 109 +++++++++++++++++++++++ 2 files changed, 113 insertions(+), 6 deletions(-) diff --git a/src/cryptonote_protocol/levin_notify.cpp b/src/cryptonote_protocol/levin_notify.cpp index 9dfefe957..00855ac26 100644 --- a/src/cryptonote_protocol/levin_notify.cpp +++ b/src/cryptonote_protocol/levin_notify.cpp @@ -511,12 +511,7 @@ namespace levin if (!zone_ || !core_ || txs_.empty()) return; - if (zone_->fluffing) - { - core_->on_transactions_relayed(epee::to_span(txs_), relay_method::fluff); - fluff_notify::run(std::move(zone_), epee::to_span(txs_), source_); - } - else // forward tx in stem + if (!zone_->fluffing) { core_->on_transactions_relayed(epee::to_span(txs_), relay_method::stem); for (int tries = 2; 0 < tries; tries--) @@ -536,6 +531,9 @@ namespace levin MERROR("Unable to send transaction(s) via Dandelion++ stem"); } + + core_->on_transactions_relayed(epee::to_span(txs_), relay_method::fluff); + fluff_notify::run(std::move(zone_), epee::to_span(txs_), source_); } }; diff --git a/tests/unit_tests/levin.cpp b/tests/unit_tests/levin.cpp index f8f1ac2da..28032fa50 100644 --- a/tests/unit_tests/levin.cpp +++ b/tests/unit_tests/levin.cpp @@ -613,6 +613,61 @@ TEST_F(levin_notify, stem_without_padding) } } +TEST_F(levin_notify, stem_no_outs_without_padding) +{ + cryptonote::levin::notify notifier = make_notifier(0, true, false); + + for (unsigned count = 0; count < 10; ++count) + add_connection(true); + + { + const auto status = notifier.get_status(); + EXPECT_FALSE(status.has_noise); + EXPECT_FALSE(status.connections_filled); + } + notifier.new_out_connection(); + io_service_.poll(); + + std::vector txs(2); + txs[0].resize(100, 'f'); + txs[1].resize(200, 'e'); + + std::vector sorted_txs = txs; + std::sort(sorted_txs.begin(), sorted_txs.end()); + + ASSERT_EQ(10u, contexts_.size()); + + auto context = contexts_.begin(); + EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::stem)); + + io_service_.reset(); + ASSERT_LT(0u, io_service_.poll()); + EXPECT_EQ(txs, events_.take_relayed(cryptonote::relay_method::fluff)); + if (events_.has_stem_txes()) + EXPECT_EQ(txs, events_.take_relayed(cryptonote::relay_method::stem)); + + + notifier.run_fluff(); + ASSERT_LT(0u, io_service_.poll()); + + std::size_t send_count = 0; + EXPECT_EQ(0u, context->process_send_queue()); + for (++context; context != contexts_.end(); ++context) + { + send_count += context->process_send_queue(); + } + + EXPECT_EQ(9u, send_count); + ASSERT_EQ(9u, receiver_.notified_size()); + for (unsigned count = 0; count < 9u; ++count) + { + auto notification = receiver_.get_notification().second; + EXPECT_EQ(sorted_txs, notification.txs); + EXPECT_TRUE(notification._.empty()); + EXPECT_TRUE(notification.dandelionpp_fluff); + } +} + TEST_F(levin_notify, local_without_padding) { cryptonote::levin::notify notifier = make_notifier(0, true, false); @@ -928,6 +983,60 @@ TEST_F(levin_notify, stem_with_padding) } } +TEST_F(levin_notify, stem_no_outs_with_padding) +{ + cryptonote::levin::notify notifier = make_notifier(0, true, true); + + for (unsigned count = 0; count < 10; ++count) + add_connection(true); + + { + const auto status = notifier.get_status(); + EXPECT_FALSE(status.has_noise); + EXPECT_FALSE(status.connections_filled); + } + notifier.new_out_connection(); + io_service_.poll(); + + std::vector txs(2); + txs[0].resize(100, 'f'); + txs[1].resize(200, 'e'); + + std::vector sorted_txs = txs; + std::sort(sorted_txs.begin(), sorted_txs.end()); + + ASSERT_EQ(10u, contexts_.size()); + + auto context = contexts_.begin(); + EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::stem)); + + io_service_.reset(); + ASSERT_LT(0u, io_service_.poll()); + EXPECT_EQ(txs, events_.take_relayed(cryptonote::relay_method::fluff)); + if (events_.has_stem_txes()) + EXPECT_EQ(txs, events_.take_relayed(cryptonote::relay_method::stem)); + + notifier.run_fluff(); + ASSERT_LT(0u, io_service_.poll()); + + std::size_t send_count = 0; + EXPECT_EQ(0u, context->process_send_queue()); + for (++context; context != contexts_.end(); ++context) + { + send_count += context->process_send_queue(); + } + + EXPECT_EQ(9u, send_count); + ASSERT_EQ(9u, receiver_.notified_size()); + for (unsigned count = 0; count < 9u; ++count) + { + auto notification = receiver_.get_notification().second; + EXPECT_EQ(sorted_txs, notification.txs); + EXPECT_FALSE(notification._.empty()); + EXPECT_TRUE(notification.dandelionpp_fluff); + } +} + TEST_F(levin_notify, local_with_padding) { cryptonote::levin::notify notifier = make_notifier(0, true, true); From 4053e2ae14ad7d1d69502f8307a1e93405d788a6 Mon Sep 17 00:00:00 2001 From: selsta Date: Thu, 22 Oct 2020 04:17:11 +0200 Subject: [PATCH 05/14] functional_tests: inrease mining timeout --- tests/functional_tests/mining.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/functional_tests/mining.py b/tests/functional_tests/mining.py index 34b4aceab..1eb6b0ba7 100755 --- a/tests/functional_tests/mining.py +++ b/tests/functional_tests/mining.py @@ -107,7 +107,7 @@ class MiningTest(): break else: assert False, 'Failed to mine successor to block %d (initial block = %d)' % (seen_height, prev_height) - timeout = 5 + timeout = 10 if via_daemon: res = daemon.stop_mining() From 755c308c2382779c6abc8c68be3727f6fae122ed Mon Sep 17 00:00:00 2001 From: moneromooo Date: Tue, 27 Oct 2020 13:18:40 +0000 Subject: [PATCH 06/14] p2p: give all hosts the same chance of being picked for connecting even if some run more than one node --- src/p2p/net_node.inl | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index 5a213f7c5..29807dee3 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -1463,13 +1463,28 @@ namespace nodetool }); } + auto get_host_string = [](const epee::net_utils::network_address &address) { +#if BOOST_VERSION > 106600 + if (address.get_type_id() == epee::net_utils::ipv6_network_address::get_type_id()) + { + boost::asio::ip::address_v6 actual_ip = address.as().ip(); + if (actual_ip.is_v4_mapped()) + { + boost::asio::ip::address_v4 v4ip = make_address_v4(boost::asio::ip::v4_mapped, actual_ip); + return epee::net_utils::ipv4_network_address(v4ip.to_uint(), 0).host_str(); + } + } +#endif + return address.host_str(); + }; + std::unordered_set hosts_added; std::deque filtered; const size_t limit = use_white_list ? 20 : std::numeric_limits::max(); for (int step = 0; step < 2; ++step) { bool skip_duplicate_class_B = step == 0; size_t idx = 0, skipped = 0; - zone.m_peerlist.foreach (use_white_list, [&classB, &filtered, &idx, &skipped, skip_duplicate_class_B, limit, next_needed_pruning_stripe](const peerlist_entry &pe){ + zone.m_peerlist.foreach (use_white_list, [&classB, &filtered, &idx, &skipped, skip_duplicate_class_B, limit, next_needed_pruning_stripe, &hosts_added, &get_host_string](const peerlist_entry &pe){ if (filtered.size() >= limit) return false; bool skip = false; @@ -1479,6 +1494,15 @@ namespace nodetool uint32_t actual_ip = na.as().ip(); skip = classB.find(actual_ip & 0x0000ffff) != classB.end(); } + + // consider each host once, to avoid giving undue inflence to hosts running several nodes + if (!skip) + { + const auto i = hosts_added.find(get_host_string(pe.adr)); + if (i != hosts_added.end()) + skip = true; + } + if (skip) ++skipped; else if (next_needed_pruning_stripe == 0 || pe.pruning_seed == 0) @@ -1486,6 +1510,7 @@ namespace nodetool else if (next_needed_pruning_stripe == tools::get_pruning_stripe(pe.pruning_seed)) filtered.push_front(idx); ++idx; + hosts_added.insert(get_host_string(pe.adr)); return true; }); if (skipped == 0 || !filtered.empty()) From c14276fb7c4be7bd737a221c92b2c85d3c8dda5d Mon Sep 17 00:00:00 2001 From: moneromooo Date: Tue, 27 Oct 2020 22:33:11 +0000 Subject: [PATCH 07/14] p2p: remove banned peers from the white list --- src/p2p/net_node.inl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index 29807dee3..abe5fbfc7 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -246,6 +246,10 @@ namespace nodetool zone.second.m_net_server.get_config_object().close(c); conns.clear(); + + peerlist_entry pe{}; + pe.adr = addr; + zone.second.m_peerlist.remove_from_peer_white(pe); } MCLOG_CYAN(el::Level::Info, "global", "Host " << addr.host_str() << " blocked."); From 9774fc7868f5eef9a2ddb277ad6194e14f728067 Mon Sep 17 00:00:00 2001 From: xiphon Date: Mon, 2 Nov 2020 15:44:36 +0000 Subject: [PATCH 08/14] rpc: on_send_raw_tx (bootstrap) - send to bootstrap daemon and P2P --- src/rpc/core_rpc_server.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 3836ffda0..605fbc13a 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -1131,6 +1131,11 @@ namespace cryptonote { RPC_TRACKER(send_raw_tx); + { + bool ok; + use_bootstrap_daemon_if_necessary(invoke_http_mode::JON, "/sendrawtransaction", req, res, ok); + } + const bool restricted = m_restricted && ctx; bool skip_validation = false; From 38f0472a6e849c215cc47d5ffc63167f933145d1 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sun, 25 Oct 2020 16:22:01 +0000 Subject: [PATCH 09/14] p2p: use /16 filtering on IPv4-within-IPv6 addresses IPv6 addresses include a range that can map IPv4 addresses, which allowed those mapped addresses to bypass filtering. This filter should be replaced by AS filtering at some point. --- src/p2p/net_node.inl | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index abe5fbfc7..0988f963c 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -1463,6 +1463,20 @@ namespace nodetool const uint32_t actual_ip = na.as().ip(); classB.insert(actual_ip & 0x0000ffff); } +#if BOOST_VERSION > 106600 + else if (cntxt.m_remote_address.get_type_id() == epee::net_utils::ipv6_network_address::get_type_id()) + { + const epee::net_utils::network_address na = cntxt.m_remote_address; + const boost::asio::ip::address_v6 &actual_ip = na.as().ip(); + if (actual_ip.is_v4_mapped()) + { + boost::asio::ip::address_v4 v4ip = make_address_v4(boost::asio::ip::v4_mapped, actual_ip); + uint32_t actual_ipv4; + memcpy(&actual_ipv4, v4ip.to_bytes().data(), sizeof(actual_ipv4)); + classB.insert(actual_ipv4 & ntohl(0xffff0000)); + } + } +#endif return true; }); } @@ -1498,6 +1512,20 @@ namespace nodetool uint32_t actual_ip = na.as().ip(); skip = classB.find(actual_ip & 0x0000ffff) != classB.end(); } +#if BOOST_VERSION > 106600 + else if (skip_duplicate_class_B && pe.adr.get_type_id() == epee::net_utils::ipv6_network_address::get_type_id()) + { + const epee::net_utils::network_address na = pe.adr; + const boost::asio::ip::address_v6 &actual_ip = na.as().ip(); + if (actual_ip.is_v4_mapped()) + { + boost::asio::ip::address_v4 v4ip = make_address_v4(boost::asio::ip::v4_mapped, actual_ip); + uint32_t actual_ipv4; + memcpy(&actual_ipv4, v4ip.to_bytes().data(), sizeof(actual_ipv4)); + skip = classB.find(actual_ipv4 & ntohl(0xffff0000)) != classB.end(); + } + } +#endif // consider each host once, to avoid giving undue inflence to hosts running several nodes if (!skip) @@ -1520,11 +1548,11 @@ namespace nodetool if (skipped == 0 || !filtered.empty()) break; if (skipped) - MINFO("Skipping " << skipped << " possible peers as they share a class B with existing peers"); + MDEBUG("Skipping " << skipped << " possible peers as they share a class B with existing peers"); } if (filtered.empty()) { - MDEBUG("No available peer in " << (use_white_list ? "white" : "gray") << " list filtered by " << next_needed_pruning_stripe); + MINFO("No available peer in " << (use_white_list ? "white" : "gray") << " list filtered by " << next_needed_pruning_stripe); return false; } if (use_white_list) From 0f998b9b550ba146d4dfa1dc4d0420b83b8010c7 Mon Sep 17 00:00:00 2001 From: moneromooo Date: Tue, 27 Oct 2020 22:02:41 +0000 Subject: [PATCH 10/14] p2p: rewrite boost's make_address_v4 to cater for < 1.66 --- src/p2p/net_node.inl | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index 0988f963c..ba6781659 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -71,6 +71,17 @@ #define MIN_WANTED_SEED_NODES 12 +static inline boost::asio::ip::address_v4 make_address_v4_from_v6(const boost::asio::ip::address_v6& a) +{ + const auto &bytes = a.to_bytes(); + uint32_t v4 = 0; + v4 = (v4 << 8) | bytes[12]; + v4 = (v4 << 8) | bytes[13]; + v4 = (v4 << 8) | bytes[14]; + v4 = (v4 << 8) | bytes[15]; + return boost::asio::ip::address_v4(v4); +} + namespace nodetool { template @@ -1463,36 +1474,32 @@ namespace nodetool const uint32_t actual_ip = na.as().ip(); classB.insert(actual_ip & 0x0000ffff); } -#if BOOST_VERSION > 106600 else if (cntxt.m_remote_address.get_type_id() == epee::net_utils::ipv6_network_address::get_type_id()) { const epee::net_utils::network_address na = cntxt.m_remote_address; const boost::asio::ip::address_v6 &actual_ip = na.as().ip(); if (actual_ip.is_v4_mapped()) { - boost::asio::ip::address_v4 v4ip = make_address_v4(boost::asio::ip::v4_mapped, actual_ip); + boost::asio::ip::address_v4 v4ip = make_address_v4_from_v6(actual_ip); uint32_t actual_ipv4; memcpy(&actual_ipv4, v4ip.to_bytes().data(), sizeof(actual_ipv4)); classB.insert(actual_ipv4 & ntohl(0xffff0000)); } } -#endif return true; }); } auto get_host_string = [](const epee::net_utils::network_address &address) { -#if BOOST_VERSION > 106600 if (address.get_type_id() == epee::net_utils::ipv6_network_address::get_type_id()) { boost::asio::ip::address_v6 actual_ip = address.as().ip(); if (actual_ip.is_v4_mapped()) { - boost::asio::ip::address_v4 v4ip = make_address_v4(boost::asio::ip::v4_mapped, actual_ip); + boost::asio::ip::address_v4 v4ip = make_address_v4_from_v6(actual_ip); return epee::net_utils::ipv4_network_address(v4ip.to_uint(), 0).host_str(); } } -#endif return address.host_str(); }; std::unordered_set hosts_added; @@ -1512,20 +1519,18 @@ namespace nodetool uint32_t actual_ip = na.as().ip(); skip = classB.find(actual_ip & 0x0000ffff) != classB.end(); } -#if BOOST_VERSION > 106600 else if (skip_duplicate_class_B && pe.adr.get_type_id() == epee::net_utils::ipv6_network_address::get_type_id()) { const epee::net_utils::network_address na = pe.adr; const boost::asio::ip::address_v6 &actual_ip = na.as().ip(); if (actual_ip.is_v4_mapped()) { - boost::asio::ip::address_v4 v4ip = make_address_v4(boost::asio::ip::v4_mapped, actual_ip); + boost::asio::ip::address_v4 v4ip = make_address_v4_from_v6(actual_ip); uint32_t actual_ipv4; memcpy(&actual_ipv4, v4ip.to_bytes().data(), sizeof(actual_ipv4)); skip = classB.find(actual_ipv4 & ntohl(0xffff0000)) != classB.end(); } } -#endif // consider each host once, to avoid giving undue inflence to hosts running several nodes if (!skip) From c40d8f5672bc0e62fbf457775828a8990da2af05 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Wed, 4 Nov 2020 23:01:23 +0000 Subject: [PATCH 11/14] p2p: make this work with boost <= 1.65 (pffff) --- src/p2p/net_node.inl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index ba6781659..d4e02f43e 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -1497,7 +1497,11 @@ namespace nodetool if (actual_ip.is_v4_mapped()) { boost::asio::ip::address_v4 v4ip = make_address_v4_from_v6(actual_ip); +#if BOOST_VERSION >= 106600 return epee::net_utils::ipv4_network_address(v4ip.to_uint(), 0).host_str(); +#else + return epee::net_utils::ipv4_network_address(v4ip.to_ulong(), 0).host_str(); +#endif } } return address.host_str(); From 9e86c1c90d66350b80e7f9623b3240ef70aaf6da Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Thu, 5 Nov 2020 16:05:54 +0000 Subject: [PATCH 12/14] p2p: fix endianness when checking IPv6 addresses mapping to IPv4 --- src/p2p/net_node.inl | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index d4e02f43e..7244940ad 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -1497,11 +1497,9 @@ namespace nodetool if (actual_ip.is_v4_mapped()) { boost::asio::ip::address_v4 v4ip = make_address_v4_from_v6(actual_ip); -#if BOOST_VERSION >= 106600 - return epee::net_utils::ipv4_network_address(v4ip.to_uint(), 0).host_str(); -#else - return epee::net_utils::ipv4_network_address(v4ip.to_ulong(), 0).host_str(); -#endif + uint32_t actual_ipv4; + memcpy(&actual_ipv4, v4ip.to_bytes().data(), sizeof(actual_ipv4)); + return epee::net_utils::ipv4_network_address(actual_ipv4, 0).host_str(); } } return address.host_str(); From 4228f785c079bfe91f27197b1b1877a05271fc2c Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sat, 7 Nov 2020 00:17:47 +0000 Subject: [PATCH 13/14] p2p: fix accessing non existent element of map --- src/p2p/net_node.inl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index 7244940ad..1d006030c 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -1274,7 +1274,10 @@ namespace nodetool template bool node_server::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) { - network_zone& zone = m_network_zones.at(na.get_zone()); + const auto i = m_network_zones.find(na.get_zone()); + if (i == m_network_zones.end()) + return false; + network_zone& zone = i->second; if (zone.m_connect == nullptr) // outgoing connections in zone not possible return false; From 711f8c9d3430986cc6be688563f9b3ea2cbb9b31 Mon Sep 17 00:00:00 2001 From: xiphon Date: Sat, 7 Nov 2020 14:09:52 +0000 Subject: [PATCH 14/14] epee: readline_buffer - fix thread safety, fix sync() after stop() --- contrib/epee/src/readline_buffer.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/contrib/epee/src/readline_buffer.cpp b/contrib/epee/src/readline_buffer.cpp index 05322b693..bcf499963 100644 --- a/contrib/epee/src/readline_buffer.cpp +++ b/contrib/epee/src/readline_buffer.cpp @@ -51,6 +51,7 @@ rdln::readline_buffer::readline_buffer() void rdln::readline_buffer::start() { + boost::lock_guard lock(sync_mutex); if(m_cout_buf != NULL) return; m_cout_buf = std::cout.rdbuf(); @@ -60,6 +61,7 @@ void rdln::readline_buffer::start() void rdln::readline_buffer::stop() { + boost::lock_guard lock(sync_mutex); if(m_cout_buf == NULL) return; std::cout.rdbuf(m_cout_buf); @@ -88,9 +90,9 @@ rdln::linestatus rdln::readline_buffer::get_line(std::string& line) const void rdln::readline_buffer::set_prompt(const std::string& prompt) { + boost::lock_guard lock(sync_mutex); if(m_cout_buf == NULL) return; - boost::lock_guard lock(sync_mutex); rl_set_prompt(std::string(m_prompt_length, ' ').c_str()); rl_redisplay(); rl_set_prompt(prompt.c_str()); @@ -113,6 +115,12 @@ const std::vector& rdln::readline_buffer::get_completions() int rdln::readline_buffer::sync() { boost::lock_guard lock(sync_mutex); + + if (m_cout_buf == nullptr) + { + return -1; + } + #if RL_READLINE_VERSION < 0x0700 char lbuf[2] = {0,0}; char *line = NULL;