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