Skip to content

Commit

Permalink
feat: implement the last 2 missing network struct functions
Browse files Browse the repository at this point in the history
and make use of them
  • Loading branch information
Green-Sky committed Nov 28, 2024
1 parent 29d1043 commit 95a1596
Show file tree
Hide file tree
Showing 8 changed files with 159 additions and 67 deletions.
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
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
183 changes: 134 additions & 49 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 @@ -1829,7 +1917,7 @@ 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)
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.

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

0 comments on commit 95a1596

Please sign in to comment.