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