Skip to content

Commit 3ce8298

Browse files
committed
Merge #15558: Don't query all DNS seeds at once
6170ec5 Do not query all DNS seed at once (Pieter Wuille) Pull request description: Before this PR, when we don't have enough connections after 11 seconds, we proceed to query all DNS seeds in a fixed order, loading responses from all of them. Change this to to only query three randomly-selected DNS seed. If 11 seconds later we still don't have enough connections, try again with another one, and so on. This reduces the amount of information DNS seeds can observe about the requesters by spreading the load over all of them. ACKs for top commit: Sjors: ACK 6170ec5 sdaftuar: ACK 6170ec5 jonasschnelli: utACK 6170ec5 - I think the risk of a single seeder codebase is orthogonal to this PR. Such risks could also be interpreted differently (diversity could also increase the risk based on the threat model). fanquake: ACK 6170ec5 - Agree with the reasoning behind the change. Did some testing with and without `-forcednsseed` and/or a `peers.dat` and monitored the DNS activity. Tree-SHA512: 33f6be5f924a85d312303ce272aa8f8d5e04cb616b4b492be98832e3ff37558d13d2b16ede68644ad399aff2bf5ff0ad33844e55eb40b7f8e3fddf9ae43add57
2 parents 13377b7 + 6170ec5 commit 3ce8298

File tree

1 file changed

+34
-27
lines changed

1 file changed

+34
-27
lines changed

src/net.cpp

Lines changed: 34 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ static_assert(MINIUPNPC_API_VERSION >= 10, "miniUPnPc API version >= 10 assumed"
5050
// Dump addresses to peers.dat every 15 minutes (900s)
5151
static constexpr int DUMP_PEERS_INTERVAL = 15 * 60;
5252

53+
/** Number of DNS seeds to query when the number of connections is low. */
54+
static constexpr int DNSSEEDS_TO_QUERY_AT_ONCE = 3;
55+
5356
// We add a random period time (0 to 1 seconds) to feeler connections to prevent synchronization.
5457
#define FEELER_SLEEP_WINDOW 1
5558

@@ -1535,35 +1538,41 @@ void StopMapPort()
15351538

15361539
void CConnman::ThreadDNSAddressSeed()
15371540
{
1538-
// goal: only query DNS seeds if address need is acute
1539-
// Avoiding DNS seeds when we don't need them improves user privacy by
1540-
// creating fewer identifying DNS requests, reduces trust by giving seeds
1541-
// less influence on the network topology, and reduces traffic to the seeds.
1542-
if ((addrman.size() > 0) &&
1543-
(!gArgs.GetBoolArg("-forcednsseed", DEFAULT_FORCEDNSSEED))) {
1544-
if (!interruptNet.sleep_for(std::chrono::seconds(11)))
1545-
return;
1541+
FastRandomContext rng;
1542+
std::vector<std::string> seeds = Params().DNSSeeds();
1543+
Shuffle(seeds.begin(), seeds.end(), rng);
1544+
int seeds_right_now = 0; // Number of seeds left before testing if we have enough connections
1545+
int found = 0;
15461546

1547-
LOCK(cs_vNodes);
1548-
int nRelevant = 0;
1549-
for (const CNode* pnode : vNodes) {
1550-
nRelevant += pnode->fSuccessfullyConnected && !pnode->fFeeler && !pnode->fOneShot && !pnode->m_manual_connection && !pnode->fInbound;
1551-
}
1552-
if (nRelevant >= 2) {
1553-
LogPrintf("P2P peers available. Skipped DNS seeding.\n");
1554-
return;
1555-
}
1547+
if (gArgs.GetBoolArg("-forcednsseed", DEFAULT_FORCEDNSSEED)) {
1548+
// When -forcednsseed is provided, query all.
1549+
seeds_right_now = seeds.size();
15561550
}
15571551

1558-
const std::vector<std::string> &vSeeds = Params().DNSSeeds();
1559-
int found = 0;
1552+
for (const std::string& seed : seeds) {
1553+
// goal: only query DNS seed if address need is acute
1554+
// Avoiding DNS seeds when we don't need them improves user privacy by
1555+
// creating fewer identifying DNS requests, reduces trust by giving seeds
1556+
// less influence on the network topology, and reduces traffic to the seeds.
1557+
if (addrman.size() > 0 && seeds_right_now == 0) {
1558+
if (!interruptNet.sleep_for(std::chrono::seconds(11))) return;
15601559

1561-
LogPrintf("Loading addresses from DNS seeds (could take a while)\n");
1560+
LOCK(cs_vNodes);
1561+
int nRelevant = 0;
1562+
for (const CNode* pnode : vNodes) {
1563+
nRelevant += pnode->fSuccessfullyConnected && !pnode->fFeeler && !pnode->fOneShot && !pnode->m_manual_connection && !pnode->fInbound;
1564+
}
1565+
if (nRelevant >= 2) {
1566+
LogPrintf("P2P peers available. Skipped DNS seeding.\n");
1567+
return;
1568+
}
1569+
seeds_right_now += DNSSEEDS_TO_QUERY_AT_ONCE;
1570+
}
15621571

1563-
for (const std::string &seed : vSeeds) {
15641572
if (interruptNet) {
15651573
return;
15661574
}
1575+
LogPrintf("Loading addresses from DNS seed %s\n", seed);
15671576
if (HaveNameProxy()) {
15681577
AddOneShot(seed);
15691578
} else {
@@ -1576,13 +1585,11 @@ void CConnman::ThreadDNSAddressSeed()
15761585
continue;
15771586
}
15781587
unsigned int nMaxIPs = 256; // Limits number of IPs learned from a DNS seed
1579-
if (LookupHost(host.c_str(), vIPs, nMaxIPs, true))
1580-
{
1581-
for (const CNetAddr& ip : vIPs)
1582-
{
1588+
if (LookupHost(host.c_str(), vIPs, nMaxIPs, true)) {
1589+
for (const CNetAddr& ip : vIPs) {
15831590
int nOneDay = 24*3600;
15841591
CAddress addr = CAddress(CService(ip, Params().GetDefaultPort()), requiredServiceBits);
1585-
addr.nTime = GetTime() - 3*nOneDay - GetRand(4*nOneDay); // use a random age between 3 and 7 days old
1592+
addr.nTime = GetTime() - 3*nOneDay - rng.randrange(4*nOneDay); // use a random age between 3 and 7 days old
15861593
vAdd.push_back(addr);
15871594
found++;
15881595
}
@@ -1593,8 +1600,8 @@ void CConnman::ThreadDNSAddressSeed()
15931600
AddOneShot(seed);
15941601
}
15951602
}
1603+
--seeds_right_now;
15961604
}
1597-
15981605
LogPrintf("%d addresses found from DNS seeds\n", found);
15991606
}
16001607

0 commit comments

Comments
 (0)