5
5
6
6
#include < netaddress.h>
7
7
8
+ #include < crypto/common.h>
9
+ #include < crypto/sha3.h>
8
10
#include < hash.h>
11
+ #include < prevector.h>
9
12
#include < tinyformat.h>
10
13
#include < util/asmap.h>
11
14
#include < util/strencodings.h>
@@ -29,7 +32,18 @@ CNetAddr::BIP155Network CNetAddr::GetBIP155Network() const
29
32
case NET_IPV6:
30
33
return BIP155Network::IPV6;
31
34
case NET_ONION:
32
- return BIP155Network::TORV2;
35
+ switch (m_addr.size ()) {
36
+ case ADDR_TORV2_SIZE:
37
+ return BIP155Network::TORV2;
38
+ case ADDR_TORV3_SIZE:
39
+ return BIP155Network::TORV3;
40
+ default :
41
+ assert (false );
42
+ }
43
+ case NET_I2P:
44
+ return BIP155Network::I2P;
45
+ case NET_CJDNS:
46
+ return BIP155Network::CJDNS;
33
47
case NET_INTERNAL: // should have been handled before calling this function
34
48
case NET_UNROUTABLE: // m_net is never and should not be set to NET_UNROUTABLE
35
49
case NET_MAX: // m_net is never and should not be set to NET_MAX
@@ -66,6 +80,30 @@ bool CNetAddr::SetNetFromBIP155Network(uint8_t possible_bip155_net, size_t addre
66
80
throw std::ios_base::failure (
67
81
strprintf (" BIP155 TORv2 address with length %u (should be %u)" , address_size,
68
82
ADDR_TORV2_SIZE));
83
+ case BIP155Network::TORV3:
84
+ if (address_size == ADDR_TORV3_SIZE) {
85
+ m_net = NET_ONION;
86
+ return true ;
87
+ }
88
+ throw std::ios_base::failure (
89
+ strprintf (" BIP155 TORv3 address with length %u (should be %u)" , address_size,
90
+ ADDR_TORV3_SIZE));
91
+ case BIP155Network::I2P:
92
+ if (address_size == ADDR_I2P_SIZE) {
93
+ m_net = NET_I2P;
94
+ return true ;
95
+ }
96
+ throw std::ios_base::failure (
97
+ strprintf (" BIP155 I2P address with length %u (should be %u)" , address_size,
98
+ ADDR_I2P_SIZE));
99
+ case BIP155Network::CJDNS:
100
+ if (address_size == ADDR_CJDNS_SIZE) {
101
+ m_net = NET_CJDNS;
102
+ return true ;
103
+ }
104
+ throw std::ios_base::failure (
105
+ strprintf (" BIP155 CJDNS address with length %u (should be %u)" , address_size,
106
+ ADDR_CJDNS_SIZE));
69
107
}
70
108
71
109
// Don't throw on addresses with unknown network ids (maybe from the future).
@@ -92,7 +130,13 @@ void CNetAddr::SetIP(const CNetAddr& ipIn)
92
130
assert (ipIn.m_addr .size () == ADDR_IPV6_SIZE);
93
131
break ;
94
132
case NET_ONION:
95
- assert (ipIn.m_addr .size () == ADDR_TORV2_SIZE);
133
+ assert (ipIn.m_addr .size () == ADDR_TORV2_SIZE || ipIn.m_addr .size () == ADDR_TORV3_SIZE);
134
+ break ;
135
+ case NET_I2P:
136
+ assert (ipIn.m_addr .size () == ADDR_I2P_SIZE);
137
+ break ;
138
+ case NET_CJDNS:
139
+ assert (ipIn.m_addr .size () == ADDR_CJDNS_SIZE);
96
140
break ;
97
141
case NET_INTERNAL:
98
142
assert (ipIn.m_addr .size () == ADDR_INTERNAL_SIZE);
@@ -150,24 +194,80 @@ bool CNetAddr::SetInternal(const std::string &name)
150
194
return true ;
151
195
}
152
196
197
+ namespace torv3 {
198
+ // https://gitweb.torproject.org/torspec.git/tree/rend-spec-v3.txt#n2135
199
+ static constexpr size_t CHECKSUM_LEN = 2 ;
200
+ static const unsigned char VERSION[] = {3 };
201
+ static constexpr size_t TOTAL_LEN = ADDR_TORV3_SIZE + CHECKSUM_LEN + sizeof (VERSION);
202
+
203
+ static void Checksum (Span<const uint8_t > addr_pubkey, uint8_t (&checksum)[CHECKSUM_LEN])
204
+ {
205
+ // TORv3 CHECKSUM = H(".onion checksum" | PUBKEY | VERSION)[:2]
206
+ static const unsigned char prefix[] = " .onion checksum" ;
207
+ static constexpr size_t prefix_len = 15 ;
208
+
209
+ SHA3_256 hasher;
210
+
211
+ hasher.Write (MakeSpan (prefix).first (prefix_len));
212
+ hasher.Write (addr_pubkey);
213
+ hasher.Write (VERSION);
214
+
215
+ uint8_t checksum_full[SHA3_256::OUTPUT_SIZE];
216
+
217
+ hasher.Finalize (checksum_full);
218
+
219
+ memcpy (checksum, checksum_full, sizeof (checksum));
220
+ }
221
+
222
+ }; // namespace torv3
223
+
153
224
/* *
154
- * Parse a TORv2 address and set this object to it.
225
+ * Parse a TOR address and set this object to it.
155
226
*
156
227
* @returns Whether or not the operation was successful.
157
228
*
158
229
* @see CNetAddr::IsTor()
159
230
*/
160
- bool CNetAddr::SetSpecial (const std::string &strName )
231
+ bool CNetAddr::SetSpecial (const std::string& str )
161
232
{
162
- if (strName.size ()>6 && strName.substr (strName.size () - 6 , 6 ) == " .onion" ) {
163
- std::vector<unsigned char > vchAddr = DecodeBase32 (strName.substr (0 , strName.size () - 6 ).c_str ());
164
- if (vchAddr.size () != ADDR_TORV2_SIZE) {
233
+ static const char * suffix{" .onion" };
234
+ static constexpr size_t suffix_len{6 };
235
+
236
+ if (!ValidAsCString (str) || str.size () <= suffix_len ||
237
+ str.substr (str.size () - suffix_len) != suffix) {
238
+ return false ;
239
+ }
240
+
241
+ bool invalid;
242
+ const auto & input = DecodeBase32 (str.substr (0 , str.size () - suffix_len).c_str (), &invalid);
243
+
244
+ if (invalid) {
245
+ return false ;
246
+ }
247
+
248
+ switch (input.size ()) {
249
+ case ADDR_TORV2_SIZE:
250
+ m_net = NET_ONION;
251
+ m_addr.assign (input.begin (), input.end ());
252
+ return true ;
253
+ case torv3::TOTAL_LEN: {
254
+ Span<const uint8_t > input_pubkey{input.data (), ADDR_TORV3_SIZE};
255
+ Span<const uint8_t > input_checksum{input.data () + ADDR_TORV3_SIZE, torv3::CHECKSUM_LEN};
256
+ Span<const uint8_t > input_version{input.data () + ADDR_TORV3_SIZE + torv3::CHECKSUM_LEN, sizeof (torv3::VERSION)};
257
+
258
+ uint8_t calculated_checksum[torv3::CHECKSUM_LEN];
259
+ torv3::Checksum (input_pubkey, calculated_checksum);
260
+
261
+ if (input_checksum != calculated_checksum || input_version != torv3::VERSION) {
165
262
return false ;
166
263
}
264
+
167
265
m_net = NET_ONION;
168
- m_addr.assign (vchAddr .begin (), vchAddr .end ());
266
+ m_addr.assign (input_pubkey .begin (), input_pubkey .end ());
169
267
return true ;
170
268
}
269
+ }
270
+
171
271
return false ;
172
272
}
173
273
@@ -284,13 +384,21 @@ bool CNetAddr::IsHeNet() const
284
384
}
285
385
286
386
/* *
287
- * @returns Whether or not this is a dummy address that maps an onion address
288
- * into IPv6.
289
- *
387
+ * Check whether this object represents a TOR address.
290
388
* @see CNetAddr::SetSpecial(const std::string &)
291
389
*/
292
390
bool CNetAddr::IsTor () const { return m_net == NET_ONION; }
293
391
392
+ /* *
393
+ * Check whether this object represents an I2P address.
394
+ */
395
+ bool CNetAddr::IsI2P () const { return m_net == NET_I2P; }
396
+
397
+ /* *
398
+ * Check whether this object represents a CJDNS address.
399
+ */
400
+ bool CNetAddr::IsCJDNS () const { return m_net == NET_CJDNS; }
401
+
294
402
bool CNetAddr::IsLocal () const
295
403
{
296
404
// IPv4 loopback (127.0.0.0/8 or 0.0.0.0/8)
@@ -377,28 +485,72 @@ enum Network CNetAddr::GetNetwork() const
377
485
return m_net;
378
486
}
379
487
488
+ static std::string IPv6ToString (Span<const uint8_t > a)
489
+ {
490
+ assert (a.size () == ADDR_IPV6_SIZE);
491
+ // clang-format off
492
+ return strprintf (" %x:%x:%x:%x:%x:%x:%x:%x" ,
493
+ ReadBE16 (&a[0 ]),
494
+ ReadBE16 (&a[2 ]),
495
+ ReadBE16 (&a[4 ]),
496
+ ReadBE16 (&a[6 ]),
497
+ ReadBE16 (&a[8 ]),
498
+ ReadBE16 (&a[10 ]),
499
+ ReadBE16 (&a[12 ]),
500
+ ReadBE16 (&a[14 ]));
501
+ // clang-format on
502
+ }
503
+
380
504
std::string CNetAddr::ToStringIP () const
381
505
{
382
- if (IsTor ())
383
- return EncodeBase32 (m_addr) + " .onion" ;
384
- if (IsInternal ())
506
+ switch (m_net) {
507
+ case NET_IPV4:
508
+ case NET_IPV6: {
509
+ CService serv (*this , 0 );
510
+ struct sockaddr_storage sockaddr;
511
+ socklen_t socklen = sizeof (sockaddr);
512
+ if (serv.GetSockAddr ((struct sockaddr *)&sockaddr, &socklen)) {
513
+ char name[1025 ] = " " ;
514
+ if (!getnameinfo ((const struct sockaddr *)&sockaddr, socklen, name,
515
+ sizeof (name), nullptr , 0 , NI_NUMERICHOST))
516
+ return std::string (name);
517
+ }
518
+ if (m_net == NET_IPV4) {
519
+ return strprintf (" %u.%u.%u.%u" , m_addr[0 ], m_addr[1 ], m_addr[2 ], m_addr[3 ]);
520
+ }
521
+ return IPv6ToString (m_addr);
522
+ }
523
+ case NET_ONION:
524
+ switch (m_addr.size ()) {
525
+ case ADDR_TORV2_SIZE:
526
+ return EncodeBase32 (m_addr) + " .onion" ;
527
+ case ADDR_TORV3_SIZE: {
528
+
529
+ uint8_t checksum[torv3::CHECKSUM_LEN];
530
+ torv3::Checksum (m_addr, checksum);
531
+
532
+ // TORv3 onion_address = base32(PUBKEY | CHECKSUM | VERSION) + ".onion"
533
+ prevector<torv3::TOTAL_LEN, uint8_t > address{m_addr.begin (), m_addr.end ()};
534
+ address.insert (address.end (), checksum, checksum + torv3::CHECKSUM_LEN);
535
+ address.insert (address.end (), torv3::VERSION, torv3::VERSION + sizeof (torv3::VERSION));
536
+
537
+ return EncodeBase32 (address) + " .onion" ;
538
+ }
539
+ default :
540
+ assert (false );
541
+ }
542
+ case NET_I2P:
543
+ return EncodeBase32 (m_addr, false /* don't pad with = */ ) + " .b32.i2p" ;
544
+ case NET_CJDNS:
545
+ return IPv6ToString (m_addr);
546
+ case NET_INTERNAL:
385
547
return EncodeBase32 (m_addr) + " .internal" ;
386
- CService serv (*this , 0 );
387
- struct sockaddr_storage sockaddr;
388
- socklen_t socklen = sizeof (sockaddr);
389
- if (serv.GetSockAddr ((struct sockaddr *)&sockaddr, &socklen)) {
390
- char name[1025 ] = " " ;
391
- if (!getnameinfo ((const struct sockaddr *)&sockaddr, socklen, name, sizeof (name), nullptr , 0 , NI_NUMERICHOST))
392
- return std::string (name);
393
- }
394
- if (IsIPv4 ())
395
- return strprintf (" %u.%u.%u.%u" , m_addr[0 ], m_addr[1 ], m_addr[2 ], m_addr[3 ]);
396
- assert (IsIPv6 ());
397
- return strprintf (" %x:%x:%x:%x:%x:%x:%x:%x" ,
398
- m_addr[0 ] << 8 | m_addr[1 ], m_addr[2 ] << 8 | m_addr[3 ],
399
- m_addr[4 ] << 8 | m_addr[5 ], m_addr[6 ] << 8 | m_addr[7 ],
400
- m_addr[8 ] << 8 | m_addr[9 ], m_addr[10 ] << 8 | m_addr[11 ],
401
- m_addr[12 ] << 8 | m_addr[13 ], m_addr[14 ] << 8 | m_addr[15 ]);
548
+ case NET_UNROUTABLE: // m_net is never and should not be set to NET_UNROUTABLE
549
+ case NET_MAX: // m_net is never and should not be set to NET_MAX
550
+ assert (false );
551
+ } // no default case, so the compiler can warn about missing cases
552
+
553
+ assert (false );
402
554
}
403
555
404
556
std::string CNetAddr::ToString () const
@@ -477,21 +629,22 @@ uint32_t CNetAddr::GetLinkedIPv4() const
477
629
assert (false );
478
630
}
479
631
480
- uint32_t CNetAddr::GetNetClass () const {
481
- uint32_t net_class = NET_IPV6;
482
- if (IsLocal ()) {
483
- net_class = 255 ;
484
- }
632
+ uint32_t CNetAddr::GetNetClass () const
633
+ {
634
+ // Make sure that if we return NET_IPV6, then IsIPv6() is true. The callers expect that.
635
+
636
+ // Check for "internal" first because such addresses are also !IsRoutable()
637
+ // and we don't want to return NET_UNROUTABLE in that case.
485
638
if (IsInternal ()) {
486
- net_class = NET_INTERNAL;
487
- } else if (!IsRoutable ()) {
488
- net_class = NET_UNROUTABLE;
489
- } else if (HasLinkedIPv4 ()) {
490
- net_class = NET_IPV4;
491
- } else if (IsTor ()) {
492
- net_class = NET_ONION;
639
+ return NET_INTERNAL;
493
640
}
494
- return net_class;
641
+ if (!IsRoutable ()) {
642
+ return NET_UNROUTABLE;
643
+ }
644
+ if (HasLinkedIPv4 ()) {
645
+ return NET_IPV4;
646
+ }
647
+ return m_net;
495
648
}
496
649
497
650
uint32_t CNetAddr::GetMappedAS (const std::vector<bool > &asmap) const {
@@ -566,7 +719,7 @@ std::vector<unsigned char> CNetAddr::GetGroup(const std::vector<bool> &asmap) co
566
719
vchRet.push_back ((ipv4 >> 24 ) & 0xFF );
567
720
vchRet.push_back ((ipv4 >> 16 ) & 0xFF );
568
721
return vchRet;
569
- } else if (IsTor ()) {
722
+ } else if (IsTor () || IsI2P () || IsCJDNS () ) {
570
723
nBits = 4 ;
571
724
} else if (IsHeNet ()) {
572
725
// for he.net, use /36 groups
@@ -791,7 +944,7 @@ std::string CService::ToStringPort() const
791
944
792
945
std::string CService::ToStringIPPort () const
793
946
{
794
- if (IsIPv4 () || IsTor () || IsInternal ()) {
947
+ if (IsIPv4 () || IsTor () || IsI2P () || IsInternal ()) {
795
948
return ToStringIP () + " :" + ToStringPort ();
796
949
} else {
797
950
return " [" + ToStringIP () + " ]:" + ToStringPort ();
0 commit comments