diff --git a/toxcore/network.c b/toxcore/network.c index 55aa4e2818..193d5f87bd 100644 --- a/toxcore/network.c +++ b/toxcore/network.c @@ -586,6 +586,108 @@ 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, int sock_type, Network_Addr **addrs) +{ + assert(addrs != nullptr); + *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 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++; + } + + // do we need to check socktype/protocol? + } + + 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 spec, 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, int protocol, 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 +702,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 +724,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 +1974,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. - - struct addrinfo *server = nullptr; + Network_Addr* addrs = nullptr; + const int rc = ns->funcs->getaddrinfo(ns->obj, address, family, 0, &addrs); - 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 +1992,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 +2010,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 +2044,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; } @@ -1974,7 +2112,7 @@ bool net_connect(const Memory *mem, const Logger *log, Socket sock, const IP_Por return true; } -int32_t net_getipport(const Memory *mem, const char *node, IP_Port **res, int tox_type) +int32_t net_getipport(const Network *ns, const Memory *mem, const char *node, IP_Port **res, int tox_type) { assert(node != nullptr); @@ -2010,25 +2148,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, 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; } @@ -2038,40 +2180,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, 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, 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, addrs); return -1; } @@ -2080,7 +2218,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, addrs); return count; } diff --git a/toxcore/network.h b/toxcore/network.h index 06857b8917..046a1d7f1e 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, int protocol, 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; @@ -517,7 +518,7 @@ bool net_connect(const Memory *mem, const Logger *log, Socket sock, const IP_Por * @retval -1 on error. */ non_null() -int32_t net_getipport(const Memory *mem, const char *node, IP_Port **res, int tox_type); +int32_t net_getipport(const Network *ns, const Memory *mem, const char *node, IP_Port **res, int tox_type); /** Deallocates memory allocated by net_getipport */ non_null(1) nullable(2) diff --git a/toxcore/network_test_util.cc b/toxcore/network_test_util.cc index 758e49500d..3f207ed79f 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, int protocol, Network_Addr **addrs) { - return net->funcs->getaddrinfo(net->obj, family, addrs); + return net->funcs->getaddrinfo(net->obj, address, family, protocol, 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..2188626a93 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, int protocol, Network_Addr **addrs) override; int freeaddrinfo(void *obj, Network_Addr *addrs) override; }; diff --git a/toxcore/tox.c b/toxcore/tox.c index 03e34414a8..fb16b27651 100644 --- a/toxcore/tox.c +++ b/toxcore/tox.c @@ -1139,7 +1139,7 @@ static int32_t resolve_bootstrap_node(Tox *tox, const char *host, uint16_t port, return -1; } - const int32_t count = net_getipport(tox->sys.mem, host, root, TOX_SOCK_DGRAM); + const int32_t count = net_getipport(tox->sys.ns, tox->sys.mem, host, root, TOX_SOCK_DGRAM); if (count < 1) { LOGGER_DEBUG(tox->m->log, "could not resolve bootstrap node '%s'", host); diff --git a/toxcore/tox_private.c b/toxcore/tox_private.c index 7b6050a9f8..75a8b2dff1 100644 --- a/toxcore/tox_private.c +++ b/toxcore/tox_private.c @@ -124,7 +124,7 @@ bool tox_dht_get_nodes(const Tox *tox, const uint8_t *public_key, const char *ip IP_Port *root; - const int32_t count = net_getipport(tox->sys.mem, ip, &root, TOX_SOCK_DGRAM); + const int32_t count = net_getipport(tox->sys.ns, tox->sys.mem, ip, &root, TOX_SOCK_DGRAM); if (count < 1) { SET_ERROR_PARAMETER(error, TOX_ERR_DHT_GET_NODES_BAD_IP);