lokinet/llarp/net/sock_addr.cpp
Thomas Winget 4c630e0437 Large collection of changes to make android work
- Previous android java and jni code updated to work, but with much love
  still needed to make it work nicely, e.g. handling when the VPN is
  turned off.

- DNS handling refactored to allow android to intercept and handle DNS
  requests as we can't set the system DNS to use a high port
  (and apparently Chrome ignores system DNS settings anyway)

- add packet router structure to allow separate handling of specific
  intercepted traffic, e.g. UDP traffic to port 53 gets handled by our
  DNS handler rather than being naively forwarded as exit traffic.

- For now, android lokinet is exit-only and hard-coded to use exit.loki
  as its exit.  The exit will be configurable before release, but
  allowing to not use exit-only mode is more of a challenge.

- some old gitignore remnants which were matching to things we don't
  want them to (and are no longer relevant) removed

- some minor changes to CI configuration
2021-03-02 13:18:22 -05:00

366 lines
7.8 KiB
C++

#include <net/sock_addr.hpp>
#include <net/address_info.hpp>
#include <net/ip.hpp>
#include <net/net_bits.hpp>
#include <util/str.hpp>
#include <util/logging/logger.hpp>
#include <util/mem.hpp>
#include <charconv>
#include <stdexcept>
namespace llarp
{
bool
operator==(const in6_addr& lh, const in6_addr& rh)
{
return memcmp(&lh, &rh, sizeof(in6_addr)) == 0;
}
/// shared utility functions
///
void
SockAddr::init()
{
llarp::Zero(&m_addr, sizeof(m_addr));
llarp::Zero(&m_addr4, sizeof(m_addr4));
}
void
SockAddr::applyIPv4MapBytes()
{
std::memcpy(m_addr.sin6_addr.s6_addr, ipv4_map_prefix.data(), ipv4_map_prefix.size());
}
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)
: SockAddr{a, b, c, d}
{
setPort(port);
}
SockAddr::SockAddr(uint32_t ip, uint16_t port)
{
init();
setIPv4(ip);
setPort(ntohs(port));
}
SockAddr::SockAddr(std::string_view addr)
{
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}
{
setPort(info.port);
}
SockAddr::SockAddr(const SockAddr& other)
{
*this = other;
}
SockAddr&
SockAddr::operator=(const SockAddr& other)
{
*this = other.m_addr;
return *this;
}
SockAddr::SockAddr(const sockaddr& addr)
{
*this = addr;
}
SockAddr&
SockAddr::operator=(const sockaddr& other)
{
if (other.sa_family == AF_INET6)
*this = reinterpret_cast<const sockaddr_in6&>(other);
else if (other.sa_family == AF_INET)
*this = reinterpret_cast<const sockaddr_in&>(other);
else
throw std::invalid_argument("Invalid sockaddr (not AF_INET or AF_INET6)");
return *this;
}
SockAddr::SockAddr(const sockaddr_in& addr)
{
*this = addr;
}
SockAddr&
SockAddr::operator=(const sockaddr_in& other)
{
init();
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));
m_addr.sin6_port = other.sin_port;
m_addr4.sin_addr.s_addr = other.sin_addr.s_addr;
m_addr4.sin_port = other.sin_port;
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));
if (ipv6_is_mapped_ipv4(other.sin6_addr))
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));
m_empty = false;
return *this;
}
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));
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;
return *this;
}
SockAddr::operator const sockaddr*() const
{
return (sockaddr*)&m_addr;
}
SockAddr::operator const sockaddr_in*() const
{
return &m_addr4;
}
SockAddr::operator const sockaddr_in6*() const
{
return &m_addr;
}
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
{
return m_addr.sin6_addr == other.m_addr.sin6_addr
and m_addr.sin6_port == other.m_addr.sin6_port;
}
huint128_t
SockAddr::asIPv6() const
{
return net::In6ToHUInt(m_addr.sin6_addr);
}
huint32_t
SockAddr::asIPv4() const
{
const nuint32_t n{m_addr4.sin_addr.s_addr};
return ToHost(n);
}
void
SockAddr::fromString(std::string_view str, bool allow_port)
{
if (str.empty())
{
init();
m_empty = true;
return;
}
// 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)
{
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;
}
// 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"));
std::array<uint8_t, 4> ipBytes;
for (int i = 0; i < 4; ++i)
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)
{
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);
}
setIPv4(ipBytes[0], ipBytes[1], ipBytes[2], ipBytes[3]);
}
std::string
SockAddr::toString() const
{
// TODO: review
if (isEmpty())
return "";
const uint8_t* ip6 = m_addr.sin6_addr.s6_addr;
std::string str;
if (ip6[10] == 0xff and ip6[11] == 0xff)
{
// handle IPv4 mapped addrs
constexpr auto MaxIPv4PlusPortStringSize = 22;
str.reserve(MaxIPv4PlusPortStringSize);
char buf[128] = {0x0};
inet_ntop(AF_INET, &m_addr4.sin_addr.s_addr, buf, sizeof(buf));
str.append(buf);
}
else
{
constexpr auto MaxIPv6PlusPortStringSize = 128;
str.reserve(MaxIPv6PlusPortStringSize);
char buf[128] = {0x0};
inet_ntop(AF_INET6, &m_addr.sin6_addr.s6_addr, buf, sizeof(buf));
str.append("[");
str.append(buf);
str.append("]");
}
str.append(1, ':');
str.append(std::to_string(getPort()));
return str;
}
bool
SockAddr::isEmpty() const
{
return m_empty;
}
uint32_t
SockAddr::getIPv4() const
{
return m_addr4.sin_addr.s_addr;
}
void
SockAddr::setIPv4(uint32_t ip)
{
m_addr.sin6_family = AF_INET;
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_addr4.sin_family = AF_INET;
m_empty = false;
}
void
SockAddr::setIPv4(uint8_t a, uint8_t b, uint8_t c, uint8_t d)
{
m_addr.sin6_family = AF_INET;
uint8_t* ip6 = m_addr.sin6_addr.s6_addr;
llarp::Zero(ip6, sizeof(m_addr.sin6_addr.s6_addr));
applyIPv4MapBytes();
ip6[12] = a;
ip6[13] = b;
ip6[14] = c;
ip6[15] = d;
const auto ip = ipaddr_ipv4_bits(a, b, c, d);
m_addr4.sin_addr.s_addr = htonl(ip.h);
m_addr4.sin_family = AF_INET;
m_empty = false;
}
void
SockAddr::setPort(uint16_t port)
{
m_addr.sin6_port = htons(port);
m_addr4.sin_port = htons(port);
}
uint16_t
SockAddr::getPort() const
{
return ntohs(m_addr.sin6_port);
}
std::ostream&
operator<<(std::ostream& out, const SockAddr& address)
{
out << address.toString();
return out;
}
} // namespace llarp