2021-03-09 22:24:35 +00:00
|
|
|
#include "sock_addr.hpp"
|
|
|
|
#include "address_info.hpp"
|
|
|
|
#include "ip.hpp"
|
|
|
|
#include "net_bits.hpp"
|
|
|
|
#include <llarp/util/str.hpp>
|
|
|
|
#include <llarp/util/logging/logger.hpp>
|
|
|
|
#include <llarp/util/mem.hpp>
|
2020-05-08 17:23:21 +00:00
|
|
|
|
|
|
|
#include <charconv>
|
|
|
|
#include <stdexcept>
|
|
|
|
|
|
|
|
namespace llarp
|
|
|
|
{
|
2021-02-22 15:01:05 +00:00
|
|
|
bool
|
|
|
|
operator==(const in6_addr& lh, const in6_addr& rh)
|
|
|
|
{
|
|
|
|
return memcmp(&lh, &rh, sizeof(in6_addr)) == 0;
|
|
|
|
}
|
2020-05-08 17:23:21 +00:00
|
|
|
/// shared utility functions
|
|
|
|
///
|
|
|
|
|
|
|
|
void
|
|
|
|
SockAddr::init()
|
|
|
|
{
|
|
|
|
llarp::Zero(&m_addr, sizeof(m_addr));
|
2021-03-03 04:34:16 +00:00
|
|
|
m_addr.sin6_family = AF_INET6;
|
2020-10-27 21:34:09 +00:00
|
|
|
llarp::Zero(&m_addr4, sizeof(m_addr4));
|
2021-03-03 04:34:16 +00:00
|
|
|
m_addr4.sin_family = AF_INET;
|
2020-05-08 17:23:21 +00:00
|
|
|
}
|
|
|
|
|
2020-05-08 22:52:00 +00:00
|
|
|
void
|
2021-02-24 23:34:42 +00:00
|
|
|
SockAddr::applyIPv4MapBytes()
|
2020-05-08 22:52:00 +00:00
|
|
|
{
|
2021-02-24 23:34:42 +00:00
|
|
|
std::memcpy(m_addr.sin6_addr.s6_addr, ipv4_map_prefix.data(), ipv4_map_prefix.size());
|
2020-05-08 22:52:00 +00:00
|
|
|
}
|
|
|
|
|
2020-05-08 17:23:21 +00:00
|
|
|
SockAddr::SockAddr()
|
|
|
|
{
|
|
|
|
init();
|
|
|
|
}
|
|
|
|
|
|
|
|
SockAddr::SockAddr(uint8_t a, uint8_t b, uint8_t c, uint8_t d)
|
|
|
|
{
|
|
|
|
init();
|
|
|
|
setIPv4(a, b, c, d);
|
|
|
|
}
|
|
|
|
|
|
|
|
SockAddr::SockAddr(uint8_t a, uint8_t b, uint8_t c, uint8_t d, uint16_t port)
|
2021-02-24 23:34:42 +00:00
|
|
|
: SockAddr{a, b, c, d}
|
2020-05-08 17:23:21 +00:00
|
|
|
{
|
|
|
|
setPort(port);
|
|
|
|
}
|
2021-03-02 18:18:22 +00:00
|
|
|
|
|
|
|
SockAddr::SockAddr(uint32_t ip, uint16_t port)
|
|
|
|
{
|
|
|
|
init();
|
|
|
|
setIPv4(ip);
|
|
|
|
setPort(ntohs(port));
|
|
|
|
}
|
|
|
|
|
2020-05-08 17:23:21 +00:00
|
|
|
SockAddr::SockAddr(std::string_view addr)
|
|
|
|
{
|
2020-05-08 20:33:44 +00:00
|
|
|
init();
|
|
|
|
fromString(addr);
|
2020-05-08 17:23:21 +00:00
|
|
|
}
|
2021-02-24 23:34:42 +00:00
|
|
|
SockAddr::SockAddr(std::string_view addr, uint16_t port)
|
|
|
|
{
|
|
|
|
init();
|
|
|
|
setPort(port);
|
|
|
|
fromString(addr, false);
|
|
|
|
}
|
2020-05-08 17:23:21 +00:00
|
|
|
|
2021-02-22 15:01:05 +00:00
|
|
|
SockAddr::SockAddr(const AddressInfo& info) : SockAddr{info.ip}
|
|
|
|
{
|
|
|
|
setPort(info.port);
|
|
|
|
}
|
|
|
|
|
2020-05-08 22:52:00 +00:00
|
|
|
SockAddr::SockAddr(const SockAddr& other)
|
2020-05-08 17:23:21 +00:00
|
|
|
{
|
2020-05-08 22:52:00 +00:00
|
|
|
*this = other;
|
2020-05-08 17:23:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SockAddr&
|
2020-05-08 22:52:00 +00:00
|
|
|
SockAddr::operator=(const SockAddr& other)
|
2020-05-08 17:23:21 +00:00
|
|
|
{
|
2020-05-08 22:52:00 +00:00
|
|
|
*this = other.m_addr;
|
|
|
|
return *this;
|
2020-05-08 17:23:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SockAddr::SockAddr(const sockaddr& addr)
|
|
|
|
{
|
2020-05-08 22:52:00 +00:00
|
|
|
*this = addr;
|
|
|
|
}
|
|
|
|
|
|
|
|
SockAddr&
|
|
|
|
SockAddr::operator=(const sockaddr& other)
|
|
|
|
{
|
|
|
|
if (other.sa_family == AF_INET6)
|
2021-02-24 23:34:42 +00:00
|
|
|
*this = reinterpret_cast<const sockaddr_in6&>(other);
|
2020-05-08 22:52:00 +00:00
|
|
|
else if (other.sa_family == AF_INET)
|
2021-02-24 23:34:42 +00:00
|
|
|
*this = reinterpret_cast<const sockaddr_in&>(other);
|
2020-05-08 22:52:00 +00:00
|
|
|
else
|
|
|
|
throw std::invalid_argument("Invalid sockaddr (not AF_INET or AF_INET6)");
|
|
|
|
|
|
|
|
return *this;
|
2020-05-08 17:23:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SockAddr::SockAddr(const sockaddr_in& addr)
|
|
|
|
{
|
2020-05-08 22:52:00 +00:00
|
|
|
*this = addr;
|
|
|
|
}
|
|
|
|
|
|
|
|
SockAddr&
|
|
|
|
SockAddr::operator=(const sockaddr_in& other)
|
|
|
|
{
|
|
|
|
init();
|
2021-02-24 23:34:42 +00:00
|
|
|
applyIPv4MapBytes();
|
2020-05-08 22:52:00 +00:00
|
|
|
|
|
|
|
// avoid byte order conversion (this is NBO -> NBO)
|
|
|
|
memcpy(m_addr.sin6_addr.s6_addr + 12, &other.sin_addr.s_addr, sizeof(in_addr));
|
|
|
|
m_addr.sin6_port = other.sin_port;
|
2020-10-27 21:34:09 +00:00
|
|
|
m_addr4.sin_addr.s_addr = other.sin_addr.s_addr;
|
|
|
|
m_addr4.sin_port = other.sin_port;
|
2020-05-08 22:52:00 +00:00
|
|
|
m_empty = false;
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
SockAddr::SockAddr(const sockaddr_in6& addr)
|
|
|
|
{
|
|
|
|
*this = addr;
|
|
|
|
}
|
|
|
|
|
|
|
|
SockAddr&
|
|
|
|
SockAddr::operator=(const sockaddr_in6& other)
|
|
|
|
{
|
|
|
|
init();
|
|
|
|
|
|
|
|
memcpy(&m_addr, &other, sizeof(sockaddr_in6));
|
2021-02-24 23:34:42 +00:00
|
|
|
if (ipv6_is_mapped_ipv4(other.sin6_addr))
|
2020-10-27 21:34:09 +00:00
|
|
|
setIPv4(
|
|
|
|
other.sin6_addr.s6_addr[12],
|
|
|
|
other.sin6_addr.s6_addr[13],
|
|
|
|
other.sin6_addr.s6_addr[14],
|
|
|
|
other.sin6_addr.s6_addr[15]);
|
|
|
|
setPort(ntohs(other.sin6_port));
|
2020-05-08 22:52:00 +00:00
|
|
|
m_empty = false;
|
|
|
|
|
|
|
|
return *this;
|
2020-05-08 17:23:21 +00:00
|
|
|
}
|
|
|
|
|
2020-05-11 16:14:07 +00:00
|
|
|
SockAddr::SockAddr(const in6_addr& addr)
|
|
|
|
{
|
|
|
|
*this = addr;
|
|
|
|
}
|
|
|
|
|
|
|
|
SockAddr&
|
|
|
|
SockAddr::operator=(const in6_addr& other)
|
|
|
|
{
|
|
|
|
init();
|
|
|
|
|
|
|
|
memcpy(&m_addr.sin6_addr.s6_addr, &other.s6_addr, sizeof(m_addr.sin6_addr.s6_addr));
|
2021-02-24 23:34:42 +00:00
|
|
|
if (ipv6_is_mapped_ipv4(other))
|
2020-10-27 21:34:09 +00:00
|
|
|
setIPv4(other.s6_addr[12], other.s6_addr[13], other.s6_addr[14], other.s6_addr[15]);
|
2020-05-11 16:14:07 +00:00
|
|
|
m_empty = false;
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2020-05-08 17:23:21 +00:00
|
|
|
SockAddr::operator const sockaddr*() const
|
|
|
|
{
|
2021-03-03 04:34:16 +00:00
|
|
|
return ipv6_is_mapped_ipv4(m_addr.sin6_addr) ? reinterpret_cast<const sockaddr*>(&m_addr4)
|
|
|
|
: reinterpret_cast<const sockaddr*>(&m_addr);
|
2020-05-08 17:23:21 +00:00
|
|
|
}
|
|
|
|
|
2020-10-27 21:34:09 +00:00
|
|
|
SockAddr::operator const sockaddr_in*() const
|
|
|
|
{
|
|
|
|
return &m_addr4;
|
|
|
|
}
|
|
|
|
|
2020-05-11 15:11:44 +00:00
|
|
|
SockAddr::operator const sockaddr_in6*() const
|
|
|
|
{
|
|
|
|
return &m_addr;
|
|
|
|
}
|
|
|
|
|
2020-05-11 17:55:36 +00:00
|
|
|
bool
|
|
|
|
SockAddr::operator<(const SockAddr& other) const
|
|
|
|
{
|
|
|
|
return (m_addr.sin6_addr.s6_addr < other.m_addr.sin6_addr.s6_addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
SockAddr::operator==(const SockAddr& other) const
|
|
|
|
{
|
2021-02-22 15:01:05 +00:00
|
|
|
return m_addr.sin6_addr == other.m_addr.sin6_addr
|
|
|
|
and m_addr.sin6_port == other.m_addr.sin6_port;
|
2020-05-11 17:55:36 +00:00
|
|
|
}
|
|
|
|
|
2021-02-16 15:59:18 +00:00
|
|
|
huint128_t
|
|
|
|
SockAddr::asIPv6() const
|
|
|
|
{
|
|
|
|
return net::In6ToHUInt(m_addr.sin6_addr);
|
|
|
|
}
|
|
|
|
|
2021-02-22 15:01:05 +00:00
|
|
|
huint32_t
|
|
|
|
SockAddr::asIPv4() const
|
|
|
|
{
|
|
|
|
const nuint32_t n{m_addr4.sin_addr.s_addr};
|
|
|
|
return ToHost(n);
|
|
|
|
}
|
|
|
|
|
2020-05-08 17:23:21 +00:00
|
|
|
void
|
2021-02-24 23:34:42 +00:00
|
|
|
SockAddr::fromString(std::string_view str, bool allow_port)
|
2020-05-08 17:23:21 +00:00
|
|
|
{
|
|
|
|
if (str.empty())
|
2020-05-11 15:11:44 +00:00
|
|
|
{
|
|
|
|
init();
|
|
|
|
m_empty = true;
|
|
|
|
return;
|
|
|
|
}
|
2020-05-08 17:23:21 +00:00
|
|
|
|
|
|
|
// NOTE: this potentially involves multiple memory allocations,
|
|
|
|
// reimplement without split() if it is performance bottleneck
|
|
|
|
auto splits = split(str, ':');
|
|
|
|
|
|
|
|
// TODO: having ":port" at the end makes this ambiguous with IPv6
|
|
|
|
// come up with a strategy for implementing
|
|
|
|
if (splits.size() > 2)
|
2021-02-16 15:59:18 +00:00
|
|
|
{
|
|
|
|
std::string data{str};
|
|
|
|
if (inet_pton(AF_INET6, data.c_str(), m_addr.sin6_addr.s6_addr) == -1)
|
|
|
|
throw std::runtime_error{"invalid ip6 address: " + data};
|
|
|
|
return;
|
|
|
|
}
|
2020-05-08 17:23:21 +00:00
|
|
|
|
|
|
|
// split() shouldn't return an empty list if str is empty (checked above)
|
|
|
|
assert(splits.size() > 0);
|
|
|
|
|
|
|
|
// splits[0] should be dot-separated IPv4
|
|
|
|
auto ipSplits = split(splits[0], '.');
|
|
|
|
if (ipSplits.size() != 4)
|
|
|
|
throw std::invalid_argument(stringify(str, " is not a valid IPv4 address"));
|
|
|
|
|
2021-02-24 23:34:42 +00:00
|
|
|
std::array<uint8_t, 4> ipBytes;
|
2020-05-08 17:23:21 +00:00
|
|
|
for (int i = 0; i < 4; ++i)
|
2021-02-24 23:34:42 +00:00
|
|
|
if (not parse_int(ipSplits[i], ipBytes[i]))
|
|
|
|
throw std::runtime_error(stringify(str, " contains invalid numeric value"));
|
2020-05-08 17:23:21 +00:00
|
|
|
|
|
|
|
// attempt port before setting IPv4 bytes
|
|
|
|
if (splits.size() == 2)
|
|
|
|
{
|
2021-02-24 23:34:42 +00:00
|
|
|
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")};
|
2020-05-08 17:23:21 +00:00
|
|
|
setPort(port);
|
|
|
|
}
|
|
|
|
|
|
|
|
setIPv4(ipBytes[0], ipBytes[1], ipBytes[2], ipBytes[3]);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string
|
|
|
|
SockAddr::toString() const
|
|
|
|
{
|
|
|
|
// TODO: review
|
|
|
|
if (isEmpty())
|
|
|
|
return "";
|
|
|
|
|
2020-05-11 20:52:30 +00:00
|
|
|
std::string str;
|
2020-05-08 17:23:21 +00:00
|
|
|
|
2021-03-03 04:34:16 +00:00
|
|
|
if (ipv6_is_mapped_ipv4(m_addr.sin6_addr))
|
2020-05-11 20:52:30 +00:00
|
|
|
{
|
2021-02-24 23:34:42 +00:00
|
|
|
// handle IPv4 mapped addrs
|
2020-05-11 20:52:30 +00:00
|
|
|
constexpr auto MaxIPv4PlusPortStringSize = 22;
|
|
|
|
str.reserve(MaxIPv4PlusPortStringSize);
|
2020-10-27 21:34:09 +00:00
|
|
|
char buf[128] = {0x0};
|
|
|
|
inet_ntop(AF_INET, &m_addr4.sin_addr.s_addr, buf, sizeof(buf));
|
|
|
|
str.append(buf);
|
2020-05-11 20:52:30 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
constexpr auto MaxIPv6PlusPortStringSize = 128;
|
|
|
|
str.reserve(MaxIPv6PlusPortStringSize);
|
2020-05-08 17:23:21 +00:00
|
|
|
|
2020-05-11 20:52:30 +00:00
|
|
|
char buf[128] = {0x0};
|
|
|
|
inet_ntop(AF_INET6, &m_addr.sin6_addr.s6_addr, buf, sizeof(buf));
|
2020-05-08 17:23:21 +00:00
|
|
|
|
2020-05-11 20:52:30 +00:00
|
|
|
str.append("[");
|
|
|
|
str.append(buf);
|
|
|
|
str.append("]");
|
|
|
|
}
|
2020-05-08 17:23:21 +00:00
|
|
|
|
|
|
|
str.append(1, ':');
|
2020-05-08 20:33:44 +00:00
|
|
|
str.append(std::to_string(getPort()));
|
2020-05-08 17:23:21 +00:00
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
SockAddr::isEmpty() const
|
|
|
|
{
|
|
|
|
return m_empty;
|
|
|
|
}
|
|
|
|
|
2021-03-02 18:18:22 +00:00
|
|
|
uint32_t
|
|
|
|
SockAddr::getIPv4() const
|
|
|
|
{
|
|
|
|
return m_addr4.sin_addr.s_addr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
SockAddr::setIPv4(uint32_t ip)
|
|
|
|
{
|
|
|
|
uint8_t* ip6 = m_addr.sin6_addr.s6_addr;
|
|
|
|
llarp::Zero(ip6, sizeof(m_addr.sin6_addr.s6_addr));
|
|
|
|
|
|
|
|
applyIPv4MapBytes();
|
|
|
|
|
|
|
|
std::memcpy(ip6 + 12, &ip, 4);
|
|
|
|
m_addr4.sin_addr.s_addr = ip;
|
|
|
|
m_empty = false;
|
|
|
|
}
|
|
|
|
|
2020-05-08 17:23:21 +00:00
|
|
|
void
|
|
|
|
SockAddr::setIPv4(uint8_t a, uint8_t b, uint8_t c, uint8_t d)
|
|
|
|
{
|
|
|
|
uint8_t* ip6 = m_addr.sin6_addr.s6_addr;
|
|
|
|
llarp::Zero(ip6, sizeof(m_addr.sin6_addr.s6_addr));
|
|
|
|
|
2021-02-24 23:34:42 +00:00
|
|
|
applyIPv4MapBytes();
|
2020-05-08 17:23:21 +00:00
|
|
|
|
|
|
|
ip6[12] = a;
|
|
|
|
ip6[13] = b;
|
|
|
|
ip6[14] = c;
|
|
|
|
ip6[15] = d;
|
2020-10-27 21:34:09 +00:00
|
|
|
const auto ip = ipaddr_ipv4_bits(a, b, c, d);
|
|
|
|
m_addr4.sin_addr.s_addr = htonl(ip.h);
|
2020-05-08 17:23:21 +00:00
|
|
|
m_empty = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
SockAddr::setPort(uint16_t port)
|
|
|
|
{
|
|
|
|
m_addr.sin6_port = htons(port);
|
2020-10-27 21:34:09 +00:00
|
|
|
m_addr4.sin_port = htons(port);
|
2020-05-08 17:23:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
uint16_t
|
|
|
|
SockAddr::getPort() const
|
|
|
|
{
|
|
|
|
return ntohs(m_addr.sin6_port);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::ostream&
|
|
|
|
operator<<(std::ostream& out, const SockAddr& address)
|
|
|
|
{
|
2020-05-11 16:17:41 +00:00
|
|
|
out << address.toString();
|
|
|
|
return out;
|
2020-05-08 17:23:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace llarp
|