diff --git a/src/common/dns_utils.cpp b/src/common/dns_utils.cpp index fd397a429..1216bc933 100644 --- a/src/common/dns_utils.cpp +++ b/src/common/dns_utils.cpp @@ -275,33 +275,13 @@ DNSResolver::DNSResolver() : m_data(new DNSResolverData()) ub_ctx_set_option(m_data->m_ub_context, string_copy("do-tcp:"), string_copy("yes")); } else { - // look for "/etc/resolv.conf" and "/etc/hosts" or platform equivalent + // Keep the system resolver and hosts. Wownero has no bundled DNSSEC + // probe or fallback resolvers to replace this initialized context. ub_ctx_resolvconf(m_data->m_ub_context, NULL); ub_ctx_hosts(m_data->m_ub_context, NULL); } add_anchors(m_data->m_ub_context); - - if (!DNS_PUBLIC) - { - // if no DNS_PUBLIC specified, we try a lookup to what we know - // should be a valid DNSSEC record, and switch to known good - // DNSSEC resolvers if verification fails - bool available, valid; - static const char *probe_hostname = ""; - auto records = get_txt_record(probe_hostname, available, valid); - if (!valid) - { - MINFO("Failed to verify DNSSEC record from " << probe_hostname << ", falling back to TCP with well known DNSSEC resolvers"); - ub_ctx_delete(m_data->m_ub_context); - m_data->m_ub_context = ub_ctx_create(); - add_anchors(m_data->m_ub_context); - for (const auto &ip: DEFAULT_DNS_PUBLIC_ADDR) - ub_ctx_set_fwd(m_data->m_ub_context, string_copy(ip)); - ub_ctx_set_option(m_data->m_ub_context, string_copy("do-udp:"), string_copy("no")); - ub_ctx_set_option(m_data->m_ub_context, string_copy("do-tcp:"), string_copy("yes")); - } - } } DNSResolver::~DNSResolver() diff --git a/tests/unit_tests/CMakeLists.txt b/tests/unit_tests/CMakeLists.txt index 2415dfea8..c8861121c 100644 --- a/tests/unit_tests/CMakeLists.txt +++ b/tests/unit_tests/CMakeLists.txt @@ -154,3 +154,21 @@ add_test( monero_add_minimal_executable(test_notifier test_notifier.cpp) target_link_libraries(test_notifier ${EXTRA_LIBRARIES}) set_property(TARGET test_notifier PROPERTY FOLDER "tests") + +# Isolate fake libunbound symbols from the network-dependent unit-test binary. +monero_add_minimal_executable(dns_resolver_configuration_tests + dns_resolver_configuration.cpp + ${CMAKE_SOURCE_DIR}/src/common/dns_utils.cpp) +target_compile_definitions(dns_resolver_configuration_tests PRIVATE + ub_ctx_create=dns_test_ctx_create + ub_ctx_delete=dns_test_ctx_delete + ub_ctx_resolvconf=dns_test_ctx_resolvconf + ub_ctx_hosts=dns_test_ctx_hosts + ub_ctx_set_fwd=dns_test_ctx_set_fwd + ub_ctx_set_option=dns_test_ctx_set_option + ub_ctx_add_ta=dns_test_ctx_add_ta + ub_resolve=dns_test_resolve + ub_resolve_free=dns_test_resolve_free) +target_include_directories(dns_resolver_configuration_tests PRIVATE ${UNBOUND_INCLUDE_DIR}) +target_link_libraries(dns_resolver_configuration_tests PRIVATE common ${GTEST_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${EXTRA_LIBRARIES}) +add_test(NAME dns_resolver_configuration_tests COMMAND dns_resolver_configuration_tests) diff --git a/tests/unit_tests/dns_resolver_configuration.cpp b/tests/unit_tests/dns_resolver_configuration.cpp new file mode 100644 index 000000000..ed79cf151 --- /dev/null +++ b/tests/unit_tests/dns_resolver_configuration.cpp @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: BSD-3-Clause +// A separate executable keeps fake libunbound symbols out of other unit tests. +#include +#include +#include +#include +#include +#include +#include "gtest/gtest.h" +#include "common/dns_utils.h" + +struct ub_ctx +{ + bool system_resolver = false; + bool hosts = false; + bool forwarder = false; +}; + +extern "C" +{ +ub_ctx* ub_ctx_create() { return new ub_ctx; } +void ub_ctx_delete(ub_ctx* context) { delete context; } +int ub_ctx_resolvconf(ub_ctx* context, const char*) { context->system_resolver = true; return 0; } +int ub_ctx_hosts(ub_ctx* context, const char*) { context->hosts = true; return 0; } +int ub_ctx_set_fwd(ub_ctx* context, const char*) { context->forwarder = true; return 0; } +int ub_ctx_set_option(ub_ctx*, const char*, const char*) { return 0; } +int ub_ctx_add_ta(ub_ctx*, const char*) { return 0; } + +int ub_resolve(ub_ctx* context, const char* name, int type, int, ub_result** output) +{ + *output = static_cast(std::calloc(1, sizeof(ub_result))); + std::string data; + if (std::strcmp(name, "seed.fixture.invalid") == 0 && type == tools::DNS_TYPE_TXT && + (context->system_resolver || context->forwarder)) + { + const std::string endpoint = "192.0.2.1:34567"; + data = std::string(1, static_cast(endpoint.size())) + endpoint; + } + if (std::strcmp(name, "host.fixture.invalid") == 0 && type == tools::DNS_TYPE_A && context->hosts) + data = std::string("\x7f\x00\x00\x07", 4); + if (!data.empty()) + { + (*output)->havedata = 1; + (*output)->data = static_cast(std::calloc(2, sizeof(char*))); + (*output)->data[0] = static_cast(std::malloc(data.size())); + std::memcpy((*output)->data[0], data.data(), data.size()); + (*output)->len = static_cast(std::malloc(sizeof(int))); + (*output)->len[0] = static_cast(data.size()); + } + return 0; +} + +void ub_resolve_free(ub_result* result) +{ + if (!result) return; + if (result->data) + { + for (char** data = result->data; *data; ++data) std::free(*data); + std::free(result->data); + } + std::free(result->len); + std::free(result); +} +} + +namespace +{ +class ResolverConfiguration : public testing::Test +{ + bool had_override = false; + std::string previous; +protected: + static void set_override(const char* value) + { +#ifdef _WIN32 + _putenv_s("DNS_PUBLIC", value ? value : ""); +#else + if (value) setenv("DNS_PUBLIC", value, 1); + else unsetenv("DNS_PUBLIC"); +#endif + } + void SetUp() override + { + const char* value = std::getenv("DNS_PUBLIC"); + had_override = value != nullptr; + if (value) previous = value; + set_override(nullptr); + } + void TearDown() override { set_override(had_override ? previous.c_str() : nullptr); } +}; + +TEST_F(ResolverConfiguration, KeepsSystemResolverWithoutBundledFallbacks) +{ + auto resolver = tools::DNSResolver::create(); + bool available, valid; + auto records = resolver.get_txt_record("seed.fixture.invalid", available, valid); + EXPECT_NE(records.end(), std::find(records.begin(), records.end(), "192.0.2.1:34567")); + EXPECT_FALSE(available); + EXPECT_FALSE(valid); +} + +TEST_F(ResolverConfiguration, KeepsSystemHostsWithoutBundledFallbacks) +{ + auto resolver = tools::DNSResolver::create(); + bool available, valid; + auto addresses = resolver.get_ipv4("host.fixture.invalid", available, valid); + EXPECT_NE(addresses.end(), std::find(addresses.begin(), addresses.end(), "127.0.0.7")); +} + +TEST_F(ResolverConfiguration, PreservesExplicitForwarderSelection) +{ + set_override("tcp://127.0.0.1"); + auto resolver = tools::DNSResolver::create(); + bool available, valid; + auto records = resolver.get_txt_record("seed.fixture.invalid", available, valid); + EXPECT_NE(records.end(), std::find(records.begin(), records.end(), "192.0.2.1:34567")); +} +}