@@ -17,6 +17,8 @@ static const CService empty_service{CService()};
1717
1818static constexpr std::string_view SAFE_CHARS_IPV4{" 1234567890." };
1919static constexpr std::string_view SAFE_CHARS_IPV4_6{" abcdefABCDEF1234567890.:[]" };
20+ static constexpr std::string_view SAFE_CHARS_RFC1035{" abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-" };
21+ static constexpr std::array<std::string_view, 2 > TLDS_SPECIAL{" .i2p" , " .onion" };
2022
2123bool IsNodeOnMainnet () { return Params ().NetworkIDString () == CBaseChainParams::MAIN; }
2224const CChainParams& MainParams ()
@@ -31,6 +33,17 @@ bool MatchCharsFilter(std::string_view input, std::string_view filter)
3133{
3234 return std::all_of (input.begin (), input.end (), [&filter](char c) { return filter.find (c) != std::string_view::npos; });
3335}
36+
37+ template <typename T1>
38+ bool MatchSuffix (const std::string& str, const T1& list)
39+ {
40+ if (str.empty ()) return false ;
41+ for (const auto & suffix : list) {
42+ if (suffix.size () > str.size ()) continue ;
43+ if (std::equal (suffix.rbegin (), suffix.rend (), str.rbegin ())) return true ;
44+ }
45+ return false ;
46+ }
3447} // anonymous namespace
3548
3649bool NetInfoEntry::operator ==(const NetInfoEntry& rhs) const
@@ -351,13 +364,16 @@ NetInfoStatus ExtNetInfo::ValidateService(const CService& service, bool is_prima
351364 if (!service.IsValid ()) {
352365 return NetInfoStatus::BadAddress;
353366 }
354- if (!service.IsCJDNS () && !service.IsIPv4 () && !service.IsIPv6 ()) {
367+ if (!service.IsCJDNS () && !service.IsI2P () && !service. IsIPv4 () && !service.IsIPv6 () && !service. IsTor ()) {
355368 return NetInfoStatus::BadType;
356369 }
357370 if (Params ().RequireRoutableExternalIP () && !service.IsRoutable ()) {
358371 return NetInfoStatus::NotRoutable;
359372 }
360- if (IsBadPort (service.GetPort ()) || service.GetPort () == 0 ) {
373+ if (service.IsI2P () && service.GetPort () != I2P_SAM31_PORT) {
374+ // I2P SAM 3.1 and earlier don't support arbitrary ports
375+ return NetInfoStatus::BadPort;
376+ } else if (!service.IsI2P () && (IsBadPort (service.GetPort ()) || service.GetPort () == 0 )) {
361377 return NetInfoStatus::BadPort;
362378 }
363379 if (is_primary) {
@@ -380,14 +396,39 @@ NetInfoStatus ExtNetInfo::AddEntry(const uint8_t purpose, const std::string& inp
380396 std::string addr;
381397 uint16_t port{0 };
382398 SplitHostPort (input, port, addr);
383- // Contains invalid characters, unlikely to pass Lookup(), fast-fail
399+
400+ // Primary addresses are subject to stricter validation rules
401+ const bool is_primary{m_data.find (purpose) == m_data.end ()};
402+
384403 if (!MatchCharsFilter (addr, SAFE_CHARS_IPV4_6)) {
385- return NetInfoStatus::BadInput;
404+ if (!MatchCharsFilter (addr, SAFE_CHARS_RFC1035)) {
405+ // Neither IP:port safe nor domain-safe, we can safely assume it's bad input
406+ return NetInfoStatus::BadInput;
407+ }
408+
409+ // Not IP:port safe but domain safe
410+ if (is_primary) {
411+ // Domains are not allowed as primary addresses
412+ return NetInfoStatus::BadType;
413+ } else if (MatchSuffix (addr, TLDS_SPECIAL)) {
414+ // Special domain, try storing it as CService
415+ CNetAddr netaddr;
416+ if (netaddr.SetSpecial (addr)) {
417+ const CService service{netaddr, port};
418+ const auto ret{ValidateService (service, /* is_primary=*/ false )};
419+ if (ret == NetInfoStatus::Success) {
420+ return ProcessCandidate (purpose, NetInfoEntry{service});
421+ }
422+ return ret; /* ValidateService() failed */
423+ }
424+ }
425+ return NetInfoStatus::BadInput; /* CService::SetSpecial() failed */
386426 }
387427
428+ // IP:port safe, try to parse it as IP:port
388429 if (auto service_opt{Lookup (addr, /* portDefault=*/ port, /* fAllowLookup=*/ false )}) {
389430 const auto service{MaybeFlipIPv6toCJDNS (*service_opt)};
390- const auto ret{ValidateService (service, /* is_primary= */ m_data. find (purpose) == m_data. end () )};
431+ const auto ret{ValidateService (service, is_primary)};
391432 if (ret == NetInfoStatus::Success) {
392433 return ProcessCandidate (purpose, NetInfoEntry{service});
393434 }
0 commit comments