mirror of https://github.com/oxen-io/lokinet
Merge pull request #1262 from notlesh/bandaids-for-sockaddr-refactor-2020-05-11
Bandaids for sockaddr refactor 2020 05 11pull/1265/head
commit
a5b09c47e1
@ -0,0 +1,136 @@
|
||||
#include <net/ip_address.hpp>
|
||||
|
||||
#include <net/net.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
IpAddress::IpAddress(std::string_view str)
|
||||
{
|
||||
setAddress(str);
|
||||
}
|
||||
|
||||
IpAddress::IpAddress(std::string_view str, std::optional<uint16_t> port)
|
||||
{
|
||||
setAddress(str, port);
|
||||
}
|
||||
|
||||
IpAddress::IpAddress(const SockAddr& addr)
|
||||
{
|
||||
m_ipAddress = addr.toString();
|
||||
uint16_t port = addr.getPort();
|
||||
if (port > 0)
|
||||
m_port = port;
|
||||
|
||||
m_empty = addr.isEmpty();
|
||||
}
|
||||
|
||||
IpAddress&
|
||||
IpAddress::operator=(const sockaddr& other)
|
||||
{
|
||||
SockAddr addr(other);
|
||||
|
||||
m_ipAddress = addr.toString();
|
||||
uint16_t port = addr.getPort();
|
||||
if (port > 0)
|
||||
m_port = port;
|
||||
|
||||
m_empty = addr.isEmpty();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::optional<uint16_t>
|
||||
IpAddress::getPort() const
|
||||
{
|
||||
return m_port;
|
||||
}
|
||||
|
||||
void
|
||||
IpAddress::setPort(std::optional<uint16_t> port)
|
||||
{
|
||||
m_port = port;
|
||||
}
|
||||
|
||||
void
|
||||
IpAddress::setAddress(std::string_view str)
|
||||
{
|
||||
SockAddr addr;
|
||||
addr.fromString(str);
|
||||
|
||||
m_ipAddress = std::string(str);
|
||||
uint16_t port = addr.getPort();
|
||||
if (port > 0)
|
||||
m_port = port;
|
||||
|
||||
m_empty = addr.isEmpty();
|
||||
}
|
||||
|
||||
void
|
||||
IpAddress::setAddress(std::string_view str, std::optional<uint16_t> port)
|
||||
{
|
||||
SockAddr addr;
|
||||
addr.fromString(str);
|
||||
|
||||
m_ipAddress = std::string(str);
|
||||
m_port = port;
|
||||
|
||||
m_empty = addr.isEmpty();
|
||||
}
|
||||
|
||||
bool
|
||||
IpAddress::isIPv4()
|
||||
{
|
||||
throw std::runtime_error("FIXME - IpAddress::isIPv4()");
|
||||
}
|
||||
|
||||
bool
|
||||
IpAddress::isEmpty() const
|
||||
{
|
||||
return m_empty;
|
||||
}
|
||||
|
||||
SockAddr
|
||||
IpAddress::createSockAddr() const
|
||||
{
|
||||
SockAddr addr(m_ipAddress);
|
||||
if (m_port)
|
||||
addr.setPort(m_port.value());
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
bool
|
||||
IpAddress::isBogon() const
|
||||
{
|
||||
SockAddr addr(m_ipAddress);
|
||||
const sockaddr_in6* addr6 = addr;
|
||||
uint8_t* raw = addr6->sin6_addr.s6_addr;
|
||||
return IsIPv4Bogon(ipaddr_ipv4_bits(raw[12], raw[13], raw[14], raw[15]));
|
||||
}
|
||||
|
||||
std::string
|
||||
IpAddress::toString() const
|
||||
{
|
||||
return m_ipAddress; // TODO: port
|
||||
}
|
||||
|
||||
bool
|
||||
IpAddress::operator<(const IpAddress& other) const
|
||||
{
|
||||
return createSockAddr() < other.createSockAddr();
|
||||
}
|
||||
|
||||
bool
|
||||
IpAddress::operator==(const IpAddress& other) const
|
||||
{
|
||||
return createSockAddr() == other.createSockAddr();
|
||||
}
|
||||
|
||||
std::ostream&
|
||||
operator<<(std::ostream& out, const IpAddress& address)
|
||||
{
|
||||
out << address.toString();
|
||||
return out;
|
||||
}
|
||||
|
||||
} // namespace llarp
|
@ -0,0 +1,147 @@
|
||||
#pragma once
|
||||
|
||||
#include <net/sock_addr.hpp>
|
||||
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
#include <string>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
/// A struct that can represent either an IPv4 or IPv6 address. It is meant for representation
|
||||
/// purposes only (e.g. serialization/deserialization). In addition, it also optionally stores
|
||||
/// a port.
|
||||
///
|
||||
/// As a convenience, it can produce a SockAddr for dealing with network libraries which depend
|
||||
/// sockaddr structs. However, it does not keep this as a member variable and isn't responsible
|
||||
/// for its lifetime/memory/etc.
|
||||
///
|
||||
/// TODO: IPv6 is not currently supported.
|
||||
struct IpAddress
|
||||
{
|
||||
/// Empty constructor.
|
||||
IpAddress() = default;
|
||||
|
||||
/// Constructor. Takes a string which can be an IPv4 or IPv6 address optionally followed by
|
||||
/// a colon and a port.
|
||||
///
|
||||
/// Examples:
|
||||
///
|
||||
/// 127.0.0.1
|
||||
/// 1.2.3.4:53
|
||||
///
|
||||
/// Note that an IPv6 + port representation must be done in an unambiguous way, e.g. wrap the
|
||||
/// IP portion of the string in brackets: [IPv6Addr]:port
|
||||
///
|
||||
/// @param str is a string representing an IP address and optionally a port
|
||||
/// @throws std::invalid_argument if str cannot be parsed
|
||||
IpAddress(std::string_view str);
|
||||
|
||||
/// Constructor. Takes an IP address (as above) and a port. The string may not contain a port.
|
||||
///
|
||||
/// @param str is a string representing an IP address and optionally a port
|
||||
/// @throws std::invalid_argument if str cannot be parsed
|
||||
IpAddress(std::string_view str, std::optional<uint16_t> port);
|
||||
|
||||
/// Construct from a SockAddr.
|
||||
///
|
||||
/// @param addr is an SockAddr to initialize from.
|
||||
IpAddress(const SockAddr& addr);
|
||||
|
||||
IpAddress&
|
||||
operator=(const sockaddr& other);
|
||||
|
||||
/// Return the port. Returns -1 if no port has been provided.
|
||||
///
|
||||
/// @return the port, if present
|
||||
std::optional<uint16_t>
|
||||
getPort() const;
|
||||
|
||||
/// Set the port.
|
||||
///
|
||||
/// @param port
|
||||
void
|
||||
setPort(std::optional<uint16_t> port);
|
||||
|
||||
/// Set the IP address. Follows the same logic as the constructor with the same signature, but
|
||||
/// doesn't overwrite the port if the port isn't present in the string.
|
||||
void
|
||||
setAddress(std::string_view str);
|
||||
void
|
||||
setAddress(std::string_view str, std::optional<uint16_t> port);
|
||||
|
||||
/// Returns true if this is an IPv4 address (or an IPv6 address representing an IPv4 address)
|
||||
///
|
||||
/// TODO: could return an int (e.g. 4 or 6) or an enum
|
||||
///
|
||||
/// @return true if this is an IPv4 address, false otherwise
|
||||
bool
|
||||
isIPv4();
|
||||
|
||||
/// Returns true if this represents a valid IpAddress, false otherwise.
|
||||
///
|
||||
/// @return whether or not this IpAddress is empty
|
||||
bool
|
||||
isEmpty() const;
|
||||
|
||||
/// Creates an instance of SockAddr representing this IpAddress.
|
||||
///
|
||||
/// @return an instance of a SockAddr created from this IpAddress
|
||||
SockAddr
|
||||
createSockAddr() const;
|
||||
|
||||
/// Returns true if this IpAddress is a bogon, false otherwise
|
||||
///
|
||||
/// @return whether or not this IpAddress is a bogon
|
||||
bool
|
||||
isBogon() const;
|
||||
|
||||
/// Returns a string representing this IpAddress
|
||||
///
|
||||
/// @return string representation of this IpAddress
|
||||
std::string
|
||||
toString() const;
|
||||
|
||||
// TODO: other utility functions left over from Addr which may be useful
|
||||
// IsBogon() const;
|
||||
// isPrivate() const;
|
||||
// struct Hash
|
||||
// to string / stream / etc
|
||||
|
||||
bool
|
||||
operator<(const IpAddress& other) const;
|
||||
|
||||
bool
|
||||
operator==(const IpAddress& other) const;
|
||||
|
||||
struct Hash
|
||||
{
|
||||
std::size_t
|
||||
operator()(const IpAddress& address) const noexcept
|
||||
{
|
||||
(void)address;
|
||||
// throw std::runtime_error("FIXME: IpAddress::Hash"); // can't do this in operator(),
|
||||
// apparently, so hopefully it's me that stumbles upon this (if not, sorry!)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
if(a.af() == AF_INET)
|
||||
{
|
||||
return a.port() ^ a.addr4()->s_addr;
|
||||
}
|
||||
static const uint8_t empty[16] = {0};
|
||||
return (a.af() + memcmp(a.addr6(), empty, 16)) ^ a.port();
|
||||
*/
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
bool m_empty = true;
|
||||
std::string m_ipAddress;
|
||||
std::optional<uint16_t> m_port = std::nullopt;
|
||||
};
|
||||
|
||||
std::ostream&
|
||||
operator<<(std::ostream& out, const IpAddress& address);
|
||||
|
||||
} // namespace llarp
|
@ -1,505 +0,0 @@
|
||||
#include <net/net.hpp>
|
||||
#include <net/net_addr.hpp>
|
||||
#include <string_view>
|
||||
|
||||
// for addrinfo
|
||||
#ifndef _WIN32
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#else
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <wspiapi.h>
|
||||
#define inet_aton(x, y) inet_pton(AF_INET, x, y)
|
||||
#endif
|
||||
|
||||
#include <util/str.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
Addr::Addr()
|
||||
{
|
||||
llarp::Zero(&_addr4, sizeof(_addr4));
|
||||
_addr4.sin_family = AF_INET;
|
||||
llarp::Zero(&_addr, sizeof(_addr));
|
||||
_addr.sin6_family = AF_INET6;
|
||||
}
|
||||
Addr::~Addr() = default;
|
||||
|
||||
void
|
||||
Addr::port(uint16_t port)
|
||||
{
|
||||
_addr4.sin_port = htons(port);
|
||||
_addr.sin6_port = htons(port);
|
||||
}
|
||||
|
||||
in6_addr*
|
||||
Addr::addr6()
|
||||
{
|
||||
return (in6_addr*)&_addr.sin6_addr.s6_addr[0];
|
||||
}
|
||||
|
||||
in_addr*
|
||||
Addr::addr4()
|
||||
{
|
||||
return (in_addr*)&_addr.sin6_addr.s6_addr[12];
|
||||
}
|
||||
|
||||
const in6_addr*
|
||||
Addr::addr6() const
|
||||
{
|
||||
return (const in6_addr*)&_addr.sin6_addr.s6_addr[0];
|
||||
}
|
||||
|
||||
const in_addr*
|
||||
Addr::addr4() const
|
||||
{
|
||||
return (const in_addr*)&_addr.sin6_addr.s6_addr[12];
|
||||
}
|
||||
|
||||
Addr::Addr(std::string_view str) : Addr()
|
||||
{
|
||||
if (not FromString(str))
|
||||
throw std::invalid_argument(stringify("failed to parse bullshit value: ", str));
|
||||
}
|
||||
|
||||
Addr::Addr(std::string_view str, const uint16_t p_port) : Addr()
|
||||
{
|
||||
if (not FromString(str))
|
||||
throw std::invalid_argument(stringify("failed to parse bullshit value: ", str));
|
||||
this->port(p_port);
|
||||
}
|
||||
|
||||
Addr::Addr(std::string_view addr_str, std::string_view port_str)
|
||||
: Addr(addr_str, std::strtoul(port_str.data(), nullptr, 10))
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
Addr::FromString(std::string_view in)
|
||||
{
|
||||
// TODO: this will overwrite port, which may not be specified in the input string
|
||||
Zero(&_addr, sizeof(sockaddr_in6));
|
||||
|
||||
std::string ipPortion;
|
||||
auto pPosition = in.find(':');
|
||||
if (pPosition != std::string_view::npos)
|
||||
{
|
||||
// parse port
|
||||
const std::string portStr = std::string(in.substr(pPosition + 1));
|
||||
uint16_t port = std::atoi(portStr.c_str());
|
||||
this->port(port);
|
||||
|
||||
ipPortion = std::string(in.substr(0, pPosition));
|
||||
}
|
||||
else
|
||||
{
|
||||
ipPortion = std::string(in);
|
||||
}
|
||||
|
||||
struct addrinfo hint, *res = nullptr;
|
||||
int ret;
|
||||
|
||||
memset(&hint, '\0', sizeof hint);
|
||||
|
||||
hint.ai_family = PF_UNSPEC;
|
||||
hint.ai_flags = AI_NUMERICHOST;
|
||||
|
||||
if (pPosition != std::string_view::npos)
|
||||
{
|
||||
ret = getaddrinfo(
|
||||
std::string(in.begin(), in.begin() + pPosition).c_str(), nullptr, &hint, &res);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = getaddrinfo(std::string(in).c_str(), nullptr, &hint, &res);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
{
|
||||
LogError("failed to determine address family: ", in);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (res->ai_family == AF_INET6)
|
||||
{
|
||||
LogError("IPv6 address not supported yet", in);
|
||||
return false;
|
||||
}
|
||||
if (res->ai_family != AF_INET)
|
||||
{
|
||||
LogError("Address family not supported yet", in);
|
||||
return false;
|
||||
}
|
||||
|
||||
// put it in _addr4
|
||||
struct in_addr* addr = &_addr4.sin_addr;
|
||||
if (inet_aton(ipPortion.c_str(), addr) == 0)
|
||||
{
|
||||
LogError("failed to parse ", in);
|
||||
return false;
|
||||
}
|
||||
|
||||
_addr.sin6_family = res->ai_family;
|
||||
_addr4.sin_family = res->ai_family;
|
||||
#if ((__APPLE__ && __MACH__) || __FreeBSD__)
|
||||
_addr4.sin_len = sizeof(in_addr);
|
||||
#endif
|
||||
// set up SIIT
|
||||
uint8_t* addrptr = _addr.sin6_addr.s6_addr;
|
||||
addrptr[11] = 0xff;
|
||||
addrptr[10] = 0xff;
|
||||
memcpy(12 + addrptr, &addr->s_addr, sizeof(in_addr));
|
||||
freeaddrinfo(res);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Addr::from_4int(const uint8_t one, const uint8_t two, const uint8_t three, const uint8_t four)
|
||||
{
|
||||
Zero(&_addr, sizeof(sockaddr_in6));
|
||||
struct in_addr* addr = &_addr4.sin_addr;
|
||||
auto* ip = (unsigned char*)&(addr->s_addr);
|
||||
|
||||
_addr.sin6_family = AF_INET; // set ipv4 mode
|
||||
_addr4.sin_family = AF_INET;
|
||||
_addr4.sin_port = 0;
|
||||
|
||||
#if ((__APPLE__ && __MACH__) || __FreeBSD__)
|
||||
_addr4.sin_len = sizeof(in_addr);
|
||||
#endif
|
||||
// FIXME: watch endian
|
||||
ip[0] = one;
|
||||
ip[1] = two;
|
||||
ip[2] = three;
|
||||
ip[3] = four;
|
||||
// set up SIIT
|
||||
uint8_t* addrptr = _addr.sin6_addr.s6_addr;
|
||||
addrptr[11] = 0xff;
|
||||
addrptr[10] = 0xff;
|
||||
memcpy(12 + addrptr, &addr->s_addr, sizeof(in_addr));
|
||||
// copy ipv6 SIIT into _addr4
|
||||
memcpy(&_addr4.sin_addr.s_addr, addr4(), sizeof(in_addr));
|
||||
return true;
|
||||
}
|
||||
|
||||
Addr::Addr(const uint8_t one, const uint8_t two, const uint8_t three, const uint8_t four) : Addr()
|
||||
{
|
||||
this->from_4int(one, two, three, four);
|
||||
}
|
||||
|
||||
Addr::Addr(
|
||||
const uint8_t one,
|
||||
const uint8_t two,
|
||||
const uint8_t three,
|
||||
const uint8_t four,
|
||||
const uint16_t p_port)
|
||||
: Addr()
|
||||
{
|
||||
this->from_4int(one, two, three, four);
|
||||
this->port(p_port);
|
||||
}
|
||||
|
||||
Addr::Addr(const AddressInfo& other) : Addr()
|
||||
{
|
||||
memcpy(addr6(), other.ip.s6_addr, 16);
|
||||
_addr.sin6_port = htons(other.port);
|
||||
if (ipv6_is_siit(other.ip))
|
||||
{
|
||||
_addr4.sin_family = AF_INET;
|
||||
_addr4.sin_port = htons(other.port);
|
||||
_addr.sin6_family = AF_INET;
|
||||
memcpy(&_addr4.sin_addr.s_addr, addr4(), sizeof(in_addr));
|
||||
}
|
||||
else
|
||||
_addr.sin6_family = AF_INET6;
|
||||
}
|
||||
|
||||
Addr::Addr(const sockaddr_in& other) : Addr()
|
||||
{
|
||||
Zero(&_addr, sizeof(sockaddr_in6));
|
||||
_addr.sin6_family = AF_INET;
|
||||
uint8_t* addrptr = _addr.sin6_addr.s6_addr;
|
||||
uint16_t* port = &_addr.sin6_port;
|
||||
// SIIT
|
||||
memcpy(12 + addrptr, &((const sockaddr_in*)(&other))->sin_addr, sizeof(in_addr));
|
||||
addrptr[11] = 0xff;
|
||||
addrptr[10] = 0xff;
|
||||
*port = ((sockaddr_in*)(&other))->sin_port;
|
||||
_addr4.sin_family = AF_INET;
|
||||
_addr4.sin_port = *port;
|
||||
memcpy(&_addr4.sin_addr.s_addr, addr4(), sizeof(in_addr));
|
||||
}
|
||||
|
||||
Addr::Addr(const sockaddr_in6& other) : Addr()
|
||||
{
|
||||
memcpy(addr6(), other.sin6_addr.s6_addr, 16);
|
||||
_addr.sin6_port = htons(other.sin6_port);
|
||||
auto ptr = &_addr.sin6_addr.s6_addr[0];
|
||||
// TODO: detect SIIT better
|
||||
if (ptr[11] == 0xff && ptr[10] == 0xff && ptr[9] == 0 && ptr[8] == 0 && ptr[7] == 0
|
||||
&& ptr[6] == 0 && ptr[5] == 0 && ptr[4] == 0 && ptr[3] == 0 && ptr[2] == 0 && ptr[1] == 0
|
||||
&& ptr[0] == 0)
|
||||
{
|
||||
_addr4.sin_family = AF_INET;
|
||||
_addr4.sin_port = htons(other.sin6_port);
|
||||
_addr.sin6_family = AF_INET;
|
||||
memcpy(&_addr4.sin_addr.s_addr, addr4(), sizeof(in_addr));
|
||||
}
|
||||
else
|
||||
_addr.sin6_family = AF_INET6;
|
||||
}
|
||||
|
||||
Addr::Addr(const sockaddr& other) : Addr()
|
||||
{
|
||||
Zero(&_addr, sizeof(sockaddr_in6));
|
||||
_addr.sin6_family = other.sa_family;
|
||||
uint8_t* addrptr = _addr.sin6_addr.s6_addr;
|
||||
uint16_t* port = &_addr.sin6_port;
|
||||
switch (other.sa_family)
|
||||
{
|
||||
case AF_INET:
|
||||
// SIIT
|
||||
memcpy(12 + addrptr, &((const sockaddr_in*)(&other))->sin_addr, sizeof(in_addr));
|
||||
addrptr[11] = 0xff;
|
||||
addrptr[10] = 0xff;
|
||||
*port = ((sockaddr_in*)(&other))->sin_port;
|
||||
_addr4.sin_family = AF_INET;
|
||||
_addr4.sin_port = *port;
|
||||
memcpy(&_addr4.sin_addr.s_addr, addr4(), sizeof(in_addr));
|
||||
break;
|
||||
case AF_INET6:
|
||||
memcpy(addrptr, &((const sockaddr_in6*)(&other))->sin6_addr.s6_addr, 16);
|
||||
*port = ((sockaddr_in6*)(&other))->sin6_port;
|
||||
break;
|
||||
// TODO : sockaddr_ll
|
||||
default:
|
||||
throw std::invalid_argument("bad address family");
|
||||
}
|
||||
}
|
||||
|
||||
std::string
|
||||
Addr::ToString() const
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << (*this);
|
||||
return std::string(ss.str().c_str());
|
||||
}
|
||||
|
||||
std::ostream&
|
||||
operator<<(std::ostream& out, const Addr& a)
|
||||
{
|
||||
char tmp[128] = {0};
|
||||
const void* ptr = nullptr;
|
||||
if (a.af() == AF_INET6)
|
||||
{
|
||||
out << "[";
|
||||
ptr = a.addr6();
|
||||
}
|
||||
else
|
||||
{
|
||||
ptr = a.addr4();
|
||||
}
|
||||
if (inet_ntop(a.af(), (void*)ptr, tmp, sizeof(tmp)))
|
||||
{
|
||||
out << tmp;
|
||||
if (a.af() == AF_INET6)
|
||||
out << "]";
|
||||
}
|
||||
return out << ":" << a.port();
|
||||
}
|
||||
|
||||
void
|
||||
Addr::CopyInto(sockaddr* other) const
|
||||
{
|
||||
void *dst, *src;
|
||||
uint16_t* ptr;
|
||||
size_t slen;
|
||||
switch (af())
|
||||
{
|
||||
case AF_INET:
|
||||
{
|
||||
auto* ipv4_dst = (sockaddr_in*)other;
|
||||
dst = (void*)&ipv4_dst->sin_addr.s_addr;
|
||||
src = (void*)&_addr4.sin_addr.s_addr;
|
||||
ptr = &((sockaddr_in*)other)->sin_port;
|
||||
slen = sizeof(in_addr);
|
||||
break;
|
||||
}
|
||||
case AF_INET6:
|
||||
{
|
||||
dst = (void*)((sockaddr_in6*)other)->sin6_addr.s6_addr;
|
||||
src = (void*)_addr.sin6_addr.s6_addr;
|
||||
ptr = &((sockaddr_in6*)other)->sin6_port;
|
||||
slen = sizeof(in6_addr);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
memcpy(dst, src, slen);
|
||||
*ptr = htons(port());
|
||||
other->sa_family = af();
|
||||
}
|
||||
|
||||
int
|
||||
Addr::af() const
|
||||
{
|
||||
return _addr.sin6_family;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
Addr::port() const
|
||||
{
|
||||
return ntohs(_addr.sin6_port);
|
||||
}
|
||||
|
||||
Addr::operator const sockaddr*() const
|
||||
{
|
||||
if (af() == AF_INET)
|
||||
return (const sockaddr*)&_addr4;
|
||||
|
||||
return (const sockaddr*)&_addr;
|
||||
}
|
||||
|
||||
Addr::operator sockaddr*() const
|
||||
{
|
||||
if (af() == AF_INET)
|
||||
return (sockaddr*)&_addr4;
|
||||
|
||||
return (sockaddr*)&_addr;
|
||||
}
|
||||
|
||||
bool
|
||||
Addr::operator<(const Addr& other) const
|
||||
{
|
||||
if (af() == AF_INET && other.af() == AF_INET)
|
||||
return port() < other.port() || addr4()->s_addr < other.addr4()->s_addr;
|
||||
|
||||
return port() < other.port() || *addr6() < *other.addr6() || af() < other.af();
|
||||
}
|
||||
|
||||
bool
|
||||
Addr::operator==(const Addr& other) const
|
||||
{
|
||||
if (af() != other.af() || port() != other.port())
|
||||
return false;
|
||||
|
||||
if (af() == AF_INET)
|
||||
return addr4()->s_addr == other.addr4()->s_addr;
|
||||
|
||||
return memcmp(addr6(), other.addr6(), 16) == 0;
|
||||
}
|
||||
|
||||
Addr&
|
||||
Addr::operator=(const sockaddr& other)
|
||||
{
|
||||
Zero(&_addr, sizeof(sockaddr_in6));
|
||||
_addr.sin6_family = other.sa_family;
|
||||
uint8_t* addrptr = _addr.sin6_addr.s6_addr;
|
||||
uint16_t* port = &_addr.sin6_port;
|
||||
switch (other.sa_family)
|
||||
{
|
||||
case AF_INET:
|
||||
// SIIT
|
||||
memcpy(12 + addrptr, &((const sockaddr_in*)(&other))->sin_addr, sizeof(in_addr));
|
||||
addrptr[11] = 0xff;
|
||||
addrptr[10] = 0xff;
|
||||
*port = ((sockaddr_in*)(&other))->sin_port;
|
||||
_addr4.sin_family = AF_INET;
|
||||
_addr4.sin_port = *port;
|
||||
memcpy(&_addr4.sin_addr.s_addr, addr4(), sizeof(in_addr));
|
||||
break;
|
||||
case AF_INET6:
|
||||
memcpy(addrptr, &((const sockaddr_in6*)(&other))->sin6_addr.s6_addr, 16);
|
||||
*port = ((sockaddr_in6*)(&other))->sin6_port;
|
||||
break;
|
||||
// TODO : sockaddr_ll
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool
|
||||
Addr::sameAddr(const Addr& other) const
|
||||
{
|
||||
return memcmp(addr6(), other.addr6(), 16) == 0;
|
||||
}
|
||||
|
||||
bool
|
||||
Addr::operator!=(const Addr& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
bool
|
||||
Addr::isTenPrivate(uint32_t byte)
|
||||
{
|
||||
uint8_t byte1 = byte >> 24 & 0xff;
|
||||
return byte1 == 10;
|
||||
}
|
||||
|
||||
bool
|
||||
Addr::isOneSevenPrivate(uint32_t byte)
|
||||
{
|
||||
uint8_t byte1 = byte >> 24 & 0xff;
|
||||
uint8_t byte2 = (0x00ff0000 & byte) >> 16;
|
||||
return byte1 == 172 && (byte2 >= 16 || byte2 <= 31);
|
||||
}
|
||||
|
||||
bool
|
||||
Addr::isOneNinePrivate(uint32_t byte)
|
||||
{
|
||||
uint8_t byte1 = byte >> 24 & 0xff;
|
||||
uint8_t byte2 = (0x00ff0000 & byte) >> 16;
|
||||
return byte1 == 192 && byte2 == 168;
|
||||
}
|
||||
|
||||
/// return true if our ipv4 address is a bogon
|
||||
/// TODO: ipv6
|
||||
bool
|
||||
Addr::IsBogon() const
|
||||
{
|
||||
return IsIPv4Bogon(xtohl());
|
||||
}
|
||||
|
||||
socklen_t
|
||||
Addr::SockLen() const
|
||||
{
|
||||
if (af() == AF_INET)
|
||||
return sizeof(sockaddr_in);
|
||||
|
||||
return sizeof(sockaddr_in6);
|
||||
}
|
||||
|
||||
bool
|
||||
Addr::isPrivate() const
|
||||
{
|
||||
return IsBogon();
|
||||
}
|
||||
|
||||
bool
|
||||
Addr::isLoopback() const
|
||||
{
|
||||
return (ntohl(addr4()->s_addr)) >> 24 == 127;
|
||||
}
|
||||
|
||||
struct Hash
|
||||
{
|
||||
std::size_t
|
||||
operator()(Addr const& a) const noexcept
|
||||
{
|
||||
if (a.af() == AF_INET)
|
||||
{
|
||||
return a.port() ^ a.addr4()->s_addr;
|
||||
}
|
||||
static const uint8_t empty[16] = {0};
|
||||
return (a.af() + memcmp(a.addr6(), empty, 16)) ^ a.port();
|
||||
}
|
||||
}; // end struct Hash
|
||||
} // namespace llarp
|
@ -1,169 +0,0 @@
|
||||
#ifndef LLARP_NET_ADDR_HPP
|
||||
#define LLARP_NET_ADDR_HPP
|
||||
|
||||
#include <net/address_info.hpp>
|
||||
#include <net/net.h>
|
||||
#include <net/net.hpp>
|
||||
#include <net/net_int.hpp>
|
||||
|
||||
#include <string_view>
|
||||
#include <string>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
// real work
|
||||
struct Addr
|
||||
{
|
||||
// network order
|
||||
sockaddr_in6 _addr;
|
||||
sockaddr_in _addr4;
|
||||
~Addr();
|
||||
|
||||
Addr();
|
||||
|
||||
Addr(std::string_view str);
|
||||
|
||||
Addr(std::string_view str, const uint16_t p_port);
|
||||
|
||||
Addr(std::string_view addr_str, std::string_view port_str);
|
||||
|
||||
void
|
||||
port(uint16_t port);
|
||||
|
||||
in6_addr*
|
||||
addr6();
|
||||
|
||||
in_addr*
|
||||
addr4();
|
||||
|
||||
const in6_addr*
|
||||
addr6() const;
|
||||
|
||||
const in_addr*
|
||||
addr4() const;
|
||||
|
||||
bool
|
||||
FromString(std::string_view str);
|
||||
|
||||
bool
|
||||
from_4int(const uint8_t one, const uint8_t two, const uint8_t three, const uint8_t four);
|
||||
|
||||
Addr(const uint8_t one, const uint8_t two, const uint8_t three, const uint8_t four);
|
||||
|
||||
Addr(
|
||||
const uint8_t one,
|
||||
const uint8_t two,
|
||||
const uint8_t three,
|
||||
const uint8_t four,
|
||||
const uint16_t p_port);
|
||||
|
||||
Addr(const AddressInfo& other);
|
||||
Addr(const sockaddr_in& other);
|
||||
Addr(const sockaddr_in6& other);
|
||||
Addr(const sockaddr& other);
|
||||
|
||||
std::string
|
||||
ToString() const;
|
||||
|
||||
friend std::ostream&
|
||||
operator<<(std::ostream& out, const Addr& a);
|
||||
|
||||
operator const sockaddr*() const;
|
||||
|
||||
operator sockaddr*() const;
|
||||
|
||||
void
|
||||
CopyInto(sockaddr* other) const;
|
||||
|
||||
int
|
||||
af() const;
|
||||
|
||||
uint16_t
|
||||
port() const;
|
||||
|
||||
bool
|
||||
operator<(const Addr& other) const;
|
||||
|
||||
bool
|
||||
operator==(const Addr& other) const;
|
||||
|
||||
Addr&
|
||||
operator=(const sockaddr& other);
|
||||
|
||||
inline uint32_t
|
||||
tohl() const
|
||||
{
|
||||
return ntohl(addr4()->s_addr);
|
||||
}
|
||||
|
||||
inline huint32_t
|
||||
xtohl() const
|
||||
{
|
||||
return huint32_t{ntohl(addr4()->s_addr)};
|
||||
}
|
||||
|
||||
inline uint32_t
|
||||
ton() const
|
||||
{
|
||||
return addr4()->s_addr;
|
||||
}
|
||||
|
||||
inline nuint32_t
|
||||
xtonl() const
|
||||
{
|
||||
return nuint32_t{addr4()->s_addr};
|
||||
}
|
||||
|
||||
bool
|
||||
sameAddr(const Addr& other) const;
|
||||
|
||||
bool
|
||||
operator!=(const Addr& other) const;
|
||||
|
||||
inline uint32_t
|
||||
getHostLong()
|
||||
{
|
||||
in_addr_t addr = this->addr4()->s_addr;
|
||||
uint32_t byte = ntohl(addr);
|
||||
return byte;
|
||||
}
|
||||
|
||||
bool
|
||||
isTenPrivate(uint32_t byte);
|
||||
|
||||
bool
|
||||
isOneSevenPrivate(uint32_t byte);
|
||||
|
||||
bool
|
||||
isOneNinePrivate(uint32_t byte);
|
||||
|
||||
/// return true if our ipv4 address is a bogon
|
||||
/// TODO: ipv6
|
||||
bool
|
||||
IsBogon() const;
|
||||
|
||||
socklen_t
|
||||
SockLen() const;
|
||||
|
||||
bool
|
||||
isPrivate() const;
|
||||
|
||||
bool
|
||||
isLoopback() const;
|
||||
|
||||
struct Hash
|
||||
{
|
||||
std::size_t
|
||||
operator()(Addr const& a) const noexcept
|
||||
{
|
||||
if (a.af() == AF_INET)
|
||||
{
|
||||
return a.port() ^ a.addr4()->s_addr;
|
||||
}
|
||||
static const uint8_t empty[16] = {0};
|
||||
return (a.af() + memcmp(a.addr6(), empty, 16)) ^ a.port();
|
||||
}
|
||||
};
|
||||
}; // end struct
|
||||
} // namespace llarp
|
||||
#endif
|
@ -0,0 +1,321 @@
|
||||
#include <net/sock_addr.hpp>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <util/str.hpp>
|
||||
#include <util/logging/logger.hpp>
|
||||
#include <util/mem.hpp>
|
||||
|
||||
#include <charconv>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
/// shared utility functions
|
||||
///
|
||||
|
||||
void
|
||||
SockAddr::init()
|
||||
{
|
||||
llarp::Zero(&m_addr, sizeof(m_addr));
|
||||
}
|
||||
|
||||
void
|
||||
SockAddr::applySIITBytes()
|
||||
{
|
||||
uint8_t* ip6 = m_addr.sin6_addr.s6_addr;
|
||||
|
||||
// SIIT == Stateless IP/ICMP Translation (represent IPv4 with IPv6)
|
||||
ip6[10] = 0xff;
|
||||
ip6[11] = 0xff;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
init();
|
||||
setIPv4(a, b, c, d);
|
||||
setPort(port);
|
||||
}
|
||||
|
||||
SockAddr::SockAddr(std::string_view addr)
|
||||
{
|
||||
init();
|
||||
fromString(addr);
|
||||
}
|
||||
|
||||
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 = (const sockaddr_in6&)other;
|
||||
else if (other.sa_family == AF_INET)
|
||||
*this = (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();
|
||||
applySIITBytes();
|
||||
|
||||
// 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_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));
|
||||
|
||||
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));
|
||||
|
||||
m_empty = false;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
SockAddr::operator const sockaddr*() const
|
||||
{
|
||||
return (sockaddr*)&m_addr;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
if (m_addr.sin6_family != other.m_addr.sin6_family)
|
||||
return false;
|
||||
|
||||
if (getPort() != other.getPort())
|
||||
return false;
|
||||
|
||||
return (
|
||||
0
|
||||
== memcmp(
|
||||
m_addr.sin6_addr.s6_addr,
|
||||
other.m_addr.sin6_addr.s6_addr,
|
||||
sizeof(m_addr.sin6_addr.s6_addr)));
|
||||
}
|
||||
|
||||
void
|
||||
SockAddr::fromString(std::string_view str)
|
||||
{
|
||||
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)
|
||||
throw std::runtime_error("IPv6 not yet supported");
|
||||
|
||||
// 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"));
|
||||
|
||||
uint8_t ipBytes[4] = {0};
|
||||
|
||||
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"));
|
||||
}
|
||||
|
||||
// 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"));
|
||||
|
||||
setPort(port);
|
||||
}
|
||||
|
||||
setIPv4(ipBytes[0], ipBytes[1], ipBytes[2], ipBytes[3]);
|
||||
}
|
||||
|
||||
std::string
|
||||
SockAddr::toString() const
|
||||
{
|
||||
// TODO: review
|
||||
if (isEmpty())
|
||||
return "";
|
||||
|
||||
uint8_t* ip6 = m_addr.sin6_addr.s6_addr;
|
||||
std::string str;
|
||||
|
||||
if (ip6[10] == 0xff and ip6[11] == 0xff)
|
||||
{
|
||||
// treat SIIT like IPv4
|
||||
constexpr auto MaxIPv4PlusPortStringSize = 22;
|
||||
str.reserve(MaxIPv4PlusPortStringSize);
|
||||
|
||||
// TODO: ensure these don't each incur a memory allocation
|
||||
str.append(std::to_string(ip6[12]));
|
||||
str.append(1, '.');
|
||||
str.append(std::to_string(ip6[13]));
|
||||
str.append(1, '.');
|
||||
str.append(std::to_string(ip6[14]));
|
||||
str.append(1, '.');
|
||||
str.append(std::to_string(ip6[15]));
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
void
|
||||
SockAddr::setIPv4(uint8_t a, uint8_t b, uint8_t c, uint8_t d)
|
||||
{
|
||||
m_addr.sin6_family = AF_INET6;
|
||||
|
||||
uint8_t* ip6 = m_addr.sin6_addr.s6_addr;
|
||||
llarp::Zero(ip6, sizeof(m_addr.sin6_addr.s6_addr));
|
||||
|
||||
applySIITBytes();
|
||||
|
||||
ip6[12] = a;
|
||||
ip6[13] = b;
|
||||
ip6[14] = c;
|
||||
ip6[15] = d;
|
||||
|
||||
m_empty = false;
|
||||
}
|
||||
|
||||
void
|
||||
SockAddr::setPort(uint16_t port)
|
||||
{
|
||||
m_addr.sin6_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
|
@ -0,0 +1,84 @@
|
||||
#pragma once
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <string_view>
|
||||
#include <string>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
/// A simple SockAddr wrapper which provides a sockaddr_in (IPv4). Memory management is handled
|
||||
/// in constructor and destructor (if needed) and copying is disabled.
|
||||
struct SockAddr
|
||||
{
|
||||
SockAddr();
|
||||
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(const SockAddr&);
|
||||
SockAddr&
|
||||
operator=(const SockAddr&);
|
||||
|
||||
SockAddr(const sockaddr& addr);
|
||||
SockAddr&
|
||||
operator=(const sockaddr& addr);
|
||||
|
||||
SockAddr(const sockaddr_in& addr);
|
||||
SockAddr&
|
||||
operator=(const sockaddr_in& addr);
|
||||
|
||||
SockAddr(const sockaddr_in6& addr);
|
||||
SockAddr&
|
||||
operator=(const sockaddr_in6& addr);
|
||||
|
||||
SockAddr(const in6_addr& addr);
|
||||
SockAddr&
|
||||
operator=(const in6_addr& addr);
|
||||
|
||||
operator const sockaddr*() const;
|
||||
operator const sockaddr_in6*() const;
|
||||
|
||||
bool
|
||||
operator<(const SockAddr& other) const;
|
||||
|
||||
bool
|
||||
operator==(const SockAddr& other) const;
|
||||
|
||||
void
|
||||
fromString(std::string_view str);
|
||||
|
||||
std::string
|
||||
toString() const;
|
||||
|
||||
/// Returns true if this is an empty SockAddr, defined by having no IP address set. An empty IP
|
||||
/// address with a valid port is still considered empty.
|
||||
///
|
||||
/// @return true if this is empty, false otherwise
|
||||
bool
|
||||
isEmpty() const;
|
||||
|
||||
void
|
||||
setIPv4(uint8_t a, uint8_t b, uint8_t c, uint8_t d);
|
||||
|
||||
void
|
||||
setPort(uint16_t port);
|
||||
|
||||
uint16_t
|
||||
getPort() const;
|
||||
|
||||
private:
|
||||
bool m_empty = true;
|
||||
sockaddr_in6 m_addr;
|
||||
|
||||
void
|
||||
init();
|
||||
|
||||
void
|
||||
applySIITBytes();
|
||||
};
|
||||
|
||||
std::ostream&
|
||||
operator<<(std::ostream& out, const SockAddr& address);
|
||||
|
||||
} // namespace llarp
|
@ -1,13 +0,0 @@
|
||||
#include <net/net_addr.hpp>
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
TEST_CASE("Addr FromString", "[addr]")
|
||||
{
|
||||
llarp::Addr addr;
|
||||
bool success = false;
|
||||
CHECK_NOTHROW(success = addr.FromString("127.0.0.1:53"));
|
||||
CHECK(success == true);
|
||||
|
||||
CHECK(addr.port() == 53);
|
||||
CHECK(addr.ToString() == "127.0.0.1:53");
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
#include <net/ip_address.hpp>
|
||||
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
TEST_CASE("IpAddress empty constructor", "[IpAdress]")
|
||||
{
|
||||
llarp::IpAddress address;
|
||||
CHECK(address.isEmpty() == true);
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
#include <util/mem.hpp>
|
||||
#include <net/sock_addr.hpp>
|
||||
#include <net/net_if.hpp>
|
||||
#include <util/logging/logger.hpp>
|
||||
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
TEST_CASE("SockAddr from IPv4", "[SockAddr]")
|
||||
{
|
||||
llarp::SockAddr addr(1, 2, 3, 4);
|
||||
CHECK(addr.toString() == "1.2.3.4:0");
|
||||
}
|
||||
|
||||
TEST_CASE("SockAddr test port", "[SockAddr]")
|
||||
{
|
||||
llarp::SockAddr addr;
|
||||
addr.setPort(42);
|
||||
CHECK(addr.getPort() == 42);
|
||||
}
|
||||
|
||||
TEST_CASE("SockAddr fromString", "[SockAddr]")
|
||||
{
|
||||
llarp::SockAddr addr;
|
||||
CHECK_NOTHROW(addr.fromString("1.2.3.4"));
|
||||
CHECK(addr.toString() == "1.2.3.4:0");
|
||||
|
||||
CHECK(llarp::SockAddr("1.3.5.7").toString() == "1.3.5.7:0");
|
||||
|
||||
CHECK(llarp::SockAddr("0.0.0.0").toString() == "0.0.0.0:0");
|
||||
CHECK(llarp::SockAddr("0.0.0.0:0").toString() == "0.0.0.0:0");
|
||||
CHECK(llarp::SockAddr("255.255.255.255").toString() == "255.255.255.255:0");
|
||||
CHECK(llarp::SockAddr("255.255.255.255:255").toString() == "255.255.255.255:255");
|
||||
CHECK(llarp::SockAddr("255.255.255.255:65535").toString() == "255.255.255.255:65535");
|
||||
|
||||
CHECK_THROWS_WITH(llarp::SockAddr("abcd"), "abcd is not a valid IPv4 address");
|
||||
|
||||
CHECK_THROWS_WITH(llarp::SockAddr("0.0.0.0:foo"), "0.0.0.0:foo contains invalid port");
|
||||
|
||||
CHECK_THROWS_WITH(llarp::SockAddr("256.257.258.259"), "256.257.258.259 contains invalid number");
|
||||
|
||||
CHECK_THROWS_WITH(llarp::SockAddr("-1.-2.-3.-4"), "-1.-2.-3.-4 contains invalid number");
|
||||
|
||||
CHECK_THROWS_WITH(llarp::SockAddr("1.2.3"), "1.2.3 is not a valid IPv4 address");
|
||||
|
||||
CHECK_THROWS_WITH(llarp::SockAddr("1.2.3."), "1.2.3. is not a valid IPv4 address");
|
||||
|
||||
CHECK_THROWS_WITH(llarp::SockAddr(".1.2.3"), ".1.2.3 is not a valid IPv4 address");
|
||||
|
||||
CHECK_THROWS_WITH(llarp::SockAddr("1.2.3.4.5"), "1.2.3.4.5 is not a valid IPv4 address");
|
||||
|
||||
CHECK_THROWS_WITH(llarp::SockAddr("1.2.3. "), "1.2.3. contains invalid number");
|
||||
|
||||
CHECK_THROWS_WITH(llarp::SockAddr("1a.2b.3c.4z"), "1a.2b.3c.4z contains non-numeric values");
|
||||
|
||||
// TODO: there's no reason this couldn't be supported
|
||||
CHECK_THROWS_WITH(
|
||||
llarp::SockAddr("0xFF.0xFF.0xFF.0xFF"), "0xFF.0xFF.0xFF.0xFF contains non-numeric values");
|
||||
|
||||
CHECK_THROWS_WITH(llarp::SockAddr(""), "cannot construct IPv4 from empty string");
|
||||
|
||||
CHECK_THROWS_WITH(llarp::SockAddr(" "), " is not a valid IPv4 address");
|
||||
|
||||
CHECK_THROWS_WITH(llarp::SockAddr("1.2.3.4:65536"), "1.2.3.4:65536 contains invalid port");
|
||||
|
||||
CHECK_THROWS_WITH(llarp::SockAddr("1.2.3.4:1a"), "1.2.3.4:1a contains junk after port");
|
||||
}
|
||||
|
||||
TEST_CASE("SockAddr from sockaddr_in", "[SockAddr]")
|
||||
{
|
||||
sockaddr_in sin4;
|
||||
llarp::Zero(&sin4, sizeof(sockaddr_in));
|
||||
sin4.sin_family = AF_INET;
|
||||
sin4.sin_addr.s_addr = inet_addr("127.0.0.1");
|
||||
sin4.sin_port = htons(1234);
|
||||
|
||||
llarp::SockAddr addr(sin4);
|
||||
|
||||
CHECK(addr.toString() == "127.0.0.1:1234");
|
||||
}
|
||||
|
||||
TEST_CASE("SockAddr from sockaddr_in6", "[SockAddr]")
|
||||
{
|
||||
sockaddr_in6 sin6;
|
||||
llarp::Zero(&sin6, sizeof(sockaddr_in6));
|
||||
sin6.sin6_family = AF_INET6;
|
||||
inet_pton(AF_INET6, "::ffff:127.0.0.1", &sin6.sin6_addr);
|
||||
|
||||
sin6.sin6_port = htons(53);
|
||||
|
||||
llarp::SockAddr addr(sin6);
|
||||
|
||||
CHECK(addr.toString() == "127.0.0.1:53");
|
||||
}
|
Loading…
Reference in New Issue