Skip to content

Commit 5ab49e6

Browse files
laanwjPastaPastaPasta
authored andcommitted
Merge bitcoin#21756: Avoid calling getnameinfo when formatting IPv6 addresses in CNetAddr::ToStringIP
54548ba net: Avoid calling getnameinfo when formatting IPv6 addresses in CNetAddr::ToStringIP (practicalswift) c10f27f net: Make IPv6ToString do zero compression as described in RFC 5952 (practicalswift) Pull request description: Avoid calling `getnameinfo` when formatting IPv6 addresses in `CNetAddr::ToStringIP`. Fixes bitcoin#21466. Fixes bitcoin#21967. The IPv4 case was fixed in bitcoin#21564. ACKs for top commit: laanwj: Code review ACK 54548ba vasild: ACK 54548ba Tree-SHA512: 8404e458b29efdb7bf78b91adc075d05e0385969d1532cccaa2c7cb69cd77411c42d95fcefc4000137b9f2076fe395731c7d9844b7d42b58a6d3bec69eed6fce
1 parent 86c874e commit 5ab49e6

File tree

1 file changed

+48
-22
lines changed

1 file changed

+48
-22
lines changed

src/netaddress.cpp

Lines changed: 48 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -542,20 +542,57 @@ static std::string IPv4ToString(Span<const uint8_t> a)
542542
return strprintf("%u.%u.%u.%u", a[0], a[1], a[2], a[3]);
543543
}
544544

545+
// Return an IPv6 address text representation with zero compression as described in RFC 5952
546+
// ("A Recommendation for IPv6 Address Text Representation").
545547
static std::string IPv6ToString(Span<const uint8_t> a)
546548
{
547549
assert(a.size() == ADDR_IPV6_SIZE);
548-
// clang-format off
549-
return strprintf("%x:%x:%x:%x:%x:%x:%x:%x",
550-
ReadBE16(&a[0]),
551-
ReadBE16(&a[2]),
552-
ReadBE16(&a[4]),
553-
ReadBE16(&a[6]),
554-
ReadBE16(&a[8]),
555-
ReadBE16(&a[10]),
556-
ReadBE16(&a[12]),
557-
ReadBE16(&a[14]));
558-
// clang-format on
550+
const std::array groups{
551+
ReadBE16(&a[0]),
552+
ReadBE16(&a[2]),
553+
ReadBE16(&a[4]),
554+
ReadBE16(&a[6]),
555+
ReadBE16(&a[8]),
556+
ReadBE16(&a[10]),
557+
ReadBE16(&a[12]),
558+
ReadBE16(&a[14]),
559+
};
560+
561+
// The zero compression implementation is inspired by Rust's std::net::Ipv6Addr, see
562+
// https://github.com/rust-lang/rust/blob/cc4103089f40a163f6d143f06359cba7043da29b/library/std/src/net/ip.rs#L1635-L1683
563+
struct ZeroSpan {
564+
size_t start_index{0};
565+
size_t len{0};
566+
};
567+
568+
// Find longest sequence of consecutive all-zero fields. Use first zero sequence if two or more
569+
// zero sequences of equal length are found.
570+
ZeroSpan longest, current;
571+
for (size_t i{0}; i < groups.size(); ++i) {
572+
if (groups[i] != 0) {
573+
current = {i + 1, 0};
574+
continue;
575+
}
576+
current.len += 1;
577+
if (current.len > longest.len) {
578+
longest = current;
579+
}
580+
}
581+
582+
std::string r;
583+
r.reserve(39);
584+
for (size_t i{0}; i < groups.size(); ++i) {
585+
// Replace the longest sequence of consecutive all-zero fields with two colons ("::").
586+
if (longest.len >= 2 && i >= longest.start_index && i < longest.start_index + longest.len) {
587+
if (i == longest.start_index) {
588+
r += "::";
589+
}
590+
continue;
591+
}
592+
r += strprintf("%s%x", ((!r.empty() && r.back() != ':') ? ":" : ""), groups[i]);
593+
}
594+
595+
return r;
559596
}
560597

561598
static std::string OnionToString(Span<const uint8_t> addr)
@@ -575,17 +612,6 @@ std::string CNetAddr::ToStringIP(bool fUseGetnameinfo) const
575612
case NET_IPV4:
576613
return IPv4ToString(m_addr);
577614
case NET_IPV6: {
578-
if (fUseGetnameinfo) {
579-
CService serv(*this, 0);
580-
struct sockaddr_storage sockaddr;
581-
socklen_t socklen = sizeof(sockaddr);
582-
if (serv.GetSockAddr((struct sockaddr*)&sockaddr, &socklen)) {
583-
char name[1025] = "";
584-
if (!getnameinfo((const struct sockaddr*)&sockaddr, socklen, name,
585-
sizeof(name), nullptr, 0, NI_NUMERICHOST))
586-
return std::string(name);
587-
}
588-
}
589615
return IPv6ToString(m_addr);
590616
}
591617
case NET_ONION:

0 commit comments

Comments
 (0)