LCOV - code coverage report
Current view: top level - src - netaddress.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 506 556 91.0 %
Date: 2026-06-25 07:23:43 Functions: 83 88 94.3 %

          Line data    Source code
       1             : // Copyright (c) 2009-2010 Satoshi Nakamoto
       2             : // Copyright (c) 2009-2021 The Bitcoin Core developers
       3             : // Distributed under the MIT software license, see the accompanying
       4             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       5             : 
       6             : #include <netaddress.h>
       7             : #include <netbase.h>
       8             : #include <crypto/common.h>
       9             : #include <crypto/sha3.h>
      10             : #include <hash.h>
      11             : #include <prevector.h>
      12             : #include <tinyformat.h>
      13             : #include <util/strencodings.h>
      14             : #include <util/string.h>
      15             : 
      16             : #include <algorithm>
      17             : #include <array>
      18             : #include <cstdint>
      19             : #include <ios>
      20             : #include <tuple>
      21             : 
      22      224784 : CNetAddr::BIP155Network CNetAddr::GetBIP155Network() const
      23             : {
      24      224784 :     switch (m_net) {
      25             :     case NET_IPV4:
      26      224055 :         return BIP155Network::IPV4;
      27             :     case NET_IPV6:
      28         250 :         return BIP155Network::IPV6;
      29             :     case NET_ONION:
      30         243 :         return BIP155Network::TORV3;
      31             :     case NET_I2P:
      32         236 :         return BIP155Network::I2P;
      33             :     case NET_CJDNS:
      34           0 :         return BIP155Network::CJDNS;
      35             :     case NET_INTERNAL:   // should have been handled before calling this function
      36             :     case NET_UNROUTABLE: // m_net is never and should not be set to NET_UNROUTABLE
      37             :     case NET_MAX:        // m_net is never and should not be set to NET_MAX
      38           0 :         assert(false);
      39             :     } // no default case, so the compiler can warn about missing cases
      40             : 
      41           0 :     assert(false);
      42      224784 : }
      43             : 
      44       84874 : bool CNetAddr::SetNetFromBIP155Network(uint8_t possible_bip155_net, size_t address_size)
      45             : {
      46       84874 :     switch (possible_bip155_net) {
      47             :     case BIP155Network::IPV4:
      48       83895 :         if (address_size == ADDR_IPV4_SIZE) {
      49       83894 :             m_net = NET_IPV4;
      50       83894 :             return true;
      51             :         }
      52           5 :         throw std::ios_base::failure(
      53           1 :             strprintf("BIP155 IPv4 address with length %u (should be %u)", address_size,
      54             :                       ADDR_IPV4_SIZE));
      55             :     case BIP155Network::IPV6:
      56         319 :         if (address_size == ADDR_IPV6_SIZE) {
      57         318 :             m_net = NET_IPV6;
      58         318 :             return true;
      59             :         }
      60           1 :         throw std::ios_base::failure(
      61           1 :             strprintf("BIP155 IPv6 address with length %u (should be %u)", address_size,
      62             :                       ADDR_IPV6_SIZE));
      63             :     case BIP155Network::TORV3:
      64         328 :         if (address_size == ADDR_TORV3_SIZE) {
      65         327 :             m_net = NET_ONION;
      66         327 :             return true;
      67             :         }
      68           1 :         throw std::ios_base::failure(
      69           1 :             strprintf("BIP155 TORv3 address with length %u (should be %u)", address_size,
      70             :                       ADDR_TORV3_SIZE));
      71             :     case BIP155Network::I2P:
      72         324 :         if (address_size == ADDR_I2P_SIZE) {
      73         323 :             m_net = NET_I2P;
      74         323 :             return true;
      75             :         }
      76           1 :         throw std::ios_base::failure(
      77           1 :             strprintf("BIP155 I2P address with length %u (should be %u)", address_size,
      78             :                       ADDR_I2P_SIZE));
      79             :     case BIP155Network::CJDNS:
      80           3 :         if (address_size == ADDR_CJDNS_SIZE) {
      81           2 :             m_net = NET_CJDNS;
      82           2 :             return true;
      83             :         }
      84           1 :         throw std::ios_base::failure(
      85           1 :             strprintf("BIP155 CJDNS address with length %u (should be %u)", address_size,
      86             :                       ADDR_CJDNS_SIZE));
      87             :     }
      88             : 
      89             :     // Don't throw on addresses with unknown network ids (maybe from the future).
      90             :     // Instead silently drop them and have the unserialization code consume
      91             :     // subsequent ones which may be known to us.
      92           5 :     return false;
      93       84874 : }
      94             : 
      95             : bool fAllowPrivateNet = DEFAULT_ALLOWPRIVATENET;
      96             : 
      97             : /**
      98             :  * Construct an unspecified IPv6 network address (::/128).
      99             :  *
     100             :  * @note This address is considered invalid by CNetAddr::IsValid()
     101             :  */
     102     7338466 : CNetAddr::CNetAddr() = default;
     103             : 
     104           3 : void CNetAddr::SetIP(const CNetAddr& ipIn)
     105             : {
     106             :     // Size check.
     107           3 :     switch (ipIn.m_net) {
     108             :     case NET_IPV4:
     109           2 :         assert(ipIn.m_addr.size() == ADDR_IPV4_SIZE);
     110           2 :         break;
     111             :     case NET_IPV6:
     112           1 :         assert(ipIn.m_addr.size() == ADDR_IPV6_SIZE);
     113           1 :         break;
     114             :     case NET_ONION:
     115           0 :         assert(ipIn.m_addr.size() == ADDR_TORV3_SIZE);
     116           0 :         break;
     117             :     case NET_I2P:
     118           0 :         assert(ipIn.m_addr.size() == ADDR_I2P_SIZE);
     119           0 :         break;
     120             :     case NET_CJDNS:
     121           0 :         assert(ipIn.m_addr.size() == ADDR_CJDNS_SIZE);
     122           0 :         break;
     123             :     case NET_INTERNAL:
     124           0 :         assert(ipIn.m_addr.size() == ADDR_INTERNAL_SIZE);
     125           0 :         break;
     126             :     case NET_UNROUTABLE:
     127             :     case NET_MAX:
     128           0 :         assert(false);
     129             :     } // no default case, so the compiler can warn about missing cases
     130             : 
     131           3 :     m_net = ipIn.m_net;
     132           3 :     m_addr = ipIn.m_addr;
     133           3 : }
     134             : 
     135       70573 : void CNetAddr::SetLegacyIPv6(Span<const uint8_t> ipv6)
     136             : {
     137       70573 :     assert(ipv6.size() == ADDR_IPV6_SIZE);
     138             : 
     139       70573 :     size_t skip{0};
     140             : 
     141       70573 :     if (HasPrefix(ipv6, IPV4_IN_IPV6_PREFIX)) {
     142             :         // IPv4-in-IPv6
     143       56012 :         m_net = NET_IPV4;
     144       56012 :         skip = sizeof(IPV4_IN_IPV6_PREFIX);
     145       70573 :     } else if (HasPrefix(ipv6, TORV2_IN_IPV6_PREFIX)) {
     146             :         // TORv2-in-IPv6 (unsupported). Unserialize as !IsValid(), thus ignoring them.
     147             :         // Mimic a default-constructed CNetAddr object which is !IsValid() and thus
     148             :         // will not be gossiped, but continue reading next addresses from the stream.
     149           0 :         m_net = NET_IPV6;
     150           0 :         m_addr.assign(ADDR_IPV6_SIZE, 0x0);
     151           0 :         return;
     152       14561 :     } else if (HasPrefix(ipv6, INTERNAL_IN_IPV6_PREFIX)) {
     153             :         // Internal-in-IPv6
     154           1 :         m_net = NET_INTERNAL;
     155           1 :         skip = sizeof(INTERNAL_IN_IPV6_PREFIX);
     156           1 :     } else {
     157             :         // IPv6
     158       14560 :         m_net = NET_IPV6;
     159             :     }
     160             : 
     161       70573 :     m_addr.assign(ipv6.begin() + skip, ipv6.end());
     162       70573 : }
     163             : 
     164             : /**
     165             :  * Create an "internal" address that represents a name or FQDN. AddrMan uses
     166             :  * these fake addresses to keep track of which DNS seeds were used.
     167             :  * @returns Whether or not the operation was successful.
     168             :  * @see NET_INTERNAL, INTERNAL_IN_IPV6_PREFIX, CNetAddr::IsInternal(), CNetAddr::IsRFC4193()
     169             :  */
     170         225 : bool CNetAddr::SetInternal(const std::string &name)
     171             : {
     172         225 :     if (name.empty()) {
     173           0 :         return false;
     174             :     }
     175         225 :     m_net = NET_INTERNAL;
     176         225 :     unsigned char hash[32] = {};
     177         225 :     CSHA256().Write((const unsigned char*)name.data(), name.size()).Finalize(hash);
     178         225 :     m_addr.assign(hash, hash + ADDR_INTERNAL_SIZE);
     179         225 :     return true;
     180         225 : }
     181             : 
     182             : namespace torv3 {
     183             : // https://gitweb.torproject.org/torspec.git/tree/rend-spec-v3.txt?id=7116c9cdaba248aae07a3f1d0e15d9dd102f62c5#n2175
     184             : static constexpr size_t CHECKSUM_LEN = 2;
     185             : static const unsigned char VERSION[] = {3};
     186             : static constexpr size_t TOTAL_LEN = ADDR_TORV3_SIZE + CHECKSUM_LEN + sizeof(VERSION);
     187             : 
     188         254 : static void Checksum(Span<const uint8_t> addr_pubkey, uint8_t (&checksum)[CHECKSUM_LEN])
     189             : {
     190             :     // TORv3 CHECKSUM = H(".onion checksum" | PUBKEY | VERSION)[:2]
     191             :     static const unsigned char prefix[] = ".onion checksum";
     192             :     static constexpr size_t prefix_len = 15;
     193             : 
     194         254 :     SHA3_256 hasher;
     195             : 
     196         254 :     hasher.Write(Span{prefix}.first(prefix_len));
     197         254 :     hasher.Write(addr_pubkey);
     198         254 :     hasher.Write(VERSION);
     199             : 
     200             :     uint8_t checksum_full[SHA3_256::OUTPUT_SIZE];
     201             : 
     202         254 :     hasher.Finalize(checksum_full);
     203             : 
     204         254 :     memcpy(checksum, checksum_full, sizeof(checksum));
     205         254 : }
     206             : 
     207             : }; // namespace torv3
     208             : 
     209     1627542 : bool CNetAddr::SetSpecial(const std::string& addr)
     210             : {
     211     1627542 :     if (!ContainsNoNUL(addr)) {
     212           2 :         return false;
     213             :     }
     214             : 
     215     1627540 :     if (SetTor(addr)) {
     216          69 :         return true;
     217             :     }
     218             : 
     219     1627471 :     if (SetI2P(addr)) {
     220          43 :         return true;
     221             :     }
     222             : 
     223     1627428 :     return false;
     224     1627542 : }
     225             : 
     226     1627539 : bool CNetAddr::SetTor(const std::string& addr)
     227             : {
     228             :     static const char* suffix{".onion"};
     229             :     static constexpr size_t suffix_len{6};
     230             : 
     231     1627539 :     if (addr.size() <= suffix_len || addr.substr(addr.size() - suffix_len) != suffix) {
     232     1627463 :         return false;
     233             :     }
     234             : 
     235          76 :     auto input = DecodeBase32(std::string_view{addr}.substr(0, addr.size() - suffix_len));
     236             : 
     237          76 :     if (!input) {
     238           1 :         return false;
     239             :     }
     240             : 
     241          75 :     if (input->size() == torv3::TOTAL_LEN) {
     242          71 :         Span<const uint8_t> input_pubkey{input->data(), ADDR_TORV3_SIZE};
     243          71 :         Span<const uint8_t> input_checksum{input->data() + ADDR_TORV3_SIZE, torv3::CHECKSUM_LEN};
     244          71 :         Span<const uint8_t> input_version{input->data() + ADDR_TORV3_SIZE + torv3::CHECKSUM_LEN, sizeof(torv3::VERSION)};
     245             : 
     246          71 :         if (input_version != torv3::VERSION) {
     247           1 :             return false;
     248             :         }
     249             : 
     250             :         uint8_t calculated_checksum[torv3::CHECKSUM_LEN];
     251          70 :         torv3::Checksum(input_pubkey, calculated_checksum);
     252             : 
     253          70 :         if (input_checksum != calculated_checksum) {
     254           1 :             return false;
     255             :         }
     256             : 
     257          69 :         m_net = NET_ONION;
     258          69 :         m_addr.assign(input_pubkey.begin(), input_pubkey.end());
     259          69 :         return true;
     260             :     }
     261             : 
     262           4 :     return false;
     263     1627539 : }
     264             : 
     265     1627470 : bool CNetAddr::SetI2P(const std::string& addr)
     266             : {
     267             :     // I2P addresses that we support consist of 52 base32 characters + ".b32.i2p".
     268             :     static constexpr size_t b32_len{52};
     269             :     static const char* suffix{".b32.i2p"};
     270             :     static constexpr size_t suffix_len{8};
     271             : 
     272     1627470 :     if (addr.size() != b32_len + suffix_len || ToLower(addr.substr(b32_len)) != suffix) {
     273     1627426 :         return false;
     274             :     }
     275             : 
     276             :     // Remove the ".b32.i2p" suffix and pad to a multiple of 8 chars, so DecodeBase32()
     277             :     // can decode it.
     278          44 :     const std::string b32_padded = addr.substr(0, b32_len) + "====";
     279             : 
     280          44 :     auto address_bytes = DecodeBase32(b32_padded);
     281             : 
     282          44 :     if (!address_bytes || address_bytes->size() != ADDR_I2P_SIZE) {
     283           1 :         return false;
     284             :     }
     285             : 
     286          43 :     m_net = NET_I2P;
     287          43 :     m_addr.assign(address_bytes->begin(), address_bytes->end());
     288             : 
     289          43 :     return true;
     290     1627470 : }
     291             : 
     292     3258541 : CNetAddr::CNetAddr(const struct in_addr& ipv4Addr)
     293     1618821 : {
     294             :     m_net = NET_IPV4;
     295             :     const uint8_t* ptr = reinterpret_cast<const uint8_t*>(&ipv4Addr);
     296             :     m_addr.assign(ptr, ptr + ADDR_IPV4_SIZE);
     297     1618821 : }
     298             : 
     299       13351 : CNetAddr::CNetAddr(const struct in6_addr& ipv6Addr, const uint32_t scope)
     300        6670 : {
     301             :     SetLegacyIPv6({reinterpret_cast<const uint8_t*>(&ipv6Addr), sizeof(ipv6Addr)});
     302             :     m_scope_id = scope;
     303        6670 : }
     304             : 
     305        6046 : bool CNetAddr::IsBindAny() const
     306             : {
     307        6046 :     if (!IsIPv4() && !IsIPv6()) {
     308           3 :         return false;
     309             :     }
     310       57359 :     return std::all_of(m_addr.begin(), m_addr.end(), [](uint8_t b) { return b == 0; });
     311        6046 : }
     312             : 
     313     1960015 : bool CNetAddr::IsRFC1918() const
     314             : {
     315     3916070 :     return IsIPv4() && (
     316     1956053 :         m_addr[0] == 10 ||
     317     3908992 :         (m_addr[0] == 192 && m_addr[1] == 168) ||
     318     1954496 :         (m_addr[0] == 172 && m_addr[1] >= 16 && m_addr[1] <= 31));
     319             : }
     320             : 
     321     1958458 : bool CNetAddr::IsRFC2544() const
     322             : {
     323     1958730 :     return IsIPv4() && m_addr[0] == 198 && (m_addr[1] == 18 || m_addr[1] == 19);
     324             : }
     325             : 
     326     1958458 : bool CNetAddr::IsRFC3927() const
     327             : {
     328     1958458 :     return IsIPv4() && HasPrefix(m_addr, std::array<uint8_t, 2>{169, 254});
     329             : }
     330             : 
     331     1958387 : bool CNetAddr::IsRFC6598() const
     332             : {
     333     1958387 :     return IsIPv4() && m_addr[0] == 100 && m_addr[1] >= 64 && m_addr[1] <= 127;
     334             : }
     335             : 
     336     1958380 : bool CNetAddr::IsRFC5737() const
     337             : {
     338     3912864 :     return IsIPv4() && (HasPrefix(m_addr, std::array<uint8_t, 3>{192, 0, 2}) ||
     339     1954484 :                         HasPrefix(m_addr, std::array<uint8_t, 3>{198, 51, 100}) ||
     340     1954484 :                         HasPrefix(m_addr, std::array<uint8_t, 3>{203, 0, 113}));
     341             : }
     342             : 
     343     3318887 : bool CNetAddr::IsRFC3849() const
     344             : {
     345     3318887 :     return IsIPv6() && HasPrefix(m_addr, std::array<uint8_t, 4>{0x20, 0x01, 0x0D, 0xB8});
     346             : }
     347             : 
     348        1595 : bool CNetAddr::IsRFC3964() const
     349             : {
     350        1595 :     return IsIPv6() && HasPrefix(m_addr, std::array<uint8_t, 2>{0x20, 0x02});
     351             : }
     352             : 
     353        1594 : bool CNetAddr::IsRFC6052() const
     354             : {
     355        3056 :     return IsIPv6() &&
     356        1462 :            HasPrefix(m_addr, std::array<uint8_t, 12>{0x00, 0x64, 0xFF, 0x9B, 0x00, 0x00,
     357             :                                                      0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
     358             : }
     359             : 
     360        1615 : bool CNetAddr::IsRFC4380() const
     361             : {
     362        1615 :     return IsIPv6() && HasPrefix(m_addr, std::array<uint8_t, 4>{0x20, 0x01, 0x00, 0x00});
     363             : }
     364             : 
     365     1958453 : bool CNetAddr::IsRFC4862() const
     366             : {
     367     1958453 :     return IsIPv6() && HasPrefix(m_addr, std::array<uint8_t, 8>{0xFE, 0x80, 0x00, 0x00,
     368             :                                                                 0x00, 0x00, 0x00, 0x00});
     369             : }
     370             : 
     371     1958383 : bool CNetAddr::IsRFC4193() const
     372             : {
     373     1958383 :     return IsIPv6() && (m_addr[0] & 0xFE) == 0xFC;
     374             : }
     375             : 
     376        1595 : bool CNetAddr::IsRFC6145() const
     377             : {
     378        3058 :     return IsIPv6() &&
     379        1463 :            HasPrefix(m_addr, std::array<uint8_t, 12>{0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     380             :                                                      0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00});
     381             : }
     382             : 
     383     1958367 : bool CNetAddr::IsRFC4843() const
     384             : {
     385     1958410 :     return IsIPv6() && HasPrefix(m_addr, std::array<uint8_t, 3>{0x20, 0x01, 0x00}) &&
     386          43 :            (m_addr[3] & 0xF0) == 0x10;
     387             : }
     388             : 
     389     1958367 : bool CNetAddr::IsRFC7343() const
     390             : {
     391     1958410 :     return IsIPv6() && HasPrefix(m_addr, std::array<uint8_t, 3>{0x20, 0x01, 0x00}) &&
     392          43 :            (m_addr[3] & 0xF0) == 0x20;
     393             : }
     394             : 
     395         460 : bool CNetAddr::IsHeNet() const
     396             : {
     397         460 :     return IsIPv6() && HasPrefix(m_addr, std::array<uint8_t, 4>{0x20, 0x01, 0x04, 0x70});
     398             : }
     399             : 
     400     2189935 : bool CNetAddr::IsLocal() const
     401             : {
     402             :     // IPv4 loopback (127.0.0.0/8 or 0.0.0.0/8)
     403     2189935 :     if (IsIPv4() && (m_addr[0] == 127 || m_addr[0] == 0)) {
     404      260535 :         return true;
     405             :     }
     406             : 
     407             :     // IPv6 loopback (::1/128)
     408             :     static const unsigned char pchLocal[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
     409     1929400 :     if (IsIPv6() && memcmp(m_addr.data(), pchLocal, sizeof(pchLocal)) == 0) {
     410           2 :         return true;
     411             :     }
     412             : 
     413     1929398 :     return false;
     414     2189935 : }
     415             : 
     416             : /**
     417             :  * @returns Whether or not this network address is a valid address that @a could
     418             :  *          be used to refer to an actual host.
     419             :  *
     420             :  * @note A valid address may or may not be publicly routable on the global
     421             :  *       internet. As in, the set of valid addresses is a superset of the set of
     422             :  *       publicly routable addresses.
     423             :  *
     424             :  * @see CNetAddr::IsRoutable()
     425             :  */
     426     3870742 : bool CNetAddr::IsValid() const
     427             : {
     428             :     // unspecified IPv6 address (::/128)
     429     3870742 :     unsigned char ipNone6[16] = {};
     430     3870742 :     if (IsIPv6() && memcmp(m_addr.data(), ipNone6, sizeof(ipNone6)) == 0) {
     431      551853 :         return false;
     432             :     }
     433             : 
     434     3318889 :     if (IsCJDNS() && !HasCJDNSPrefix()) {
     435           1 :         return false;
     436             :     }
     437             : 
     438             :     // documentation IPv6 address
     439     3318888 :     if (IsRFC3849())
     440           0 :         return false;
     441             : 
     442     3318888 :     if (IsInternal())
     443           1 :         return false;
     444             : 
     445     3318887 :     if (IsIPv4()) {
     446     3312602 :         const uint32_t addr = ReadBE32(m_addr.data());
     447     3312602 :         if (addr == INADDR_ANY || addr == INADDR_NONE) {
     448        1170 :             return false;
     449             :         }
     450     3311432 :     }
     451             : 
     452     3317717 :     return true;
     453     3870742 : }
     454             : 
     455             : /**
     456             :  * @returns Whether or not this network address is publicly routable on the
     457             :  *          global internet.
     458             :  *
     459             :  * @note A routable address is always valid. As in, the set of routable addresses
     460             :  *       is a subset of the set of valid addresses.
     461             :  *
     462             :  * @see CNetAddr::IsValid()
     463             :  */
     464     2204668 : bool CNetAddr::IsRoutable() const
     465             : {
     466     2204668 :     if (!IsValid())
     467      244648 :         return false;
     468     1960020 :     if (!fAllowPrivateNet && IsRFC1918())
     469        1558 :         return false;
     470     1958462 :     return !(IsRFC2544() || IsRFC3927() || IsRFC4862() || IsRFC6598() || IsRFC5737() || IsRFC4193() || IsRFC4843() || IsRFC7343() || IsLocal() || IsInternal());
     471     2204662 : }
     472             : 
     473             : /**
     474             :  * @returns Whether or not this is a dummy address that represents a name.
     475             :  *
     476             :  * @see CNetAddr::SetInternal(const std::string &)
     477             :  */
     478     8271182 : bool CNetAddr::IsInternal() const
     479             : {
     480     8271182 :    return m_net == NET_INTERNAL;
     481             : }
     482             : 
     483      629275 : bool CNetAddr::IsAddrV1Compatible() const
     484             : {
     485      629275 :     switch (m_net) {
     486             :     case NET_IPV4:
     487             :     case NET_IPV6:
     488             :     case NET_INTERNAL:
     489      629011 :         return true;
     490             :     case NET_ONION:
     491             :     case NET_I2P:
     492             :     case NET_CJDNS:
     493         264 :         return false;
     494             :     case NET_UNROUTABLE: // m_net is never and should not be set to NET_UNROUTABLE
     495             :     case NET_MAX:        // m_net is never and should not be set to NET_MAX
     496           0 :         assert(false);
     497             :     } // no default case, so the compiler can warn about missing cases
     498             : 
     499           0 :     assert(false);
     500      629275 : }
     501             : 
     502      209293 : enum Network CNetAddr::GetNetwork() const
     503             : {
     504      209293 :     if (IsInternal())
     505           1 :         return NET_INTERNAL;
     506             : 
     507      209292 :     if (!IsRoutable())
     508       12115 :         return NET_UNROUTABLE;
     509             : 
     510      197177 :     return m_net;
     511      209293 : }
     512             : 
     513     1431454 : static std::string IPv4ToString(Span<const uint8_t> a)
     514             : {
     515     1431454 :     return strprintf("%u.%u.%u.%u", a[0], a[1], a[2], a[3]);
     516             : }
     517             : 
     518             : // Return an IPv6 address text representation with zero compression as described in RFC 5952
     519             : // ("A Recommendation for IPv6 Address Text Representation").
     520       12918 : static std::string IPv6ToString(Span<const uint8_t> a, uint32_t scope_id)
     521             : {
     522       12918 :     assert(a.size() == ADDR_IPV6_SIZE);
     523       12918 :     const std::array groups{
     524      103344 :         ReadBE16(&a[0]),
     525       12918 :         ReadBE16(&a[2]),
     526       12918 :         ReadBE16(&a[4]),
     527       12918 :         ReadBE16(&a[6]),
     528       12918 :         ReadBE16(&a[8]),
     529       12918 :         ReadBE16(&a[10]),
     530       12918 :         ReadBE16(&a[12]),
     531       12918 :         ReadBE16(&a[14]),
     532             :     };
     533             : 
     534             :     // The zero compression implementation is inspired by Rust's std::net::Ipv6Addr, see
     535             :     // https://github.com/rust-lang/rust/blob/cc4103089f40a163f6d143f06359cba7043da29b/library/std/src/net/ip.rs#L1635-L1683
     536       25836 :     struct ZeroSpan {
     537       25836 :         size_t start_index{0};
     538       25836 :         size_t len{0};
     539             :     };
     540             : 
     541             :     // Find longest sequence of consecutive all-zero fields. Use first zero sequence if two or more
     542             :     // zero sequences of equal length are found.
     543       12918 :     ZeroSpan longest, current;
     544      116262 :     for (size_t i{0}; i < groups.size(); ++i) {
     545      103344 :         if (groups[i] != 0) {
     546        8268 :             current = {i + 1, 0};
     547        8268 :             continue;
     548             :         }
     549       95076 :         current.len += 1;
     550       95076 :         if (current.len > longest.len) {
     551       95053 :             longest = current;
     552       95053 :         }
     553       95076 :     }
     554             : 
     555       12918 :     std::string r;
     556       12918 :     r.reserve(39);
     557      116262 :     for (size_t i{0}; i < groups.size(); ++i) {
     558             :         // Replace the longest sequence of consecutive all-zero fields with two colons ("::").
     559      103344 :         if (longest.len >= 2 && i >= longest.start_index && i < longest.start_index + longest.len) {
     560       95045 :             if (i == longest.start_index) {
     561       12375 :                 r += "::";
     562       12375 :             }
     563       95045 :             continue;
     564             :         }
     565        8299 :         r += strprintf("%s%x", ((!r.empty() && r.back() != ':') ? ":" : ""), groups[i]);
     566        8299 :     }
     567             : 
     568       12918 :     if (scope_id != 0) {
     569           1 :         r += strprintf("%%%u", scope_id);
     570           1 :     }
     571             : 
     572       12918 :     return r;
     573       12918 : }
     574             : 
     575         184 : std::string OnionToString(Span<const uint8_t> addr)
     576             : {
     577             :     uint8_t checksum[torv3::CHECKSUM_LEN];
     578         184 :     torv3::Checksum(addr, checksum);
     579             :     // TORv3 onion_address = base32(PUBKEY | CHECKSUM | VERSION) + ".onion"
     580         184 :     prevector<torv3::TOTAL_LEN, uint8_t> address{addr.begin(), addr.end()};
     581         184 :     address.insert(address.end(), checksum, checksum + torv3::CHECKSUM_LEN);
     582         184 :     address.insert(address.end(), torv3::VERSION, torv3::VERSION + sizeof(torv3::VERSION));
     583         184 :     return EncodeBase32(address) + ".onion";
     584         184 : }
     585             : 
     586     1444690 : std::string CNetAddr::ToStringAddr() const
     587             : {
     588     1444690 :     switch (m_net) {
     589             :     case NET_IPV4:
     590     1431454 :         return IPv4ToString(m_addr);
     591             :     case NET_IPV6: {
     592       12904 :         return IPv6ToString(m_addr, m_scope_id);
     593             :     }
     594             :     case NET_ONION:
     595         181 :         return OnionToString(m_addr);
     596             :     case NET_I2P:
     597         135 :         return EncodeBase32(m_addr, false /* don't pad with = */) + ".b32.i2p";
     598             :     case NET_CJDNS:
     599          14 :         return IPv6ToString(m_addr, 0);
     600             :     case NET_INTERNAL:
     601           2 :         return EncodeBase32(m_addr) + ".internal";
     602             :     case NET_UNROUTABLE: // m_net is never and should not be set to NET_UNROUTABLE
     603             :     case NET_MAX:        // m_net is never and should not be set to NET_MAX
     604           0 :         assert(false);
     605             :     } // no default case, so the compiler can warn about missing cases
     606             : 
     607           0 :     assert(false);
     608     1444690 : }
     609             : 
     610      804897 : bool operator==(const CNetAddr& a, const CNetAddr& b)
     611             : {
     612      804897 :     return a.m_net == b.m_net && a.m_addr == b.m_addr;
     613             : }
     614             : 
     615      379741 : bool operator<(const CNetAddr& a, const CNetAddr& b)
     616             : {
     617      379741 :     return std::tie(a.m_net, a.m_addr) < std::tie(b.m_net, b.m_addr);
     618             : }
     619             : 
     620             : /**
     621             :  * Try to get our IPv4 address.
     622             :  *
     623             :  * @param[out] pipv4Addr The in_addr struct to which to copy.
     624             :  *
     625             :  * @returns Whether or not the operation was successful, in particular, whether
     626             :  *          or not our address was an IPv4 address.
     627             :  *
     628             :  * @see CNetAddr::IsIPv4()
     629             :  */
     630       11642 : bool CNetAddr::GetInAddr(struct in_addr* pipv4Addr) const
     631             : {
     632       11642 :     if (!IsIPv4())
     633           0 :         return false;
     634       11642 :     assert(sizeof(*pipv4Addr) == m_addr.size());
     635       11642 :     memcpy(pipv4Addr, m_addr.data(), m_addr.size());
     636       11642 :     return true;
     637       11642 : }
     638             : 
     639             : /**
     640             :  * Try to get our IPv6 (or CJDNS) address.
     641             :  *
     642             :  * @param[out] pipv6Addr The in6_addr struct to which to copy.
     643             :  *
     644             :  * @returns Whether or not the operation was successful, in particular, whether
     645             :  *          or not our address was an IPv6 address.
     646             :  *
     647             :  * @see CNetAddr::IsIPv6()
     648             :  */
     649          28 : bool CNetAddr::GetIn6Addr(struct in6_addr* pipv6Addr) const
     650             : {
     651          28 :     if (!IsIPv6() && !IsCJDNS()) {
     652           0 :         return false;
     653             :     }
     654          28 :     assert(sizeof(*pipv6Addr) == m_addr.size());
     655          28 :     memcpy(pipv6Addr, m_addr.data(), m_addr.size());
     656          28 :     return true;
     657          28 : }
     658             : 
     659      725715 : bool CNetAddr::HasLinkedIPv4() const
     660             : {
     661     1451430 :     return IsRoutable() && (IsIPv4() || IsRFC6145() || IsRFC6052() || IsRFC3964() || IsRFC4380());
     662             : }
     663             : 
     664      145294 : uint32_t CNetAddr::GetLinkedIPv4() const
     665             : {
     666      145294 :     if (IsIPv4()) {
     667      145290 :         return ReadBE32(m_addr.data());
     668           4 :     } else if (IsRFC6052() || IsRFC6145()) {
     669             :         // mapped IPv4, SIIT translated IPv4: the IPv4 address is the last 4 bytes of the address
     670           2 :         return ReadBE32(Span{m_addr}.last(ADDR_IPV4_SIZE).data());
     671           2 :     } else if (IsRFC3964()) {
     672             :         // 6to4 tunneled IPv4: the IPv4 address is in bytes 2-6
     673           1 :         return ReadBE32(Span{m_addr}.subspan(2, ADDR_IPV4_SIZE).data());
     674           1 :     } else if (IsRFC4380()) {
     675             :         // Teredo tunneled IPv4: the IPv4 address is in the last 4 bytes of the address, but bitflipped
     676           1 :         return ~ReadBE32(Span{m_addr}.last(ADDR_IPV4_SIZE).data());
     677             :     }
     678           0 :     assert(false);
     679      145294 : }
     680             : 
     681      954247 : Network CNetAddr::GetNetClass() const
     682             : {
     683             :     // Make sure that if we return NET_IPV6, then IsIPv6() is true. The callers expect that.
     684             : 
     685             :     // Check for "internal" first because such addresses are also !IsRoutable()
     686             :     // and we don't want to return NET_UNROUTABLE in that case.
     687      954247 :     if (IsInternal()) {
     688           2 :         return NET_INTERNAL;
     689             :     }
     690      954245 :     if (!IsRoutable()) {
     691      374310 :         return NET_UNROUTABLE;
     692             :     }
     693      579935 :     if (HasLinkedIPv4()) {
     694      578890 :         return NET_IPV4;
     695             :     }
     696        1045 :     return m_net;
     697      954247 : }
     698             : 
     699      488644 : std::vector<unsigned char> CNetAddr::GetAddrBytes() const
     700             : {
     701      488644 :     if (IsAddrV1Compatible()) {
     702             :         uint8_t serialized[V1_SERIALIZATION_SIZE];
     703      488577 :         SerializeV1Array(serialized);
     704      488577 :         return {std::begin(serialized), std::end(serialized)};
     705             :     }
     706          67 :     return std::vector<unsigned char>(m_addr.begin(), m_addr.end());
     707      488644 : }
     708             : 
     709             : // private extensions to enum Network, only returned by GetExtNetwork,
     710             : // and only used in GetReachabilityFrom
     711             : static const int NET_TEREDO = NET_MAX;
     712          68 : int static GetExtNetwork(const CNetAddr& addr)
     713             : {
     714          68 :     if (addr.IsRFC4380())
     715          11 :         return NET_TEREDO;
     716          57 :     return addr.GetNetwork();
     717          68 : }
     718             : 
     719             : /** Calculates a metric for how reachable (*this) is from a given partner */
     720          35 : int CNetAddr::GetReachabilityFrom(const CNetAddr& paddrPartner) const
     721             : {
     722             :     enum Reachability {
     723             :         REACH_UNREACHABLE,
     724             :         REACH_DEFAULT,
     725             :         REACH_TEREDO,
     726             :         REACH_IPV6_WEAK,
     727             :         REACH_IPV4,
     728             :         REACH_IPV6_STRONG,
     729             :         REACH_PRIVATE
     730             :     };
     731             : 
     732          35 :     if (!IsRoutable() || IsInternal())
     733           1 :         return REACH_UNREACHABLE;
     734             : 
     735          34 :     int ourNet = GetExtNetwork(*this);
     736          34 :     int theirNet = GetExtNetwork(paddrPartner);
     737          34 :     bool fTunnel = IsRFC3964() || IsRFC6052() || IsRFC6145();
     738             : 
     739          34 :     switch(theirNet) {
     740             :     case NET_IPV4:
     741           6 :         switch(ourNet) {
     742           4 :         default:       return REACH_DEFAULT;
     743           2 :         case NET_IPV4: return REACH_IPV4;
     744             :         }
     745             :     case NET_IPV6:
     746          12 :         switch(ourNet) {
     747           2 :         default:         return REACH_DEFAULT;
     748           2 :         case NET_TEREDO: return REACH_TEREDO;
     749           4 :         case NET_IPV4:   return REACH_IPV4;
     750           4 :         case NET_IPV6:   return fTunnel ? REACH_IPV6_WEAK : REACH_IPV6_STRONG; // only prefer giving our IPv6 address if it's not tunnelled
     751             :         }
     752             :     case NET_ONION:
     753           2 :         switch(ourNet) {
     754           0 :         default:         return REACH_DEFAULT;
     755           0 :         case NET_IPV4:   return REACH_IPV4; // Tor users can connect to IPv4 as well
     756           2 :         case NET_ONION:    return REACH_PRIVATE;
     757             :         }
     758             :     case NET_I2P:
     759           2 :         switch (ourNet) {
     760           2 :         case NET_I2P: return REACH_PRIVATE;
     761           0 :         default: return REACH_DEFAULT;
     762             :         }
     763             :     case NET_CJDNS:
     764           6 :         switch (ourNet) {
     765           1 :         case NET_CJDNS: return REACH_PRIVATE;
     766           5 :         default: return REACH_DEFAULT;
     767             :         }
     768             :     case NET_TEREDO:
     769           6 :         switch(ourNet) {
     770           1 :         default:          return REACH_DEFAULT;
     771           1 :         case NET_TEREDO:  return REACH_TEREDO;
     772           2 :         case NET_IPV6:    return REACH_IPV6_WEAK;
     773           2 :         case NET_IPV4:    return REACH_IPV4;
     774             :         }
     775           0 :     case NET_UNROUTABLE:
     776             :     default:
     777           0 :         switch(ourNet) {
     778           0 :         default:          return REACH_DEFAULT;
     779           0 :         case NET_TEREDO:  return REACH_TEREDO;
     780           0 :         case NET_IPV6:    return REACH_IPV6_WEAK;
     781           0 :         case NET_IPV4:    return REACH_IPV4;
     782           0 :         case NET_ONION:     return REACH_PRIVATE; // either from Tor, or don't care about our address
     783             :         }
     784             :     }
     785          35 : }
     786             : 
     787     7094902 : CService::CService() : port(0)
     788     3271610 : {
     789     7094902 : }
     790             : 
     791     3227185 : CService::CService(const CNetAddr& cip, uint16_t portIn) : CNetAddr(cip), port(portIn)
     792     1613594 : {
     793     3227185 : }
     794             : 
     795        5680 : CService::CService(const struct in_addr& ipv4Addr, uint16_t portIn) : CNetAddr(ipv4Addr), port(portIn)
     796        2840 : {
     797        5680 : }
     798             : 
     799          22 : CService::CService(const struct in6_addr& ipv6Addr, uint16_t portIn) : CNetAddr(ipv6Addr), port(portIn)
     800          11 : {
     801          22 : }
     802             : 
     803       36118 : CService::CService(const struct sockaddr_in& addr) : CNetAddr(addr.sin_addr), port(ntohs(addr.sin_port))
     804       18059 : {
     805       18059 :     assert(addr.sin_family == AF_INET);
     806       36118 : }
     807             : 
     808           0 : CService::CService(const struct sockaddr_in6 &addr) : CNetAddr(addr.sin6_addr, addr.sin6_scope_id), port(ntohs(addr.sin6_port))
     809           0 : {
     810           0 :    assert(addr.sin6_family == AF_INET6);
     811           0 : }
     812             : 
     813       18065 : bool CService::SetSockAddr(const struct sockaddr *paddr)
     814             : {
     815       18065 :     switch (paddr->sa_family) {
     816             :     case AF_INET:
     817       18059 :         *this = CService(*(const struct sockaddr_in*)paddr);
     818       18059 :         return true;
     819             :     case AF_INET6:
     820           0 :         *this = CService(*(const struct sockaddr_in6*)paddr);
     821           0 :         return true;
     822             :     default:
     823           6 :         return false;
     824             :     }
     825       18065 : }
     826             : 
     827       11662 : sa_family_t CService::GetSAFamily() const
     828             : {
     829       11662 :     switch (m_net) {
     830             :     case NET_IPV4:
     831       11634 :         return AF_INET;
     832             :     case NET_IPV6:
     833             :     case NET_CJDNS:
     834          28 :         return AF_INET6;
     835             :     default:
     836           0 :         return AF_UNSPEC;
     837             :     }
     838       11662 : }
     839             : 
     840      110967 : uint16_t CService::GetPort() const
     841             : {
     842      110967 :     return port;
     843             : }
     844             : 
     845      367174 : bool operator==(const CService& a, const CService& b)
     846             : {
     847      367174 :     return static_cast<CNetAddr>(a) == static_cast<CNetAddr>(b) && a.port == b.port;
     848           0 : }
     849             : 
     850      371832 : bool operator<(const CService& a, const CService& b)
     851             : {
     852      371832 :     return static_cast<CNetAddr>(a) < static_cast<CNetAddr>(b) || (static_cast<CNetAddr>(a) == static_cast<CNetAddr>(b) && a.port < b.port);
     853           0 : }
     854             : 
     855             : /**
     856             :  * Obtain the IPv4/6 socket address this represents.
     857             :  *
     858             :  * @param[out] paddr The obtained socket address.
     859             :  * @param[in,out] addrlen The size, in bytes, of the address structure pointed
     860             :  *                        to by paddr. The value that's pointed to by this
     861             :  *                        parameter might change after calling this function if
     862             :  *                        the size of the corresponding address structure
     863             :  *                        changed.
     864             :  *
     865             :  * @returns Whether or not the operation was successful.
     866             :  */
     867       11670 : bool CService::GetSockAddr(struct sockaddr* paddr, socklen_t *addrlen) const
     868             : {
     869       11670 :     if (IsIPv4()) {
     870       11642 :         if (*addrlen < (socklen_t)sizeof(struct sockaddr_in))
     871           0 :             return false;
     872       11642 :         *addrlen = sizeof(struct sockaddr_in);
     873       11642 :         struct sockaddr_in *paddrin = (struct sockaddr_in*)paddr;
     874       11642 :         memset(paddrin, 0, *addrlen);
     875       11642 :         if (!GetInAddr(&paddrin->sin_addr))
     876           0 :             return false;
     877       11642 :         paddrin->sin_family = AF_INET;
     878       11642 :         paddrin->sin_port = htons(port);
     879       11642 :         return true;
     880             :     }
     881          28 :     if (IsIPv6() || IsCJDNS()) {
     882          28 :         if (*addrlen < (socklen_t)sizeof(struct sockaddr_in6))
     883           0 :             return false;
     884          28 :         *addrlen = sizeof(struct sockaddr_in6);
     885          28 :         struct sockaddr_in6 *paddrin6 = (struct sockaddr_in6*)paddr;
     886          28 :         memset(paddrin6, 0, *addrlen);
     887          28 :         if (!GetIn6Addr(&paddrin6->sin6_addr))
     888           0 :             return false;
     889          28 :         paddrin6->sin6_scope_id = m_scope_id;
     890          28 :         paddrin6->sin6_family = AF_INET6;
     891          28 :         paddrin6->sin6_port = htons(port);
     892          28 :         return true;
     893             :     }
     894           0 :     return false;
     895       11670 : }
     896             : 
     897             : /**
     898             :  * @returns An identifier unique to this service's address and port number.
     899             :  */
     900      312823 : std::vector<unsigned char> CService::GetKey() const
     901             : {
     902      312823 :     auto key = GetAddrBytes();
     903      312823 :     key.push_back(port / 0x100); // most significant byte of our port
     904      312823 :     key.push_back(port & 0x0FF); // least significant byte of our port
     905      312823 :     return key;
     906      312823 : }
     907             : 
     908     1316603 : std::string CService::ToStringAddrPort() const
     909             : {
     910     1316603 :     const auto port_str = strprintf("%u", port);
     911             : 
     912     1316603 :     if (IsIPv4() || IsTor() || IsI2P() || IsInternal()) {
     913     1307025 :         return ToStringAddr() + ":" + port_str;
     914             :     } else {
     915        9578 :         return "[" + ToStringAddr() + "]:" + port_str;
     916             :     }
     917     1316603 : }
     918             : 
     919       15422 : CSubNet::CSubNet():
     920        7711 :     valid(false)
     921        7711 : {
     922        7711 :     memset(netmask, 0, sizeof(netmask));
     923       15422 : }
     924             : 
     925        3103 : CSubNet::CSubNet(const CNetAddr& addr, uint8_t mask) : CSubNet()
     926             : {
     927        3127 :     valid = (addr.IsIPv4() && mask <= ADDR_IPV4_SIZE * 8) ||
     928          24 :             (addr.IsIPv6() && mask <= ADDR_IPV6_SIZE * 8);
     929        3103 :     if (!valid) {
     930           7 :         return;
     931             :     }
     932             : 
     933        3096 :     assert(mask <= sizeof(netmask) * 8);
     934             : 
     935        3096 :     network = addr;
     936             : 
     937        3096 :     uint8_t n = mask;
     938       15684 :     for (size_t i = 0; i < network.m_addr.size(); ++i) {
     939       12588 :         const uint8_t bits = n < 8 ? n : 8;
     940       12588 :         netmask[i] = (uint8_t)((uint8_t)0xFF << (8 - bits)); // Set first bits.
     941       12588 :         network.m_addr[i] &= netmask[i]; // Normalize network according to netmask.
     942       12588 :         n -= bits;
     943       12588 :     }
     944        3103 : }
     945             : 
     946             : /**
     947             :  * @returns The number of 1-bits in the prefix of the specified subnet mask. If
     948             :  *          the specified subnet mask is not a valid one, -1.
     949             :  */
     950       52435 : static inline int NetmaskBits(uint8_t x)
     951             : {
     952       52435 :     switch(x) {
     953         108 :     case 0x00: return 0;
     954           8 :     case 0x80: return 1;
     955           8 :     case 0xc0: return 2;
     956          36 :     case 0xe0: return 3;
     957           8 :     case 0xf0: return 4;
     958           8 :     case 0xf8: return 5;
     959          11 :     case 0xfc: return 6;
     960           9 :     case 0xfe: return 7;
     961       52237 :     case 0xff: return 8;
     962           2 :     default: return -1;
     963             :     }
     964       52435 : }
     965             : 
     966          50 : CSubNet::CSubNet(const CNetAddr& addr, const CNetAddr& mask) : CSubNet()
     967             : {
     968          50 :     valid = (addr.IsIPv4() || addr.IsIPv6()) && addr.m_net == mask.m_net;
     969          50 :     if (!valid) {
     970           3 :         return;
     971             :     }
     972             :     // Check if `mask` contains 1-bits after 0-bits (which is an invalid netmask).
     973          47 :     bool zeros_found = false;
     974         281 :     for (auto b : mask.m_addr) {
     975         238 :         const int num_bits = NetmaskBits(b);
     976         238 :         if (num_bits == -1 || (zeros_found && num_bits != 0)) {
     977           4 :             valid = false;
     978           4 :             return;
     979             :         }
     980         234 :         if (num_bits < 8) {
     981         138 :             zeros_found = true;
     982         138 :         }
     983             :     }
     984             : 
     985          43 :     assert(mask.m_addr.size() <= sizeof(netmask));
     986             : 
     987          43 :     memcpy(netmask, mask.m_addr.data(), mask.m_addr.size());
     988             : 
     989          43 :     network = addr;
     990             : 
     991             :     // Normalize network according to netmask
     992         263 :     for (size_t x = 0; x < network.m_addr.size(); ++x) {
     993         220 :         network.m_addr[x] &= netmask[x];
     994         220 :     }
     995          50 : }
     996             : 
     997        3513 : CSubNet::CSubNet(const CNetAddr& addr) : CSubNet()
     998             : {
     999        3513 :     switch (addr.m_net) {
    1000             :     case NET_IPV4:
    1001             :     case NET_IPV6:
    1002        3494 :         valid = true;
    1003        3494 :         assert(addr.m_addr.size() <= sizeof(netmask));
    1004        3494 :         memset(netmask, 0xFF, addr.m_addr.size());
    1005        3494 :         break;
    1006             :     case NET_ONION:
    1007             :     case NET_I2P:
    1008             :     case NET_CJDNS:
    1009          19 :         valid = true;
    1010          19 :         break;
    1011             :     case NET_INTERNAL:
    1012             :     case NET_UNROUTABLE:
    1013             :     case NET_MAX:
    1014           0 :         return;
    1015             :     }
    1016             : 
    1017        3513 :     network = addr;
    1018        3513 : }
    1019             : 
    1020             : /**
    1021             :  * @returns True if this subnet is valid, the specified address is valid, and
    1022             :  *          the specified address belongs in this subnet.
    1023             :  */
    1024      500827 : bool CSubNet::Match(const CNetAddr &addr) const
    1025             : {
    1026      500827 :     if (!valid || !addr.IsValid() || network.m_net != addr.m_net)
    1027          19 :         return false;
    1028             : 
    1029      500808 :     switch (network.m_net) {
    1030             :     case NET_IPV4:
    1031             :     case NET_IPV6:
    1032      500805 :         break;
    1033             :     case NET_ONION:
    1034             :     case NET_I2P:
    1035             :     case NET_CJDNS:
    1036             :     case NET_INTERNAL:
    1037           3 :         return addr == network;
    1038             :     case NET_UNROUTABLE:
    1039             :     case NET_MAX:
    1040           0 :         return false;
    1041             :     }
    1042             : 
    1043      500805 :     assert(network.m_addr.size() == addr.m_addr.size());
    1044     2504000 :     for (size_t x = 0; x < addr.m_addr.size(); ++x) {
    1045     2003226 :         if ((addr.m_addr[x] & netmask[x]) != network.m_addr[x]) {
    1046          31 :             return false;
    1047             :         }
    1048     2003195 :     }
    1049      500774 :     return true;
    1050      500827 : }
    1051             : 
    1052        6299 : std::string CSubNet::ToString() const
    1053             : {
    1054        6299 :     std::string suffix;
    1055             : 
    1056        6299 :     switch (network.m_net) {
    1057             :     case NET_IPV4:
    1058             :     case NET_IPV6: {
    1059        6278 :         assert(network.m_addr.size() <= sizeof(netmask));
    1060             : 
    1061        6278 :         uint8_t cidr = 0;
    1062             : 
    1063       58475 :         for (size_t i = 0; i < network.m_addr.size(); ++i) {
    1064       55334 :             if (netmask[i] == 0x00) {
    1065        3137 :                 break;
    1066             :             }
    1067       52197 :             cidr += NetmaskBits(netmask[i]);
    1068       52197 :         }
    1069             : 
    1070        6278 :         suffix = strprintf("/%u", cidr);
    1071        6278 :         break;
    1072             :     }
    1073             :     case NET_ONION:
    1074             :     case NET_I2P:
    1075             :     case NET_CJDNS:
    1076             :     case NET_INTERNAL:
    1077             :     case NET_UNROUTABLE:
    1078             :     case NET_MAX:
    1079          21 :         break;
    1080             :     }
    1081             : 
    1082        6299 :     return network.ToStringAddr() + suffix;
    1083        6299 : }
    1084             : 
    1085        1346 : bool CSubNet::IsValid() const
    1086             : {
    1087        1346 :     return valid;
    1088             : }
    1089             : 
    1090           2 : bool operator==(const CSubNet& a, const CSubNet& b)
    1091             : {
    1092           2 :     return a.valid == b.valid && a.network == b.network && !memcmp(a.netmask, b.netmask, 16);
    1093             : }
    1094             : 
    1095         426 : bool operator<(const CSubNet& a, const CSubNet& b)
    1096             : {
    1097         426 :     return (a.network < b.network || (a.network == b.network && memcmp(a.netmask, b.netmask, 16) < 0));
    1098             : }

Generated by: LCOV version 1.16