diff --git a/auto_tests/network_test.c b/auto_tests/network_test.c index 76cb94a17f..ebf3982708 100644 --- a/auto_tests/network_test.c +++ b/auto_tests/network_test.c @@ -28,7 +28,7 @@ static void test_addr_resolv_localhost(void) IP ip; ip_init(&ip, 0); // ipv6enabled = 0 - bool res = addr_resolve_or_parse_ip(ns, localhost, &ip, nullptr); + bool res = addr_resolve_or_parse_ip(ns, localhost, &ip, nullptr, true); int error = net_error(); char *strerror = net_new_strerror(error); @@ -42,14 +42,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); + res = addr_resolve_or_parse_ip(ns, 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); + res = addr_resolve_or_parse_ip(ns, "ip6-localhost", &ip, nullptr, true); localhost_split = 1; } @@ -75,7 +75,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); + res = addr_resolve_or_parse_ip(ns, localhost, &ip, &extra, true); error = net_error(); strerror = net_new_strerror(error); ck_assert_msg(res, "Resolver failed: %d, %s", error, strerror); diff --git a/other/DHT_bootstrap.c b/other/DHT_bootstrap.c index 8a15fb5e00..7dd552a60d 100644 --- a/other/DHT_bootstrap.c +++ b/other/DHT_bootstrap.c @@ -228,9 +228,12 @@ int main(int argc, char *argv[]) const uint16_t port = net_htons((uint16_t)port_conv); + // TODO(iphydf): Maybe disable and only use IP addresses? + const bool dns_enabled = true; + uint8_t *bootstrap_key = hex_string_to_bin(argv[argvoffset + 3]); const bool res = dht_bootstrap_from_address(dht, argv[argvoffset + 1], - ipv6enabled, port, bootstrap_key); + ipv6enabled, dns_enabled, port, bootstrap_key); free(bootstrap_key); if (!res) { diff --git a/other/bootstrap_daemon/src/config.c b/other/bootstrap_daemon/src/config.c index 891912dce1..725e23114f 100644 --- a/other/bootstrap_daemon/src/config.c +++ b/other/bootstrap_daemon/src/config.c @@ -377,6 +377,9 @@ bool bootstrap_from_config(const char *cfg_file_path, DHT *dht, bool enable_ipv6 bool address_resolved; uint8_t *bs_public_key_bin; + // TODO(iphydf): Maybe disable it and only use IP addresses? + const bool dns_enabled = true; + node = config_setting_get_elem(node_list, 0); if (node == nullptr) { @@ -416,7 +419,7 @@ bool bootstrap_from_config(const char *cfg_file_path, DHT *dht, bool enable_ipv6 } bs_public_key_bin = bootstrap_hex_string_to_bin(bs_public_key); - address_resolved = dht_bootstrap_from_address(dht, bs_address, enable_ipv6, net_htons(bs_port), + address_resolved = dht_bootstrap_from_address(dht, bs_address, enable_ipv6, dns_enabled, net_htons(bs_port), bs_public_key_bin); free(bs_public_key_bin); diff --git a/testing/Messenger_test.c b/testing/Messenger_test.c index 65ea8a9d2e..18d7347e66 100644 --- a/testing/Messenger_test.c +++ b/testing/Messenger_test.c @@ -118,10 +118,13 @@ int main(int argc, char *argv[]) exit(1); } + // TODO(iphydf): Maybe disable. + const bool dns_enabled = true; + const uint16_t port = net_htons((uint16_t)port_conv); uint8_t *bootstrap_key = hex_string_to_bin(argv[argvoffset + 3]); bool res = dht_bootstrap_from_address(m->dht, argv[argvoffset + 1], - ipv6enabled, port, bootstrap_key); + ipv6enabled, dns_enabled, port, bootstrap_key); free(bootstrap_key); if (!res) { diff --git a/toxcore/DHT.c b/toxcore/DHT.c index 2567d1b5a8..00ccb6c7ad 100644 --- a/toxcore/DHT.c +++ b/toxcore/DHT.c @@ -1840,7 +1840,7 @@ bool dht_bootstrap(DHT *dht, const IP_Port *ip_port, const uint8_t *public_key) return dht_getnodes(dht, ip_port, public_key, dht->self_public_key); } -bool dht_bootstrap_from_address(DHT *dht, const char *address, bool ipv6enabled, +bool dht_bootstrap_from_address(DHT *dht, const char *address, bool ipv6enabled, bool dns_enabled, uint16_t port, const uint8_t *public_key) { IP_Port ip_port_v64; @@ -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)) { + if (addr_resolve_or_parse_ip(dht->ns, address, &ip_port_v64.ip, ip_extra, dns_enabled)) { ip_port_v64.port = port; dht_bootstrap(dht, &ip_port_v64, public_key); diff --git a/toxcore/DHT.h b/toxcore/DHT.h index 19a9e1d937..38e98ba64f 100644 --- a/toxcore/DHT.h +++ b/toxcore/DHT.h @@ -404,12 +404,13 @@ bool dht_bootstrap(DHT *dht, const IP_Port *ip_port, const uint8_t *public_key); * @param address can be a hostname or an IP address (IPv4 or IPv6). * @param ipv6enabled if false, the resolving sticks STRICTLY to IPv4 addresses. * Otherwise, the resolving looks for IPv6 addresses first, then IPv4 addresses. + * @param dns_enabled if false, the resolving does not use DNS, only IP addresses are supported. * * @retval true if the address could be converted into an IP address * @retval false otherwise */ non_null() -bool dht_bootstrap_from_address(DHT *dht, const char *address, bool ipv6enabled, +bool dht_bootstrap_from_address(DHT *dht, const char *address, bool ipv6enabled, bool dns_enabled, uint16_t port, const uint8_t *public_key); /** @brief Start sending packets after DHT loaded_friends_list and loaded_clients_list are set. diff --git a/toxcore/Messenger.h b/toxcore/Messenger.h index cace3340b2..135423a599 100644 --- a/toxcore/Messenger.h +++ b/toxcore/Messenger.h @@ -86,6 +86,8 @@ typedef struct Messenger_Options { Messenger_State_Plugin *state_plugins; uint8_t state_plugins_length; + + bool dns_enabled; } Messenger_Options; struct Receipts { diff --git a/toxcore/network.c b/toxcore/network.c index 55aa4e2818..8a57a2d698 100644 --- a/toxcore/network.c +++ b/toxcore/network.c @@ -1815,19 +1815,19 @@ bool addr_parse_ip(const char *address, IP *to) * prefers v6 if `ip.family` was TOX_AF_UNSPEC and both available * Returns in `*extra` an IPv4 address, if family was TOX_AF_UNSPEC and `*to` is TOX_AF_INET6 * - * @return 0 on failure, `TOX_ADDR_RESOLVE_*` on success. + * @return false on failure, true on success. */ non_null(1, 2, 3) nullable(4) -static int addr_resolve(const Network *ns, const char *address, IP *to, IP *extra) +static bool addr_resolve(const Network *ns, const char *address, IP *to, IP *extra) { #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION if ((true)) { - return 0; + return false; } #endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */ if (address == nullptr || to == nullptr) { - return 0; + return false; } const Family tox_family = to->family; @@ -1843,7 +1843,7 @@ static int addr_resolve(const Network *ns, const char *address, IP *to, IP *extr // Lookup failed. if (rc != 0) { - return 0; + return false; } IP ip4; @@ -1907,18 +1907,16 @@ static int addr_resolve(const Network *ns, const char *address, IP *to, IP *extr } freeaddrinfo(server); - return result; + return result != 0; } -bool addr_resolve_or_parse_ip(const Network *ns, const char *address, IP *to, IP *extra) +bool addr_resolve_or_parse_ip(const Network *ns, const char *address, IP *to, IP *extra, bool dns_enabled) { - if (addr_resolve(ns, address, to, extra) == 0) { - if (!addr_parse_ip(address, to)) { - return false; - } + if (dns_enabled && addr_resolve(ns, address, to, extra)) { + return true; } - return true; + return addr_parse_ip(address, to); } bool net_connect(const Memory *mem, const Logger *log, Socket sock, const IP_Port *ip_port) @@ -1974,7 +1972,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 Memory *mem, const char *node, IP_Port **res, int tox_type, bool dns_enabled) { assert(node != nullptr); @@ -1996,6 +1994,10 @@ int32_t net_getipport(const Memory *mem, const char *node, IP_Port **res, int to return 1; } + if (!dns_enabled) { + return -1; + } + #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION if ((true)) { IP_Port *ip_port = (IP_Port *)mem_alloc(mem, sizeof(IP_Port)); diff --git a/toxcore/network.h b/toxcore/network.h index 06857b8917..bd781f1577 100644 --- a/toxcore/network.h +++ b/toxcore/network.h @@ -396,21 +396,22 @@ non_null() void ipport_copy(IP_Port *target, const IP_Port *source); /** - * Resolves string into an IP address + * @brief Resolves string into an IP address. * - * @param address a hostname (or something parseable to an IP address) - * @param to to.family MUST be initialized, either set to a specific IP version + * @param[in] address a hostname (or something parseable to an IP address). + * @param[in,out] to to.family MUST be initialized, either set to a specific IP version * (TOX_AF_INET/TOX_AF_INET6) or to the unspecified TOX_AF_UNSPEC (0), if both - * IP versions are acceptable - * @param extra can be NULL and is only set in special circumstances, see returns + * IP versions are acceptable. + * @param[out] extra can be NULL and is only set in special circumstances, see returns. + * @param[in] dns_enabled if false, DNS resolution is skipped. * - * Returns in `*to` a matching address (IPv6 or IPv4) - * Returns in `*extra`, if not NULL, an IPv4 address, if `to->family` was TOX_AF_UNSPEC + * Returns in `*to` a matching address (IPv6 or IPv4). + * Returns in `*extra`, if not NULL, an IPv4 address, if `to->family` was `TOX_AF_UNSPEC`. * * @return true on success, false on failure */ non_null(1, 2, 3) nullable(4) -bool addr_resolve_or_parse_ip(const Network *ns, const char *address, IP *to, IP *extra); +bool addr_resolve_or_parse_ip(const Network *ns, const char *address, IP *to, IP *extra, bool dns_enabled); /** @brief Function to receive data, ip and port of sender is put into ip_port. * Packet data is put into data. @@ -510,14 +511,20 @@ bool net_connect(const Memory *mem, const Logger *log, Socket sock, const IP_Por * address that can be specified by calling `net_connect()`, the port is ignored. * * Skip all addresses with socktype != type (use type = -1 to get all addresses) - * To correctly deallocate array memory use `net_freeipport()` + * To correctly deallocate array memory use `net_freeipport()`. + * + * @param mem Memory allocator. + * @param node The node parameter identifies the host or service on which to connect. + * @param[out] res An array of IP_Port structures will be allocated into this pointer. + * @param tox_type The type of socket to use (stream or datagram), only relevant for DNS lookups. + * @param dns_enabled If false, DNS resolution is skipped, when passed a hostname, this function will return an error. * * @return number of elements in res array. * @retval 0 if res array empty. * @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 Memory *mem, const char *node, IP_Port **res, int tox_type, bool dns_enabled); /** Deallocates memory allocated by net_getipport */ non_null(1) nullable(2) diff --git a/toxcore/tox.c b/toxcore/tox.c index 03e34414a8..f5887ce331 100644 --- a/toxcore/tox.c +++ b/toxcore/tox.c @@ -752,6 +752,8 @@ static Tox *tox_new_system(const struct Tox_Options *options, Tox_Err_New *error Messenger_Options m_options = {false}; + m_options.dns_enabled = tox_options_get_dns_enabled(opts); + bool load_savedata_sk = false; bool load_savedata_tox = false; @@ -855,9 +857,10 @@ static Tox *tox_new_system(const struct Tox_Options *options, Tox_Err_New *error } const char *const proxy_host = tox_options_get_proxy_host(opts); + const bool dns_enabled = tox_options_get_dns_enabled(opts); if (proxy_host == nullptr - || !addr_resolve_or_parse_ip(tox->sys.ns, proxy_host, &m_options.proxy_info.ip_port.ip, nullptr)) { + || !addr_resolve_or_parse_ip(tox->sys.ns, proxy_host, &m_options.proxy_info.ip_port.ip, nullptr, dns_enabled)) { SET_ERROR_PARAMETER(error, TOX_ERR_NEW_PROXY_BAD_HOST); // TODO(irungentoo): TOX_ERR_NEW_PROXY_NOT_FOUND if domain. mem_delete(sys->mem, tox); @@ -1139,7 +1142,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.mem, host, root, TOX_SOCK_DGRAM, tox->m->options.dns_enabled); if (count < 1) { LOGGER_DEBUG(tox->m->log, "could not resolve bootstrap node '%s'", host); diff --git a/toxcore/tox.h b/toxcore/tox.h index aea2db0e90..51f2a8659b 100644 --- a/toxcore/tox.h +++ b/toxcore/tox.h @@ -668,6 +668,22 @@ struct Tox_Options { * Default: false. */ bool experimental_groups_persistence; + + /** + * @brief Allow passing unresolved DNS hostnames to hostname parameters. + * + * Hostnames or IP addresses are passed to the bootstrap/add_tcp_relay function + * and proxy host options. If disabled, only IP addresses are allowed. + * + * If this is set to false, the library will not attempt to resolve hostnames. + * This is useful for clients that want to resolve hostnames themselves and + * pass the resolved IP addresses to the library (e.g. in case it wants to use Tor). + * Passing hostnames will result in a TOX_ERR_BOOTSTRAP_BAD_HOST error if this is + * set to false. + * + * Default: true. May become false in the future (0.3.0). + */ + bool dns_enabled; }; bool tox_options_get_ipv6_enabled(const Tox_Options *options); @@ -742,6 +758,10 @@ bool tox_options_get_experimental_groups_persistence(const Tox_Options *options) void tox_options_set_experimental_groups_persistence(Tox_Options *options, bool experimental_groups_persistence); +bool tox_options_get_dns_enabled(const Tox_Options *options); + +void tox_options_set_dns_enabled(Tox_Options *options, bool dns_enabled); + /** * @brief Initialises a Tox_Options object with the default options. * diff --git a/toxcore/tox_api.c b/toxcore/tox_api.c index 6d0d9851c7..d23e910241 100644 --- a/toxcore/tox_api.c +++ b/toxcore/tox_api.c @@ -274,6 +274,14 @@ void tox_options_set_experimental_groups_persistence( { options->experimental_groups_persistence = experimental_groups_persistence; } +bool tox_options_get_dns_enabled(const Tox_Options *options) +{ + return options->dns_enabled; +} +void tox_options_set_dns_enabled(Tox_Options *options, bool dns_enabled) +{ + options->dns_enabled = dns_enabled; +} const uint8_t *tox_options_get_savedata_data(const Tox_Options *options) { @@ -299,6 +307,7 @@ void tox_options_default(Tox_Options *options) tox_options_set_dht_announcements_enabled(options, true); tox_options_set_experimental_thread_safety(options, false); tox_options_set_experimental_groups_persistence(options, false); + tox_options_set_dns_enabled(options, true); } } diff --git a/toxcore/tox_private.c b/toxcore/tox_private.c index 7b6050a9f8..8c141ff9d2 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.mem, ip, &root, TOX_SOCK_DGRAM, tox->m->options.dns_enabled); if (count < 1) { SET_ERROR_PARAMETER(error, TOX_ERR_DHT_GET_NODES_BAD_IP);