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 <netbase.h>10#include <compat/compat.h>11#include <sync.h>12#include <tinyformat.h>13#include <util/log.h>14#include <util/sock.h>15#include <util/strencodings.h>16#include <util/string.h>17#include <util/time.h>19#include <atomic>20#include <chrono>21#include <cstdint>22#include <functional>23#include <limits>24#include <memory>26#ifdef HAVE_SOCKADDR_UN27#include <sys/un.h>28#endif30using util::ContainsNUL;32// Settings33static GlobalMutex g_proxyinfo_mutex;34static Proxy proxyInfo[NET_MAX] GUARDED_BY(g_proxyinfo_mutex);35static Proxy nameProxy GUARDED_BY(g_proxyinfo_mutex);36int nConnectTimeout = DEFAULT_CONNECT_TIMEOUT;37bool fNameLookup = DEFAULT_NAME_LOOKUP;39// Need ample time for negotiation for very slow proxies such as Tor40std::chrono::milliseconds g_socks5_recv_timeout = 20s;41CThreadInterrupt g_socks5_interrupt;43ReachableNets g_reachable_nets;45std::vector<CNetAddr> WrappedGetAddrInfo(const std::string& name, bool allow_lookup)46{47addrinfo ai_hint{};48// We want a TCP port, which is a streaming socket type49ai_hint.ai_socktype = SOCK_STREAM;50ai_hint.ai_protocol = IPPROTO_TCP;51// We don't care which address family (IPv4 or IPv6) is returned52ai_hint.ai_family = AF_UNSPEC;54// If we allow lookups of hostnames, use the AI_ADDRCONFIG flag to only55// return addresses whose family we have an address configured for.56//57// If we don't allow lookups, then use the AI_NUMERICHOST flag for58// getaddrinfo to only decode numerical network addresses and suppress59// hostname lookups.60ai_hint.ai_flags = allow_lookup ? AI_ADDRCONFIG : AI_NUMERICHOST;62addrinfo* ai_res{nullptr};63const int n_err{getaddrinfo(name.c_str(), nullptr, &ai_hint, &ai_res)};64if (n_err != 0) {65if ((ai_hint.ai_flags & AI_ADDRCONFIG) == AI_ADDRCONFIG) {66// AI_ADDRCONFIG on some systems may exclude loopback-only addresses67// If first lookup failed we perform a second lookup without AI_ADDRCONFIG68ai_hint.ai_flags = (ai_hint.ai_flags & ~AI_ADDRCONFIG);69const int n_err_retry{getaddrinfo(name.c_str(), nullptr, &ai_hint, &ai_res)};70if (n_err_retry != 0) {71return {};72}73} else {74return {};75}76}78// Traverse the linked list starting with ai_trav.79addrinfo* ai_trav{ai_res};80std::vector<CNetAddr> resolved_addresses;81while (ai_trav != nullptr) {82if (ai_trav->ai_family == AF_INET) {83assert(ai_trav->ai_addrlen >= sizeof(sockaddr_in));84resolved_addresses.emplace_back(reinterpret_cast<sockaddr_in*>(ai_trav->ai_addr)->sin_addr);85}86if (ai_trav->ai_family == AF_INET6) {87assert(ai_trav->ai_addrlen >= sizeof(sockaddr_in6));88const sockaddr_in6* s6{reinterpret_cast<sockaddr_in6*>(ai_trav->ai_addr)};89resolved_addresses.emplace_back(s6->sin6_addr, s6->sin6_scope_id);90}91ai_trav = ai_trav->ai_next;92}93freeaddrinfo(ai_res);95return resolved_addresses;96}98DNSLookupFn g_dns_lookup{WrappedGetAddrInfo};100enum Network ParseNetwork(const std::string& net_in) {101std::string net = ToLower(net_in);102if (net == "ipv4") return NET_IPV4;103if (net == "ipv6") return NET_IPV6;104if (net == "onion") return NET_ONION;105if (net == "i2p") {106return NET_I2P;107}108if (net == "cjdns") {109return NET_CJDNS;110}111return NET_UNROUTABLE;112}114std::string GetNetworkName(enum Network net)115{116switch (net) {117case NET_UNROUTABLE: return "not_publicly_routable";118case NET_IPV4: return "ipv4";119case NET_IPV6: return "ipv6";120case NET_ONION: return "onion";121case NET_I2P: return "i2p";122case NET_CJDNS: return "cjdns";123case NET_INTERNAL: return "internal";124case NET_MAX: assert(false);125} // no default case, so the compiler can warn about missing cases127assert(false);128}130std::vector<std::string> GetNetworkNames(bool append_unroutable)131{132std::vector<std::string> names;133for (int n = 0; n < NET_MAX; ++n) {134const enum Network network{static_cast<Network>(n)};135if (network == NET_UNROUTABLE || network == NET_INTERNAL) continue;136names.emplace_back(GetNetworkName(network));137}138if (append_unroutable) {139names.emplace_back(GetNetworkName(NET_UNROUTABLE));140}141return names;142}144static std::vector<CNetAddr> LookupIntern(const std::string& name, unsigned int nMaxSolutions, bool fAllowLookup, DNSLookupFn dns_lookup_function)145{146if (ContainsNUL(name)) return {};147{148CNetAddr addr;149// From our perspective, onion addresses are not hostnames but rather150// direct encodings of CNetAddr much like IPv4 dotted-decimal notation151// or IPv6 colon-separated hextet notation. Since we can't use152// getaddrinfo to decode them and it wouldn't make sense to resolve153// them, we return a network address representing it instead. See154// CNetAddr::SetSpecial(const std::string&) for more details.155if (addr.SetSpecial(name)) return {addr};156}158std::vector<CNetAddr> addresses;160for (const CNetAddr& resolved : dns_lookup_function(name, fAllowLookup)) {161if (nMaxSolutions > 0 && addresses.size() >= nMaxSolutions) {162break;163}164/* Never allow resolving to an internal address. Consider any such result invalid */165if (!resolved.IsInternal()) {166addresses.push_back(resolved);167}168}170return addresses;171}173std::vector<CNetAddr> LookupHost(const std::string& name, unsigned int nMaxSolutions, bool fAllowLookup, DNSLookupFn dns_lookup_function)174{175if (ContainsNUL(name)) return {};176std::string strHost = name;177if (strHost.empty()) return {};178if (strHost.front() == '[' && strHost.back() == ']') {179strHost = strHost.substr(1, strHost.size() - 2);180}182return LookupIntern(strHost, nMaxSolutions, fAllowLookup, dns_lookup_function);183}185std::optional<CNetAddr> LookupHost(const std::string& name, bool fAllowLookup, DNSLookupFn dns_lookup_function)186{187const std::vector<CNetAddr> addresses{LookupHost(name, 1, fAllowLookup, dns_lookup_function)};188return addresses.empty() ? std::nullopt : std::make_optional(addresses.front());189}191std::vector<CService> Lookup(const std::string& name, uint16_t portDefault, bool fAllowLookup, unsigned int nMaxSolutions, DNSLookupFn dns_lookup_function)192{193if (name.empty() || ContainsNUL(name)) {194return {};195}196uint16_t port{portDefault};197std::string hostname;198SplitHostPort(name, port, hostname);200const std::vector<CNetAddr> addresses{LookupIntern(hostname, nMaxSolutions, fAllowLookup, dns_lookup_function)};201if (addresses.empty()) return {};202std::vector<CService> services;203services.reserve(addresses.size());204for (const auto& addr : addresses)205services.emplace_back(addr, port);206return services;207}209std::optional<CService> Lookup(const std::string& name, uint16_t portDefault, bool fAllowLookup, DNSLookupFn dns_lookup_function)210{211const std::vector<CService> services{Lookup(name, portDefault, fAllowLookup, 1, dns_lookup_function)};213return services.empty() ? std::nullopt : std::make_optional(services.front());214}216CService LookupNumeric(const std::string& name, uint16_t portDefault, DNSLookupFn dns_lookup_function)217{218if (ContainsNUL(name)) {219return {};220}221// "1.2:345" will fail to resolve the ip, but will still set the port.222// If the ip fails to resolve, re-init the result.223return Lookup(name, portDefault, /*fAllowLookup=*/false, dns_lookup_function).value_or(CService{});224}226bool IsUnixSocketPath(const std::string& name)227{228#ifdef HAVE_SOCKADDR_UN229if (!name.starts_with(ADDR_PREFIX_UNIX)) return false;231// Split off "unix:" prefix232std::string str{name.substr(ADDR_PREFIX_UNIX.length())};234// Path size limit is platform-dependent235// see https://manpages.ubuntu.com/manpages/xenial/en/man7/unix.7.html236if (str.size() + 1 > sizeof(((sockaddr_un*)nullptr)->sun_path)) return false;238return true;239#else240return false;241#endif242}244/** SOCKS version */245enum SOCKSVersion: uint8_t {246SOCKS4 = 0x04,247SOCKS5 = 0x05248};250/** Values defined for METHOD in RFC1928 */