SockAddr fixes and cleanups

- Remove SIIT from method names & comments because we're doing IPv4
mapped addresses (::ffff:0:0/96) rather than actual SIIT
(::ffff:0:0:0/96).

- add constructor taking a string+numeric port (and then don't allow a
port in the string).

- simplify IP string parsing by using parse_int()

- replace addrIsV4 with call to ipv6_is_mapped_ipv4 (this also fixes a
bug where addrIsV4 was not checking for leading 0s and so could return
true for a public IPv6 that happened to have ffff in the wrong spot).
pull/1545/head
Jason Rhinelander 3 years ago
parent 291aa2e56d
commit 56cbef6086

@ -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

@ -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)

@ -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<uint8_t, 12> 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

@ -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<const sockaddr_in6&>(other);
else if (other.sa_family == AF_INET)
*this = (const sockaddr_in&)other;
*this = reinterpret_cast<const sockaddr_in&>(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<uint8_t, 4> 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;

@ -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&

Loading…
Cancel
Save