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