diff options
author | W. J. van der Laan <laanwj@protonmail.com> | 2021-05-17 12:52:02 +0200 |
---|---|---|
committer | W. J. van der Laan <laanwj@protonmail.com> | 2021-05-17 13:08:14 +0200 |
commit | 7b87fca930ff7129f267906e71be217851146ade (patch) | |
tree | 46be96dc99746a5cefe6cde95a49f7329ce322c4 /src | |
parent | 1ef34ee25ed34b2b092f15bf3dca5c0508092829 (diff) | |
parent | 54548bae8004a8f49d73bd29aeca8b41894214c4 (diff) |
Merge bitcoin/bitcoin#21756: Avoid calling `getnameinfo` when formatting IPv6 addresses in `CNetAddr::ToStringIP`
54548bae8004a8f49d73bd29aeca8b41894214c4 net: Avoid calling getnameinfo when formatting IPv6 addresses in CNetAddr::ToStringIP (practicalswift)
c10f27fdb2d335954dd1017ce6d5800159427374 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 #21466.
Fixes #21967.
The IPv4 case was fixed in #21564.
ACKs for top commit:
laanwj:
Code review ACK 54548bae8004a8f49d73bd29aeca8b41894214c4
vasild:
ACK 54548bae8004a8f49d73bd29aeca8b41894214c4
Tree-SHA512: 8404e458b29efdb7bf78b91adc075d05e0385969d1532cccaa2c7cb69cd77411c42d95fcefc4000137b9f2076fe395731c7d9844b7d42b58a6d3bec69eed6fce
Diffstat (limited to 'src')
-rw-r--r-- | src/netaddress.cpp | 68 |
1 files changed, 48 insertions, 20 deletions
diff --git a/src/netaddress.cpp b/src/netaddress.cpp index d56ae78e92..112e216c09 100644 --- a/src/netaddress.cpp +++ b/src/netaddress.cpp @@ -556,20 +556,57 @@ static std::string IPv4ToString(Span<const uint8_t> a) return strprintf("%u.%u.%u.%u", a[0], a[1], a[2], a[3]); } +// Return an IPv6 address text representation with zero compression as described in RFC 5952 +// ("A Recommendation for IPv6 Address Text Representation"). static std::string IPv6ToString(Span<const uint8_t> a) { assert(a.size() == ADDR_IPV6_SIZE); - // clang-format off - return strprintf("%x:%x:%x:%x:%x:%x:%x:%x", - ReadBE16(&a[0]), - ReadBE16(&a[2]), - ReadBE16(&a[4]), - ReadBE16(&a[6]), - ReadBE16(&a[8]), - ReadBE16(&a[10]), - ReadBE16(&a[12]), - ReadBE16(&a[14])); - // clang-format on + const std::array groups{ + ReadBE16(&a[0]), + ReadBE16(&a[2]), + ReadBE16(&a[4]), + ReadBE16(&a[6]), + ReadBE16(&a[8]), + ReadBE16(&a[10]), + ReadBE16(&a[12]), + ReadBE16(&a[14]), + }; + + // The zero compression implementation is inspired by Rust's std::net::Ipv6Addr, see + // https://github.com/rust-lang/rust/blob/cc4103089f40a163f6d143f06359cba7043da29b/library/std/src/net/ip.rs#L1635-L1683 + struct ZeroSpan { + size_t start_index{0}; + size_t len{0}; + }; + + // Find longest sequence of consecutive all-zero fields. Use first zero sequence if two or more + // zero sequences of equal length are found. + ZeroSpan longest, current; + for (size_t i{0}; i < groups.size(); ++i) { + if (groups[i] != 0) { + current = {i + 1, 0}; + continue; + } + current.len += 1; + if (current.len > longest.len) { + longest = current; + } + } + + std::string r; + r.reserve(39); + for (size_t i{0}; i < groups.size(); ++i) { + // Replace the longest sequence of consecutive all-zero fields with two colons ("::"). + if (longest.len >= 2 && i >= longest.start_index && i < longest.start_index + longest.len) { + if (i == longest.start_index) { + r += "::"; + } + continue; + } + r += strprintf("%s%x", ((!r.empty() && r.back() != ':') ? ":" : ""), groups[i]); + } + + return r; } std::string CNetAddr::ToStringIP() const @@ -578,15 +615,6 @@ std::string CNetAddr::ToStringIP() const case NET_IPV4: return IPv4ToString(m_addr); case NET_IPV6: { - CService serv(*this, 0); - struct sockaddr_storage sockaddr; - socklen_t socklen = sizeof(sockaddr); - if (serv.GetSockAddr((struct sockaddr*)&sockaddr, &socklen)) { - char name[1025] = ""; - if (!getnameinfo((const struct sockaddr*)&sockaddr, socklen, name, - sizeof(name), nullptr, 0, NI_NUMERICHOST)) - return std::string(name); - } return IPv6ToString(m_addr); } case NET_ONION: |