diff --git a/toxcore/network.c b/toxcore/network.c index 55aa4e2818..b428ca07d0 100644 --- a/toxcore/network.c +++ b/toxcore/network.c @@ -586,6 +586,101 @@ 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 char *address, int family, Network_Addr **addrs) +{ + assert(addrs != nullptr); + *addrs = nullptr; + + struct addrinfo hints = {0}; + hints.ai_family = family; + // hints.ai_socktype = SOCK_DGRAM; // type of socket Tox uses. + + 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 size_t max_count = min_u64(SIZE_MAX, INT32_MAX) / sizeof(Network_Addr); + int result = 0; + + // we count number of "valid" results + for (struct addrinfo *walker = infos; walker != nullptr; walker = walker->ai_next) { + if (walker->ai_family == family || family == AF_UNSPEC) { + result++; + } + } + + assert(max_count >= result); + + // HACK: use default memory allocator + const Memory* mem = os_memory(); + + *addrs = (Network_Addr *)mem_valloc(mem, result, sizeof(Network_Addr)); + if (*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) { + (*addrs)[i].size = sizeof(struct sockaddr_storage); + (*addrs)[i].addr.ss_family = walker->ai_family; + + // according to sped, storage is supposed to be large enough (and source shows they are) + // storage is 128 bytes + assert(walker->ai_addrlen <= (*addrs)[i].size); + + memcpy(&(*addrs)[i].addr, walker->ai_addr, walker->ai_addrlen); + (*addrs)[i].size = walker->ai_addrlen; + + i++; + } + } + + assert(i == result); + + freeaddrinfo(infos); + + // number of entries in addrs + return result; +} + +non_null() +static int sys_getaddrinfo_dummy(void *obj, const char *address, int family, Network_Addr **addrs) +{ + return 0; +} + +non_null() +static int sys_freeaddrinfo(void *obj, Network_Addr *addrs) +{ + if (addrs == nullptr) { + return 0; + } + + // HACK: use default memory allocator + const Memory* mem = os_memory(); + mem_delete(mem, addrs); + + return 0; +} + +non_null() +static int sys_freeaddrinfo_dummy(void *obj, Network_Addr *addrs) +{ + return 0; +} + static const Network_Funcs os_network_funcs = { sys_close, sys_accept, @@ -600,8 +695,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) { @@ -620,6 +717,43 @@ const Network *os_network(void) return &os_network_obj; } +static const Network_Funcs os_network_no_dns_funcs = { + sys_close, + sys_accept, + sys_bind, + sys_listen, + sys_recvbuf, + sys_recv, + sys_recvfrom, + sys_send, + sys_sendto, + sys_socket, + sys_socket_nonblock, + sys_getsockopt, + sys_setsockopt, + sys_getaddrinfo_dummy, + sys_freeaddrinfo_dummy +}; + +static const Network os_network_no_dns_obj = {&os_network_no_dns_funcs, nullptr}; + +const Network *os_network_no_dns(void) +{ +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + if ((true)) { + return nullptr; + } +#endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */ +#ifdef OS_WIN32 + WSADATA wsaData; + + if (WSAStartup(MAKEWORD(2, 2), &wsaData) != NO_ERROR) { + return nullptr; + } +#endif /* OS_WIN32 */ + return &os_network_no_dns_obj; +} + #if 0 /* TODO(iphydf): Call this from functions that use `os_network()`. */ void os_network_deinit(const Network *ns) @@ -1833,19 +1967,16 @@ static int addr_resolve(const Network *ns, const char *address, IP *to, IP *extr 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. + Network_Addr* addrs = nullptr; + const int rc = ns->funcs->getaddrinfo(ns->obj, address, family, &addrs); - struct addrinfo *server = nullptr; - - const int rc = getaddrinfo(address, nullptr, &hints, &server); - - // Lookup failed. - if (rc != 0) { + // Lookup failed / empty. + if (rc <= 0) { return 0; } + assert(addrs != nullptr); + IP ip4; ip_init(&ip4, false); // ipv6enabled = false IP ip6; @@ -1854,16 +1985,16 @@ static int addr_resolve(const Network *ns, const char *address, IP *to, IP *extr 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; } @@ -1872,16 +2003,16 @@ static int addr_resolve(const Network *ns, const char *address, IP *to, IP *extr } 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; } @@ -1906,7 +2037,7 @@ static int addr_resolve(const Network *ns, const char *address, IP *to, IP *extr } } - freeaddrinfo(server); + ns->funcs->freeaddrinfo(ns->obj, addrs); return result; } diff --git a/toxcore/network.h b/toxcore/network.h index 06857b8917..f8bcbe382f 100644 --- a/toxcore/network.h +++ b/toxcore/network.h @@ -48,7 +48,7 @@ typedef Socket net_socket_cb(void *obj, int domain, int type, int proto); typedef int net_socket_nonblock_cb(void *obj, Socket sock, bool nonblock); typedef int net_getsockopt_cb(void *obj, Socket sock, int level, int optname, void *optval, size_t *optlen); typedef int net_setsockopt_cb(void *obj, Socket sock, int level, int optname, const void *optval, size_t optlen); -typedef int net_getaddrinfo_cb(void *obj, int family, Network_Addr **addrs); +typedef int net_getaddrinfo_cb(void *obj, const char *address, int family, Network_Addr **addrs); typedef int net_freeaddrinfo_cb(void *obj, Network_Addr *addrs); /** @brief Functions wrapping POSIX network functions. @@ -80,6 +80,7 @@ typedef struct Network { } Network; const Network *os_network(void); +const Network *os_network_no_dns(void); typedef struct Family { uint8_t value; diff --git a/toxcore/network_test_util.cc b/toxcore/network_test_util.cc index 758e49500d..18482fb93a 100644 --- a/toxcore/network_test_util.cc +++ b/toxcore/network_test_util.cc @@ -70,9 +70,9 @@ int Test_Network::setsockopt( { return net->funcs->setsockopt(net->obj, sock, level, optname, optval, optlen); } -int Test_Network::getaddrinfo(void *obj, int family, Network_Addr **addrs) +int Test_Network::getaddrinfo(void *obj, const char *address, int family, Network_Addr **addrs) { - return net->funcs->getaddrinfo(net->obj, family, addrs); + return net->funcs->getaddrinfo(net->obj, address, family, addrs); } int Test_Network::freeaddrinfo(void *obj, Network_Addr *addrs) { diff --git a/toxcore/network_test_util.hh b/toxcore/network_test_util.hh index 70f238aa92..197dcb3aea 100644 --- a/toxcore/network_test_util.hh +++ b/toxcore/network_test_util.hh @@ -60,7 +60,7 @@ class Test_Network : public Network_Class { void *obj, Socket sock, int level, int optname, void *optval, size_t *optlen) override; int setsockopt( void *obj, Socket sock, int level, int optname, const void *optval, size_t optlen) override; - int getaddrinfo(void *obj, int family, Network_Addr **addrs) override; + int getaddrinfo(void *obj, const char *address, int family, Network_Addr **addrs) override; int freeaddrinfo(void *obj, Network_Addr *addrs) override; };