fix(p2p): consume the published TXT seed records

This commit is contained in:
2026-10-18 16:03:03 -04:00
committed by John Winter Murphy
parent 85e57e19fd
commit 66d7ecf34e
5 changed files with 72 additions and 4 deletions
+7
View File
@@ -156,3 +156,10 @@ Once the node has caught up, `--block-sync-size` can be removed.
Copyright (c) 2014-2026 The Monero Project.
Portions Copyright (c) 2012-2013 The Cryptonote developers.
### DNS seed discovery
Mainnet discovers peers from TXT records at `seeds.wownero.org`. Records contain
literal IPv4 endpoints (`IP:port`), either individually or separated by semicolons.
Invalid and local endpoints are ignored. The built-in seed list remains the
fallback when DNS is unavailable or returns too few usable endpoints.
+37
View File
@@ -0,0 +1,37 @@
// SPDX-License-Identifier: BSD-3-Clause
#pragma once
#include <boost/algorithm/string.hpp>
#include <cstdint>
#include <set>
#include <string>
#include <vector>
#include "net/parse.h"
namespace nodetool
{
// TXT seed records contain literal IPv4 endpoints, separated by semicolons.
inline std::set<std::string> parse_dns_seed_records(const std::vector<std::string>& records, uint16_t default_port)
{
std::set<std::string> seeds;
for (const auto& record : records)
{
std::vector<std::string> endpoints;
boost::split(endpoints, record, boost::is_any_of(";"));
for (auto endpoint : endpoints)
{
boost::trim(endpoint);
const auto address = net::get_network_address(endpoint, default_port);
if (!address || address->get_type_id() != epee::net_utils::address_type::ipv4)
continue;
const auto& ipv4 = address->as<epee::net_utils::ipv4_network_address>();
if (ipv4.ip() == 0 || ipv4.port() == 0 || ipv4.is_loopback() || ipv4.is_local())
continue;
seeds.insert(address->str());
}
}
return seeds;
}
}
+1 -1
View File
@@ -297,7 +297,7 @@ namespace nodetool
private:
const std::vector<std::string> m_seed_nodes_list =
{
"seeds.wownero.com"
"seeds.wownero.org"
};
bool islimitup=false;
+4 -3
View File
@@ -59,6 +59,7 @@
#include "storages/levin_abstract_invoke2.h"
#include "cryptonote_core/cryptonote_core.h"
#include "net/parse.h"
#include "p2p/dns_seed.h"
#undef MONERO_DEFAULT_LOG_CATEGORY
@@ -801,7 +802,7 @@ namespace nodetool
MDEBUG("dns_threads[" << result_index << "] created for: " << addr_str);
// TODO: care about dnssec avail/valid
bool avail, valid;
std::vector<std::string> addr_list = tools::DNSResolver::instance().get_ipv4(addr_str, avail, valid);
std::vector<std::string> addr_list = tools::DNSResolver::instance().get_txt_record(addr_str, avail, valid);
MINFO("dns_threads[" << result_index << "] addr_str: " << addr_str << " number of results: " << addr_list.size());
const auto frame = frame_weak.lock();
if (frame)
@@ -836,8 +837,8 @@ namespace nodetool
// if no results for node, thread's lookup likely timed out
if (result.size())
{
for (const auto& addr_string : result)
full_addrs.insert(addr_string + ":" + std::to_string(cryptonote::get_config(m_nettype).P2P_DEFAULT_PORT));
const auto seeds = parse_dns_seed_records(result, cryptonote::get_config(m_nettype).P2P_DEFAULT_PORT);
full_addrs.insert(seeds.begin(), seeds.end());
}
++i;
}
+23
View File
@@ -1451,3 +1451,26 @@ TEST(regtest, isolates_p2p_state_from_mainnet_data_dir)
namespace nodetool { template class node_server<cryptonote::t_cryptonote_protocol_handler<test_core>>; }
namespace cryptonote { template class t_cryptonote_protocol_handler<test_core>; }
TEST(dns_seed_records, accepts_grouped_and_individual_endpoints)
{
const auto seeds = nodetool::parse_dns_seed_records({
"198.51.100.10:34567; 203.0.113.20:34567", "198.51.100.30", "198.51.100.10:34567"}, 34567);
const std::set<std::string> expected{
"198.51.100.10:34567", "203.0.113.20:34567", "198.51.100.30:34567"};
EXPECT_EQ(expected, seeds);
}
TEST(dns_seed_records, ignores_invalid_and_local_endpoints)
{
const auto seeds = nodetool::parse_dns_seed_records({
";invalid;198.51.100.10:65536;127.0.0.1:34567;192.168.1.2:34567;0.0.0.0:34567;198.51.100.20:0;",
"203.0.113.20:34567"}, 34567);
EXPECT_EQ((std::set<std::string>{"203.0.113.20:34567"}), seeds);
}
TEST(dns_seed_records, empty_results_allow_hardcoded_fallback)
{
EXPECT_TRUE(nodetool::parse_dns_seed_records({}, 34567).empty());
EXPECT_TRUE(nodetool::parse_dns_seed_records({"", "; ;", "invalid"}, 34567).empty());
}