Merge pull request #33534 from neighbourhoodie/tests/dns-query
Tests for DnsQuery functions
This commit is contained in:
@@ -243,6 +243,17 @@ executables += [
|
||||
],
|
||||
'include_directories' : resolve_includes,
|
||||
},
|
||||
test_template + {
|
||||
'sources' : [
|
||||
files('test-dns-query.c'),
|
||||
basic_dns_sources,
|
||||
systemd_resolved_sources,
|
||||
],
|
||||
'dependencies' : [
|
||||
systemd_resolved_dependencies,
|
||||
],
|
||||
'include_directories' : resolve_includes,
|
||||
},
|
||||
test_template + {
|
||||
'sources' : [
|
||||
files('test-resolved-stream.c'),
|
||||
|
||||
@@ -0,0 +1,883 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "log.h"
|
||||
#include "resolved-dns-query.h"
|
||||
#include "resolved-dns-rr.h"
|
||||
#include "resolved-dns-scope.h"
|
||||
#include "resolved-dns-server.h"
|
||||
#include "resolved-link.h"
|
||||
#include "resolved-manager.h"
|
||||
#include "tests.h"
|
||||
|
||||
static char* checked_strdup(const char *str) {
|
||||
char *copy = strdup(str);
|
||||
ASSERT_NOT_NULL(copy);
|
||||
return copy;
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
* dns_query_new()
|
||||
* ================================================================ */
|
||||
|
||||
TEST(dns_query_new_single_question) {
|
||||
Manager manager = {};
|
||||
_cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
|
||||
_cleanup_(dns_query_freep) DnsQuery *query = NULL;
|
||||
|
||||
ASSERT_OK(dns_question_new_address(&question, AF_INET, "www.example.com", false));
|
||||
ASSERT_NOT_NULL(question);
|
||||
|
||||
ASSERT_OK(dns_query_new(&manager, &query, question, NULL, NULL, 1, 0));
|
||||
ASSERT_NOT_NULL(query);
|
||||
}
|
||||
|
||||
TEST(dns_query_new_multi_question_same_domain) {
|
||||
Manager manager = {};
|
||||
_cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
|
||||
_cleanup_(dns_query_freep) DnsQuery *query = NULL;
|
||||
DnsResourceKey *key = NULL;
|
||||
|
||||
question = dns_question_new(2);
|
||||
ASSERT_NOT_NULL(question);
|
||||
|
||||
key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, "www.example.com");
|
||||
ASSERT_NOT_NULL(key);
|
||||
ASSERT_OK(dns_question_add(question, key, 0));
|
||||
dns_resource_key_unref(key);
|
||||
|
||||
key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_AAAA, "www.example.com");
|
||||
ASSERT_NOT_NULL(key);
|
||||
ASSERT_OK(dns_question_add(question, key, 0));
|
||||
dns_resource_key_unref(key);
|
||||
|
||||
ASSERT_OK(dns_query_new(&manager, &query, question, NULL, NULL, 1, 0));
|
||||
ASSERT_NOT_NULL(query);
|
||||
}
|
||||
|
||||
TEST(dns_query_new_multi_question_different_domain) {
|
||||
Manager manager = {};
|
||||
_cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
|
||||
_cleanup_(dns_query_freep) DnsQuery *query = NULL;
|
||||
DnsResourceKey *key = NULL;
|
||||
|
||||
question = dns_question_new(2);
|
||||
ASSERT_NOT_NULL(question);
|
||||
|
||||
key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, "ns1.example.com");
|
||||
ASSERT_NOT_NULL(key);
|
||||
ASSERT_OK(dns_question_add(question, key, 0));
|
||||
dns_resource_key_unref(key);
|
||||
|
||||
key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_AAAA, "ns2.example.com");
|
||||
ASSERT_NOT_NULL(key);
|
||||
ASSERT_OK(dns_question_add(question, key, 0));
|
||||
dns_resource_key_unref(key);
|
||||
|
||||
ASSERT_ERROR(dns_query_new(&manager, &query, question, NULL, NULL, 1, 0), EINVAL);
|
||||
ASSERT_NULL(query);
|
||||
}
|
||||
|
||||
#if HAVE_LIBIDN || HAVE_LIBIDN2
|
||||
TEST(dns_query_new_same_utf8_and_idna) {
|
||||
Manager manager = {};
|
||||
_cleanup_(dns_question_unrefp) DnsQuestion *q_utf8 = NULL, *q_idna = NULL;
|
||||
_cleanup_(dns_query_freep) DnsQuery *query = NULL;
|
||||
|
||||
ASSERT_OK(dns_question_new_address(&q_utf8, AF_INET, "www.\xF0\x9F\x98\xB1.com", false));
|
||||
ASSERT_NOT_NULL(q_utf8);
|
||||
|
||||
ASSERT_OK(dns_question_new_address(&q_idna, AF_INET, "www.\xF0\x9F\x98\xB1.com", true));
|
||||
ASSERT_NOT_NULL(q_idna);
|
||||
|
||||
ASSERT_OK(dns_query_new(&manager, &query, q_utf8, q_idna, NULL, 1, 0));
|
||||
ASSERT_NOT_NULL(query);
|
||||
}
|
||||
|
||||
TEST(dns_query_new_different_utf8_and_idna) {
|
||||
Manager manager = {};
|
||||
_cleanup_(dns_question_unrefp) DnsQuestion *q_utf8 = NULL, *q_idna = NULL;
|
||||
_cleanup_(dns_query_freep) DnsQuery *query = NULL;
|
||||
|
||||
ASSERT_OK(dns_question_new_address(&q_utf8, AF_INET, "www.\xF0\x9F\x98\xB1.com", false));
|
||||
ASSERT_NOT_NULL(q_utf8);
|
||||
|
||||
ASSERT_OK(dns_question_new_address(&q_idna, AF_INET, "www.\xF0\x9F\x8E\xBC.com", true));
|
||||
ASSERT_NOT_NULL(q_idna);
|
||||
|
||||
ASSERT_OK(dns_query_new(&manager, &query, q_utf8, q_idna, NULL, 1, 0));
|
||||
ASSERT_NOT_NULL(query);
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(dns_query_new_bypass_ok) {
|
||||
Manager manager = {};
|
||||
_cleanup_(dns_query_freep) DnsQuery *query = NULL;
|
||||
_cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL;
|
||||
_cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
|
||||
|
||||
ASSERT_OK(dns_packet_new_query(&packet, DNS_PROTOCOL_DNS, 0, false));
|
||||
ASSERT_NOT_NULL(packet);
|
||||
|
||||
ASSERT_OK(dns_question_new_address(&question, AF_INET, "www.example.com", false));
|
||||
ASSERT_NOT_NULL(question);
|
||||
|
||||
ASSERT_OK(dns_packet_append_question(packet, question));
|
||||
|
||||
ASSERT_OK(dns_query_new(&manager, &query, NULL, NULL, packet, 1, 0));
|
||||
ASSERT_NOT_NULL(query);
|
||||
}
|
||||
|
||||
TEST(dns_query_new_bypass_conflict) {
|
||||
Manager manager = {};
|
||||
_cleanup_(dns_query_freep) DnsQuery *query = NULL;
|
||||
_cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL;
|
||||
_cleanup_(dns_question_unrefp) DnsQuestion *question = NULL, *extra_q = NULL;
|
||||
|
||||
ASSERT_OK(dns_packet_new_query(&packet, DNS_PROTOCOL_DNS, 0, false));
|
||||
ASSERT_NOT_NULL(packet);
|
||||
|
||||
ASSERT_OK(dns_question_new_address(&question, AF_INET, "www.example.com", false));
|
||||
ASSERT_NOT_NULL(question);
|
||||
|
||||
ASSERT_OK(dns_packet_append_question(packet, question));
|
||||
|
||||
ASSERT_OK(dns_question_new_address(&extra_q, AF_INET, "www.example.com", false));
|
||||
ASSERT_NOT_NULL(extra_q);
|
||||
|
||||
ASSERT_ERROR(dns_query_new(&manager, &query, extra_q, NULL, packet, 1, 0), EINVAL);
|
||||
ASSERT_NULL(query);
|
||||
}
|
||||
|
||||
#define MAX_QUERIES 2048
|
||||
|
||||
TEST(dns_query_new_too_many_questions) {
|
||||
Manager manager = {};
|
||||
DnsQuestion *question = NULL;
|
||||
DnsQuery *queries[MAX_QUERIES + 1];
|
||||
|
||||
for (size_t i = 0; i < MAX_QUERIES; i++) {
|
||||
ASSERT_OK(dns_question_new_address(&question, AF_INET, "www.example.com", false));
|
||||
ASSERT_NOT_NULL(question);
|
||||
|
||||
ASSERT_OK(dns_query_new(&manager, &queries[i], question, NULL, NULL, 1, 0));
|
||||
ASSERT_NOT_NULL(queries[i]);
|
||||
|
||||
dns_question_unref(question);
|
||||
}
|
||||
|
||||
ASSERT_OK(dns_question_new_address(&question, AF_INET, "www.example.com", false));
|
||||
ASSERT_NOT_NULL(question);
|
||||
|
||||
ASSERT_ERROR(dns_query_new(&manager, &queries[MAX_QUERIES], question, NULL, NULL, 1, 0), EBUSY);
|
||||
dns_question_unref(question);
|
||||
|
||||
for (size_t i = 0; i < MAX_QUERIES; i++)
|
||||
dns_query_free(queries[i]);
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
* dns_query_make_auxiliary()
|
||||
* ================================================================ */
|
||||
|
||||
TEST(dns_query_make_auxiliary) {
|
||||
Manager manager = {};
|
||||
_cleanup_(dns_question_unrefp) DnsQuestion *qn1 = NULL, *qn2 = NULL, *qn3 = NULL;
|
||||
_cleanup_(dns_query_freep) DnsQuery *q1 = NULL, *q2 = NULL, *q3 = NULL;
|
||||
|
||||
ASSERT_OK(dns_question_new_address(&qn1, AF_INET, "www.example.com", false));
|
||||
ASSERT_NOT_NULL(qn1);
|
||||
ASSERT_OK(dns_query_new(&manager, &q1, qn1, NULL, NULL, 1, 0));
|
||||
ASSERT_NOT_NULL(q1);
|
||||
|
||||
ASSERT_OK(dns_question_new_address(&qn2, AF_INET, "www.example.net", false));
|
||||
ASSERT_NOT_NULL(qn2);
|
||||
ASSERT_OK(dns_query_new(&manager, &q2, qn2, NULL, NULL, 1, 0));
|
||||
ASSERT_NOT_NULL(q2);
|
||||
|
||||
ASSERT_OK(dns_question_new_address(&qn3, AF_INET, "www.example.org", false));
|
||||
ASSERT_NOT_NULL(qn3);
|
||||
ASSERT_OK(dns_query_new(&manager, &q3, qn3, NULL, NULL, 1, 0));
|
||||
ASSERT_NOT_NULL(q3);
|
||||
|
||||
ASSERT_OK(dns_query_make_auxiliary(q2, q1));
|
||||
ASSERT_OK(dns_query_make_auxiliary(q3, q1));
|
||||
|
||||
ASSERT_EQ(q1->n_auxiliary_queries, 2u);
|
||||
ASSERT_TRUE(q1->auxiliary_queries == q3);
|
||||
ASSERT_TRUE(q1->auxiliary_queries->auxiliary_queries_next == q2);
|
||||
|
||||
ASSERT_TRUE(q2->auxiliary_for == q1);
|
||||
ASSERT_TRUE(q3->auxiliary_for == q1);
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
* dns_query_process_cname_one()
|
||||
* ================================================================ */
|
||||
|
||||
TEST(dns_query_process_cname_one_null) {
|
||||
Manager manager = {};
|
||||
_cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
|
||||
_cleanup_(dns_query_freep) DnsQuery *query = NULL;
|
||||
|
||||
ASSERT_OK(dns_question_new_address(&question, AF_INET, "www.example.com", false));
|
||||
ASSERT_NOT_NULL(question);
|
||||
|
||||
ASSERT_OK(dns_query_new(&manager, &query, NULL, question, NULL, 1, 0));
|
||||
ASSERT_NOT_NULL(query);
|
||||
|
||||
ASSERT_EQ(dns_query_process_cname_one(query), DNS_QUERY_MATCH);
|
||||
}
|
||||
|
||||
TEST(dns_query_process_cname_one_success_exact_match) {
|
||||
Manager manager = {};
|
||||
_cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
|
||||
_cleanup_(dns_query_freep) DnsQuery *query = NULL;
|
||||
DnsResourceRecord *rr = NULL;
|
||||
|
||||
ASSERT_OK(dns_question_new_address(&question, AF_INET, "www.example.com", false));
|
||||
ASSERT_NOT_NULL(question);
|
||||
|
||||
ASSERT_OK(dns_query_new(&manager, &query, NULL, question, NULL, 1, 0));
|
||||
ASSERT_NOT_NULL(query);
|
||||
|
||||
query->state = DNS_TRANSACTION_SUCCESS;
|
||||
query->answer_protocol = DNS_PROTOCOL_DNS;
|
||||
query->answer_family = AF_INET;
|
||||
query->answer = dns_answer_new(1);
|
||||
ASSERT_NOT_NULL(query->answer);
|
||||
|
||||
rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, "www.example.com");
|
||||
ASSERT_NOT_NULL(rr);
|
||||
rr->ttl = 3600;
|
||||
rr->a.in_addr.s_addr = htobe32(0xc0a8017f);
|
||||
dns_answer_add(query->answer, rr, 1, 0, NULL);
|
||||
dns_resource_record_unref(rr);
|
||||
|
||||
ASSERT_EQ(dns_query_process_cname_one(query), DNS_QUERY_MATCH);
|
||||
|
||||
ASSERT_EQ(query->n_cname_redirects, 0u);
|
||||
}
|
||||
|
||||
TEST(dns_query_process_cname_one_success_no_match) {
|
||||
Manager manager = {};
|
||||
_cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
|
||||
_cleanup_(dns_query_freep) DnsQuery *query = NULL;
|
||||
DnsResourceRecord *rr = NULL;
|
||||
|
||||
ASSERT_OK(dns_question_new_address(&question, AF_INET, "www.example.com", false));
|
||||
ASSERT_NOT_NULL(question);
|
||||
|
||||
ASSERT_OK(dns_query_new(&manager, &query, NULL, question, NULL, 1, 0));
|
||||
ASSERT_NOT_NULL(query);
|
||||
|
||||
query->state = DNS_TRANSACTION_SUCCESS;
|
||||
query->answer_protocol = DNS_PROTOCOL_DNS;
|
||||
query->answer_family = AF_INET;
|
||||
query->answer = dns_answer_new(1);
|
||||
ASSERT_NOT_NULL(query->answer);
|
||||
|
||||
rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, "tmp.example.com");
|
||||
ASSERT_NOT_NULL(rr);
|
||||
rr->ttl = 3600;
|
||||
rr->a.in_addr.s_addr = htobe32(0xc0a8017f);
|
||||
dns_answer_add(query->answer, rr, 1, 0, NULL);
|
||||
dns_resource_record_unref(rr);
|
||||
|
||||
ASSERT_EQ(dns_query_process_cname_one(query), DNS_QUERY_NOMATCH);
|
||||
|
||||
ASSERT_EQ(query->n_cname_redirects, 0u);
|
||||
}
|
||||
|
||||
TEST(dns_query_process_cname_one_success_match_cname) {
|
||||
Manager manager = {};
|
||||
_cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
|
||||
_cleanup_(dns_query_freep) DnsQuery *query = NULL;
|
||||
DnsResourceRecord *rr = NULL;
|
||||
DnsResourceKey *key = NULL;
|
||||
|
||||
ASSERT_OK(dns_question_new_address(&question, AF_INET, "www.example.com", false));
|
||||
ASSERT_NOT_NULL(question);
|
||||
|
||||
ASSERT_OK(dns_query_new(&manager, &query, NULL, question, NULL, 1, 0));
|
||||
ASSERT_NOT_NULL(query);
|
||||
|
||||
query->state = DNS_TRANSACTION_SUCCESS;
|
||||
query->answer_protocol = DNS_PROTOCOL_DNS;
|
||||
query->answer_family = AF_INET;
|
||||
query->answer_query_flags = SD_RESOLVED_FROM_NETWORK;
|
||||
query->answer = dns_answer_new(1);
|
||||
ASSERT_NOT_NULL(query->answer);
|
||||
|
||||
rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_CNAME, "www.example.com");
|
||||
ASSERT_NOT_NULL(rr);
|
||||
rr->ttl = 3600;
|
||||
rr->cname.name = checked_strdup("example.com");
|
||||
dns_answer_add(query->answer, rr, 1, 0, NULL);
|
||||
dns_resource_record_unref(rr);
|
||||
|
||||
ASSERT_EQ(dns_query_process_cname_one(query), DNS_QUERY_CNAME);
|
||||
|
||||
ASSERT_FALSE(dns_query_fully_authenticated(query));
|
||||
ASSERT_FALSE(dns_query_fully_confidential(query));
|
||||
ASSERT_FALSE(dns_query_fully_authoritative(query));
|
||||
|
||||
ASSERT_GT(query->flags & SD_RESOLVED_NO_SEARCH, 0u);
|
||||
|
||||
ASSERT_EQ(query->n_cname_redirects, 1u);
|
||||
|
||||
ASSERT_EQ(dns_question_size(query->collected_questions), 1u);
|
||||
ASSERT_NULL(query->question_utf8);
|
||||
ASSERT_EQ(dns_question_size(query->question_idna), 1u);
|
||||
|
||||
key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, "www.example.com");
|
||||
ASSERT_NOT_NULL(key);
|
||||
ASSERT_TRUE(dns_question_contains_key(query->collected_questions, key));
|
||||
dns_resource_key_unref(key);
|
||||
|
||||
key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, "example.com");
|
||||
ASSERT_NOT_NULL(key);
|
||||
ASSERT_TRUE(dns_question_contains_key(query->question_idna, key));
|
||||
dns_resource_key_unref(key);
|
||||
}
|
||||
|
||||
TEST(dns_query_process_cname_one_success_flags) {
|
||||
Manager manager = {};
|
||||
_cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
|
||||
_cleanup_(dns_query_freep) DnsQuery *query = NULL;
|
||||
DnsResourceRecord *rr = NULL;
|
||||
|
||||
ASSERT_OK(dns_question_new_address(&question, AF_INET, "www.example.com", false));
|
||||
ASSERT_NOT_NULL(question);
|
||||
|
||||
ASSERT_OK(dns_query_new(&manager, &query, NULL, question, NULL, 1, 0));
|
||||
ASSERT_NOT_NULL(query);
|
||||
|
||||
query->state = DNS_TRANSACTION_SUCCESS;
|
||||
query->answer_protocol = DNS_PROTOCOL_DNS;
|
||||
query->answer_family = AF_INET;
|
||||
query->answer = dns_answer_new(1);
|
||||
ASSERT_NOT_NULL(query->answer);
|
||||
|
||||
query->answer_query_flags = SD_RESOLVED_FROM_NETWORK |
|
||||
SD_RESOLVED_AUTHENTICATED |
|
||||
SD_RESOLVED_CONFIDENTIAL |
|
||||
SD_RESOLVED_SYNTHETIC;
|
||||
|
||||
rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_CNAME, "www.example.com");
|
||||
ASSERT_NOT_NULL(rr);
|
||||
rr->ttl = 3600;
|
||||
rr->cname.name = checked_strdup("example.com");
|
||||
dns_answer_add(query->answer, rr, 1, 0, NULL);
|
||||
dns_resource_record_unref(rr);
|
||||
|
||||
ASSERT_EQ(dns_query_process_cname_one(query), DNS_QUERY_CNAME);
|
||||
|
||||
ASSERT_TRUE(dns_query_fully_authenticated(query));
|
||||
ASSERT_TRUE(dns_query_fully_confidential(query));
|
||||
ASSERT_TRUE(dns_query_fully_authoritative(query));
|
||||
}
|
||||
|
||||
TEST(dns_query_process_cname_one_success_match_dname) {
|
||||
Manager manager = {};
|
||||
_cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
|
||||
_cleanup_(dns_query_freep) DnsQuery *query = NULL;
|
||||
DnsResourceRecord *rr = NULL;
|
||||
DnsResourceKey *key = NULL;
|
||||
|
||||
ASSERT_OK(dns_question_new_address(&question, AF_INET, "www.example.com", false));
|
||||
ASSERT_NOT_NULL(question);
|
||||
|
||||
ASSERT_OK(dns_query_new(&manager, &query, NULL, question, NULL, 1, 0));
|
||||
ASSERT_NOT_NULL(query);
|
||||
|
||||
query->state = DNS_TRANSACTION_SUCCESS;
|
||||
query->answer_protocol = DNS_PROTOCOL_DNS;
|
||||
query->answer_family = AF_INET;
|
||||
query->answer = dns_answer_new(1);
|
||||
ASSERT_NOT_NULL(query->answer);
|
||||
|
||||
rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNAME, "example.com");
|
||||
ASSERT_NOT_NULL(rr);
|
||||
rr->ttl = 3600;
|
||||
rr->dname.name = checked_strdup("v2.example.com");
|
||||
dns_answer_add(query->answer, rr, 1, 0, NULL);
|
||||
dns_resource_record_unref(rr);
|
||||
|
||||
ASSERT_EQ(dns_query_process_cname_one(query), DNS_QUERY_CNAME);
|
||||
|
||||
ASSERT_EQ(query->n_cname_redirects, 1u);
|
||||
|
||||
ASSERT_EQ(dns_question_size(query->collected_questions), 1u);
|
||||
ASSERT_NULL(query->question_utf8);
|
||||
ASSERT_EQ(dns_question_size(query->question_idna), 1u);
|
||||
|
||||
key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, "www.example.com");
|
||||
ASSERT_NOT_NULL(key);
|
||||
ASSERT_TRUE(dns_question_contains_key(query->collected_questions, key));
|
||||
dns_resource_key_unref(key);
|
||||
|
||||
key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, "www.v2.example.com");
|
||||
ASSERT_NOT_NULL(key);
|
||||
ASSERT_TRUE(dns_question_contains_key(query->question_idna, key));
|
||||
dns_resource_key_unref(key);
|
||||
}
|
||||
|
||||
#if HAVE_LIBIDN || HAVE_LIBIDN2
|
||||
TEST(dns_query_process_cname_one_success_match_dname_utf8_same) {
|
||||
Manager manager = {};
|
||||
_cleanup_(dns_question_unrefp) DnsQuestion *q_utf8 = NULL, *q_idna = NULL;
|
||||
_cleanup_(dns_query_freep) DnsQuery *query = NULL;
|
||||
DnsResourceRecord *rr = NULL;
|
||||
DnsResourceKey *key = NULL;
|
||||
|
||||
ASSERT_OK(dns_question_new_address(&q_utf8, AF_INET, "www.xn--tl8h.com", false));
|
||||
ASSERT_NOT_NULL(q_utf8);
|
||||
|
||||
ASSERT_OK(dns_question_new_address(&q_idna, AF_INET, "www.\xF0\x9F\x8E\xBC.com", true));
|
||||
ASSERT_NOT_NULL(q_idna);
|
||||
|
||||
ASSERT_OK(dns_query_new(&manager, &query, q_utf8, q_idna, NULL, 1, 0));
|
||||
ASSERT_NOT_NULL(query);
|
||||
|
||||
query->state = DNS_TRANSACTION_SUCCESS;
|
||||
query->answer_protocol = DNS_PROTOCOL_DNS;
|
||||
query->answer_family = AF_INET;
|
||||
query->answer = dns_answer_new(1);
|
||||
ASSERT_NOT_NULL(query->answer);
|
||||
|
||||
rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNAME, "xn--tl8h.com");
|
||||
ASSERT_NOT_NULL(rr);
|
||||
rr->ttl = 3600;
|
||||
rr->dname.name = checked_strdup("v2.xn--tl8h.com");
|
||||
dns_answer_add(query->answer, rr, 1, 0, NULL);
|
||||
dns_resource_record_unref(rr);
|
||||
|
||||
ASSERT_EQ(dns_query_process_cname_one(query), DNS_QUERY_CNAME);
|
||||
|
||||
ASSERT_EQ(query->n_cname_redirects, 1u);
|
||||
|
||||
ASSERT_EQ(dns_question_size(query->collected_questions), 1u);
|
||||
ASSERT_EQ(dns_question_size(query->question_utf8), 1u);
|
||||
ASSERT_EQ(dns_question_size(query->question_idna), 1u);
|
||||
|
||||
key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, "www.xn--tl8h.com");
|
||||
ASSERT_NOT_NULL(key);
|
||||
ASSERT_TRUE(dns_question_contains_key(query->collected_questions, key));
|
||||
dns_resource_key_unref(key);
|
||||
|
||||
key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, "www.v2.xn--tl8h.com");
|
||||
ASSERT_NOT_NULL(key);
|
||||
ASSERT_TRUE(dns_question_contains_key(query->question_utf8, key));
|
||||
dns_resource_key_unref(key);
|
||||
|
||||
key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, "www.v2.xn--tl8h.com");
|
||||
ASSERT_NOT_NULL(key);
|
||||
ASSERT_TRUE(dns_question_contains_key(query->question_idna, key));
|
||||
dns_resource_key_unref(key);
|
||||
}
|
||||
|
||||
TEST(dns_query_process_cname_one_success_match_dname_utf8_different) {
|
||||
Manager manager = {};
|
||||
_cleanup_(dns_question_unrefp) DnsQuestion *q_utf8 = NULL, *q_idna = NULL;
|
||||
_cleanup_(dns_query_freep) DnsQuery *query = NULL;
|
||||
DnsResourceRecord *rr = NULL;
|
||||
DnsResourceKey *key = NULL;
|
||||
|
||||
ASSERT_OK(dns_question_new_address(&q_utf8, AF_INET, "www.\xF0\x9F\x98\xB1.com", false));
|
||||
ASSERT_NOT_NULL(q_utf8);
|
||||
|
||||
ASSERT_OK(dns_question_new_address(&q_idna, AF_INET, "www.\xF0\x9F\x8E\xBC.com", true));
|
||||
ASSERT_NOT_NULL(q_idna);
|
||||
|
||||
ASSERT_OK(dns_query_new(&manager, &query, q_utf8, q_idna, NULL, 1, 0));
|
||||
ASSERT_NOT_NULL(query);
|
||||
|
||||
query->state = DNS_TRANSACTION_SUCCESS;
|
||||
query->answer_protocol = DNS_PROTOCOL_DNS;
|
||||
query->answer_family = AF_INET;
|
||||
query->answer = dns_answer_new(1);
|
||||
ASSERT_NOT_NULL(query->answer);
|
||||
|
||||
rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNAME, "xn--tl8h.com");
|
||||
ASSERT_NOT_NULL(rr);
|
||||
rr->ttl = 3600;
|
||||
rr->dname.name = checked_strdup("v2.xn--tl8h.com");
|
||||
dns_answer_add(query->answer, rr, 1, 0, NULL);
|
||||
dns_resource_record_unref(rr);
|
||||
|
||||
ASSERT_EQ(dns_query_process_cname_one(query), DNS_QUERY_CNAME);
|
||||
|
||||
ASSERT_EQ(query->n_cname_redirects, 1u);
|
||||
|
||||
ASSERT_EQ(dns_question_size(query->collected_questions), 2u);
|
||||
ASSERT_NULL(query->question_utf8);
|
||||
ASSERT_EQ(dns_question_size(query->question_idna), 1u);
|
||||
|
||||
key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, "www.\xF0\x9F\x98\xB1.com");
|
||||
ASSERT_NOT_NULL(key);
|
||||
ASSERT_TRUE(dns_question_contains_key(query->collected_questions, key));
|
||||
dns_resource_key_unref(key);
|
||||
|
||||
key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, "www.xn--tl8h.com");
|
||||
ASSERT_NOT_NULL(key);
|
||||
ASSERT_TRUE(dns_question_contains_key(query->collected_questions, key));
|
||||
dns_resource_key_unref(key);
|
||||
|
||||
key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, "www.v2.xn--tl8h.com");
|
||||
ASSERT_NOT_NULL(key);
|
||||
ASSERT_TRUE(dns_question_contains_key(query->question_idna, key));
|
||||
dns_resource_key_unref(key);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ================================================================
|
||||
* dns_query_process_cname_many()
|
||||
* ================================================================ */
|
||||
|
||||
TEST(dns_query_process_cname_many_success_match_multiple_cname) {
|
||||
Manager manager = {};
|
||||
_cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
|
||||
_cleanup_(dns_query_freep) DnsQuery *query = NULL;
|
||||
DnsResourceRecord *rr = NULL;
|
||||
DnsResourceKey *key = NULL;
|
||||
|
||||
ASSERT_OK(dns_question_new_address(&question, AF_INET, "www.example.com", false));
|
||||
ASSERT_NOT_NULL(question);
|
||||
|
||||
ASSERT_OK(dns_query_new(&manager, &query, NULL, question, NULL, 1, 0));
|
||||
ASSERT_NOT_NULL(query);
|
||||
|
||||
query->state = DNS_TRANSACTION_SUCCESS;
|
||||
query->answer_protocol = DNS_PROTOCOL_DNS;
|
||||
query->answer_family = AF_INET;
|
||||
query->answer_query_flags = SD_RESOLVED_FROM_NETWORK;
|
||||
query->answer = dns_answer_new(4);
|
||||
ASSERT_NOT_NULL(query->answer);
|
||||
|
||||
rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, "example.com");
|
||||
ASSERT_NOT_NULL(rr);
|
||||
rr->ttl = 3600;
|
||||
rr->a.in_addr.s_addr = htobe32(0xc0a8017f);
|
||||
dns_answer_add(query->answer, rr, 1, 0, NULL);
|
||||
dns_resource_record_unref(rr);
|
||||
|
||||
rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_CNAME, "www.example.com");
|
||||
ASSERT_NOT_NULL(rr);
|
||||
rr->ttl = 3600;
|
||||
rr->cname.name = checked_strdup("tmp1.example.com");
|
||||
dns_answer_add(query->answer, rr, 1, 0, NULL);
|
||||
dns_resource_record_unref(rr);
|
||||
|
||||
rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_CNAME, "tmp2.example.com");
|
||||
ASSERT_NOT_NULL(rr);
|
||||
rr->ttl = 3600;
|
||||
rr->cname.name = checked_strdup("example.com");
|
||||
dns_answer_add(query->answer, rr, 1, 0, NULL);
|
||||
dns_resource_record_unref(rr);
|
||||
|
||||
rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_CNAME, "tmp1.example.com");
|
||||
ASSERT_NOT_NULL(rr);
|
||||
rr->ttl = 3600;
|
||||
rr->cname.name = checked_strdup("tmp2.example.com");
|
||||
dns_answer_add(query->answer, rr, 1, 0, NULL);
|
||||
dns_resource_record_unref(rr);
|
||||
|
||||
ASSERT_EQ(dns_query_process_cname_many(query), DNS_QUERY_MATCH);
|
||||
|
||||
ASSERT_FALSE(dns_query_fully_authenticated(query));
|
||||
ASSERT_FALSE(dns_query_fully_confidential(query));
|
||||
ASSERT_FALSE(dns_query_fully_authoritative(query));
|
||||
|
||||
ASSERT_GT(query->flags & SD_RESOLVED_NO_SEARCH, 0u);
|
||||
|
||||
ASSERT_EQ(query->n_cname_redirects, 3u);
|
||||
|
||||
ASSERT_EQ(dns_question_size(query->collected_questions), 3u);
|
||||
ASSERT_NULL(query->question_utf8);
|
||||
ASSERT_EQ(dns_question_size(query->question_idna), 1u);
|
||||
|
||||
key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, "www.example.com");
|
||||
ASSERT_NOT_NULL(key);
|
||||
ASSERT_TRUE(dns_question_contains_key(query->collected_questions, key));
|
||||
dns_resource_key_unref(key);
|
||||
|
||||
key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, "tmp1.example.com");
|
||||
ASSERT_NOT_NULL(key);
|
||||
ASSERT_TRUE(dns_question_contains_key(query->collected_questions, key));
|
||||
dns_resource_key_unref(key);
|
||||
|
||||
key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, "tmp2.example.com");
|
||||
ASSERT_NOT_NULL(key);
|
||||
ASSERT_TRUE(dns_question_contains_key(query->collected_questions, key));
|
||||
dns_resource_key_unref(key);
|
||||
|
||||
key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, "example.com");
|
||||
ASSERT_NOT_NULL(key);
|
||||
ASSERT_TRUE(dns_question_contains_key(query->question_idna, key));
|
||||
dns_resource_key_unref(key);
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
* dns_query_string()
|
||||
* ================================================================ */
|
||||
|
||||
TEST(dns_query_string_question_utf8) {
|
||||
Manager manager = {};
|
||||
_cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
|
||||
_cleanup_(dns_query_freep) DnsQuery *query = NULL;
|
||||
|
||||
ASSERT_OK(dns_question_new_address(&question, AF_INET, "utf8.example.com", false));
|
||||
ASSERT_NOT_NULL(question);
|
||||
|
||||
ASSERT_OK(dns_query_new(&manager, &query, question, NULL, NULL, 1, 0));
|
||||
ASSERT_NOT_NULL(query);
|
||||
|
||||
const char *str = dns_query_string(query);
|
||||
ASSERT_STREQ(str, "utf8.example.com");
|
||||
}
|
||||
|
||||
TEST(dns_query_string_question_idna) {
|
||||
Manager manager = {};
|
||||
_cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
|
||||
_cleanup_(dns_query_freep) DnsQuery *query = NULL;
|
||||
|
||||
ASSERT_OK(dns_question_new_address(&question, AF_INET, "idna.example.com", false));
|
||||
ASSERT_NOT_NULL(question);
|
||||
|
||||
ASSERT_OK(dns_query_new(&manager, &query, NULL, question, NULL, 1, 0));
|
||||
ASSERT_NOT_NULL(query);
|
||||
|
||||
const char *str = dns_query_string(query);
|
||||
ASSERT_STREQ(str, "idna.example.com");
|
||||
}
|
||||
|
||||
TEST(dns_query_string_question_bypass) {
|
||||
Manager manager = {};
|
||||
_cleanup_(dns_query_freep) DnsQuery *query = NULL;
|
||||
_cleanup_(dns_packet_unrefp) DnsPacket * packet = NULL;
|
||||
|
||||
ASSERT_OK(dns_packet_new_query(&packet, DNS_PROTOCOL_DNS, 0, false));
|
||||
ASSERT_NOT_NULL(packet);
|
||||
|
||||
ASSERT_OK(dns_question_new_address(&packet->question, AF_INET, "bypass.example.com", false));
|
||||
ASSERT_NOT_NULL(packet->question);
|
||||
|
||||
ASSERT_OK(dns_query_new(&manager, &query, NULL, NULL, packet, 1, 0));
|
||||
ASSERT_NOT_NULL(query);
|
||||
|
||||
const char *str = dns_query_string(query);
|
||||
ASSERT_STREQ(str, "bypass.example.com");
|
||||
}
|
||||
|
||||
TEST(dns_query_string_request_address) {
|
||||
Manager manager = {};
|
||||
_cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
|
||||
_cleanup_(dns_query_freep) DnsQuery *query = NULL;
|
||||
|
||||
ASSERT_OK(dns_question_new_address(&question, AF_INET, "www.example.com", false));
|
||||
ASSERT_NOT_NULL(question);
|
||||
|
||||
ASSERT_OK(dns_query_new(&manager, &query, question, NULL, NULL, 1, 0));
|
||||
ASSERT_NOT_NULL(query);
|
||||
|
||||
query->request_family = AF_INET;
|
||||
query->request_address.in.s_addr = htobe32(0x7f000001);
|
||||
query->request_address_valid = true;
|
||||
|
||||
const char *str = dns_query_string(query);
|
||||
ASSERT_STREQ(str, "127.0.0.1");
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
* dns_query_go()
|
||||
* ================================================================ */
|
||||
|
||||
/* Testing this function is somewhat problematic since, in addition to setting up the state for query
|
||||
* candidates, their scopes and transactions, it also directly initiates I/O to files and the network. In
|
||||
* particular:
|
||||
*
|
||||
* - The very first thing it does is try to respond to the query by reading the system /etc/hosts file, which
|
||||
* may be symlinked to a SystemD resource. Ideally we could test this without accessing global files.
|
||||
*
|
||||
* - dns_scope_get_dns_server() calls manager_get_dns_server(), which tries to read /etc/resolv.conf.
|
||||
*
|
||||
* - A potential solution to these issues would be to let these file paths be configured instead of
|
||||
* hard-coded into the source.
|
||||
*
|
||||
* - dns_scope_good_domain(), by checking dns_scope_get_dns_server(), will not match with a scope that does
|
||||
* not have a server configured, either on the scope's link (if it has one) or the manager's main/fallback
|
||||
* server. Configuring a server means that dns_query_candidate_go() and then dns_transaction_go() will send
|
||||
* UDP/TCP traffic to that server. Ideally we'd like to test that we can set up all the candidate and
|
||||
* transaction state without actually causing any requests to be sent.
|
||||
*/
|
||||
|
||||
typedef struct GoConfig {
|
||||
bool has_scope;
|
||||
bool use_link;
|
||||
bool use_bypass;
|
||||
size_t n_search_domains;
|
||||
} GoConfig;
|
||||
|
||||
static GoConfig mk_go_config(void) {
|
||||
return (GoConfig) {
|
||||
.has_scope = true,
|
||||
.use_link = false,
|
||||
.use_bypass = false,
|
||||
.n_search_domains = 0
|
||||
};
|
||||
}
|
||||
|
||||
typedef struct GoEnvironment {
|
||||
Manager manager;
|
||||
DnsProtocol protocol;
|
||||
int family;
|
||||
int ifindex;
|
||||
Link *link;
|
||||
DnsScope *scope;
|
||||
DnsServerType server_type;
|
||||
union in_addr_union server_addr;
|
||||
char *server_name;
|
||||
uint16_t server_port;
|
||||
DnsServer *server;
|
||||
size_t n_search_domains;
|
||||
DnsSearchDomain *search_domains[4];
|
||||
} GoEnvironment;
|
||||
|
||||
static void go_env_teardown(GoEnvironment *env) {
|
||||
ASSERT_NOT_NULL(env);
|
||||
|
||||
for (size_t i = 0 ; i < env->n_search_domains; i++)
|
||||
dns_search_domain_unref(env->search_domains[i]);
|
||||
|
||||
dns_server_unref(env->server);
|
||||
dns_server_unref(env->server);
|
||||
free(env->server_name);
|
||||
dns_scope_free(env->scope);
|
||||
sd_event_unref(env->manager.event);
|
||||
}
|
||||
|
||||
static const char *SEARCH_DOMAINS[] = { "local", "example.com", "org", "edu" };
|
||||
|
||||
static void go_env_setup(GoEnvironment *env, GoConfig *cfg) {
|
||||
ASSERT_NOT_NULL(env);
|
||||
ASSERT_NOT_NULL(cfg);
|
||||
|
||||
env->manager = (Manager) {};
|
||||
env->protocol = DNS_PROTOCOL_DNS;
|
||||
env->family = AF_INET;
|
||||
|
||||
ASSERT_OK(sd_event_new(&env->manager.event));
|
||||
ASSERT_NOT_NULL(env->manager.event);
|
||||
|
||||
if (cfg->use_link) {
|
||||
env->ifindex = 1;
|
||||
ASSERT_OK(link_new(&env->manager, &env->link, env->ifindex));
|
||||
ASSERT_NOT_NULL(env->link);
|
||||
env->server_type = DNS_SERVER_LINK;
|
||||
} else {
|
||||
env->ifindex = 0;
|
||||
env->link = NULL;
|
||||
env->server_type = DNS_SERVER_FALLBACK;
|
||||
}
|
||||
|
||||
if (cfg->has_scope) {
|
||||
ASSERT_OK(dns_scope_new(&env->manager, &env->scope, env->link, env->protocol, env->family));
|
||||
ASSERT_NOT_NULL(env->scope);
|
||||
|
||||
env->server_addr.in.s_addr = htobe32(0x7f000001);
|
||||
env->server_name = checked_strdup("localhost");
|
||||
env->server_port = 53;
|
||||
|
||||
ASSERT_OK(dns_server_new(&env->manager, &env->server, env->server_type,
|
||||
env->link, env->family, &env->server_addr, env->server_port,
|
||||
env->ifindex, env->server_name, RESOLVE_CONFIG_SOURCE_DBUS));
|
||||
|
||||
ASSERT_NOT_NULL(env->server);
|
||||
} else {
|
||||
env->scope = NULL;
|
||||
env->server_name = NULL;
|
||||
env->server = NULL;
|
||||
}
|
||||
|
||||
env->n_search_domains = cfg->n_search_domains;
|
||||
|
||||
for (size_t i = 0 ; i < env->n_search_domains; i++) {
|
||||
DnsSearchDomainType type = (env->link == NULL) ? DNS_SEARCH_DOMAIN_SYSTEM : DNS_SEARCH_DOMAIN_LINK;
|
||||
ASSERT_OK(dns_search_domain_new(&env->manager, &env->search_domains[i], type, env->link, SEARCH_DOMAINS[i]));
|
||||
ASSERT_NOT_NULL(env->search_domains[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void exercise_dns_query_go(GoConfig *cfg, void (*check_query)(DnsQuery *query)) {
|
||||
_cleanup_(go_env_teardown) GoEnvironment env = {};
|
||||
_cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
|
||||
_cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL;
|
||||
_cleanup_(dns_query_freep) DnsQuery *query = NULL;
|
||||
|
||||
go_env_setup(&env, cfg);
|
||||
|
||||
int flags = SD_RESOLVED_FLAGS_MAKE(env.protocol, env.family, false, false);
|
||||
|
||||
if (cfg->n_search_domains > 0) {
|
||||
/* search domains trigger on single-label domains */
|
||||
ASSERT_OK(dns_question_new_address(&question, env.family, "berlin", false));
|
||||
flags &= ~SD_RESOLVED_NO_SEARCH;
|
||||
} else {
|
||||
ASSERT_OK(dns_question_new_address(&question, env.family, "www.example.com", false));
|
||||
}
|
||||
|
||||
ASSERT_NOT_NULL(question);
|
||||
|
||||
if (cfg->use_bypass) {
|
||||
ASSERT_OK(dns_packet_new_query(&packet, env.protocol, 0, false));
|
||||
ASSERT_NOT_NULL(packet);
|
||||
DNS_PACKET_HEADER(packet)->qdcount = htobe16(1);
|
||||
packet->question = dns_question_ref(question);
|
||||
ASSERT_OK(dns_packet_append_question(packet, question));
|
||||
|
||||
/* search domains must be turned off for bypass queries, otherwise dns_query_add_candidate()
|
||||
* tries to extract the domain name from question_idna which cannot exist on bypasses. */
|
||||
flags |= SD_RESOLVED_NO_SEARCH;
|
||||
ASSERT_OK(dns_query_new(&env.manager, &query, NULL, NULL, packet, env.ifindex, flags));
|
||||
} else {
|
||||
ASSERT_OK(dns_query_new(&env.manager, &query, question, question, NULL, env.ifindex, flags));
|
||||
}
|
||||
|
||||
ASSERT_NOT_NULL(query);
|
||||
ASSERT_TRUE(dns_query_go(query));
|
||||
|
||||
if (check_query != NULL)
|
||||
check_query(query);
|
||||
}
|
||||
|
||||
static void check_query_no_servers(DnsQuery *query) {
|
||||
ASSERT_NOT_NULL(query);
|
||||
|
||||
ASSERT_EQ(dns_answer_size(query->answer), 0u);
|
||||
ASSERT_EQ(query->answer_rcode, DNS_RCODE_SUCCESS);
|
||||
}
|
||||
|
||||
TEST(dns_query_go) {
|
||||
GoConfig cfg;
|
||||
|
||||
cfg = mk_go_config();
|
||||
exercise_dns_query_go(&cfg, NULL);
|
||||
|
||||
cfg = mk_go_config();
|
||||
cfg.use_link = true;
|
||||
exercise_dns_query_go(&cfg, NULL);
|
||||
|
||||
cfg = mk_go_config();
|
||||
cfg.use_bypass = true;
|
||||
exercise_dns_query_go(&cfg, NULL);
|
||||
|
||||
cfg = mk_go_config();
|
||||
cfg.has_scope = false;
|
||||
exercise_dns_query_go(&cfg, check_query_no_servers);
|
||||
|
||||
cfg = mk_go_config();
|
||||
cfg.n_search_domains = 2;
|
||||
exercise_dns_query_go(&cfg, NULL);
|
||||
}
|
||||
|
||||
DEFINE_TEST_MAIN(LOG_DEBUG);
|
||||
Reference in New Issue
Block a user