Inside Bitcoin
Opening the selected file…
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1// Copyright (c) 2009-2010 Satoshi Nakamoto2// Copyright (c) 2009-present The Bitcoin Core developers3// Distributed under the MIT software license, see the accompanying4// file COPYING or http://www.opensource.org/licenses/mit-license.php.6#include <bitcoin-build-config.h> // IWYU pragma: keep8#include <net.h>10#include <addrdb.h>11#include <addrman.h>12#include <banman.h>13#include <clientversion.h>14#include <common/args.h>15#include <common/netif.h>16#include <compat/compat.h>17#include <consensus/consensus.h>18#include <crypto/sha256.h>19#include <i2p.h>20#include <key.h>21#include <logging.h>22#include <memusage.h>23#include <net_permissions.h>24#include <netaddress.h>25#include <netbase.h>26#include <node/eviction.h>27#include <node/interface_ui.h>28#include <protocol.h>29#include <random.h>30#include <scheduler.h>31#include <util/fs.h>32#include <util/overflow.h>33#include <util/sock.h>34#include <util/strencodings.h>35#include <util/thread.h>36#include <util/threadinterrupt.h>37#include <util/trace.h>38#include <util/translation.h>39#include <util/vector.h>41#include <algorithm>42#include <array>43#include <cmath>44#include <cstdint>45#include <cstring>46#include <functional>47#include <optional>48#include <string_view>49#include <unordered_map>51TRACEPOINT_SEMAPHORE(net, closed_connection);52TRACEPOINT_SEMAPHORE(net, evicted_inbound_connection);53TRACEPOINT_SEMAPHORE(net, inbound_connection);54TRACEPOINT_SEMAPHORE(net, outbound_connection);55TRACEPOINT_SEMAPHORE(net, outbound_message);57/** Maximum number of block-relay-only anchor connections */58static constexpr size_t MAX_BLOCK_RELAY_ONLY_ANCHORS = 2;59static_assert (MAX_BLOCK_RELAY_ONLY_ANCHORS <= static_cast<size_t>(MAX_BLOCK_RELAY_ONLY_CONNECTIONS), "MAX_BLOCK_RELAY_ONLY_ANCHORS must not exceed MAX_BLOCK_RELAY_ONLY_CONNECTIONS.");60/** Anchor IP address database file name */61const char* const ANCHORS_DATABASE_FILENAME = "anchors.dat";63// How often to dump addresses to peers.dat64static constexpr std::chrono::minutes DUMP_PEERS_INTERVAL{15};66/** Number of DNS seeds to query when the number of connections is low. */67static constexpr int DNSSEEDS_TO_QUERY_AT_ONCE = 3;69/** Minimum number of outbound connections under which we will keep fetching our address seeds. */70static constexpr int SEED_OUTBOUND_CONNECTION_THRESHOLD = 2;72/** How long to delay before querying DNS seeds73*74* If we have more than THRESHOLD entries in addrman, then it's likely75* that we got those addresses from having previously connected to the P2P76* network, and that we'll be able to successfully reconnect to the P2P77* network via contacting one of them. So if that's the case, spend a78* little longer trying to connect to known peers before querying the79* DNS seeds.80*/81static constexpr std::chrono::seconds DNSSEEDS_DELAY_FEW_PEERS{11};82static constexpr std::chrono::minutes DNSSEEDS_DELAY_MANY_PEERS{5};83static constexpr int DNSSEEDS_DELAY_PEER_THRESHOLD = 1000; // "many" vs "few" peers85/** The default timeframe for -maxuploadtarget. 1 day. */86static constexpr std::chrono::seconds MAX_UPLOAD_TIMEFRAME{60 * 60 * 24};88// A random time period (0 to 1 seconds) is added to feeler connections to prevent synchronization.89static constexpr auto FEELER_SLEEP_WINDOW{1s};91/** Frequency to attempt extra connections to reachable networks we're not connected to yet **/92static constexpr auto EXTRA_NETWORK_PEER_INTERVAL{5min};94/** Used to pass flags to the Bind() function */95enum BindFlags {96BF_NONE = 0,97BF_REPORT_ERROR = (1U << 0),98/**99* Do not call AddLocal() for our special addresses, e.g., for incoming100* Tor connections, to prevent gossiping them over the network.101*/102BF_DONT_ADVERTISE = (1U << 1),103};105// The set of sockets cannot be modified while waiting106// The sleep time needs to be small to avoid new sockets stalling107static const uint64_t SELECT_TIMEOUT_MILLISECONDS = 50;109const std::string NET_MESSAGE_TYPE_OTHER = "*other*";111static const uint64_t RANDOMIZER_ID_NETGROUP = 0x6c0edd8036ef4036ULL; // SHA256("netgroup")[0:8]112static const uint64_t RANDOMIZER_ID_LOCALHOSTNONCE = 0xd93e69e2bbfa5735ULL; // SHA256("localhostnonce")[0:8]113static const uint64_t RANDOMIZER_ID_NETWORKKEY = 0x0e8a2b136c592a7dULL; // SHA256("networkkey")[0:8]114//115// Global state variables116//117bool fDiscover = true;118bool fListen = true;119GlobalMutex g_maplocalhost_mutex;120std::map<CNetAddr, LocalServiceInfo> mapLocalHost GUARDED_BY(g_maplocalhost_mutex);121std::string strSubVersion;123size_t CSerializedNetMsg::GetMemoryUsage() const noexcept124{125return sizeof(*this) + memusage::DynamicUsage(m_type) + memusage::DynamicUsage(data);126}128size_t CNetMessage::GetMemoryUsage() const noexcept129{130return sizeof(*this) + memusage::DynamicUsage(m_type) + m_recv.GetMemoryUsage();131}133void CConnman::AddAddrFetch(const std::string& strDest)134{135LOCK(m_addr_fetches_mutex);136m_addr_fetches.push_back(strDest);137}139uint16_t GetListenPort()140{141// If -bind= is provided with ":port" part, use that (first one if multiple are provided).142for (const std::string& bind_arg : gArgs.GetArgs("-bind")) {143constexpr uint16_t dummy_port = 0;145const std::optional<CService> bind_addr{Lookup(bind_arg, dummy_port, /*fAllowLookup=*/false)};146if (bind_addr.has_value() && bind_addr->GetPort() != dummy_port) return bind_addr->GetPort();147}149// Otherwise, if -whitebind= without NetPermissionFlags::NoBan is provided, use that150// (-whitebind= is required to have ":port").151for (const std::string& whitebind_arg : gArgs.GetArgs("-whitebind")) {152NetWhitebindPermissions whitebind;153bilingual_str error;154if (NetWhitebindPermissions::TryParse(whitebind_arg, whitebind, error)) {155if (!NetPermissions::HasFlag(whitebind.m_flags, NetPermissionFlags::NoBan)) {156return whitebind.m_service.GetPort();157}158}159}161// Otherwise, if -port= is provided, use that. Otherwise use the default port.162return static_cast<uint16_t>(gArgs.GetIntArg("-port", Params().GetDefaultPort()));163}165// Determine the "best" local address for a particular peer.166[[nodiscard]] static std::optional<CService> GetLocal(const CNode& peer)167{168if (!fListen) return std::nullopt;170std::optional<CService> addr;171int nBestScore = -1;172int nBestReachability = -1;173{174LOCK(g_maplocalhost_mutex);175for (const auto& [local_addr, local_service_info] : mapLocalHost) {176// For privacy reasons, don't advertise our privacy-network address177// to other networks and don't advertise our other-network address178// to privacy networks.179if (local_addr.GetNetwork() != peer.ConnectedThroughNetwork()180&& (local_addr.IsPrivacyNet() || peer.IsConnectedThroughPrivacyNet())) {181continue;182}183const int nScore{local_service_info.nScore};184const int nReachability{local_addr.GetReachabilityFrom(peer.addr)};185if (nReachability > nBestReachability || (nReachability == nBestReachability && nScore > nBestScore)) {186addr.emplace(CService{local_addr, local_service_info.nPort});187nBestReachability = nReachability;188nBestScore = nScore;189}190}191}192return addr;193}195//! Convert the serialized seeds into usable address objects.196static std::vector<CAddress> ConvertSeeds(const std::vector<uint8_t> &vSeedsIn)197{198// It'll only connect to one or two seed nodes because once it connects,199// it'll get a pile of addresses with newer timestamps.200// Seed nodes are given a random 'last seen time' of between one and two201// weeks ago.202const auto one_week{7 * 24h};203std::vector<CAddress> vSeedsOut;204FastRandomContext rng;205ParamsStream s{SpanReader{vSeedsIn}, CAddress::V2_NETWORK};206while (!s.empty()) {207CService endpoint;208s >> endpoint;209CAddress addr{endpoint, SeedsAssumedServiceFlags()};210addr.nTime = rng.rand_uniform_delay(Now<NodeSeconds>() - one_week, -one_week);211LogDebug(BCLog::NET, "Added hardcoded seed: %s\n", addr.ToStringAddrPort());212vSeedsOut.push_back(addr);213}214return vSeedsOut;215}217// Determine the "best" local address for a particular peer.218// If none, return the unroutable 0.0.0.0 but filled in with219// the normal parameters, since the IP may be changed to a useful220// one by discovery.221CService GetLocalAddress(const CNode& peer)222{223return GetLocal(peer).value_or(CService{CNetAddr(), GetListenPort()});224}226static int GetnScore(const CService& addr)227{228LOCK(g_maplocalhost_mutex);229const auto it = mapLocalHost.find(addr);230return (it != mapLocalHost.end()) ? it->second.nScore : 0;231}233// Is our peer's addrLocal potentially useful as an external IP source?234[[nodiscard]] static bool IsPeerAddrLocalGood(CNode *pnode)235{236CService addrLocal = pnode->GetAddrLocal();237return fDiscover && pnode->addr.IsRoutable() && addrLocal.IsRoutable() &&238g_reachable_nets.Contains(addrLocal);239}241std::optional<CService> GetLocalAddrForPeer(CNode& node)242{243CService addrLocal{GetLocalAddress(node)};244// If discovery is enabled, sometimes give our peer the address it245// tells us that it sees us as in case it has a better idea of our246// address than we do.247FastRandomContext rng;248if (IsPeerAddrLocalGood(&node) && (!addrLocal.IsRoutable() ||249rng.randbits((GetnScore(addrLocal) > LOCAL_MANUAL) ? 3 : 1) == 0))250{