malcontent/nss/test_resolver.cc

193 lines
6.0 KiB
C++

// SPDX-FileCopyrightText: Matteo Settenvini <matteo.settenvini@montecristosoftware.eu>
// SPDX-License-Identifier: GPL-3.0-or-later
#include "testsuite.hh"
#include "resolver.hh"
#include <glib.h>
#include <array>
#include <format>
#include <netdb.h>
#include <sys/socket.h>
namespace /* anonymous */ {
auto resolver_valid_dns_address(gconstpointer addr_cstr) -> void;
auto resolver_invalid_dns_address(gconstpointer addr_cstr) -> void;
auto resolver_dns0eu_blocks_unsafe_domains(gconstpointer should_be_blocked_cstr) -> void;
auto resolver_cloudflare_family_blocks_unsafe_domains(gconstpointer should_be_blocked_cstr) -> void;
} // ~ namespace anonymous
auto define_resolver_tests() -> void {
auto valid_dns_addrs = std::array {
"192.168.0.1",
"192.168.0.1:53",
"192.168.0.1#dns.example.com",
"192.168.0.1:53#dns.example.com",
"192.168.0.1#",
"2345:0425:2ca1:0000:0000:0567:5673:23b5",
"2345:425:2ca1::567:5673:23b5",
"[2345::5673:23b5]:63",
"[2345::5673:23b5]:63#example.com",
"2345::5673:23b5#example.com",
"[2345::5673:23b5]:",
"[2345::5673:23b5]:#foo.bar",
"2345::5673:23b5#",
};
for (auto addr: valid_dns_addrs) {
g_test_add_data_func(std::format("/resolver/parses-valid-dns/{}", addr).c_str(),
addr, resolver_valid_dns_address);
}
auto invalid_dns_addrs = std::array {
"192.168.0.1.1",
"192.168.0.256",
"192.168..20",
"-192.168.0.1",
"192.168.0.1:",
"192.168.0.1:#foo.bar",
"2345:0425:2ca1:0000:0000:0567:5673:23b5:2020:2021",
"2345::5673::23b5",
"2345::5673:ghij",
"2345::5673:23b5:",
};
for (auto addr: invalid_dns_addrs) {
g_test_add_data_func(std::format("/resolver/rejects-invalid-dns/{}", addr).c_str(),
addr, resolver_invalid_dns_address);
}
// dns0.eu seems fairly good as blockfilters go
auto should_be_blocked_dns0 = std::array {
"pornhub.com",
"bookmaker.com",
"thepiratebay.org",
};
for (auto hostname : should_be_blocked_dns0) {
g_test_add_data_func(std::format("/resolver/kids.dns0.eu/blocks/{}", hostname).c_str(),
hostname, resolver_dns0eu_blocks_unsafe_domains);
}
// Cloudflare family seems far less restrictive
auto should_be_blocked_cff = std::array {
"pornhub.com",
"thepiratebay.org",
};
for (auto hostname : should_be_blocked_cff) {
g_test_add_data_func(std::format("/resolver/family.cloudflare-dns.com/blocks/{}", hostname).c_str(),
hostname, resolver_cloudflare_family_blocks_unsafe_domains);
}
}
namespace /* anonymous */ {
auto resolver_valid_dns_address(gconstpointer addr_cstr) -> void {
auto addr = static_cast<const char *>(addr_cstr);
try {
malcontent::Resolver resolver({ addr });
} catch (const std::exception& e) {
g_assert_unreachable(e.what());
}
}
auto resolver_invalid_dns_address(gconstpointer addr_cstr) -> void {
auto addr = static_cast<const char *>(addr_cstr);
try {
malcontent::Resolver resolver({ addr });
auto error = std::format("DNS addr parsing did not fail as expected for {}", addr);
g_assert_unreachable(error.c_str());
} catch (const std::invalid_argument& e) {
g_assert_true(std::string(e.what()).find("unable to parse DNS server address") != std::string::npos);
} catch (const std::exception& e) {
g_assert_unreachable(e.what());
}
}
auto resolver_dns0eu_blocks_unsafe_domains(gconstpointer should_be_blocked_cstr) -> void {
auto should_be_blocked = static_cast<const char *>(should_be_blocked_cstr);
try {
malcontent::Resolver resolver({
"193.110.81.1#kids.dns0.eu",
"2a0f:fc80::1#kids.dns0.eu",
"185.253.5.1#kids.dns0.eu",
"2a0f:fc81::1#kids.dns0.eu",
});
hostent result;
int local_errno{};
HErrno local_herrno{};
malcontent::ResolverArgs args {
.name = should_be_blocked,
.family = AF_INET,
.result = &result,
.buffer = nullptr,
.buflen = 0,
.errnop = &local_errno,
.h_errnop = &local_herrno,
.ttlp = nullptr,
};
resolver.resolve(args);
g_assert_cmpint(local_errno, ==, 0);
g_assert_true(local_herrno == HErrno::HostNotFound);
} catch (const std::exception& e) {
g_assert_unreachable(e.what());
}
}
auto resolver_cloudflare_family_blocks_unsafe_domains(gconstpointer should_be_blocked_cstr) -> void {
auto should_be_blocked = static_cast<const char *>(should_be_blocked_cstr);
const char NULL_NULL_NULL_NULL[] = { 0x0, 0x0, 0x0, 0x0 };
try {
malcontent::Resolver resolver({
"1.1.1.3#family.cloudflare-dns.com",
"1.0.0.3#family.cloudflare-dns.com",
"2606:4700:4700::1113#family.cloudflare-dns.com",
"2606:4700:4700::1003#family.cloudflare-dns.com",
});
constexpr size_t BUFLEN = 2056;
char buffer[BUFLEN];
hostent result;
int local_errno{};
HErrno local_herrno{};
malcontent::ResolverArgs args {
.name = should_be_blocked,
.family = AF_INET,
.result = &result,
.buffer = buffer,
.buflen = BUFLEN,
.errnop = &local_errno,
.h_errnop = &local_herrno,
.ttlp = nullptr,
};
resolver.resolve(args);
g_assert_cmpint(local_errno, ==, 0);
g_assert_true(local_herrno == HErrno::Success);
g_assert_cmpint(result.h_addrtype, ==, AF_INET);
g_assert_cmpint(result.h_length, ==, 4);
g_assert_nonnull(result.h_addr_list);
g_assert_cmpmem(*result.h_addr_list, result.h_length, NULL_NULL_NULL_NULL, 4);
g_assert_null(result.h_addr_list[1]);
} catch (const std::exception& e) {
g_assert_unreachable(e.what());
}
}
// TODO: TEST canary
} // ~ namespace anonymous