diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -553,6 +553,7 @@ consensus/activation.cpp consensus/tx_verify.cpp dbwrapper.cpp + dnsseeds.cpp flatfile.cpp httprpc.cpp httpserver.cpp diff --git a/src/chainparams.h b/src/chainparams.h --- a/src/chainparams.h +++ b/src/chainparams.h @@ -85,7 +85,6 @@ /** Return the BIP70 network string (main, test or regtest) */ std::string NetworkIDString() const { return strNetworkID; } /** Return the list of hostnames to look up for DNS seeds */ - const std::vector &DNSSeeds() const { return vSeeds; } const std::vector &Base58Prefix(Base58Type type) const { return base58Prefixes[type]; } @@ -116,6 +115,9 @@ bool m_is_mockable_chain; CCheckpointData checkpointData; ChainTxData chainTxData; + + friend const std::vector + GetRandomizedDNSSeeds(const CChainParams ¶ms); }; /** diff --git a/src/dnsseeds.h b/src/dnsseeds.h new file mode 100644 --- /dev/null +++ b/src/dnsseeds.h @@ -0,0 +1,17 @@ +// Copyright (c) 2021 The Bitcoin developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_DNSSEEDS_H +#define BITCOIN_DNSSEEDS_H + +#include + +#include +#include + +/** Return the list of hostnames to look up for DNS seeds */ +const std::vector +GetRandomizedDNSSeeds(const CChainParams ¶ms); + +#endif // BITCOIN_DNSSEEDS_H diff --git a/src/dnsseeds.cpp b/src/dnsseeds.cpp new file mode 100644 --- /dev/null +++ b/src/dnsseeds.cpp @@ -0,0 +1,22 @@ +// Copyright (c) 2021 The Bitcoin developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include + +const std::vector +GetRandomizedDNSSeeds(const CChainParams ¶ms) { + FastRandomContext rng; + std::vector seeds; + if (gArgs.IsArgSet("-overridednsseed")) { + seeds = {gArgs.GetArg("-overridednsseed", "")}; + } else { + seeds = params.vSeeds; + } + + Shuffle(seeds.begin(), seeds.end(), rng); + return seeds; +} diff --git a/src/init.cpp b/src/init.cpp --- a/src/init.cpp +++ b/src/init.cpp @@ -665,6 +665,10 @@ "Always query for peer addresses via DNS lookup (default: %d)", DEFAULT_FORCEDNSSEED), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); + argsman.AddArg("-overridednsseed", + "If set, only use the specified DNS seed when " + "querying for peer addresses via DNS lookup.", + ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsman.AddArg( "-listen", "Accept connections from outside (default: 1 if no -proxy or -connect)", diff --git a/src/net.cpp b/src/net.cpp --- a/src/net.cpp +++ b/src/net.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -1725,8 +1726,8 @@ void CConnman::ThreadDNSAddressSeed() { FastRandomContext rng; - std::vector seeds = config->GetChainParams().DNSSeeds(); - Shuffle(seeds.begin(), seeds.end(), rng); + std::vector seeds = + GetRandomizedDNSSeeds(config->GetChainParams()); // Number of seeds left before testing if we have enough connections int seeds_right_now = 0; int found = 0; diff --git a/src/seeder/main.cpp b/src/seeder/main.cpp --- a/src/seeder/main.cpp +++ b/src/seeder/main.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -146,6 +147,10 @@ ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsman.AddArg("-onion=", "Tor proxy IP/Port", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); + argsman.AddArg("-overridednsseed", + "If set, only use the specified DNS seed when " + "querying for peer addresses via DNS lookup.", + ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsman.AddArg("-proxyipv4=", "IPV4 SOCKS5 proxy IP/Port", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsman.AddArg("-proxyipv6=", "IPV6 SOCKS5 proxy IP/Port", @@ -458,7 +463,7 @@ extern "C" void *ThreadSeeder(void *) { do { - for (const std::string &seed : Params().DNSSeeds()) { + for (const std::string &seed : GetRandomizedDNSSeeds(Params())) { std::vector ips; LookupHost(seed.c_str(), ips, MAX_HOSTS_PER_SEED, true); for (auto &ip : ips) { diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -196,6 +196,7 @@ script_standard_tests.cpp script_tests.cpp scriptnum_tests.cpp + dnsseeds_tests.cpp serialize_tests.cpp settings_tests.cpp sigcache_tests.cpp diff --git a/src/test/dnsseeds_tests.cpp b/src/test/dnsseeds_tests.cpp new file mode 100644 --- /dev/null +++ b/src/test/dnsseeds_tests.cpp @@ -0,0 +1,24 @@ +// Copyright (c) 2020-2021 The Bitcoin developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include + +#include + +BOOST_FIXTURE_TEST_SUITE(dnsseeds_tests, TestingSetup) + +BOOST_AUTO_TEST_CASE(override_dns_seed) { + // No override should always provide some DNS seeds + const auto params = CreateChainParams(CBaseChainParams::MAIN); + BOOST_CHECK(GetRandomizedDNSSeeds(*params).size() > 0); + + // Overriding should only return that DNS seed + gArgs.ForceSetArg("-overridednsseed", "localhost"); + BOOST_CHECK(GetRandomizedDNSSeeds(*params) == + std::vector{{"localhost"}}); +} + +BOOST_AUTO_TEST_SUITE_END()