Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(net): implement the address resolution network struct functions #2773

Merged
merged 1 commit into from
Nov 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions auto_tests/network_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,15 @@ static void test_addr_resolv_localhost(void)
const Network *ns = os_network();
ck_assert(ns != nullptr);

const Memory *mem = os_memory();
ck_assert(mem != nullptr);

const char localhost[] = "localhost";

IP ip;
ip_init(&ip, 0); // ipv6enabled = 0

bool res = addr_resolve_or_parse_ip(ns, localhost, &ip, nullptr, true);
bool res = addr_resolve_or_parse_ip(ns, mem, localhost, &ip, nullptr, true);

int error = net_error();
char *strerror = net_new_strerror(error);
Expand All @@ -42,14 +45,14 @@ static void test_addr_resolv_localhost(void)
net_ip_ntoa(&ip, &ip_str));

ip_init(&ip, 1); // ipv6enabled = 1
res = addr_resolve_or_parse_ip(ns, localhost, &ip, nullptr, true);
res = addr_resolve_or_parse_ip(ns, mem, localhost, &ip, nullptr, true);

#if USE_IPV6

int localhost_split = 0;

if (!net_family_is_ipv6(ip.family)) {
res = addr_resolve_or_parse_ip(ns, "ip6-localhost", &ip, nullptr, true);
res = addr_resolve_or_parse_ip(ns, mem, "ip6-localhost", &ip, nullptr, true);
localhost_split = 1;
}

Expand All @@ -75,7 +78,7 @@ static void test_addr_resolv_localhost(void)
ip.family = net_family_unspec();
IP extra;
ip_reset(&extra);
res = addr_resolve_or_parse_ip(ns, localhost, &ip, &extra, true);
res = addr_resolve_or_parse_ip(ns, mem, localhost, &ip, &extra, true);
error = net_error();
strerror = net_new_strerror(error);
ck_assert_msg(res, "Resolver failed: %d, %s", error, strerror);
Expand Down
1 change: 1 addition & 0 deletions toxcore/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,7 @@ cc_library(
hdrs = ["network_test_util.hh"],
deps = [
":crypto_core",
":mem",
":network",
":test_util",
],
Expand Down
2 changes: 1 addition & 1 deletion toxcore/DHT.c
Original file line number Diff line number Diff line change
Expand Up @@ -1855,7 +1855,7 @@ bool dht_bootstrap_from_address(DHT *dht, const char *address, bool ipv6enabled,
ip_extra = &ip_port_v4.ip;
}

if (addr_resolve_or_parse_ip(dht->ns, address, &ip_port_v64.ip, ip_extra, dns_enabled)) {
if (addr_resolve_or_parse_ip(dht->ns, dht->mem, address, &ip_port_v64.ip, ip_extra, dns_enabled)) {
ip_port_v64.port = port;
dht_bootstrap(dht, &ip_port_v64, public_key);

Expand Down
185 changes: 135 additions & 50 deletions toxcore/network.c
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,92 @@ static int sys_setsockopt(void *obj, Socket sock, int level, int optname, const
return setsockopt(net_socket_to_native(sock), level, optname, (const char *)optval, optlen);
}

// sets and fills an array of addrs for address
// returns the number of entries in addrs
non_null()
static int sys_getaddrinfo(void *obj, const Memory *mem, const char *address, int family, int sock_type, Network_Addr **addrs)
{
assert(addrs != nullptr);

struct addrinfo hints = {0};
hints.ai_family = family;


// different platforms favour a different field
// hints.ai_socktype = SOCK_DGRAM; // type of socket Tox uses.
hints.ai_socktype = sock_type;
// hints.ai_protocol = protocol;

struct addrinfo *infos = nullptr;

const int rc = getaddrinfo(address, nullptr, &hints, &infos);

// Lookup failed.
if (rc != 0) {
// TODO(Green-Sky): log error
return 0;
}

const int32_t max_count = INT32_MAX / sizeof(Network_Addr);

// we count number of "valid" results
int result = 0;
for (struct addrinfo *walker = infos; walker != nullptr && result < max_count; walker = walker->ai_next) {
if (walker->ai_family == family || family == AF_UNSPEC) {
++result;
}

// do we need to check socktype/protocol?
}

assert(max_count >= result);

Network_Addr *tmp_addrs = (Network_Addr *)mem_valloc(mem, result, sizeof(Network_Addr));
if (tmp_addrs == nullptr) {
freeaddrinfo(infos);
return 0;
}

// now we fill in
int i = 0;
for (struct addrinfo *walker = infos; walker != nullptr; walker = walker->ai_next) {
if (walker->ai_family == family || family == AF_UNSPEC) {
tmp_addrs[i].size = sizeof(struct sockaddr_storage);
tmp_addrs[i].addr.ss_family = walker->ai_family;

// according to spec, storage is supposed to be large enough (and source shows they are)
// storage is 128 bytes
assert(walker->ai_addrlen <= tmp_addrs[i].size);

memcpy(&tmp_addrs[i].addr, walker->ai_addr, walker->ai_addrlen);
tmp_addrs[i].size = walker->ai_addrlen;

++i;
}
}

assert(i == result);

freeaddrinfo(infos);

*addrs = tmp_addrs;

// number of entries in addrs
return result;
}

non_null()
static int sys_freeaddrinfo(void *obj, const Memory *mem, Network_Addr *addrs)
{
if (addrs == nullptr) {
return 0;
}

mem_delete(mem, addrs);

return 0;
}

static const Network_Funcs os_network_funcs = {
sys_close,
sys_accept,
Expand All @@ -607,8 +693,10 @@ static const Network_Funcs os_network_funcs = {
sys_socket_nonblock,
sys_getsockopt,
sys_setsockopt,
sys_getaddrinfo,
sys_freeaddrinfo,
};
static const Network os_network_obj = {&os_network_funcs};
static const Network os_network_obj = {&os_network_funcs, nullptr};

const Network *os_network(void)
{
Expand Down Expand Up @@ -1828,8 +1916,8 @@ bool addr_parse_ip(const char *address, IP *to)
*
* @return false on failure, true on success.
*/
non_null(1, 2, 3) nullable(4)
static bool addr_resolve(const Network *ns, const char *address, IP *to, IP *extra)
non_null(1, 2, 3, 4) nullable(5)
static bool addr_resolve(const Network *ns, const Memory *mem, const char *address, IP *to, IP *extra)
{
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
if ((true)) {
Expand All @@ -1844,19 +1932,16 @@ static bool addr_resolve(const Network *ns, const char *address, IP *to, IP *ext
const Family tox_family = to->family;
const int family = make_family(tox_family);

struct addrinfo hints = {0};
hints.ai_family = family;
hints.ai_socktype = SOCK_DGRAM; // type of socket Tox uses.
Green-Sky marked this conversation as resolved.
Show resolved Hide resolved

struct addrinfo *server = nullptr;
Network_Addr *addrs = nullptr;
const int rc = ns->funcs->getaddrinfo(ns->obj, mem, address, family, 0, &addrs);

const int rc = getaddrinfo(address, nullptr, &hints, &server);

// Lookup failed.
if (rc != 0) {
// Lookup failed / empty.
if (rc <= 0) {
return false;
}

assert(addrs != nullptr);

IP ip4;
ip_init(&ip4, false); // ipv6enabled = false
IP ip6;
Expand All @@ -1865,16 +1950,16 @@ static bool addr_resolve(const Network *ns, const char *address, IP *to, IP *ext
int result = 0;
bool done = false;

for (struct addrinfo *walker = server; walker != nullptr && !done; walker = walker->ai_next) {
switch (walker->ai_family) {
for (int i = 0; i < rc && !done; ++i) {
switch (addrs[i].addr.ss_family) {
case AF_INET: {
if (walker->ai_family == family) { /* AF_INET requested, done */
const struct sockaddr_in *addr = (const struct sockaddr_in *)(const void *)walker->ai_addr;
if (addrs[i].addr.ss_family == family) { /* AF_INET requested, done */
const struct sockaddr_in *addr = (const struct sockaddr_in *)(const void *)&addrs[i].addr;
get_ip4(&to->ip.v4, &addr->sin_addr);
result = TOX_ADDR_RESOLVE_INET;
done = true;
} else if ((result & TOX_ADDR_RESOLVE_INET) == 0) { /* AF_UNSPEC requested, store away */
const struct sockaddr_in *addr = (const struct sockaddr_in *)(const void *)walker->ai_addr;
const struct sockaddr_in *addr = (const struct sockaddr_in *)(const void *)&addrs[i].addr;
get_ip4(&ip4.ip.v4, &addr->sin_addr);
result |= TOX_ADDR_RESOLVE_INET;
}
Expand All @@ -1883,16 +1968,16 @@ static bool addr_resolve(const Network *ns, const char *address, IP *to, IP *ext
}

case AF_INET6: {
if (walker->ai_family == family) { /* AF_INET6 requested, done */
if (walker->ai_addrlen == sizeof(struct sockaddr_in6)) {
const struct sockaddr_in6 *addr = (const struct sockaddr_in6 *)(void *)walker->ai_addr;
if (addrs[i].addr.ss_family == family) { /* AF_INET6 requested, done */
if (addrs[i].size == sizeof(struct sockaddr_in6)) {
const struct sockaddr_in6 *addr = (const struct sockaddr_in6 *)(void *)&addrs[i].addr;
get_ip6(&to->ip.v6, &addr->sin6_addr);
result = TOX_ADDR_RESOLVE_INET6;
done = true;
}
} else if ((result & TOX_ADDR_RESOLVE_INET6) == 0) { /* AF_UNSPEC requested, store away */
if (walker->ai_addrlen == sizeof(struct sockaddr_in6)) {
const struct sockaddr_in6 *addr = (const struct sockaddr_in6 *)(void *)walker->ai_addr;
if (addrs[i].size == sizeof(struct sockaddr_in6)) {
const struct sockaddr_in6 *addr = (const struct sockaddr_in6 *)(void *)&addrs[i].addr;
get_ip6(&ip6.ip.v6, &addr->sin6_addr);
result |= TOX_ADDR_RESOLVE_INET6;
}
Expand All @@ -1917,13 +2002,13 @@ static bool addr_resolve(const Network *ns, const char *address, IP *to, IP *ext
}
}

freeaddrinfo(server);
ns->funcs->freeaddrinfo(ns->obj, mem, addrs);
return result != 0;
}

bool addr_resolve_or_parse_ip(const Network *ns, const char *address, IP *to, IP *extra, bool dns_enabled)
bool addr_resolve_or_parse_ip(const Network *ns, const Memory *mem, const char *address, IP *to, IP *extra, bool dns_enabled)
{
if (dns_enabled && addr_resolve(ns, address, to, extra)) {
if (dns_enabled && addr_resolve(ns, mem, address, to, extra)) {
return true;
}

Expand Down Expand Up @@ -1982,7 +2067,7 @@ bool net_connect(const Network *ns, const Memory *mem, const Logger *log, Socket
return true;
}

int32_t net_getipport(const Memory *mem, const char *node, IP_Port **res, int tox_type, bool dns_enabled)
int32_t net_getipport(const Network *ns, const Memory *mem, const char *node, IP_Port **res, int tox_type, bool dns_enabled)
{
assert(node != nullptr);

Expand Down Expand Up @@ -2022,25 +2107,29 @@ int32_t net_getipport(const Memory *mem, const char *node, IP_Port **res, int to
}
#endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */

int type = make_socktype(tox_type);
// ugly
if (tox_type == -1) {
type = 0;
}

// It's not an IP address, so now we try doing a DNS lookup.
struct addrinfo *infos;
const int ret = getaddrinfo(node, nullptr, nullptr, &infos);
Network_Addr *addrs = nullptr;
const int rc = ns->funcs->getaddrinfo(ns->obj, mem, node, AF_UNSPEC, type, &addrs);

if (ret != 0) {
// Lookup failed / empty.
if (rc <= 0) {
return -1;
}

assert(addrs != nullptr);

// Used to avoid calloc parameter overflow
const size_t max_count = min_u64(SIZE_MAX, INT32_MAX) / sizeof(IP_Port);
const int type = make_socktype(tox_type);
size_t count = 0;

for (struct addrinfo *cur = infos; count < max_count && cur != nullptr; cur = cur->ai_next) {
if (cur->ai_socktype != 0 && type > 0 && cur->ai_socktype != type) {
continue;
}

if (cur->ai_family != AF_INET && cur->ai_family != AF_INET6) {
for (int i = 0; i < rc && count < max_count; ++i) {
if (addrs[i].addr.ss_family != AF_INET && addrs[i].addr.ss_family != AF_INET6) {
continue;
}

Expand All @@ -2050,40 +2139,36 @@ int32_t net_getipport(const Memory *mem, const char *node, IP_Port **res, int to
assert(count <= max_count);

if (count == 0) {
freeaddrinfo(infos);
ns->funcs->freeaddrinfo(ns->obj, mem, addrs);
return 0;
}

IP_Port *ip_port = (IP_Port *)mem_valloc(mem, count, sizeof(IP_Port));

if (ip_port == nullptr) {
freeaddrinfo(infos);
ns->funcs->freeaddrinfo(ns->obj, mem, addrs);
*res = nullptr;
return -1;
}

*res = ip_port;

for (struct addrinfo *cur = infos; cur != nullptr; cur = cur->ai_next) {
if (cur->ai_socktype != 0 && type > 0 && cur->ai_socktype != type) {
continue;
}

if (cur->ai_family == AF_INET) {
const struct sockaddr_in *addr = (const struct sockaddr_in *)(const void *)cur->ai_addr;
for (int i = 0; i < rc && count < max_count; ++i) {
if (addrs[i].addr.ss_family == AF_INET) {
const struct sockaddr_in *addr = (const struct sockaddr_in *)(const void *)&addrs[i].addr;
ip_port->ip.ip.v4.uint32 = addr->sin_addr.s_addr;
} else if (cur->ai_family == AF_INET6) {
const struct sockaddr_in6 *addr = (const struct sockaddr_in6 *)(const void *)cur->ai_addr;
} else if (addrs[i].addr.ss_family == AF_INET6) {
const struct sockaddr_in6 *addr = (const struct sockaddr_in6 *)(const void *)&addrs[i].addr;
memcpy(ip_port->ip.ip.v6.uint8, addr->sin6_addr.s6_addr, sizeof(IP6));
} else {
continue;
}

const Family *const family = make_tox_family(cur->ai_family);
const Family *const family = make_tox_family(addrs[i].addr.ss_family);
assert(family != nullptr);

if (family == nullptr) {
freeaddrinfo(infos);
ns->funcs->freeaddrinfo(ns->obj, mem, addrs);
return -1;
}

Expand All @@ -2092,7 +2177,7 @@ int32_t net_getipport(const Memory *mem, const char *node, IP_Port **res, int to
++ip_port;
}

freeaddrinfo(infos);
ns->funcs->freeaddrinfo(ns->obj, mem, addrs);

return count;
}
Expand Down
Loading
Loading