aboutsummaryrefslogtreecommitdiff
path: root/src/net.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/net.cpp')
-rw-r--r--src/net.cpp225
1 files changed, 129 insertions, 96 deletions
diff --git a/src/net.cpp b/src/net.cpp
index 4801f5c1f9..de974f39cb 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -3,9 +3,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#if defined(HAVE_CONFIG_H)
-#include <config/bitcoin-config.h>
-#endif
+#include <config/bitcoin-config.h> // IWYU pragma: keep
#include <net.h>
@@ -198,8 +196,7 @@ static std::vector<CAddress> ConvertSeeds(const std::vector<uint8_t> &vSeedsIn)
const auto one_week{7 * 24h};
std::vector<CAddress> vSeedsOut;
FastRandomContext rng;
- DataStream underlying_stream{vSeedsIn};
- ParamsStream s{CAddress::V2_NETWORK, underlying_stream};
+ ParamsStream s{DataStream{vSeedsIn}, CAddress::V2_NETWORK};
while (!s.eof()) {
CService endpoint;
s >> endpoint;
@@ -615,7 +612,6 @@ void CNode::CopyStats(CNodeStats& stats)
X(m_last_tx_time);
X(m_last_block_time);
X(m_connected);
- X(nTimeOffset);
X(m_addr_name);
X(nVersion);
{
@@ -2184,11 +2180,36 @@ void CConnman::WakeMessageHandler()
void CConnman::ThreadDNSAddressSeed()
{
+ constexpr int TARGET_OUTBOUND_CONNECTIONS = 2;
+ int outbound_connection_count = 0;
+
+ if (gArgs.IsArgSet("-seednode")) {
+ auto start = NodeClock::now();
+ constexpr std::chrono::seconds SEEDNODE_TIMEOUT = 30s;
+ LogPrintf("-seednode enabled. Trying the provided seeds for %d seconds before defaulting to the dnsseeds.\n", SEEDNODE_TIMEOUT.count());
+ while (!interruptNet) {
+ if (!interruptNet.sleep_for(std::chrono::milliseconds(500)))
+ return;
+
+ // Abort if we have spent enough time without reaching our target.
+ // Giving seed nodes 30 seconds so this does not become a race against fixedseeds (which triggers after 1 min)
+ if (NodeClock::now() > start + SEEDNODE_TIMEOUT) {
+ LogPrintf("Couldn't connect to enough peers via seed nodes. Handing fetch logic to the DNS seeds.\n");
+ break;
+ }
+
+ outbound_connection_count = GetFullOutboundConnCount();
+ if (outbound_connection_count >= TARGET_OUTBOUND_CONNECTIONS) {
+ LogPrintf("P2P peers available. Finished fetching data from seed nodes.\n");
+ break;
+ }
+ }
+ }
+
FastRandomContext rng;
std::vector<std::string> seeds = m_params.DNSSeeds();
Shuffle(seeds.begin(), seeds.end(), rng);
int seeds_right_now = 0; // Number of seeds left before testing if we have enough connections
- int found = 0;
if (gArgs.GetBoolArg("-forcednsseed", DEFAULT_FORCEDNSSEED)) {
// When -forcednsseed is provided, query all.
@@ -2200,102 +2221,101 @@ void CConnman::ThreadDNSAddressSeed()
seeds_right_now = seeds.size();
}
- // goal: only query DNS seed if address need is acute
- // * If we have a reasonable number of peers in addrman, spend
- // some time trying them first. This improves user privacy by
- // creating fewer identifying DNS requests, reduces trust by
- // giving seeds less influence on the network topology, and
- // reduces traffic to the seeds.
- // * When querying DNS seeds query a few at once, this ensures
- // that we don't give DNS seeds the ability to eclipse nodes
- // that query them.
- // * If we continue having problems, eventually query all the
- // DNS seeds, and if that fails too, also try the fixed seeds.
- // (done in ThreadOpenConnections)
- const std::chrono::seconds seeds_wait_time = (addrman.Size() >= DNSSEEDS_DELAY_PEER_THRESHOLD ? DNSSEEDS_DELAY_MANY_PEERS : DNSSEEDS_DELAY_FEW_PEERS);
-
- for (const std::string& seed : seeds) {
- if (seeds_right_now == 0) {
- seeds_right_now += DNSSEEDS_TO_QUERY_AT_ONCE;
-
- if (addrman.Size() > 0) {
- LogPrintf("Waiting %d seconds before querying DNS seeds.\n", seeds_wait_time.count());
- std::chrono::seconds to_wait = seeds_wait_time;
- while (to_wait.count() > 0) {
- // if sleeping for the MANY_PEERS interval, wake up
- // early to see if we have enough peers and can stop
- // this thread entirely freeing up its resources
- std::chrono::seconds w = std::min(DNSSEEDS_DELAY_FEW_PEERS, to_wait);
- if (!interruptNet.sleep_for(w)) return;
- to_wait -= w;
-
- int nRelevant = 0;
- {
- LOCK(m_nodes_mutex);
- for (const CNode* pnode : m_nodes) {
- if (pnode->fSuccessfullyConnected && pnode->IsFullOutboundConn()) ++nRelevant;
+ // Proceed with dnsseeds if seednodes hasn't reached the target or if forcednsseed is set
+ if (outbound_connection_count < TARGET_OUTBOUND_CONNECTIONS || seeds_right_now) {
+ // goal: only query DNS seed if address need is acute
+ // * If we have a reasonable number of peers in addrman, spend
+ // some time trying them first. This improves user privacy by
+ // creating fewer identifying DNS requests, reduces trust by
+ // giving seeds less influence on the network topology, and
+ // reduces traffic to the seeds.
+ // * When querying DNS seeds query a few at once, this ensures
+ // that we don't give DNS seeds the ability to eclipse nodes
+ // that query them.
+ // * If we continue having problems, eventually query all the
+ // DNS seeds, and if that fails too, also try the fixed seeds.
+ // (done in ThreadOpenConnections)
+ int found = 0;
+ const std::chrono::seconds seeds_wait_time = (addrman.Size() >= DNSSEEDS_DELAY_PEER_THRESHOLD ? DNSSEEDS_DELAY_MANY_PEERS : DNSSEEDS_DELAY_FEW_PEERS);
+
+ for (const std::string& seed : seeds) {
+ if (seeds_right_now == 0) {
+ seeds_right_now += DNSSEEDS_TO_QUERY_AT_ONCE;
+
+ if (addrman.Size() > 0) {
+ LogPrintf("Waiting %d seconds before querying DNS seeds.\n", seeds_wait_time.count());
+ std::chrono::seconds to_wait = seeds_wait_time;
+ while (to_wait.count() > 0) {
+ // if sleeping for the MANY_PEERS interval, wake up
+ // early to see if we have enough peers and can stop
+ // this thread entirely freeing up its resources
+ std::chrono::seconds w = std::min(DNSSEEDS_DELAY_FEW_PEERS, to_wait);
+ if (!interruptNet.sleep_for(w)) return;
+ to_wait -= w;
+
+ if (GetFullOutboundConnCount() >= TARGET_OUTBOUND_CONNECTIONS) {
+ if (found > 0) {
+ LogPrintf("%d addresses found from DNS seeds\n", found);
+ LogPrintf("P2P peers available. Finished DNS seeding.\n");
+ } else {
+ LogPrintf("P2P peers available. Skipped DNS seeding.\n");
+ }
+ return;
}
}
- if (nRelevant >= 2) {
- if (found > 0) {
- LogPrintf("%d addresses found from DNS seeds\n", found);
- LogPrintf("P2P peers available. Finished DNS seeding.\n");
- } else {
- LogPrintf("P2P peers available. Skipped DNS seeding.\n");
- }
- return;
- }
}
}
- }
-
- if (interruptNet) return;
- // hold off on querying seeds if P2P network deactivated
- if (!fNetworkActive) {
- LogPrintf("Waiting for network to be reactivated before querying DNS seeds.\n");
- do {
- if (!interruptNet.sleep_for(std::chrono::seconds{1})) return;
- } while (!fNetworkActive);
- }
+ if (interruptNet) return;
- LogPrintf("Loading addresses from DNS seed %s\n", seed);
- // If -proxy is in use, we make an ADDR_FETCH connection to the DNS resolved peer address
- // for the base dns seed domain in chainparams
- if (HaveNameProxy()) {
- AddAddrFetch(seed);
- } else {
- std::vector<CAddress> vAdd;
- constexpr ServiceFlags requiredServiceBits{SeedsServiceFlags()};
- std::string host = strprintf("x%x.%s", requiredServiceBits, seed);
- CNetAddr resolveSource;
- if (!resolveSource.SetInternal(host)) {
- continue;
+ // hold off on querying seeds if P2P network deactivated
+ if (!fNetworkActive) {
+ LogPrintf("Waiting for network to be reactivated before querying DNS seeds.\n");
+ do {
+ if (!interruptNet.sleep_for(std::chrono::seconds{1})) return;
+ } while (!fNetworkActive);
}
- // Limit number of IPs learned from a single DNS seed. This limit exists to prevent the results from
- // one DNS seed from dominating AddrMan. Note that the number of results from a UDP DNS query is
- // bounded to 33 already, but it is possible for it to use TCP where a larger number of results can be
- // returned.
- unsigned int nMaxIPs = 32;
- const auto addresses{LookupHost(host, nMaxIPs, true)};
- if (!addresses.empty()) {
- for (const CNetAddr& ip : addresses) {
- CAddress addr = CAddress(CService(ip, m_params.GetDefaultPort()), requiredServiceBits);
- addr.nTime = rng.rand_uniform_delay(Now<NodeSeconds>() - 3 * 24h, -4 * 24h); // use a random age between 3 and 7 days old
- vAdd.push_back(addr);
- found++;
- }
- addrman.Add(vAdd, resolveSource);
- } else {
- // If the seed does not support a subdomain with our desired service bits,
- // we make an ADDR_FETCH connection to the DNS resolved peer address for the
- // base dns seed domain in chainparams
+
+ LogPrintf("Loading addresses from DNS seed %s\n", seed);
+ // If -proxy is in use, we make an ADDR_FETCH connection to the DNS resolved peer address
+ // for the base dns seed domain in chainparams
+ if (HaveNameProxy()) {
AddAddrFetch(seed);
+ } else {
+ std::vector<CAddress> vAdd;
+ constexpr ServiceFlags requiredServiceBits{SeedsServiceFlags()};
+ std::string host = strprintf("x%x.%s", requiredServiceBits, seed);
+ CNetAddr resolveSource;
+ if (!resolveSource.SetInternal(host)) {
+ continue;
+ }
+ // Limit number of IPs learned from a single DNS seed. This limit exists to prevent the results from
+ // one DNS seed from dominating AddrMan. Note that the number of results from a UDP DNS query is
+ // bounded to 33 already, but it is possible for it to use TCP where a larger number of results can be
+ // returned.
+ unsigned int nMaxIPs = 32;
+ const auto addresses{LookupHost(host, nMaxIPs, true)};
+ if (!addresses.empty()) {
+ for (const CNetAddr& ip : addresses) {
+ CAddress addr = CAddress(CService(ip, m_params.GetDefaultPort()), requiredServiceBits);
+ addr.nTime = rng.rand_uniform_delay(Now<NodeSeconds>() - 3 * 24h, -4 * 24h); // use a random age between 3 and 7 days old
+ vAdd.push_back(addr);
+ found++;
+ }
+ addrman.Add(vAdd, resolveSource);
+ } else {
+ // If the seed does not support a subdomain with our desired service bits,
+ // we make an ADDR_FETCH connection to the DNS resolved peer address for the
+ // base dns seed domain in chainparams
+ AddAddrFetch(seed);
+ }
}
+ --seeds_right_now;
}
- --seeds_right_now;
+ LogPrintf("%d addresses found from DNS seeds\n", found);
+ } else {
+ LogPrintf("Skipping DNS seeds. Enough peers have been found\n");
}
- LogPrintf("%d addresses found from DNS seeds\n", found);
}
void CConnman::DumpAddresses()
@@ -2346,6 +2366,19 @@ void CConnman::StartExtraBlockRelayPeers()
m_start_extra_block_relay_peers = true;
}
+// Return the number of outbound connections that are full relay (not blocks only)
+int CConnman::GetFullOutboundConnCount() const
+{
+ int nRelevant = 0;
+ {
+ LOCK(m_nodes_mutex);
+ for (const CNode* pnode : m_nodes) {
+ if (pnode->fSuccessfullyConnected && pnode->IsFullOutboundConn()) ++nRelevant;
+ }
+ }
+ return nRelevant;
+}
+
// Return the number of peers we have over our outbound connection limit
// Exclude peers that are marked for disconnect, or are going to be
// disconnected soon (eg ADDR_FETCH and FEELER)
@@ -2798,7 +2831,7 @@ std::vector<AddedNodeInfo> CConnman::GetAddedNodeInfo(bool include_connected) co
}
for (const auto& addr : lAddresses) {
- CService service(LookupNumeric(addr.m_added_node, GetDefaultPort(addr.m_added_node)));
+ CService service{MaybeFlipIPv6toCJDNS(LookupNumeric(addr.m_added_node, GetDefaultPort(addr.m_added_node)))};
AddedNodeInfo addedNode{addr, CService(), false, false};
if (service.IsValid()) {
// strAddNode is an IP:port
@@ -3077,8 +3110,7 @@ void Discover()
{
if (ifa->ifa_addr == nullptr) continue;
if ((ifa->ifa_flags & IFF_UP) == 0) continue;
- if (strcmp(ifa->ifa_name, "lo") == 0) continue;
- if (strcmp(ifa->ifa_name, "lo0") == 0) continue;
+ if ((ifa->ifa_flags & IFF_LOOPBACK) != 0) continue;
if (ifa->ifa_addr->sa_family == AF_INET)
{
struct sockaddr_in* s4 = (struct sockaddr_in*)(ifa->ifa_addr);
@@ -3704,8 +3736,9 @@ CNode::CNode(NodeId idIn,
{
if (inbound_onion) assert(conn_type_in == ConnectionType::INBOUND);
- for (const std::string &msg : getAllNetMessageTypes())
+ for (const auto& msg : ALL_NET_MESSAGE_TYPES) {
mapRecvBytesPerMsgType[msg] = 0;
+ }
mapRecvBytesPerMsgType[NET_MESSAGE_TYPE_OTHER] = 0;
if (fLogIPs) {