diff --git a/llarp/net/ip_range.hpp b/llarp/net/ip_range.hpp index 747914f1e..fcb3b97fe 100644 --- a/llarp/net/ip_range.hpp +++ b/llarp/net/ip_range.hpp @@ -20,12 +20,12 @@ namespace llarp return IPRange{net::ExpandV4(ipaddr_ipv4_bits(a, b, c, d)), netmask_ipv6_bits(mask + 96)}; } - /// return true if this iprange is in the SIIT range for containing ipv4 addresses + /// return true if this iprange is in the IPv4 mapping range for containing ipv4 addresses constexpr bool IsV4() const { - constexpr auto siit = IPRange{huint128_t{0x0000'ffff'0000'0000UL}, netmask_ipv6_bits(96)}; - return siit.Contains(addr); + constexpr auto ipv4_map = IPRange{huint128_t{0x0000'ffff'0000'0000UL}, netmask_ipv6_bits(96)}; + return ipv4_map.Contains(addr); } /// return the number of bits set in the hostmask diff --git a/llarp/net/net.cpp b/llarp/net/net.cpp index ceb3d3b14..d795e4d93 100644 --- a/llarp/net/net.cpp +++ b/llarp/net/net.cpp @@ -599,7 +599,7 @@ namespace llarp (void)addr; return false; #else - if (!ipv6_is_siit(addr)) + if (!ipv6_is_mapped_ipv4(addr)) { static in6_addr zero = {}; if (addr == zero) diff --git a/llarp/net/net_bits.hpp b/llarp/net/net_bits.hpp index b57603eb2..0f6c5359c 100644 --- a/llarp/net/net_bits.hpp +++ b/llarp/net/net_bits.hpp @@ -37,12 +37,15 @@ namespace llarp return huint32_t{(d) | (c << 8) | (b << 16) | (a << 24)}; } + // IPv4 mapped address live at ::ffff:0:0/96 + constexpr std::array ipv4_map_prefix{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}; + constexpr bool - ipv6_is_siit(const in6_addr& addr) + ipv6_is_mapped_ipv4(const in6_addr& addr) { - return addr.s6_addr[11] == 0xff && addr.s6_addr[10] == 0xff && addr.s6_addr[9] == 0 - && addr.s6_addr[8] == 0 && addr.s6_addr[7] == 0 && addr.s6_addr[6] == 0 - && addr.s6_addr[5] == 0 && addr.s6_addr[4] == 0 && addr.s6_addr[3] == 0 - && addr.s6_addr[2] == 0 && addr.s6_addr[1] == 0 && addr.s6_addr[0] == 0; + for (size_t i = 0; i < ipv4_map_prefix.size(); i++) + if (addr.s6_addr[i] != ipv4_map_prefix[i]) + return false; + return true; } } // namespace llarp diff --git a/llarp/net/sock_addr.cpp b/llarp/net/sock_addr.cpp index 495cea5b1..416af3fdb 100644 --- a/llarp/net/sock_addr.cpp +++ b/llarp/net/sock_addr.cpp @@ -19,10 +19,6 @@ namespace llarp /// shared utility functions /// - constexpr auto addrIsV4 = [](const in6_addr& addr) -> bool { - return addr.s6_addr[10] == 0xff and addr.s6_addr[11] == 0xff; - }; - void SockAddr::init() { @@ -31,13 +27,9 @@ namespace llarp } void - SockAddr::applySIITBytes() + SockAddr::applyIPv4MapBytes() { - uint8_t* ip6 = m_addr.sin6_addr.s6_addr; - - // SIIT == Stateless IP/ICMP Translation (represent IPv4 with IPv6) - ip6[10] = 0xff; - ip6[11] = 0xff; + std::memcpy(m_addr.sin6_addr.s6_addr, ipv4_map_prefix.data(), ipv4_map_prefix.size()); } SockAddr::SockAddr() @@ -52,9 +44,8 @@ namespace llarp } SockAddr::SockAddr(uint8_t a, uint8_t b, uint8_t c, uint8_t d, uint16_t port) + : SockAddr{a, b, c, d} { - init(); - setIPv4(a, b, c, d); setPort(port); } SockAddr::SockAddr(std::string_view addr) @@ -62,6 +53,12 @@ namespace llarp init(); fromString(addr); } + SockAddr::SockAddr(std::string_view addr, uint16_t port) + { + init(); + setPort(port); + fromString(addr, false); + } SockAddr::SockAddr(const AddressInfo& info) : SockAddr{info.ip} { @@ -89,9 +86,9 @@ namespace llarp SockAddr::operator=(const sockaddr& other) { if (other.sa_family == AF_INET6) - *this = (const sockaddr_in6&)other; + *this = reinterpret_cast(other); else if (other.sa_family == AF_INET) - *this = (const sockaddr_in&)other; + *this = reinterpret_cast(other); else throw std::invalid_argument("Invalid sockaddr (not AF_INET or AF_INET6)"); @@ -107,7 +104,7 @@ namespace llarp SockAddr::operator=(const sockaddr_in& other) { init(); - applySIITBytes(); + applyIPv4MapBytes(); // avoid byte order conversion (this is NBO -> NBO) memcpy(m_addr.sin6_addr.s6_addr + 12, &other.sin_addr.s_addr, sizeof(in_addr)); @@ -130,7 +127,7 @@ namespace llarp init(); memcpy(&m_addr, &other, sizeof(sockaddr_in6)); - if (addrIsV4(other.sin6_addr)) + if (ipv6_is_mapped_ipv4(other.sin6_addr)) setIPv4( other.sin6_addr.s6_addr[12], other.sin6_addr.s6_addr[13], @@ -153,7 +150,7 @@ namespace llarp init(); memcpy(&m_addr.sin6_addr.s6_addr, &other.s6_addr, sizeof(m_addr.sin6_addr.s6_addr)); - if (addrIsV4(other)) + if (ipv6_is_mapped_ipv4(other)) setIPv4(other.s6_addr[12], other.s6_addr[13], other.s6_addr[14], other.s6_addr[15]); m_empty = false; @@ -202,7 +199,7 @@ namespace llarp } void - SockAddr::fromString(std::string_view str) + SockAddr::fromString(std::string_view str, bool allow_port) { if (str.empty()) { @@ -233,33 +230,19 @@ namespace llarp if (ipSplits.size() != 4) throw std::invalid_argument(stringify(str, " is not a valid IPv4 address")); - uint8_t ipBytes[4] = {0}; - + std::array ipBytes; for (int i = 0; i < 4; ++i) - { - auto byteStr = ipSplits[i]; - auto result = std::from_chars(byteStr.data(), byteStr.data() + byteStr.size(), ipBytes[i]); - - if (result.ec != std::errc()) - throw std::runtime_error(stringify(str, " contains invalid number")); - - if (result.ptr != (byteStr.data() + byteStr.size())) - throw std::runtime_error(stringify(str, " contains non-numeric values")); - } + if (not parse_int(ipSplits[i], ipBytes[i])) + throw std::runtime_error(stringify(str, " contains invalid numeric value")); // attempt port before setting IPv4 bytes if (splits.size() == 2) { - uint16_t port = 0; - auto portStr = splits[1]; - auto result = std::from_chars(portStr.data(), portStr.data() + portStr.size(), port); - - if (result.ec != std::errc()) - throw std::runtime_error(stringify(str, " contains invalid port")); - - if (result.ptr != (portStr.data() + portStr.size())) - throw std::runtime_error(stringify(str, " contains junk after port")); - + if (not allow_port) + throw std::runtime_error{stringify("invalid ip address (port not allowed here): ", str)}; + uint16_t port; + if (not parse_int(splits[1], port)) + throw std::runtime_error{stringify(splits[1], " is not a valid port")}; setPort(port); } @@ -278,7 +261,7 @@ namespace llarp if (ip6[10] == 0xff and ip6[11] == 0xff) { - // treat SIIT like IPv4 + // handle IPv4 mapped addrs constexpr auto MaxIPv4PlusPortStringSize = 22; str.reserve(MaxIPv4PlusPortStringSize); char buf[128] = {0x0}; @@ -317,7 +300,7 @@ namespace llarp uint8_t* ip6 = m_addr.sin6_addr.s6_addr; llarp::Zero(ip6, sizeof(m_addr.sin6_addr.s6_addr)); - applySIITBytes(); + applyIPv4MapBytes(); ip6[12] = a; ip6[13] = b; diff --git a/llarp/net/sock_addr.hpp b/llarp/net/sock_addr.hpp index 5784f3ab1..15696ae30 100644 --- a/llarp/net/sock_addr.hpp +++ b/llarp/net/sock_addr.hpp @@ -30,6 +30,7 @@ namespace llarp SockAddr(uint8_t a, uint8_t b, uint8_t c, uint8_t d); SockAddr(uint8_t a, uint8_t b, uint8_t c, uint8_t d, uint16_t port); SockAddr(std::string_view addr); + SockAddr(std::string_view addr, uint16_t port); SockAddr(const AddressInfo&); @@ -64,7 +65,7 @@ namespace llarp operator==(const SockAddr& other) const; void - fromString(std::string_view str); + fromString(std::string_view str, bool allow_port = true); std::string toString() const; @@ -113,7 +114,7 @@ namespace llarp init(); void - applySIITBytes(); + applyIPv4MapBytes(); }; std::ostream&