55
66#include < netaddress.h>
77
8+ #include < crypto/common.h>
9+ #include < crypto/sha3.h>
810#include < hash.h>
11+ #include < prevector.h>
912#include < tinyformat.h>
1013#include < util/asmap.h>
1114#include < util/strencodings.h>
@@ -29,7 +32,18 @@ CNetAddr::BIP155Network CNetAddr::GetBIP155Network() const
2932 case NET_IPV6:
3033 return BIP155Network::IPV6;
3134 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;
3347 case NET_INTERNAL: // should have been handled before calling this function
3448 case NET_UNROUTABLE: // m_net is never and should not be set to NET_UNROUTABLE
3549 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
6680 throw std::ios_base::failure (
6781 strprintf (" BIP155 TORv2 address with length %u (should be %u)" , address_size,
6882 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));
69107 }
70108
71109 // Don't throw on addresses with unknown network ids (maybe from the future).
@@ -92,7 +130,13 @@ void CNetAddr::SetIP(const CNetAddr& ipIn)
92130 assert (ipIn.m_addr .size () == ADDR_IPV6_SIZE);
93131 break ;
94132 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);
96140 break ;
97141 case NET_INTERNAL:
98142 assert (ipIn.m_addr .size () == ADDR_INTERNAL_SIZE);
@@ -150,24 +194,80 @@ bool CNetAddr::SetInternal(const std::string &name)
150194 return true ;
151195}
152196
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+
153224/* *
154- * Parse a TORv2 address and set this object to it.
225+ * Parse a TOR address and set this object to it.
155226 *
156227 * @returns Whether or not the operation was successful.
157228 *
158229 * @see CNetAddr::IsTor()
159230 */
160- bool CNetAddr::SetSpecial (const std::string &strName )
231+ bool CNetAddr::SetSpecial (const std::string& str )
161232{
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) {
165262 return false ;
166263 }
264+
167265 m_net = NET_ONION;
168- m_addr.assign (vchAddr .begin (), vchAddr .end ());
266+ m_addr.assign (input_pubkey .begin (), input_pubkey .end ());
169267 return true ;
170268 }
269+ }
270+
171271 return false ;
172272}
173273
@@ -284,13 +384,21 @@ bool CNetAddr::IsHeNet() const
284384}
285385
286386/* *
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.
290388 * @see CNetAddr::SetSpecial(const std::string &)
291389 */
292390bool CNetAddr::IsTor () const { return m_net == NET_ONION; }
293391
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+
294402bool CNetAddr::IsLocal () const
295403{
296404 // IPv4 loopback (127.0.0.0/8 or 0.0.0.0/8)
@@ -377,28 +485,72 @@ enum Network CNetAddr::GetNetwork() const
377485 return m_net;
378486}
379487
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+
380504std::string CNetAddr::ToStringIP () const
381505{
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:
385547 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 );
402554}
403555
404556std::string CNetAddr::ToString () const
@@ -477,21 +629,22 @@ uint32_t CNetAddr::GetLinkedIPv4() const
477629 assert (false );
478630}
479631
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.
485638 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;
493640 }
494- return net_class;
641+ if (!IsRoutable ()) {
642+ return NET_UNROUTABLE;
643+ }
644+ if (HasLinkedIPv4 ()) {
645+ return NET_IPV4;
646+ }
647+ return m_net;
495648}
496649
497650uint32_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
566719 vchRet.push_back ((ipv4 >> 24 ) & 0xFF );
567720 vchRet.push_back ((ipv4 >> 16 ) & 0xFF );
568721 return vchRet;
569- } else if (IsTor ()) {
722+ } else if (IsTor () || IsI2P () || IsCJDNS () ) {
570723 nBits = 4 ;
571724 } else if (IsHeNet ()) {
572725 // for he.net, use /36 groups
@@ -791,7 +944,7 @@ std::string CService::ToStringPort() const
791944
792945std::string CService::ToStringIPPort () const
793946{
794- if (IsIPv4 () || IsTor () || IsInternal ()) {
947+ if (IsIPv4 () || IsTor () || IsI2P () || IsInternal ()) {
795948 return ToStringIP () + " :" + ToStringPort ();
796949 } else {
797950 return " [" + ToStringIP () + " ]:" + ToStringPort ();
0 commit comments