Inside Bitcoin
Opening the selected file…
Inside Bitcoin
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.
751case NET_ONION:752switch(ourNet) {753default: return REACH_DEFAULT;754case NET_IPV4: return REACH_IPV4; // Tor users can connect to IPv4 as well755case NET_ONION: return REACH_PRIVATE;756}757case NET_I2P:758switch (ourNet) {759case NET_I2P: return REACH_PRIVATE;760default: return REACH_DEFAULT;761}762case NET_CJDNS:763switch (ourNet) {764case NET_CJDNS: return REACH_PRIVATE;765default: return REACH_DEFAULT;766}767case NET_TEREDO:768switch(ourNet) {769default: return REACH_DEFAULT;770case NET_TEREDO: return REACH_TEREDO;771case NET_IPV6: return REACH_IPV6_WEAK;772case NET_IPV4: return REACH_IPV4;773}774case NET_UNROUTABLE:775default:776switch(ourNet) {777default: return REACH_DEFAULT;778case NET_TEREDO: return REACH_TEREDO;779case NET_IPV6: return REACH_IPV6_WEAK;780case NET_IPV4: return REACH_IPV4;781case NET_ONION: return REACH_PRIVATE; // either from Tor, or don't care about our address782}783}784}786CService::CService() : port(0)787{788}790CService::CService(const CNetAddr& cip, uint16_t portIn) : CNetAddr(cip), port(portIn)791{792}794CService::CService(const struct in_addr& ipv4Addr, uint16_t portIn) : CNetAddr(ipv4Addr), port(portIn)795{796}798CService::CService(const struct in6_addr& ipv6Addr, uint16_t portIn) : CNetAddr(ipv6Addr), port(portIn)799{800}802CService::CService(const struct sockaddr_in& addr) : CNetAddr(addr.sin_addr), port(ntohs(addr.sin_port))803{804assert(addr.sin_family == AF_INET);805}807CService::CService(const struct sockaddr_in6 &addr) : CNetAddr(addr.sin6_addr, addr.sin6_scope_id), port(ntohs(addr.sin6_port))808{809assert(addr.sin6_family == AF_INET6);810}812bool CService::SetSockAddr(const struct sockaddr *paddr, socklen_t addrlen)813{814switch (paddr->sa_family) {815case AF_INET:816if (addrlen != sizeof(struct sockaddr_in)) return false;817*this = CService(*(const struct sockaddr_in*)paddr);818return true;819case AF_INET6:820if (addrlen != sizeof(struct sockaddr_in6)) return false;821*this = CService(*(const struct sockaddr_in6*)paddr);822return true;823default:824return false;825}826}828sa_family_t CService::GetSAFamily() const829{830switch (m_net) {831case NET_IPV4:832return AF_INET;833case NET_IPV6:834case NET_CJDNS:835return AF_INET6;836default:837return AF_UNSPEC;838}839}841uint16_t CService::GetPort() const842{843return port;844}846bool operator==(const CService& a, const CService& b)847{848return static_cast<CNetAddr>(a) == static_cast<CNetAddr>(b) && a.port == b.port;849}851bool operator<(const CService& a, const CService& b)852{853return static_cast<CNetAddr>(a) < static_cast<CNetAddr>(b) || (static_cast<CNetAddr>(a) == static_cast<CNetAddr>(b) && a.port < b.port);854}856/**857* Obtain the IPv4/6 socket address this represents.858*859* @param[out] paddr The obtained socket address.860* @param[in,out] addrlen The size, in bytes, of the address structure pointed861* to by paddr. The value that's pointed to by this862* parameter might change after calling this function if863* the size of the corresponding address structure864* changed.865*866* @returns Whether or not the operation was successful.867*/868bool CService::GetSockAddr(struct sockaddr* paddr, socklen_t *addrlen) const869{870if (IsIPv4()) {871if (*addrlen < (socklen_t)sizeof(struct sockaddr_in))872return false;873*addrlen = sizeof(struct sockaddr_in);874struct sockaddr_in *paddrin = (struct sockaddr_in*)paddr;875memset(paddrin, 0, *addrlen);876if (!GetInAddr(&paddrin->sin_addr))877return false;878paddrin->sin_family = AF_INET;879paddrin->sin_port = htons(port);880return true;881}882if (IsIPv6() || IsCJDNS()) {883if (*addrlen < (socklen_t)sizeof(struct sockaddr_in6))884return false;885*addrlen = sizeof(struct sockaddr_in6);886struct sockaddr_in6 *paddrin6 = (struct sockaddr_in6*)paddr;887memset(paddrin6, 0, *addrlen);888if (!GetIn6Addr(&paddrin6->sin6_addr))889return false;890paddrin6->sin6_scope_id = m_scope_id;891paddrin6->sin6_family = AF_INET6;892paddrin6->sin6_port = htons(port);893return true;894}895return false;896}898/**899* @returns An identifier unique to this service's address and port number.900*/901std::vector<unsigned char> CService::GetKey() const902{903auto key = GetAddrBytes();904key.push_back(port / 0x100); // most significant byte of our port905key.push_back(port & 0x0FF); // least significant byte of our port906return key;907}909std::string CService::ToStringAddrPort() const910{911const auto port_str = strprintf("%u", port);913if (IsIPv4() || IsTor() || IsI2P() || IsInternal()) {914return ToStringAddr() + ":" + port_str;915} else {916return "[" + ToStringAddr() + "]:" + port_str;917}918}920CSubNet::CSubNet():921valid(false)922{923memset(netmask, 0, sizeof(netmask));924}926CSubNet::CSubNet(const CNetAddr& addr, uint8_t mask) : CSubNet()927{928valid = (addr.IsIPv4() && mask <= ADDR_IPV4_SIZE * 8) ||929(addr.IsIPv6() && mask <= ADDR_IPV6_SIZE * 8);930if (!valid) {931return;932}934assert(mask <= sizeof(netmask) * 8);936network = addr;938uint8_t n = mask;939for (size_t i = 0; i < network.m_addr.size(); ++i) {940const uint8_t bits = n < 8 ? n : 8;941netmask[i] = (uint8_t)((uint8_t)0xFF << (8 - bits)); // Set first bits.942network.m_addr[i] &= netmask[i]; // Normalize network according to netmask.943n -= bits;944}945}947/**948* @returns The number of 1-bits in the prefix of the specified subnet mask. If949* the specified subnet mask is not a valid one, -1.950*/951static inline int NetmaskBits(uint8_t x)952{953switch(x) {954case 0x00: return 0;955case 0x80: return 1;956case 0xc0: return 2;957case 0xe0: return 3;958case 0xf0: return 4;959case 0xf8: return 5;960case 0xfc: return 6;961case 0xfe: return 7;962case 0xff: return 8;963default: return -1;964}965}967CSubNet::CSubNet(const CNetAddr& addr, const CNetAddr& mask) : CSubNet()968{969valid = (addr.IsIPv4() || addr.IsIPv6()) && addr.m_net == mask.m_net;970if (!valid) {971return;972}973// Check if `mask` contains 1-bits after 0-bits (which is an invalid netmask).974bool zeros_found = false;975for (auto b : mask.m_addr) {976const int num_bits = NetmaskBits(b);977if (num_bits == -1 || (zeros_found && num_bits != 0)) {978valid = false;979return;980}981if (num_bits < 8) {982zeros_found = true;983}984}986assert(mask.m_addr.size() <= sizeof(netmask));988memcpy(netmask, mask.m_addr.data(), mask.m_addr.size());990network = addr;992// Normalize network according to netmask993for (size_t x = 0; x < network.m_addr.size(); ++x) {994network.m_addr[x] &= netmask[x];995}996}998CSubNet::CSubNet(const CNetAddr& addr) : CSubNet()999{1000switch (addr.m_net) {