From b8112c9d68ac21206abde3ffbdae2853459f3032 Mon Sep 17 00:00:00 2001 From: James Coglan Date: Wed, 5 Jun 2024 15:07:45 +0100 Subject: [PATCH 01/40] resolved: tests for parsing DNS packet headers --- src/resolve/meson.build | 3 + src/resolve/test-dns-packet-extract.c | 252 ++++++++++++++++++++++++++ 2 files changed, 255 insertions(+) create mode 100644 src/resolve/test-dns-packet-extract.c diff --git a/src/resolve/meson.build b/src/resolve/meson.build index d336b2c07b..47383feec3 100644 --- a/src/resolve/meson.build +++ b/src/resolve/meson.build @@ -165,6 +165,9 @@ executables += [ resolve_test_template + { 'sources' : files('test-dns-packet.c'), }, + resolve_test_template + { + 'sources' : files('test-dns-packet-extract.c'), + }, resolve_test_template + { 'sources' : files( 'test-resolved-etc-hosts.c', diff --git a/src/resolve/test-dns-packet-extract.c b/src/resolve/test-dns-packet-extract.c new file mode 100644 index 0000000000..36a26072c4 --- /dev/null +++ b/src/resolve/test-dns-packet-extract.c @@ -0,0 +1,252 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "resolved-dns-packet.h" + +#include "log.h" +#include "tests.h" + +#define BIT_QR (1 << 7) +#define BIT_AA (1 << 2) +#define BIT_TC (1 << 1) +#define BIT_RD (1 << 0) + +#define BIT_RA (1 << 7) +#define BIT_AD (1 << 5) +#define BIT_CD (1 << 4) + +/* ================================================================ + * packet header + * ================================================================ */ + +TEST(packet_header_query_basic) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_EQ(be16toh(DNS_PACKET_ID(packet)), 66); + + ASSERT_EQ(DNS_PACKET_QR(packet), 0); + ASSERT_EQ(DNS_PACKET_OPCODE(packet), 0); + ASSERT_EQ(DNS_PACKET_AA(packet), 0); + ASSERT_EQ(DNS_PACKET_TC(packet), 0); + ASSERT_EQ(DNS_PACKET_RD(packet), 0); + + ASSERT_EQ(DNS_PACKET_RA(packet), 0); + ASSERT_EQ(DNS_PACKET_AD(packet), 0); + ASSERT_EQ(DNS_PACKET_CD(packet), 0); + ASSERT_EQ(DNS_PACKET_RCODE(packet), 0); + + ASSERT_EQ(DNS_PACKET_QDCOUNT(packet), 1); + ASSERT_EQ(DNS_PACKET_ANCOUNT(packet), 0); + ASSERT_EQ(DNS_PACKET_NSCOUNT(packet), 0); + ASSERT_EQ(DNS_PACKET_ARCOUNT(packet), 0); +} + +TEST(packet_header_query_status_recursion_desired) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, (2 << 3) | BIT_RD, 0x00, + 0x01, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_EQ(be16toh(DNS_PACKET_ID(packet)), 66); + + ASSERT_EQ(DNS_PACKET_QR(packet), 0); + ASSERT_EQ(DNS_PACKET_OPCODE(packet), 2); + ASSERT_EQ(DNS_PACKET_AA(packet), 0); + ASSERT_EQ(DNS_PACKET_TC(packet), 0); + ASSERT_EQ(DNS_PACKET_RD(packet), 1); + + ASSERT_EQ(DNS_PACKET_RA(packet), 0); + ASSERT_EQ(DNS_PACKET_AD(packet), 0); + ASSERT_EQ(DNS_PACKET_CD(packet), 0); + ASSERT_EQ(DNS_PACKET_RCODE(packet), 0); + + ASSERT_EQ(DNS_PACKET_QDCOUNT(packet), 339); + ASSERT_EQ(DNS_PACKET_ANCOUNT(packet), 0); + ASSERT_EQ(DNS_PACKET_NSCOUNT(packet), 0); + ASSERT_EQ(DNS_PACKET_ARCOUNT(packet), 0); +} + +TEST(packet_header_reply_authoritative) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_EQ(be16toh(DNS_PACKET_ID(packet)), 66); + + ASSERT_EQ(DNS_PACKET_QR(packet), 1); + ASSERT_EQ(DNS_PACKET_OPCODE(packet), 0); + ASSERT_EQ(DNS_PACKET_AA(packet), 1); + ASSERT_EQ(DNS_PACKET_TC(packet), 0); + ASSERT_EQ(DNS_PACKET_RD(packet), 0); + + ASSERT_EQ(DNS_PACKET_RA(packet), 0); + ASSERT_EQ(DNS_PACKET_AD(packet), 0); + ASSERT_EQ(DNS_PACKET_CD(packet), 0); + ASSERT_EQ(DNS_PACKET_RCODE(packet), DNS_RCODE_SUCCESS); + + ASSERT_EQ(DNS_PACKET_QDCOUNT(packet), 3); + ASSERT_EQ(DNS_PACKET_ANCOUNT(packet), 4); + ASSERT_EQ(DNS_PACKET_NSCOUNT(packet), 0); + ASSERT_EQ(DNS_PACKET_ARCOUNT(packet), 0); +} + +TEST(packet_header_reply_nxdomain) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_NXDOMAIN, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_EQ(be16toh(DNS_PACKET_ID(packet)), 66); + + ASSERT_EQ(DNS_PACKET_QR(packet), 1); + ASSERT_EQ(DNS_PACKET_OPCODE(packet), 0); + ASSERT_EQ(DNS_PACKET_AA(packet), 1); + ASSERT_EQ(DNS_PACKET_TC(packet), 0); + ASSERT_EQ(DNS_PACKET_RD(packet), 0); + + ASSERT_EQ(DNS_PACKET_RA(packet), 0); + ASSERT_EQ(DNS_PACKET_AD(packet), 0); + ASSERT_EQ(DNS_PACKET_CD(packet), 0); + ASSERT_EQ(DNS_PACKET_RCODE(packet), DNS_RCODE_NXDOMAIN); + + ASSERT_EQ(DNS_PACKET_QDCOUNT(packet), 1); + ASSERT_EQ(DNS_PACKET_ANCOUNT(packet), 0); + ASSERT_EQ(DNS_PACKET_NSCOUNT(packet), 1); + ASSERT_EQ(DNS_PACKET_ARCOUNT(packet), 0); +} + +TEST(packet_header_reply_recursive_non_authoritative) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_RD, BIT_RA | DNS_RCODE_SUCCESS, + 0x05, 0x03, 0x0e, 0x04, 0x00, 0x00, 0x00, 0x00 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_EQ(be16toh(DNS_PACKET_ID(packet)), 66); + + ASSERT_EQ(DNS_PACKET_QR(packet), 1); + ASSERT_EQ(DNS_PACKET_OPCODE(packet), 0); + ASSERT_EQ(DNS_PACKET_AA(packet), 0); + ASSERT_EQ(DNS_PACKET_TC(packet), 0); + ASSERT_EQ(DNS_PACKET_RD(packet), 1); + + ASSERT_EQ(DNS_PACKET_RA(packet), 1); + ASSERT_EQ(DNS_PACKET_AD(packet), 0); + ASSERT_EQ(DNS_PACKET_CD(packet), 0); + ASSERT_EQ(DNS_PACKET_RCODE(packet), DNS_RCODE_SUCCESS); + + ASSERT_EQ(DNS_PACKET_QDCOUNT(packet), 1283); + ASSERT_EQ(DNS_PACKET_ANCOUNT(packet), 3588); + ASSERT_EQ(DNS_PACKET_NSCOUNT(packet), 0); + ASSERT_EQ(DNS_PACKET_ARCOUNT(packet), 0); +} + +TEST(packet_header_reply_delegate) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR, DNS_RCODE_SUCCESS, + 0x00, 0x01, 0x00, 0x00, 0x09, 0x0d, 0x0c, 0x1a + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_EQ(be16toh(DNS_PACKET_ID(packet)), 66u); + + ASSERT_EQ(DNS_PACKET_QR(packet), 1); + ASSERT_EQ(DNS_PACKET_OPCODE(packet), 0); + ASSERT_EQ(DNS_PACKET_AA(packet), 0); + ASSERT_EQ(DNS_PACKET_TC(packet), 0); + ASSERT_EQ(DNS_PACKET_RD(packet), 0); + + ASSERT_EQ(DNS_PACKET_RA(packet), 0); + ASSERT_EQ(DNS_PACKET_AD(packet), 0); + ASSERT_EQ(DNS_PACKET_CD(packet), 0); + ASSERT_EQ(DNS_PACKET_RCODE(packet), DNS_RCODE_SUCCESS); + + ASSERT_EQ(DNS_PACKET_QDCOUNT(packet), 1); + ASSERT_EQ(DNS_PACKET_ANCOUNT(packet), 0); + ASSERT_EQ(DNS_PACKET_NSCOUNT(packet), 2317); + ASSERT_EQ(DNS_PACKET_ARCOUNT(packet), 3098); +} + +TEST(packet_header_reply_dnssec_bits) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, BIT_AD | BIT_CD | DNS_RCODE_SUCCESS, + 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_EQ(be16toh(DNS_PACKET_ID(packet)), 66); + + ASSERT_EQ(DNS_PACKET_QR(packet), 1); + ASSERT_EQ(DNS_PACKET_OPCODE(packet), 0); + ASSERT_EQ(DNS_PACKET_AA(packet), 1); + ASSERT_EQ(DNS_PACKET_TC(packet), 0); + ASSERT_EQ(DNS_PACKET_RD(packet), 0); + + ASSERT_EQ(DNS_PACKET_RA(packet), 0); + ASSERT_EQ(DNS_PACKET_AD(packet), 1); + ASSERT_EQ(DNS_PACKET_CD(packet), 1); + ASSERT_EQ(DNS_PACKET_RCODE(packet), DNS_RCODE_SUCCESS); + + ASSERT_EQ(DNS_PACKET_QDCOUNT(packet), 3); + ASSERT_EQ(DNS_PACKET_ANCOUNT(packet), 4); + ASSERT_EQ(DNS_PACKET_NSCOUNT(packet), 0); + ASSERT_EQ(DNS_PACKET_ARCOUNT(packet), 0); +} + +DEFINE_TEST_MAIN(LOG_DEBUG) From e50e5cffded9f4c98871966f559bfae3b438fde3 Mon Sep 17 00:00:00 2001 From: James Coglan Date: Wed, 5 Jun 2024 15:31:05 +0100 Subject: [PATCH 02/40] resolved: tests for dns_packet_extract(); parsing of queries --- src/resolve/test-dns-packet-extract.c | 166 ++++++++++++++++++++++++++ 1 file changed, 166 insertions(+) diff --git a/src/resolve/test-dns-packet-extract.c b/src/resolve/test-dns-packet-extract.c index 36a26072c4..566cc37ee2 100644 --- a/src/resolve/test-dns-packet-extract.c +++ b/src/resolve/test-dns-packet-extract.c @@ -1,6 +1,8 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ +#include "dns-type.h" #include "resolved-dns-packet.h" +#include "resolved-dns-rr.h" #include "log.h" #include "tests.h" @@ -249,4 +251,168 @@ TEST(packet_header_reply_dnssec_bits) { ASSERT_EQ(DNS_PACKET_ARCOUNT(packet), 0); } +/* ================================================================ + * queries + * ================================================================ */ + +TEST(packet_query_single) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x03, 'w', 'w', 'w', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* A */ 0x00, 0x01, + /* IN */ 0x00, 0x01 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + ASSERT_EQ(dns_question_size(packet->question), 1u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); + + key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, "www.example.com"); + ASSERT_NOT_NULL(key); + ASSERT_TRUE(dns_question_contains_key(packet->question, key)); +} + +TEST(packet_query_multi) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + DnsResourceKey *key = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x03, 'w', 'w', 'w', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* A */ 0x00, 0x01, + /* IN */ 0x00, 0x01, + + /* name */ 0x04, 'm', 'a', 'i', 'l', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* MX */ 0x00, 0x0f, + /* ANY */ 0x00, 0xff + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + ASSERT_EQ(dns_question_size(packet->question), 2u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); + + key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, "www.example.com"); + ASSERT_NOT_NULL(key); + ASSERT_TRUE(dns_question_contains_key(packet->question, key)); + dns_resource_key_unref(key); + + key = dns_resource_key_new(DNS_CLASS_ANY, DNS_TYPE_MX, "mail.example.com"); + ASSERT_NOT_NULL(key); + ASSERT_TRUE(dns_question_contains_key(packet->question, key)); + dns_resource_key_unref(key); +} + +TEST(packet_query_multi_compressed_domain_1) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + DnsResourceKey *key = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x03, 'w', 'w', 'w', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* A */ 0x00, 0x01, + /* IN */ 0x00, 0x01, + + /* name */ 0x04, 'm', 'a', 'i', 'l', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0xc0, 0x18, + /* MX */ 0x00, 0x0f, + /* ANY */ 0x00, 0xff + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + ASSERT_EQ(dns_question_size(packet->question), 2u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); + + key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, "www.example.com"); + ASSERT_NOT_NULL(key); + ASSERT_TRUE(dns_question_contains_key(packet->question, key)); + dns_resource_key_unref(key); + + key = dns_resource_key_new(DNS_CLASS_ANY, DNS_TYPE_MX, "mail.example.com"); + ASSERT_NOT_NULL(key); + ASSERT_TRUE(dns_question_contains_key(packet->question, key)); + dns_resource_key_unref(key); +} + +TEST(packet_query_multi_compressed_domain_2) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + DnsResourceKey *key = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x03, 'w', 'w', 'w', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* AAAA */ 0x00, 0x1c, + /* IN */ 0x00, 0x01, + + /* name */ 0x04, 'm', 'a', 'i', 'l', + 0xc0, 0x10, + /* MX */ 0x00, 0x0f, + /* ANY */ 0x00, 0xff + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + ASSERT_EQ(dns_question_size(packet->question), 2u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); + + key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_AAAA, "www.example.com"); + ASSERT_NOT_NULL(key); + ASSERT_TRUE(dns_question_contains_key(packet->question, key)); + dns_resource_key_unref(key); + + key = dns_resource_key_new(DNS_CLASS_ANY, DNS_TYPE_MX, "mail.example.com"); + ASSERT_NOT_NULL(key); + ASSERT_TRUE(dns_question_contains_key(packet->question, key)); + dns_resource_key_unref(key); +} + DEFINE_TEST_MAIN(LOG_DEBUG) From 48b0b8f0cdd9afd2d42ae14e6fb1d752cb34cc46 Mon Sep 17 00:00:00 2001 From: James Coglan Date: Wed, 5 Jun 2024 16:24:13 +0100 Subject: [PATCH 03/40] resolved: tests for dns_packet_extract(); A and CNAME answers with domain compression --- src/resolve/test-dns-packet-extract.c | 192 ++++++++++++++++++++++++++ 1 file changed, 192 insertions(+) diff --git a/src/resolve/test-dns-packet-extract.c b/src/resolve/test-dns-packet-extract.c index 566cc37ee2..b16ca02032 100644 --- a/src/resolve/test-dns-packet-extract.c +++ b/src/resolve/test-dns-packet-extract.c @@ -415,4 +415,196 @@ TEST(packet_query_multi_compressed_domain_2) { dns_resource_key_unref(key); } +/* ================================================================ + * reply: A + * ================================================================ */ + +static void check_answer_contains(DnsPacket *packet, DnsResourceRecord *rr, DnsAnswerFlags flags) { + DnsAnswerFlags key_flags; + + ASSERT_TRUE(dns_answer_contains(packet->answer, rr)); + + ASSERT_TRUE(dns_answer_match_key(packet->answer, rr->key, &key_flags)); + ASSERT_EQ(key_flags, flags); +} + +TEST(packet_reply_a_single) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + DnsResourceRecord *rr = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x03, 'w', 'w', 'w', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* A */ 0x00, 0x01, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x04, + /* ip */ 0xc0, 0xa8, 0x01, 0x7f + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 1u); + + 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); + + check_answer_contains(packet, rr, DNS_ANSWER_SECTION_ANSWER | DNS_ANSWER_CACHEABLE); + dns_resource_record_unref(rr); +} + +/* ================================================================ + * reply: CNAME, compression + * ================================================================ */ + +static void check_cname_reply_compression(const uint8_t *data, size_t len) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + DnsResourceKey *key = NULL; + DnsResourceRecord *rr = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + ASSERT_OK(dns_packet_append_blob(packet, data, len, NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + ASSERT_EQ(dns_question_size(packet->question), 1u); + ASSERT_EQ(dns_answer_size(packet->answer), 2u); + + key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, "www.example.com"); + ASSERT_NOT_NULL(key); + ASSERT_TRUE(dns_question_contains_key(packet->question, key)); + dns_resource_key_unref(key); + + 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 = strdup("example.com"); + + check_answer_contains(packet, rr, DNS_ANSWER_SECTION_ANSWER | DNS_ANSWER_CACHEABLE); + dns_resource_record_unref(rr); + + 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); + + check_answer_contains(packet, rr, DNS_ANSWER_SECTION_ANSWER | DNS_ANSWER_CACHEABLE); + dns_resource_record_unref(rr); +} + +TEST(packet_reply_cname_uncompressed) { + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x03, 'w', 'w', 'w', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* A */ 0x00, 0x01, + /* IN */ 0x00, 0x01, + + /* name */ 0x03, 'w', 'w', 'w', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* CNAME */ 0x00, 0x05, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x0d, + /* name */ 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + + /* name */ 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* A */ 0x00, 0x01, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x04, + /* ip */ 0xc0, 0xa8, 0x01, 0x7f + }; + + check_cname_reply_compression(data, sizeof(data)); +} + +TEST(packet_reply_cname_partial_compression) { + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x03, 'w', 'w', 'w', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* A */ 0x00, 0x01, + /* IN */ 0x00, 0x01, + + /* name */ 0x03, 'w', 'w', 'w', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0xc0, 0x18, + /* CNAME */ 0x00, 0x05, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x02, + /* name */ 0xc0, 0x25, + + /* name */ 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0xc0, 0x2d, + /* A */ 0x00, 0x01, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x04, + /* ip */ 0xc0, 0xa8, 0x01, 0x7f + }; + + check_cname_reply_compression(data, sizeof(data)); +} + +TEST(packet_reply_cname_full_compression) { + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x03, 'w', 'w', 'w', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* A */ 0x00, 0x01, + /* IN */ 0x00, 0x01, + + /* name */ 0xc0, 0x0c, + /* CNAME */ 0x00, 0x05, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x02, + /* name */ 0xc0, 0x10, + + /* name */ 0xc0, 0x10, + /* A */ 0x00, 0x01, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x04, + /* ip */ 0xc0, 0xa8, 0x01, 0x7f + }; + + check_cname_reply_compression(data, sizeof(data)); +} + DEFINE_TEST_MAIN(LOG_DEBUG) From f97d7a6969f8704dea937953e09b334cfd12d772 Mon Sep 17 00:00:00 2001 From: James Coglan Date: Thu, 6 Jun 2024 15:46:43 +0100 Subject: [PATCH 04/40] resolved: tests for dns_packet_extract(); checking for malformed queries --- src/resolve/test-dns-packet-extract.c | 520 ++++++++++++++++++++++++++ 1 file changed, 520 insertions(+) diff --git a/src/resolve/test-dns-packet-extract.c b/src/resolve/test-dns-packet-extract.c index b16ca02032..0b7f9e45a4 100644 --- a/src/resolve/test-dns-packet-extract.c +++ b/src/resolve/test-dns-packet-extract.c @@ -415,6 +415,526 @@ TEST(packet_query_multi_compressed_domain_2) { dns_resource_key_unref(key); } +TEST(packet_query_single_missing_bytes) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x03, 'c', 'o', 'm', + 0x00, + /* A */ 0x00, 0x01 + /* missing class */ + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_extract(packet), EMSGSIZE); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); +} + +TEST(packet_query_single_unknown_class) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x03, 'c', 'o', 'm', + 0x00, + /* A */ 0x00, 0x01, + /* ??? */ 0x00, 0x20 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + ASSERT_EQ(dns_question_size(packet->question), 1u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); + + key = dns_resource_key_new(32, DNS_TYPE_A, "com"); + ASSERT_NOT_NULL(key); + ASSERT_TRUE(dns_question_contains_key(packet->question, key)); +} + +TEST(packet_query_single_unknown_type) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x03, 'c', 'o', 'm', + 0x00, + /* ??? */ 0x00, 0x50, + /* IN */ 0x00, 0x01 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + ASSERT_EQ(dns_question_size(packet->question), 1u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); + + key = dns_resource_key_new(DNS_CLASS_IN, 80, "com"); + ASSERT_NOT_NULL(key); + ASSERT_TRUE(dns_question_contains_key(packet->question, key)); +} + +TEST(packet_query_single_bad_type) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x03, 'c', 'o', 'm', + 0x00, + /* OPT */ 0x00, 0x29, + /* IN */ 0x00, 0x01 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_extract(packet), EBADMSG); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); +} + +TEST(packet_query_single_long_domain) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x10, 'a', 'b', 's', 'o', 'r', 'p', 't', 'i', 'v', 'e', 'n', 'e', 's', 's', 'e', 's', + 0x10, 'c', 'a', 'l', 'l', 'i', 'g', 'r', 'a', 'p', 'h', 'i', 'c', 'a', 'l', 'l', 'y', + 0x10, 'd', 'e', 'a', 'c', 'i', 'd', 'i', 'f', 'i', 'c', 'a', 't', 'i', 'o', 'n', 's', + 0x10, 'e', 'c', 'o', 'p', 'h', 'y', 's', 'i', 'o', 'l', 'o', 'g', 'i', 'c', 'a', 'l', + 0x10, 'f', 'a', 'l', 's', 'i', 'f', 'i', 'a', 'b', 'i', 'l', 'i', 't', 'i', 'e', 's', + 0x10, 'h', 'e', 't', 'e', 'r', 'o', 'c', 'h', 'r', 'o', 'm', 'a', 't', 'i', 's', 'm', + 0x10, 'i', 'c', 'o', 's', 'i', 't', 'e', 't', 'r', 'a', 'h', 'e', 'd', 'r', 'o', 'n', + 0x10, 'j', 'o', 'u', 'r', 'n', 'a', 'l', 'i', 's', 't', 'i', 'c', 'a', 'l', 'l', 'y', + 0x10, 'k', 'i', 'n', 'a', 'e', 's', 't', 'h', 'e', 't', 'i', 'c', 'a', 'l', 'l', 'y', + 0x10, 'l', 'a', 'c', 't', 'o', 'v', 'e', 'g', 'e', 't', 'a', 'r', 'i', 'a', 'n', 's', + 0x10, 'm', 'i', 's', 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 'a', 'b', 'l', 'e', + 0x10, 'n', 'i', 't', 'r', 'o', 's', 'y', 'l', 's', 'u', 'l', 'f', 'u', 'r', 'i', 'c', + 0x10, 'o', 'b', 'j', 'e', 'c', 't', 'l', 'e', 's', 's', 'n', 'e', 's', 's', 'e', 's', + 0x10, 'p', 'a', 'r', 't', 'r', 'i', 'd', 'g', 'e', 'b', 'e', 'r', 'r', 'i', 'e', 's', + 0x10, 'r', 'e', 'a', 's', 'o', 'n', 'l', 'e', 's', 's', 'n', 'e', 's', 's', 'e', 's', + 0x10, 's', 'e', 'm', 'i', 'p', 'a', 't', 'h', 'o', 'l', 'o', 'g', 'i', 'c', 'a', 'l', + 0x10, 't', 'o', 'm', 'f', 'o', 'o', 'l', 'i', 's', 'h', 'n', 'e', 's', 's', 'e', 's', + 0x10, 'u', 'n', 'd', 'e', 'r', 'c', 'a', 'p', 'i', 't', 'a', 'l', 'i', 'z', 'e', 'd', + 0x10, 'v', 'e', 'c', 't', 'o', 'r', 'c', 'a', 'r', 'd', 'i', 'o', 'g', 'r', 'a', 'm', + 0x10, 'w', 'e', 'a', 't', 'h', 'e', 'r', 'p', 'r', 'o', 'o', 'f', 'n', 'e', 's', 's', + 0x00, + /* A */ 0x00, 0x01, + /* IN */ 0x00, 0x01 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + ASSERT_EQ(dns_question_size(packet->question), 1u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); + + key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, + "absorptivenesses.calligraphically.deacidifications.ecophysiological." + "falsifiabilities.heterochromatism.icositetrahedron.journalistically." + "kinaesthetically.lactovegetarians.misinterpretable.nitrosylsulfuric." + "objectlessnesses.partridgeberries.reasonlessnesses.semipathological." + "tomfoolishnesses.undercapitalized.vectorcardiogram.weatherproofness"); + + ASSERT_NOT_NULL(key); + ASSERT_TRUE(dns_question_contains_key(packet->question, key)); +} + +TEST(packet_query_single_long_label) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x48, 'a', '-', 'd', 'o', 'm', 'a', 'i', 'n', '-', + 'n', 'a', 'm', 'e', '-', 'l', 'a', 'b', 'e', 'l', '-', + 't', 'h', 'a', 't', '-', 'g', 'o', 'e', 's', '-', + 'p', 'a', 's', 't', '-', 't', 'h', 'e', '-', + 'l', 'e', 'n', 'g', 't', 'h', '-', 'l', 'i', 'm', 'i', 't', '-', + 'o', 'f', '-', 's', 'i', 'x', 't', 'y', '-', + 't', 'h', 'r', 'e', 'e', '-', 'b', 'y', 't', 'e', 's', + 0x00, + /* A */ 0x00, 0x01, + /* IN */ 0x00, 0x01 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_extract(packet), EBADMSG); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); +} + +TEST(packet_query_single_invalid_label) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x03, '9', '_', '?', + 0x00, + /* A */ 0x00, 0x01, + /* IN */ 0x00, 0x01 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + ASSERT_EQ(dns_question_size(packet->question), 1u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); + + key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, "9_?"); + ASSERT_NOT_NULL(key); + ASSERT_TRUE(dns_question_contains_key(packet->question, key)); +} + +TEST(packet_query_single_extra_bytes) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x03, 'c', 'o', 'm', + 0x00, + /* A */ 0x00, 0x01, + /* IN */ 0x00, 0x01, + /* extra */ 0x04, 'm', 'a', 'i', 'l' + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + ASSERT_EQ(dns_question_size(packet->question), 1u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); + + key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, "com"); + ASSERT_NOT_NULL(key); + ASSERT_TRUE(dns_question_contains_key(packet->question, key)); +} + +TEST(packet_query_single_domain_overflow) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x03, 'm', 'a', 'i', 'l', + 0x00, + /* A */ 0x00, 0x01, + /* IN */ 0x00, 0x01 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_extract(packet), EBADMSG); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); +} + +TEST(packet_query_single_domain_underflow) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x04, 'c', 'o', 'm', + 0x00, + /* A */ 0x00, 0x01, + /* IN */ 0x00, 0x01 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_extract(packet), EMSGSIZE); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); +} + +TEST(packet_query_single_domain_missing_root) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x03, 'c', 'o', 'm', + /* missing 0x00 */ + /* A */ 0x00, 0x01, + /* IN */ 0x00, 0x01 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_extract(packet), EMSGSIZE); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); +} + +TEST(packet_query_missing_question) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x03, 'c', 'o', 'm', + 0x00, + /* A */ 0x00, 0x01, + /* IN */ 0x00, 0x01 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_extract(packet), EMSGSIZE); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); +} + +TEST(packet_query_extra_question) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x03, 'c', 'o', 'm', + 0x00, + /* A */ 0x00, 0x01, + /* IN */ 0x00, 0x01, + + /* name */ 0x03, 'o', 'r', 'g', + 0x00, + /* AAAA */ 0x00, 0x1c, + /* IN */ 0x00, 0x01 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + ASSERT_EQ(dns_question_size(packet->question), 1u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); + + key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, "com"); + ASSERT_NOT_NULL(key); + ASSERT_TRUE(dns_question_contains_key(packet->question, key)); +} + +TEST(packet_query_bad_compression) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x03, 'c', 'o', 'm', + 0x00, + /* A */ 0x00, 0x01, + /* IN */ 0x00, 0x01, + + /* name */ 0xc0, 0x0b, /* points 1 byte before start of "com" */ + /* AAAA */ 0x00, 0x1c, + /* IN */ 0x00, 0x01 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_extract(packet), EBADMSG); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); +} + +TEST(packet_query_bad_compression_2) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x03, 'c', 'o', 'm', + 0x00, + /* A */ 0x00, 0x01, + /* IN */ 0x00, 0x01, + + /* name */ 0xc0, 0x0d, /* points 1 byte after start of "com" */ + /* AAAA */ 0x00, 0x1c, + /* IN */ 0x00, 0x01 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_extract(packet), EBADMSG); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); +} + +TEST(packet_query_bad_compression_3) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x03, 'c', 'o', 'm', + 0x00, + /* A */ 0x00, 0x01, + /* IN */ 0x00, 0x01, + + /* name */ 0xc0, 0x0c, + 0x00, /* extra null terminator */ + /* AAAA */ 0x00, 0x1c, + /* IN */ 0x00, 0x01 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_extract(packet), EBADMSG); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); +} + +TEST(packet_query_bad_compression_4) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x03, 'c', 'o', 'm', + 0x00, + /* A */ 0x00, 0x01, + /* IN */ 0x00, 0x01, + + /* name */ 0xc0, 0x80, /* points past end of message */ + /* AAAA */ 0x00, 0x1c, + /* IN */ 0x00, 0x01 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_extract(packet), EBADMSG); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); +} + +TEST(packet_query_bad_compression_5) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0xc0, 0x12, /* points at "com" in next question */ + /* A */ 0x00, 0x01, + /* IN */ 0x00, 0x01, + + /* name */ 0x03, 'c', 'o', 'm', + 0x00, + /* AAAA */ 0x00, 0x1c, + /* IN */ 0x00, 0x01 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_extract(packet), EBADMSG); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); +} + /* ================================================================ * reply: A * ================================================================ */ From 326ba6a5b0c17729b55b15fef9a677ab3b891045 Mon Sep 17 00:00:00 2001 From: James Coglan Date: Mon, 10 Jun 2024 14:46:55 +0100 Subject: [PATCH 05/40] resolved: tests for dns_packet_extract(); check handling of self-referential compression pointers --- src/resolve/test-dns-packet-extract.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/resolve/test-dns-packet-extract.c b/src/resolve/test-dns-packet-extract.c index 0b7f9e45a4..14de04b806 100644 --- a/src/resolve/test-dns-packet-extract.c +++ b/src/resolve/test-dns-packet-extract.c @@ -935,6 +935,30 @@ TEST(packet_query_bad_compression_5) { ASSERT_EQ(dns_answer_size(packet->answer), 0u); } +TEST(packet_query_bad_compression_6) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x2a, 0x01, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x03, 'w', 'w', 'w', + 0xc0, 0x0c, /* points at the current name */ + /* A */ 0x00, 0x01, + /* IN */ 0x00, 0x01 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_extract(packet), EBADMSG); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); +} + /* ================================================================ * reply: A * ================================================================ */ From 0afc219da8e8c422c51c5a7fc6e31da696ca0d08 Mon Sep 17 00:00:00 2001 From: James Coglan Date: Fri, 7 Jun 2024 08:28:00 +0100 Subject: [PATCH 06/40] resolved: tests for dns_packet_extract(); parsing A records --- src/resolve/test-dns-packet-extract.c | 150 +++++++++++++++++++++++++- 1 file changed, 146 insertions(+), 4 deletions(-) diff --git a/src/resolve/test-dns-packet-extract.c b/src/resolve/test-dns-packet-extract.c index 14de04b806..5946080aa6 100644 --- a/src/resolve/test-dns-packet-extract.c +++ b/src/resolve/test-dns-packet-extract.c @@ -974,7 +974,7 @@ static void check_answer_contains(DnsPacket *packet, DnsResourceRecord *rr, DnsA TEST(packet_reply_a_single) { _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; - DnsResourceRecord *rr = NULL; + _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); ASSERT_NOT_NULL(packet); @@ -984,8 +984,7 @@ TEST(packet_reply_a_single) { 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, - /* name */ 0x03, 'w', 'w', 'w', - 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + /* name */ 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0x03, 'c', 'o', 'm', 0x00, /* A */ 0x00, 0x01, @@ -1001,13 +1000,156 @@ TEST(packet_reply_a_single) { ASSERT_EQ(dns_question_size(packet->question), 0u); ASSERT_EQ(dns_answer_size(packet->answer), 1u); - rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, "www.example.com"); + 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); + + check_answer_contains(packet, rr, DNS_ANSWER_SECTION_ANSWER | DNS_ANSWER_CACHEABLE); +} + +TEST(packet_reply_a_zero_ip) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* A */ 0x00, 0x01, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x04, + /* ip */ 0x00, 0x00, 0x00, 0x00 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 1u); + + 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(0); + + check_answer_contains(packet, rr, DNS_ANSWER_SECTION_ANSWER | DNS_ANSWER_CACHEABLE); +} + +TEST(packet_reply_a_multi) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + DnsResourceRecord *rr = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* A */ 0x00, 0x01, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x04, + /* ip */ 0xc0, 0xa8, 0x01, 0x7f, + + /* name */ 0xc0, 0x0c, + /* A */ 0x00, 0x01, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x04, + /* ip */ 0xa9, 0xfe, 0x01, 0x00 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 2u); + + 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); check_answer_contains(packet, rr, DNS_ANSWER_SECTION_ANSWER | DNS_ANSWER_CACHEABLE); dns_resource_record_unref(rr); + + 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(0xa9fe0100); + + check_answer_contains(packet, rr, DNS_ANSWER_SECTION_ANSWER | DNS_ANSWER_CACHEABLE); + dns_resource_record_unref(rr); +} + +TEST(packet_reply_a_bad_rdata_size) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* A */ 0x00, 0x01, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x05, + /* ip */ 0xc0, 0xa8, 0x01, 0x7f, 0x99 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_extract(packet), EBADMSG); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); +} + +TEST(packet_reply_a_rdata_truncated) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* A */ 0x00, 0x01, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x04, + /* ip */ 0xc0, 0xa8, 0x01 /* missing last byte */ + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_extract(packet), EBADMSG); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); } /* ================================================================ From 8a5e122d951522d4a46e2e2e39b0a019cf258d8d Mon Sep 17 00:00:00 2001 From: James Coglan Date: Fri, 7 Jun 2024 08:54:18 +0100 Subject: [PATCH 07/40] resolved: tests for dns_packet_extract(); parsing NS records --- src/resolve/test-dns-packet-extract.c | 236 +++++++++++++++++++++++++- 1 file changed, 235 insertions(+), 1 deletion(-) diff --git a/src/resolve/test-dns-packet-extract.c b/src/resolve/test-dns-packet-extract.c index 5946080aa6..f198e770e5 100644 --- a/src/resolve/test-dns-packet-extract.c +++ b/src/resolve/test-dns-packet-extract.c @@ -1153,7 +1153,241 @@ TEST(packet_reply_a_rdata_truncated) { } /* ================================================================ - * reply: CNAME, compression + * reply: NS + * ================================================================ */ + +TEST(packet_reply_ns_single) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + DnsResourceRecord *rr = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + + /* name */ 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* NS */ 0x00, 0x02, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x06, + /* name */ 0x03, 'n', 's', '1', + 0xc0, 0x0c + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 1u); + + rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_NS, "example.com"); + ASSERT_NOT_NULL(rr); + rr->ttl = 3600; + rr->ns.name = strdup("ns1.example.com"); + + check_answer_contains(packet, rr, DNS_ANSWER_SECTION_AUTHORITY); + dns_resource_record_unref(rr); +} + +TEST(packet_reply_ns_multi) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + DnsResourceRecord *rr = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, + + /* name */ 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* NS */ 0x00, 0x02, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x06, + /* name */ 0x03, 'n', 's', '1', + 0xc0, 0x0c, + + /* name */ 0xc0, 0x0c, + /* NS */ 0x00, 0x02, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x06, + /* name */ 0x03, 'n', 's', '2', + 0xc0, 0x0c, + + /* name */ 0xc0, 0x0c, + /* NS */ 0x00, 0x02, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x06, + /* name */ 0x03, 'n', 's', '3', + 0xc0, 0x0c + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 3u); + + rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_NS, "example.com"); + ASSERT_NOT_NULL(rr); + rr->ttl = 3600; + rr->ns.name = strdup("ns1.example.com"); + + check_answer_contains(packet, rr, DNS_ANSWER_SECTION_AUTHORITY); + dns_resource_record_unref(rr); + + rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_NS, "example.com"); + ASSERT_NOT_NULL(rr); + rr->ttl = 3600; + rr->ns.name = strdup("ns2.example.com"); + + check_answer_contains(packet, rr, DNS_ANSWER_SECTION_AUTHORITY); + dns_resource_record_unref(rr); + + rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_NS, "example.com"); + ASSERT_NOT_NULL(rr); + rr->ttl = 3600; + rr->ns.name = strdup("ns3.example.com"); + + check_answer_contains(packet, rr, DNS_ANSWER_SECTION_AUTHORITY); + dns_resource_record_unref(rr); +} + +TEST(packet_reply_ns_domain_underflows_rdata) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + + /* name */ 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* NS */ 0x00, 0x02, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x12, + /* name */ 0x03, 'n', 's', '1', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_extract(packet), EBADMSG); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); +} + +TEST(packet_reply_ns_domain_overflows_rdata) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + + /* name */ 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* NS */ 0x00, 0x02, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x06, + /* name */ 0x03, 'n', 's', '1', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_extract(packet), EBADMSG); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); +} + +TEST(packet_reply_ns_domain_overflows_rdata_compressed) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + + /* name */ 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* NS */ 0x00, 0x02, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x05, + /* name */ 0x03, 'n', 's', '1', + 0xc0, 0x0c + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_extract(packet), EBADMSG); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); +} + +TEST(packet_reply_ns_domain_unterminated) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + + /* name */ 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* NS */ 0x00, 0x02, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x10, + /* name */ 0x03, 'n', 's', '1', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm' + /* missing 0x00 */ + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_extract(packet), EMSGSIZE); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); +} + +/* ================================================================ + * reply: CNAME with A, compression * ================================================================ */ static void check_cname_reply_compression(const uint8_t *data, size_t len) { From 3d0df33fc207b254d5687e6c528f42dd24ed0b49 Mon Sep 17 00:00:00 2001 From: James Coglan Date: Fri, 7 Jun 2024 09:22:26 +0100 Subject: [PATCH 08/40] resolved: tests for dns_packet_extract(); parsing SOA records --- src/resolve/test-dns-packet-extract.c | 201 ++++++++++++++++++++++++++ 1 file changed, 201 insertions(+) diff --git a/src/resolve/test-dns-packet-extract.c b/src/resolve/test-dns-packet-extract.c index f198e770e5..b2d65cf640 100644 --- a/src/resolve/test-dns-packet-extract.c +++ b/src/resolve/test-dns-packet-extract.c @@ -1527,4 +1527,205 @@ TEST(packet_reply_cname_full_compression) { check_cname_reply_compression(data, sizeof(data)); } +/* ================================================================ + * reply: SOA + * ================================================================ */ + +TEST(packet_reply_soa_basic) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + DnsResourceRecord *rr = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_NXDOMAIN, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + + /* name */ 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* SOA */ 0x00, 0x06, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x27, + /* mname */ 0x03, 'n', 's', '0', + 0xc0, 0x0c, + /* rname */ 0x0a, 'h', 'o', 's', 't', 'm', 'a', 's', 't', 'e', 'r', + 0xc0, 0x0c, + /* serial */ 0x78, 0x85, 0x75, 0x2e, + /* refresh */ 0x00, 0x02, 0xa3, 0x00, + /* retry */ 0x00, 0x00, 0x00, 0xb4, + /* expire */ 0x00, 0x24, 0xea, 0x00, + /* minimum */ 0x00, 0x00, 0x00, 0x3c + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 1u); + + rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_SOA, "example.com"); + ASSERT_NOT_NULL(rr); + rr->ttl = 3600; + rr->soa.mname = strdup("ns0.example.com"); + rr->soa.rname = strdup("hostmaster.example.com"); + rr->soa.serial = 2022012206; + rr->soa.refresh = 172800; + rr->soa.retry = 180; + rr->soa.expire = 2419200; + rr->soa.minimum = 60; + + check_answer_contains(packet, rr, DNS_ANSWER_SECTION_AUTHORITY); + dns_resource_record_unref(rr); +} + +TEST(packet_reply_soa_rdata_overflow) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_NXDOMAIN, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + + /* name */ 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* SOA */ 0x00, 0x06, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x26, + /* mname */ 0x03, 'n', 's', '0', + 0xc0, 0x0c, + /* rname */ 0x0a, 'h', 'o', 's', 't', 'm', 'a', 's', 't', 'e', 'r', + 0xc0, 0x0c, + /* serial */ 0x78, 0x85, 0x75, 0x2e, + /* refresh */ 0x00, 0x02, 0xa3, 0x00, + /* retry */ 0x00, 0x00, 0x00, 0xb4, + /* expire */ 0x00, 0x24, 0xea, 0x00, + /* minimum */ 0x00, 0x00, 0x00, 0x3c + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_extract(packet), EBADMSG); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); +} + +TEST(packet_reply_soa_rdata_underminated_domain) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_NXDOMAIN, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + + /* name */ 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* SOA */ 0x00, 0x06, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x31, + /* mname */ 0x03, 'n', 's', '0', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + /* missing 0x00 */ + /* rname */ 0x0a, 'h', 'o', 's', 't', 'm', 'a', 's', 't', 'e', 'r', + 0xc0, 0x0c, + /* serial */ 0x78, 0x85, 0x75, 0x2e, + /* refresh */ 0x00, 0x02, 0xa3, 0x00, + /* retry */ 0x00, 0x00, 0x00, 0xb4, + /* expire */ 0x00, 0x24, 0xea, 0x00, + /* minimum */ 0x00, 0x00, 0x00, 0x3c + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_extract(packet), EBADMSG); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); +} + +TEST(packet_reply_soa_rdata_missing_field) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_NXDOMAIN, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + + /* name */ 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* SOA */ 0x00, 0x06, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x23, + /* mname */ 0x03, 'n', 's', '0', + 0xc0, 0x0c, + /* rname */ 0x0a, 'h', 'o', 's', 't', 'm', 'a', 's', 't', 'e', 'r', + 0xc0, 0x0c, + /* serial */ 0x78, 0x85, 0x75, 0x2e, + /* refresh */ 0x00, 0x02, 0xa3, 0x00, + /* retry */ 0x00, 0x00, 0x00, 0xb4, + /* expire */ 0x00, 0x24, 0xea, 0x00 + /* minimum (missing) */ + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_extract(packet), EMSGSIZE); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); +} + +TEST(packet_reply_soa_rdata_partial_final_field) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_NXDOMAIN, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + + /* name */ 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* SOA */ 0x00, 0x06, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x26, + /* mname */ 0x03, 'n', 's', '0', + 0xc0, 0x0c, + /* rname */ 0x0a, 'h', 'o', 's', 't', 'm', 'a', 's', 't', 'e', 'r', + 0xc0, 0x0c, + /* serial */ 0x78, 0x85, 0x75, 0x2e, + /* refresh */ 0x00, 0x02, 0xa3, 0x00, + /* retry */ 0x00, 0x00, 0x00, 0xb4, + /* expire */ 0x00, 0x24, 0xea, 0x00, + /* minimum */ 0x00, 0x00, 0x00 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_extract(packet), EMSGSIZE); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); +} + DEFINE_TEST_MAIN(LOG_DEBUG) From 887bc3623172e0edfd150dcc24ac98f517f86804 Mon Sep 17 00:00:00 2001 From: James Coglan Date: Fri, 7 Jun 2024 09:56:40 +0100 Subject: [PATCH 09/40] resolved: tests for dns_packet_extract(); handling ANY class/type in answers --- src/resolve/test-dns-packet-extract.c | 60 +++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/src/resolve/test-dns-packet-extract.c b/src/resolve/test-dns-packet-extract.c index b2d65cf640..f528d87299 100644 --- a/src/resolve/test-dns-packet-extract.c +++ b/src/resolve/test-dns-packet-extract.c @@ -959,6 +959,66 @@ TEST(packet_query_bad_compression_6) { ASSERT_EQ(dns_answer_size(packet->answer), 0u); } +/* ================================================================ + * reply: bad keys + * ================================================================ */ + +TEST(packet_reply_cannot_use_class_any) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* A */ 0x00, 0x01, + /* ANY */ 0x00, 0xff, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x04, + /* ip */ 0xc0, 0xa8, 0x01, 0x7f + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_extract(packet), EBADMSG); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); +} + +TEST(packet_reply_cannot_use_type_any) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* ANY */ 0x00, 0xff, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x04, + /* ip */ 0xc0, 0xa8, 0x01, 0x7f + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_extract(packet), EBADMSG); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); +} + /* ================================================================ * reply: A * ================================================================ */ From 02ea4cb9197faf27cc01e797cb7d2b82d6e89448 Mon Sep 17 00:00:00 2001 From: James Coglan Date: Fri, 7 Jun 2024 14:45:56 +0100 Subject: [PATCH 10/40] resolved: tests for dns_packet_extract(); parsing SRV records --- src/resolve/test-dns-packet-extract.c | 175 ++++++++++++++++++++++++++ 1 file changed, 175 insertions(+) diff --git a/src/resolve/test-dns-packet-extract.c b/src/resolve/test-dns-packet-extract.c index f528d87299..86b2b6ad35 100644 --- a/src/resolve/test-dns-packet-extract.c +++ b/src/resolve/test-dns-packet-extract.c @@ -1788,4 +1788,179 @@ TEST(packet_reply_soa_rdata_partial_final_field) { ASSERT_EQ(dns_answer_size(packet->answer), 0u); } +/* ================================================================ + * reply: SRV + * ================================================================ */ + +TEST(packet_reply_srv_with_a) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + DnsResourceRecord *rr = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, + + /* name */ 0x05, '_', 'l', 'd', 'a', 'p', + 0x04, '_', 't', 'c', 'p', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* SRV */ 0x00, 0x21, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x19, + /* priority */ 0x43, 0x21, + /* weight */ 0x65, 0x78, + /* port */ 0x01, 0x85, + /* name */ 0x05, 'c', 'l', 'o', 'u', 'd', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + + /* name */ 0xc0, 0x34, + /* A */ 0x00, 0x01, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x04, + /* ip */ 0xc0, 0xa8, 0x01, 0x7f + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 2u); + + rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_SRV, "_ldap._tcp.example.com"); + ASSERT_NOT_NULL(rr); + rr->ttl = 3600; + rr->srv.priority = 17185; + rr->srv.weight = 25976; + rr->srv.port = 389; + rr->srv.name = strdup("cloud.example.com"); + + check_answer_contains(packet, rr, DNS_ANSWER_SECTION_ANSWER | DNS_ANSWER_CACHEABLE); + dns_resource_record_unref(rr); + + rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, "cloud.example.com"); + ASSERT_NOT_NULL(rr); + rr->ttl = 3600; + rr->a.in_addr.s_addr = htobe32(0xc0a8017f); + + check_answer_contains(packet, rr, DNS_ANSWER_SECTION_ADDITIONAL); + dns_resource_record_unref(rr); +} + +/* we allow compression of the SRV target field even though RFC 2782 advises against it */ + +TEST(packet_reply_srv_compression) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + DnsResourceRecord *rr = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, + + /* name */ 0x05, '_', 'l', 'd', 'a', 'p', + 0x04, '_', 't', 'c', 'p', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* SRV */ 0x00, 0x21, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x0e, + /* priority */ 0x00, 0x0a, + /* weight */ 0x00, 0x05, + /* port */ 0x01, 0x85, + /* name */ 0x05, 'c', 'l', 'o', 'u', 'd', + 0xc0, 0x17, + + /* name */ 0xc0, 0x34, + /* A */ 0x00, 0x01, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x04, + /* ip */ 0xc0, 0xa8, 0x01, 0x7f + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 2u); + + rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_SRV, "_ldap._tcp.example.com"); + ASSERT_NOT_NULL(rr); + rr->ttl = 3600; + rr->srv.priority = 10; + rr->srv.weight = 5; + rr->srv.port = 389; + rr->srv.name = strdup("cloud.example.com"); + + check_answer_contains(packet, rr, DNS_ANSWER_SECTION_ANSWER | DNS_ANSWER_CACHEABLE); + dns_resource_record_unref(rr); + + rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, "cloud.example.com"); + ASSERT_NOT_NULL(rr); + rr->ttl = 3600; + rr->a.in_addr.s_addr = htobe32(0xc0a8017f); + + check_answer_contains(packet, rr, DNS_ANSWER_SECTION_ADDITIONAL); + dns_resource_record_unref(rr); +} + +TEST(packet_reply_srv_allow_non_srv_names) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + DnsResourceRecord *rr = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x03, 'w', 'w', 'w', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* SRV */ 0x00, 0x21, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x0e, + /* priority */ 0x00, 0x0a, + /* weight */ 0x00, 0x05, + /* port */ 0x01, 0x85, + /* name */ 0x05, 'c', 'l', 'o', 'u', 'd', + 0xc0, 0x10 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 1u); + + rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_SRV, "www.example.com"); + ASSERT_NOT_NULL(rr); + rr->ttl = 3600; + rr->srv.priority = 10; + rr->srv.weight = 5; + rr->srv.port = 389; + rr->srv.name = strdup("cloud.example.com"); + + check_answer_contains(packet, rr, DNS_ANSWER_SECTION_ANSWER | DNS_ANSWER_CACHEABLE); + dns_resource_record_unref(rr); +} + DEFINE_TEST_MAIN(LOG_DEBUG) From c0ae07ec2bff7d5f1851490c70a28a06bf018bb7 Mon Sep 17 00:00:00 2001 From: James Coglan Date: Fri, 7 Jun 2024 15:42:31 +0100 Subject: [PATCH 11/40] resolved: tests for dns_packet_extract(); parsing RRSIG records --- src/resolve/test-dns-packet-extract.c | 217 ++++++++++++++++++++++++++ 1 file changed, 217 insertions(+) diff --git a/src/resolve/test-dns-packet-extract.c b/src/resolve/test-dns-packet-extract.c index 86b2b6ad35..e7138280b9 100644 --- a/src/resolve/test-dns-packet-extract.c +++ b/src/resolve/test-dns-packet-extract.c @@ -1963,4 +1963,221 @@ TEST(packet_reply_srv_allow_non_srv_names) { dns_resource_record_unref(rr); } +/* ================================================================ + * reply: RRSIG + * ================================================================ */ + +TEST(packet_reply_rrsig_for_a) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + DnsResourceRecord *rr = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x03, 'w', 'w', 'w', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* A */ 0x00, 0x01, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x04, + /* ip */ 0xc0, 0xa8, 0x01, 0x7f, + + /* name */ 0xc0, 0x0c, + /* RRSIG */ 0x00, 0x2e, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x27, + /* type */ 0x00, 0x01, + /* algo */ 0x04, + /* labels */ 0x03, + /* orig ttl */ 0x00, 0x00, 0x0e, 0x10, + /* expiry */ 0x66, 0x8a, 0xa1, 0x57, + /* inception */ 0x66, 0x63, 0x14, 0x57, + /* key tag */ 0x12, 0x34, + /* signer */ 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* signature */ 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 + }; + + const uint8_t signature[] = { + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 2u); + + 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); + + check_answer_contains(packet, rr, DNS_ANSWER_SECTION_ANSWER | DNS_ANSWER_CACHEABLE); + dns_resource_record_unref(rr); + + rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_RRSIG, "www.example.com"); + ASSERT_NOT_NULL(rr); + rr->ttl = 3600; + rr->rrsig.type_covered = DNS_TYPE_A; + rr->rrsig.algorithm = DNSSEC_ALGORITHM_ECC; + rr->rrsig.labels = 3; + rr->rrsig.original_ttl = 3600; + rr->rrsig.expiration = 1720361303; + rr->rrsig.inception = 1717769303; + rr->rrsig.key_tag = 0x1234; + rr->rrsig.signer = strdup("example.com"); + + rr->rrsig.signature_size = sizeof(signature); + rr->rrsig.signature = memdup(signature, rr->rrsig.signature_size); + + check_answer_contains(packet, rr, DNS_ANSWER_SECTION_ANSWER | DNS_ANSWER_CACHEABLE); + dns_resource_record_unref(rr); +} + +TEST(packet_reply_rrsig_no_compression) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x03, 'w', 'w', 'w', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* A */ 0x00, 0x01, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x04, + /* ip */ 0xc0, 0xa8, 0x01, 0x7f, + + /* name */ 0xc0, 0x0c, + /* RRSIG */ 0x00, 0x2e, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x1c, + /* type */ 0x00, 0x01, + /* algo */ 0x04, + /* labels */ 0x03, + /* orig ttl */ 0x00, 0x00, 0x0e, 0x10, + /* expiry */ 0x66, 0x8a, 0xa1, 0x57, + /* inception */ 0x66, 0x63, 0x14, 0x57, + /* key tag */ 0x12, 0x34, + /* signer */ 0xc0, 0x10, + /* signature */ 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_extract(packet), EBADMSG); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); +} + +TEST(packet_reply_rrsig_signature_underflow) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x03, 'w', 'w', 'w', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* A */ 0x00, 0x01, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x04, + /* ip */ 0xc0, 0xa8, 0x01, 0x7f, + + /* name */ 0xc0, 0x0c, + /* RRSIG */ 0x00, 0x2e, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x28, + /* type */ 0x00, 0x01, + /* algo */ 0x04, + /* labels */ 0x03, + /* orig ttl */ 0x00, 0x00, 0x0e, 0x10, + /* expiry */ 0x66, 0x8a, 0xa1, 0x57, + /* inception */ 0x66, 0x63, 0x14, 0x57, + /* key tag */ 0x12, 0x34, + /* signer */ 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* signature */ 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_extract(packet), EBADMSG); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); +} + +TEST(packet_reply_rrsig_signer_overflow) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x03, 'w', 'w', 'w', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* A */ 0x00, 0x01, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x04, + /* ip */ 0xc0, 0xa8, 0x01, 0x7f, + + /* name */ 0xc0, 0x0c, + /* RRSIG */ 0x00, 0x2e, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x1e, + /* type */ 0x00, 0x01, + /* algo */ 0x04, + /* labels */ 0x03, + /* orig ttl */ 0x00, 0x00, 0x0e, 0x10, + /* expiry */ 0x66, 0x8a, 0xa1, 0x57, + /* inception */ 0x66, 0x63, 0x14, 0x57, + /* key tag */ 0x12, 0x34, + /* signer */ 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* signature */ 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_extract(packet), EBADMSG); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); +} + DEFINE_TEST_MAIN(LOG_DEBUG) From 5e663903f331197e950db221e7eba9b0f42bebbb Mon Sep 17 00:00:00 2001 From: James Coglan Date: Tue, 11 Jun 2024 09:32:24 +0100 Subject: [PATCH 12/40] resolved: tests for dns_packet_extract(); parsing SVCB and HTTPS records --- src/resolve/test-dns-packet-extract.c | 739 ++++++++++++++++++++++++++ 1 file changed, 739 insertions(+) diff --git a/src/resolve/test-dns-packet-extract.c b/src/resolve/test-dns-packet-extract.c index e7138280b9..c185bb95ea 100644 --- a/src/resolve/test-dns-packet-extract.c +++ b/src/resolve/test-dns-packet-extract.c @@ -2180,4 +2180,743 @@ TEST(packet_reply_rrsig_signer_overflow) { ASSERT_EQ(dns_answer_size(packet->answer), 0u); } +/* ================================================================ + * reply: SVCB/HTTPS + * ================================================================ */ + +static DnsSvcParam* add_svcb_param(DnsResourceRecord *rr, uint16_t key, const char *value, size_t len) { + DnsSvcParam *param = calloc(1, offsetof(DnsSvcParam, value) + len); + ASSERT_NOT_NULL(param); + + param->key = key; + param->length = len; + + if (value != NULL) + memcpy(param->value, value, len); + + LIST_APPEND(params, rr->svcb.params, param); + return param; +} + +TEST(packet_reply_svcb_alias_mode) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + DnsResourceRecord *rr = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + + /* name */ 0x04, '_', '4', '4', '3', + 0x04, '_', 'w', 's', 's', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* SVCB */ 0x00, 0x40, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x14, + /* priority */ 0x00, 0x00, + /* target */ 0x04, 's', 'o', 'c', 'k', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 1u); + + rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_SVCB, "_443._wss.example.com"); + ASSERT_NOT_NULL(rr); + rr->ttl = 3600; + rr->svcb.priority = 0; + rr->svcb.target_name = strdup("sock.example.com"); + + check_answer_contains(packet, rr, DNS_ANSWER_SECTION_ADDITIONAL); + dns_resource_record_unref(rr); +} + +TEST(packet_reply_svcb_compressed_target) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + + /* name */ 0x04, '_', '4', '4', '3', + 0x04, '_', 'w', 's', 's', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* SVCB */ 0x00, 0x40, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x09, + /* priority */ 0x00, 0x00, + /* target */ 0x04, 's', 'o', 'c', 'k', + 0xc0, 0x16 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_extract(packet), EBADMSG); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); +} + +/* RFC 9460 says that alias-mode RRs SHOULD NOT have the same owner and target. + * We accept this when parsing messages. */ + +TEST(packet_reply_svcb_alias_mode_same_owner_and_target) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + DnsResourceRecord *rr = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + + /* name */ 0x04, 's', 'o', 'c', 'k', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* SVCB */ 0x00, 0x40, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x14, + /* priority */ 0x00, 0x00, + /* target */ 0x04, 's', 'o', 'c', 'k', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 1u); + + rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_SVCB, "sock.example.com"); + ASSERT_NOT_NULL(rr); + rr->ttl = 3600; + rr->svcb.priority = 0; + rr->svcb.target_name = strdup("sock.example.com"); + + check_answer_contains(packet, rr, DNS_ANSWER_SECTION_ADDITIONAL); + dns_resource_record_unref(rr); +} + +/* RFC 9460 says that recipients MUST ignore any params presented in alias mode RRs. We parse them out of the + * message and their handling is down to further business logic, rather than rejecting such RRs in the + * parser. */ + +TEST(packet_reply_svcb_alias_mode_with_param) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + DnsResourceRecord *rr = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + + /* name */ 0x04, '_', '4', '4', '3', + 0x04, '_', 'w', 's', 's', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* SVCB */ 0x00, 0x40, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x18, + /* priority */ 0x00, 0x00, + /* target */ 0x04, 's', 'o', 'c', 'k', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* no-deflt */ 0x00, 0x02, + 0x00, 0x00, + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 1u); + + rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_SVCB, "_443._wss.example.com"); + ASSERT_NOT_NULL(rr); + rr->ttl = 3600; + rr->svcb.priority = 0; + rr->svcb.target_name = strdup("sock.example.com"); + + add_svcb_param(rr, DNS_SVC_PARAM_KEY_NO_DEFAULT_ALPN, NULL, 0); + + check_answer_contains(packet, rr, DNS_ANSWER_SECTION_ADDITIONAL); + dns_resource_record_unref(rr); +} + +TEST(packet_reply_svcb_service_mode) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + DnsResourceRecord *rr = NULL; + DnsSvcParam *param = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + + /* name */ 0x04, '_', '4', '4', '3', + 0x04, '_', 'w', 's', 's', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* SVCB */ 0x00, 0x40, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x54, + /* priority */ 0x00, 0x02, + /* target */ 0x04, 's', 'o', 'c', 'k', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* mandatory */ 0x00, 0x00, + 0x00, 0x04, + 0x00, 0x01, 0x00, 0x03, + /* alpn */ 0x00, 0x01, + 0x00, 0x0a, + 0x09, 'w', 'e', 'b', 's', 'o', 'c', 'k', 'e', 't', + /* no-deflt */ 0x00, 0x02, + 0x00, 0x00, + /* port */ 0x00, 0x03, + 0x00, 0x02, + 0x01, 0xbb, + /* ipv4hint */ 0x00, 0x04, + 0x00, 0x08, + 0x72, 0x84, 0xfd, 0x3a, + 0x48, 0xbc, 0xc7, 0xc0, + /* ipv6hint */ 0x00, 0x06, + 0x00, 0x10, + 0xf2, 0x34, 0x32, 0x2e, 0xb8, 0x25, 0x38, 0x35, + 0x2f, 0xd7, 0xdb, 0x7b, 0x28, 0x7e, 0x60, 0xbb + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 1u); + + rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_SVCB, "_443._wss.example.com"); + ASSERT_NOT_NULL(rr); + rr->ttl = 3600; + rr->svcb.priority = 2; + rr->svcb.target_name = strdup("sock.example.com"); + + add_svcb_param(rr, DNS_SVC_PARAM_KEY_MANDATORY, "\x00\x01\x00\x03", 4); + add_svcb_param(rr, DNS_SVC_PARAM_KEY_ALPN, "\x09websocket", 10); + add_svcb_param(rr, DNS_SVC_PARAM_KEY_NO_DEFAULT_ALPN, "", 0); + add_svcb_param(rr, DNS_SVC_PARAM_KEY_PORT, "\x01\xbb", 2); + + param = add_svcb_param(rr, DNS_SVC_PARAM_KEY_IPV4HINT, NULL, 2 * sizeof(struct in_addr)); + param->value_in_addr[0].s_addr = htobe32(0x7284fd3a); + param->value_in_addr[1].s_addr = htobe32(0x48bcc7c0); + + param = add_svcb_param(rr, DNS_SVC_PARAM_KEY_IPV6HINT, NULL, sizeof(struct in6_addr)); + param->value_in6_addr[0] = (struct in6_addr) { .s6_addr = { 0xf2, 0x34, 0x32, 0x2e, 0xb8, 0x25, 0x38, 0x35, 0x2f, 0xd7, 0xdb, 0x7b, 0x28, 0x7e, 0x60, 0xbb } }; + + check_answer_contains(packet, rr, DNS_ANSWER_SECTION_ADDITIONAL); + dns_resource_record_unref(rr); +} + +/* RFC 9460 says that clients MUST ignore any param keys that they do not recognise. We allow such keys to be + * parsed; handling of them is down to later business logic. */ + +TEST(packet_reply_svcb_service_mode_unknown_param) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + DnsResourceRecord *rr = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + + /* name */ 0x04, '_', '4', '4', '3', + 0x04, '_', 'w', 's', 's', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* HTTPS */ 0x00, 0x41, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x18, + /* priority */ 0x00, 0x02, + /* target */ 0x04, 's', 'o', 'c', 'k', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* unknown */ 0x00, 0x99, + 0x00, 0x00 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 1u); + + rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_HTTPS, "_443._wss.example.com"); + ASSERT_NOT_NULL(rr); + rr->ttl = 3600; + rr->svcb.priority = 2; + rr->svcb.target_name = strdup("sock.example.com"); + + add_svcb_param(rr, 153, NULL, 0); + + check_answer_contains(packet, rr, DNS_ANSWER_SECTION_ADDITIONAL); + dns_resource_record_unref(rr); +} + +TEST(packet_reply_svcb_service_mode_duplicate_key) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + + /* name */ 0x04, '_', '4', '4', '3', + 0x04, '_', 'w', 's', 's', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* SVCB */ 0x00, 0x40, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x20, + /* priority */ 0x00, 0x02, + /* target */ 0x04, 's', 'o', 'c', 'k', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* port */ 0x00, 0x03, + 0x00, 0x02, + 0x01, 0xbb, + /* port */ 0x00, 0x03, + 0x00, 0x02, + 0x01, 0xbc, + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_extract(packet), EBADMSG); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); +} + +TEST(packet_reply_svcb_service_mode_key_bad_order) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + + /* name */ 0x04, '_', '4', '4', '3', + 0x04, '_', 'w', 's', 's', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* SVCB */ 0x00, 0x40, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x1e, + /* priority */ 0x00, 0x02, + /* target */ 0x04, 's', 'o', 'c', 'k', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* port */ 0x00, 0x03, + 0x00, 0x02, + 0x01, 0xbb, + /* no-deflt */ 0x00, 0x02, + 0x00, 0x00 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_extract(packet), EBADMSG); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); +} + +TEST(packet_reply_svcb_service_mode_alpn_too_long) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + + /* name */ 0x04, '_', '4', '4', '3', + 0x04, '_', 'w', 's', 's', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* SVCB */ 0x00, 0x40, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x20, + /* priority */ 0x00, 0x02, + /* target */ 0x04, 's', 'o', 'c', 'k', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* alpn */ 0x00, 0x01, + 0x00, 0x07, + 0x04, 'h', 't', 't', 'p', + 0x02, 'w', 's' + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_extract(packet), EBADMSG); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); +} + +TEST(packet_reply_svcb_service_mode_alpn_too_short) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + + /* name */ 0x04, '_', '4', '4', '3', + 0x04, '_', 'w', 's', 's', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* SVCB */ 0x00, 0x40, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x20, + /* priority */ 0x00, 0x02, + /* target */ 0x04, 's', 'o', 'c', 'k', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* alpn */ 0x00, 0x01, + 0x00, 0x09, + 0x04, 'h', 't', 't', 'p', + 0x02, 'w', 's' + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_extract(packet), EMSGSIZE); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); +} + +TEST(packet_reply_svcb_service_mode_valid_alpn_overflows_rdata) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + + /* name */ 0x04, '_', '4', '4', '3', + 0x04, '_', 'w', 's', 's', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* SVCB */ 0x00, 0x40, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x1f, + /* priority */ 0x00, 0x02, + /* target */ 0x04, 's', 'o', 'c', 'k', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* alpn */ 0x00, 0x01, + 0x00, 0x08, + 0x04, 'h', 't', 't', 'p', + 0x02, 'w', 's' + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_extract(packet), EBADMSG); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); +} + +TEST(packet_reply_svcb_service_mode_valid_alpn_and_port_overflows_rdata) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + + /* name */ 0x04, '_', '4', '4', '3', + 0x04, '_', 'w', 's', 's', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* SVCB */ 0x00, 0x40, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x25, + /* priority */ 0x00, 0x02, + /* target */ 0x04, 's', 'o', 'c', 'k', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* alpn */ 0x00, 0x01, + 0x00, 0x08, + 0x04, 'h', 't', 't', 'p', + 0x02, 'w', 's', + /* port */ 0x00, 0x03, + 0x00, 0x02, + 0x01, 0xbb + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_extract(packet), EBADMSG); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); +} + +TEST(packet_reply_svcb_service_mode_bad_no_default_alpn) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + + /* name */ 0x04, '_', '4', '4', '3', + 0x04, '_', 'w', 's', 's', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* SVCB */ 0x00, 0x40, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x19, + /* priority */ 0x00, 0x02, + /* target */ 0x04, 's', 'o', 'c', 'k', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* no-deflt */ 0x00, 0x02, + 0x00, 0x01, + 0x0a + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_extract(packet), EBADMSG); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); +} + +TEST(packet_reply_svcb_service_mode_port_too_long) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + + /* name */ 0x04, '_', '4', '4', '3', + 0x04, '_', 'w', 's', 's', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* SVCB */ 0x00, 0x40, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x1b, + /* priority */ 0x00, 0x02, + /* target */ 0x04, 's', 'o', 'c', 'k', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* port */ 0x00, 0x03, + 0x00, 0x03, + 0x01, 0xbb, 0xff + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_extract(packet), EBADMSG); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); +} + +TEST(packet_reply_svcb_service_mode_port_too_short) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + + /* name */ 0x04, '_', '4', '4', '3', + 0x04, '_', 'w', 's', 's', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* SVCB */ 0x00, 0x40, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x19, + /* priority */ 0x00, 0x02, + /* target */ 0x04, 's', 'o', 'c', 'k', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* port */ 0x00, 0x03, + 0x00, 0x01, + 0xbb + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_extract(packet), EBADMSG); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); +} + +TEST(packet_reply_svcb_service_mode_bad_ipv4hint) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + + /* name */ 0x04, '_', '4', '4', '3', + 0x04, '_', 'w', 's', 's', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* SVCB */ 0x00, 0x40, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x1b, + /* priority */ 0x00, 0x02, + /* target */ 0x04, 's', 'o', 'c', 'k', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* ipv4hint */ 0x00, 0x04, + 0x00, 0x03, + 0x2f, 0x47, 0x34 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_extract(packet), EBADMSG); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); +} + +TEST(packet_reply_svcb_service_mode_bad_ipv6hint) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + + /* name */ 0x04, '_', '4', '4', '3', + 0x04, '_', 'w', 's', 's', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* SVCB */ 0x00, 0x40, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x27, + /* priority */ 0x00, 0x02, + /* target */ 0x04, 's', 'o', 'c', 'k', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* ipv6hint */ 0x00, 0x06, + 0x00, 0x0f, + 0x09, 0x36, 0xba, 0x5d, 0x17, 0x42, 0x47, 0xa2, + 0x14, 0xcc, 0x77, 0x67, 0x51, 0x68, 0xef + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_extract(packet), EBADMSG); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); +} + DEFINE_TEST_MAIN(LOG_DEBUG) From b0a0743b7175970f5987327b24728c4e242fc901 Mon Sep 17 00:00:00 2001 From: James Coglan Date: Tue, 11 Jun 2024 10:26:02 +0100 Subject: [PATCH 13/40] resolved: tests for dns_packet_extract(); parsing HINFO records --- src/resolve/test-dns-packet-extract.c | 140 ++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) diff --git a/src/resolve/test-dns-packet-extract.c b/src/resolve/test-dns-packet-extract.c index c185bb95ea..d467002832 100644 --- a/src/resolve/test-dns-packet-extract.c +++ b/src/resolve/test-dns-packet-extract.c @@ -1788,6 +1788,146 @@ TEST(packet_reply_soa_rdata_partial_final_field) { ASSERT_EQ(dns_answer_size(packet->answer), 0u); } +/* ================================================================ + * reply: HINFO + * ================================================================ */ + +TEST(packet_reply_hinfo_basic) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + DnsResourceRecord *rr = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* HINFO */ 0x00, 0x0d, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x14, + /* cpu */ 0x09, 'I', 'n', 't', 'e', 'l', ' ', 'x', '6', '4', + /* os */ 0x09, 'G', 'N', 'U', '/', 'L', 'i', 'n', 'u', 'x' + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 1u); + + rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_HINFO, "example.com"); + ASSERT_NOT_NULL(rr); + rr->ttl = 3600; + rr->hinfo.cpu = strdup("Intel x64"); + rr->hinfo.os = strdup("GNU/Linux"); + + check_answer_contains(packet, rr, DNS_ANSWER_SECTION_ANSWER | DNS_ANSWER_CACHEABLE); + dns_resource_record_unref(rr); +} + +TEST(packet_reply_hinfo_overflow) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + + /* name */ 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* HINFO */ 0x00, 0x0d, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x13, + /* cpu */ 0x09, 'I', 'n', 't', 'e', 'l', ' ', 'x', '6', '4', + /* os */ 0x09, 'G', 'N', 'U', '/', 'L', 'i', 'n', 'u', 'x' + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_extract(packet), EBADMSG); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); +} + +TEST(packet_reply_hinfo_valid_utf8) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + DnsResourceRecord *rr = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* HINFO */ 0x00, 0x0d, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x17, + /* cpu */ 0x09, 'I', 'n', 't', 'e', 'l', ' ', 'x', '6', '4', + /* os */ 0x0c, 'G', 'N', 0xf0, 0x9d, 0x95, 0x8c, '/', 'L', 'i', 'n', 'u', 'x' + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 1u); + + rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_HINFO, "example.com"); + ASSERT_NOT_NULL(rr); + rr->ttl = 3600; + rr->hinfo.cpu = strdup("Intel x64"); + rr->hinfo.os = strdup("GN𝕌/Linux"); + + check_answer_contains(packet, rr, DNS_ANSWER_SECTION_ANSWER | DNS_ANSWER_CACHEABLE); + dns_resource_record_unref(rr); +} + +TEST(packet_reply_hinfo_invalid_utf8) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + + /* name */ 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* HINFO */ 0x00, 0x0d, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x16, + /* cpu */ 0x09, 'I', 'n', 't', 'e', 'l', ' ', 'x', '6', '4', + /* os */ 0x0b, 'G', 'N', 0xf0, 0x9d, 0x95, '/', 'L', 'i', 'n', 'u', 'x' + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_extract(packet), EBADMSG); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); +} + /* ================================================================ * reply: SRV * ================================================================ */ From 99fe3607cab69256ef7b2bd643ea3157c117db8e Mon Sep 17 00:00:00 2001 From: James Coglan Date: Tue, 11 Jun 2024 10:36:10 +0100 Subject: [PATCH 14/40] resolved: tests for dns_packet_extract(); parsing NAPTR records --- src/resolve/test-dns-packet-extract.c | 104 ++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/src/resolve/test-dns-packet-extract.c b/src/resolve/test-dns-packet-extract.c index d467002832..e9cec06469 100644 --- a/src/resolve/test-dns-packet-extract.c +++ b/src/resolve/test-dns-packet-extract.c @@ -2103,6 +2103,110 @@ TEST(packet_reply_srv_allow_non_srv_names) { dns_resource_record_unref(rr); } +/* ================================================================ + * reply: NAPTR + * ================================================================ */ + +TEST(packet_reply_naptr_basic) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + DnsResourceRecord *rr = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x01, '4', 0x01, '3', 0x01, '2', 0x01, '1', + 0x01, '5', 0x01, '5', 0x01, '5', + 0x01, '0', 0x01, '0', 0x01, '8', 0x01, '1', + 0x04, 'e', '1', '6', '4', + 0x04, 'a', 'r', 'p', 'a', + 0x00, + /* NAPTR */ 0x00, 0x23, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x4d, + /* order */ 0x00, 0x66, + /* pref */ 0x00, 0x0a, + /* flags */ 0x01, 'U', + /* services */ 0x07, 'E', '2', 'U', '+', 's', 'i', 'p', + /* regexp */ 0x27, + '!', '^', '.', '*', '$', '!', 's', 'i', + 'p', ':', 'c', 'u', 's', 't', 'o', 'm', + 'e', 'r', '-', 's', 'e', 'r', 'v', 'i', + 'c', 'e', '@', 'e', 'x', 'a', 'm', 'p', + 'l', 'e', '.', 'c', 'o', 'm', '!', + /* replace */ 0x04, '_', 's', 'i', 'p', + 0x04, '_', 'u', 'd', 'p', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 1u); + + rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_NAPTR, "4.3.2.1.5.5.5.0.0.8.1.e164.arpa"); + ASSERT_NOT_NULL(rr); + rr->ttl = 3600; + rr->naptr.order = 102; + rr->naptr.preference = 10; + rr->naptr.flags = strdup("U"); + rr->naptr.services = strdup("E2U+sip"); + rr->naptr.regexp = strdup("!^.*$!sip:customer-service@example.com!"); + rr->naptr.replacement = strdup("_sip._udp.example.com"); + + check_answer_contains(packet, rr, DNS_ANSWER_SECTION_ANSWER | DNS_ANSWER_CACHEABLE); + dns_resource_record_unref(rr); +} + +TEST(packet_reply_naptr_compressed_replace) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x01, '4', 0x01, '3', 0x01, '2', 0x01, '1', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* NAPTR */ 0x00, 0x23, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x4d, + /* order */ 0x00, 0x66, + /* pref */ 0x00, 0x0a, + /* flags */ 0x01, 'U', + /* services */ 0x07, 'E', '2', 'U', '+', 's', 'i', 'p', + /* regexp */ 0x27, + '!', '^', '.', '*', '$', '!', 's', 'i', + 'p', ':', 'c', 'u', 's', 't', 'o', 'm', + 'e', 'r', '-', 's', 'e', 'r', 'v', 'i', + 'c', 'e', '@', 'e', 'x', 'a', 'm', 'p', + 'l', 'e', '.', 'c', 'o', 'm', '!', + /* replace */ 0x04, '_', 's', 'i', 'p', + 0x04, '_', 'u', 'd', 'p', + 0xc0, 0x14 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_extract(packet), EBADMSG); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); +} + /* ================================================================ * reply: RRSIG * ================================================================ */ From 6cf9767e1c9f1b61a10415061afec5a95fde0ffa Mon Sep 17 00:00:00 2001 From: James Coglan Date: Tue, 11 Jun 2024 11:57:36 +0100 Subject: [PATCH 15/40] resolved: tests for dns_packet_extract(); parsing OPT records These tests identify a couple of problems with OPT pseudo-RR parsing. First, any TTL value with the high bit set is replaced with zero before checking the record type. For most types this is correct, since TTLs have the range of signed int32. But for OPT records where the TTL is repurposed to hold the extended RCODE, EDNS version and flags, it means that the high bit cannot be used in extended RCODEs. Any RCODE with the high bit set will be read as zero. Second, the DNS_PACKET_RCODE() function bit-shifts the extended RCODE by 24 places instead of 20, so that it ends up forming the lower 8 bits of a 12-bit RCODE, instead of the upper 8 bits as intended. We intend to fix these issues in other pull requests. --- src/resolve/test-dns-packet-extract.c | 403 ++++++++++++++++++++++++++ 1 file changed, 403 insertions(+) diff --git a/src/resolve/test-dns-packet-extract.c b/src/resolve/test-dns-packet-extract.c index e9cec06469..65cb08f2bc 100644 --- a/src/resolve/test-dns-packet-extract.c +++ b/src/resolve/test-dns-packet-extract.c @@ -2207,6 +2207,409 @@ TEST(packet_reply_naptr_compressed_replace) { ASSERT_EQ(dns_answer_size(packet->answer), 0u); } +/* ================================================================ + * reply: OPT + * ================================================================ */ + +TEST(packet_reply_opt_no_do_empty) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + DnsResourceRecord *rr = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_NXDOMAIN, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + + /* name */ 0x00, + /* OPT */ 0x00, 0x29, + /* udp max */ 0x02, 0x01, + /* rcode */ 0x9a, + /* version */ 0x00, + /* flags */ 0x00, 0x00, + /* rdata */ 0x00, 0x00 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); + + rr = dns_resource_record_new_full(513, DNS_TYPE_OPT, ""); + ASSERT_NOT_NULL(rr); + rr->ttl = 2046820352; + + ASSERT_TRUE(dns_resource_record_equal(packet->opt, rr)); + dns_resource_record_unref(rr); + + ASSERT_EQ(DNS_PACKET_PAYLOAD_SIZE_MAX(packet), 513u); + ASSERT_EQ(DNS_PACKET_RCODE(packet), 2467u); + ASSERT_EQ(DNS_PACKET_DO(packet), 0u); +} + +TEST(packet_reply_opt_multiple) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + + /* name */ 0x00, + /* OPT */ 0x00, 0x29, + /* udp max */ 0x02, 0x01, + /* rcode */ 0x7a, + /* version */ 0x00, + /* flags */ 0x00, 0x00, + /* rdata */ 0x00, 0x00, + + /* name */ 0x00, + /* OPT */ 0x00, 0x29, + /* udp max */ 0x02, 0x01, + /* rcode */ 0x7a, + /* version */ 0x00, + /* flags */ 0x00, 0x00, + /* rdata */ 0x00, 0x00 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); + ASSERT_NULL(packet->opt); +} + +TEST(packet_reply_opt_not_root) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + + /* name */ 0x03, 'c', 'o', 'm', + 0x00, + /* OPT */ 0x00, 0x29, + /* udp max */ 0x02, 0x01, + /* rcode */ 0x00, + /* version */ 0x00, + /* flags */ 0x00, 0x00, + /* rdata */ 0x00, 0x00 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); + ASSERT_NULL(packet->opt); +} + +TEST(packet_reply_opt_wrong_section) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + + /* name */ 0x00, + /* OPT */ 0x00, 0x29, + /* udp max */ 0x02, 0x01, + /* rcode */ 0x00, + /* version */ 0x00, + /* flags */ 0x00, 0x00, + /* rdata */ 0x00, 0x00 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); + ASSERT_NULL(packet->opt); +} + +TEST(packet_query_opt_version_ok) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + DnsResourceRecord *rr = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + + /* name */ 0x00, + /* OPT */ 0x00, 0x29, + /* udp max */ 0x02, 0x01, + /* rcode */ 0x00, + /* version */ 0x01, + /* flags */ 0x00, 0x00, + /* rdata */ 0x00, 0x00 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); + + rr = dns_resource_record_new_full(513, DNS_TYPE_OPT, ""); + ASSERT_NOT_NULL(rr); + rr->ttl = 65536; + + ASSERT_TRUE(dns_resource_record_equal(packet->opt, rr)); + dns_resource_record_unref(rr); + + ASSERT_EQ(DNS_PACKET_PAYLOAD_SIZE_MAX(packet), 513u); + ASSERT_EQ(DNS_PACKET_DO(packet), 0u); +} + +TEST(packet_reply_opt_version_bad) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + + /* name */ 0x00, + /* OPT */ 0x00, 0x29, + /* udp max */ 0x02, 0x01, + /* rcode */ 0x00, + /* version */ 0x01, + /* flags */ 0x00, 0x00, + /* rdata */ 0x00, 0x00 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_extract(packet), EBADMSG); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); + ASSERT_NULL(packet->opt); +} + +TEST(packet_reply_opt_with_do) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + DnsResourceRecord *rr = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + + /* name */ 0x00, + /* OPT */ 0x00, 0x29, + /* udp max */ 0x10, 0x01, + /* rcode */ 0x00, + /* version */ 0x00, + /* flags */ 0x80, 0x00, + /* rdata */ 0x00, 0x00 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); + + rr = dns_resource_record_new_full(4097, DNS_TYPE_OPT, ""); + ASSERT_NOT_NULL(rr); + rr->ttl = 32768; + + ASSERT_TRUE(dns_resource_record_equal(packet->opt, rr)); + dns_resource_record_unref(rr); + + ASSERT_EQ(DNS_PACKET_PAYLOAD_SIZE_MAX(packet), 4097u); + ASSERT_EQ(DNS_PACKET_DO(packet), 1u); +} + +TEST(packet_reply_opt_with_data) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + DnsResourceRecord *rr = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + + /* name */ 0x00, + /* OPT */ 0x00, 0x29, + /* udp max */ 0x02, 0x01, + /* rcode */ 0x00, + /* version */ 0x00, + /* flags */ 0x00, 0x00, + /* rdata */ 0x00, 0x12, + 0x00, 0x01, + 0x00, 0x05, + 'h', 'e', 'l', 'l', 'o', + 0x00, 0x02, + 0x00, 0x05, + 'w', 'o', 'r', 'l', 'd' + }; + + const uint8_t opt_data[] = { + 0x00, 0x01, + 0x00, 0x05, + 'h', 'e', 'l', 'l', 'o', + 0x00, 0x02, + 0x00, 0x05, + 'w', 'o', 'r', 'l', 'd' + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); + + rr = dns_resource_record_new_full(513, DNS_TYPE_OPT, ""); + ASSERT_NOT_NULL(rr); + rr->ttl = 0; + rr->opt.data_size = sizeof(opt_data); + rr->opt.data = calloc(rr->opt.data_size, sizeof(uint8_t)); + ASSERT_NOT_NULL(rr->opt.data); + memcpy(rr->opt.data, opt_data, sizeof(opt_data)); + + ASSERT_TRUE(dns_resource_record_equal(packet->opt, rr)); + dns_resource_record_unref(rr); +} + +TEST(packet_reply_opt_bad_data_size) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + + /* name */ 0x00, + /* OPT */ 0x00, 0x29, + /* udp max */ 0x02, 0x01, + /* rcode */ 0x00, + /* version */ 0x00, + /* flags */ 0x00, 0x00, + /* rdata */ 0x00, 0x13, + 0x00, 0x01, + 0x00, 0x05, + 'h', 'e', 'l', 'l', 'o', + 0x00, 0x02, + 0x00, 0x05, + 'w', 'o', 'r', 'l', 'd' + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_extract(packet), EBADMSG); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); + ASSERT_NULL(packet->opt); +} + +TEST(packet_query_opt_with_rfc6975_data) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + DnsResourceRecord *rr = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + + /* name */ 0x00, + /* OPT */ 0x00, 0x29, + /* udp max */ 0x02, 0x01, + /* rcode */ 0x00, + /* version */ 0x00, + /* flags */ 0x00, 0x00, + /* rdata */ 0x00, 0x05, + 0x00, 0x05, /* RFC 6975 defines codes 5, 6, 7 */ + 0x00, 0x01, + 0xff + }; + + const uint8_t opt_data[] = { 0x00, 0x05, 0x00, 0x01, 0xff }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); + + rr = dns_resource_record_new_full(513, DNS_TYPE_OPT, ""); + ASSERT_NOT_NULL(rr); + rr->ttl = 0; + rr->opt.data_size = sizeof(opt_data); + rr->opt.data = calloc(rr->opt.data_size, sizeof(uint8_t)); + ASSERT_NOT_NULL(rr->opt.data); + memcpy(rr->opt.data, opt_data, sizeof(opt_data)); + + ASSERT_TRUE(dns_resource_record_equal(packet->opt, rr)); + dns_resource_record_unref(rr); +} + +TEST(packet_reply_opt_with_rfc6975_data) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + + /* name */ 0x00, + /* OPT */ 0x00, 0x29, + /* udp max */ 0x02, 0x01, + /* rcode */ 0x00, + /* version */ 0x00, + /* flags */ 0x00, 0x00, + /* rdata */ 0x00, 0x05, + 0x00, 0x05, /* RFC 6975 defines codes 5, 6, 7 */ + 0x00, 0x01, + 0xff + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); + ASSERT_NULL(packet->opt); +} + /* ================================================================ * reply: RRSIG * ================================================================ */ From 2dd00dba2546f5ac42ec769991f153971e7c2cad Mon Sep 17 00:00:00 2001 From: James Coglan Date: Wed, 12 Jun 2024 13:27:52 +0100 Subject: [PATCH 16/40] resolved: tests for dns_packet_extract(); parsing TXT records --- src/resolve/test-dns-packet-extract.c | 119 ++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) diff --git a/src/resolve/test-dns-packet-extract.c b/src/resolve/test-dns-packet-extract.c index 65cb08f2bc..9f077a2252 100644 --- a/src/resolve/test-dns-packet-extract.c +++ b/src/resolve/test-dns-packet-extract.c @@ -1928,6 +1928,125 @@ TEST(packet_reply_hinfo_invalid_utf8) { ASSERT_EQ(dns_answer_size(packet->answer), 0u); } +/* ================================================================ + * reply: TXT + * ================================================================ */ + +TEST(packet_reply_txt) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + DnsResourceRecord *rr = NULL; + DnsTxtItem *item = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* TXT */ 0x00, 0x10, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x09, + 0x02, 'h', 'i', + 0x05, 'w', 'o', 'r', 'l', 'd' + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 1u); + + rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_TXT, "example.com"); + ASSERT_NOT_NULL(rr); + rr->ttl = 3600; + + item = calloc(1, offsetof(DnsTxtItem, data) + 3); + ASSERT_NOT_NULL(item); + item->length = 2; + memcpy(item->data, "hi", 3); + LIST_APPEND(items, rr->txt.items, item); + + item = calloc(1, offsetof(DnsTxtItem, data) + 6); + ASSERT_NOT_NULL(item); + item->length = 5; + memcpy(item->data, "world", 6); + LIST_APPEND(items, rr->txt.items, item); + + check_answer_contains(packet, rr, DNS_ANSWER_SECTION_ANSWER | DNS_ANSWER_CACHEABLE); + dns_resource_record_unref(rr); +} + +TEST(packet_reply_txt_empty) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + DnsResourceRecord *rr = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* TXT */ 0x00, 0x10, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x00 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 1u); + + rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_TXT, "example.com"); + ASSERT_NOT_NULL(rr); + rr->ttl = 3600; + dns_txt_item_new_empty(&rr->txt.items); + + check_answer_contains(packet, rr, DNS_ANSWER_SECTION_ANSWER | DNS_ANSWER_CACHEABLE); + dns_resource_record_unref(rr); +} + +TEST(packet_reply_txt_overflow_rdata) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* TXT */ 0x00, 0x10, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x08, + 0x02, 'h', 'i', + 0x05, 'w', 'o', 'r', 'l', 'd' + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_extract(packet), EBADMSG); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 0u); +} + /* ================================================================ * reply: SRV * ================================================================ */ From e067858bb1e9f8fec96eeaaa618e8c1a66771563 Mon Sep 17 00:00:00 2001 From: James Coglan Date: Wed, 12 Jun 2024 18:47:30 +0100 Subject: [PATCH 17/40] resolved: tests for dns_packet_extract(); parsing LOC records --- src/resolve/test-dns-packet-extract.c | 99 +++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/src/resolve/test-dns-packet-extract.c b/src/resolve/test-dns-packet-extract.c index 9f077a2252..9cca1c2981 100644 --- a/src/resolve/test-dns-packet-extract.c +++ b/src/resolve/test-dns-packet-extract.c @@ -2047,6 +2047,105 @@ TEST(packet_reply_txt_overflow_rdata) { ASSERT_EQ(dns_answer_size(packet->answer), 0u); } +/* ================================================================ + * reply: LOC + * ================================================================ */ + +TEST(packet_reply_loc_basic) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + DnsResourceRecord *rr = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* LOC */ 0x00, 0x1d, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x10, + /* version */ 0x00, + /* size */ 0x29, + /* horiz pre */ 0x34, + /* vert pre */ 0x53, + /* latitude */ 0x8b, 0x0d, 0x08, 0xf5, + /* longitude */ 0x7f, 0xf8, 0x39, 0x48, + /* altitude */ 0x00, 0x98, 0x96, 0x80 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 1u); + + rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_LOC, "example.com"); + ASSERT_NOT_NULL(rr); + rr->ttl = 3600; + rr->loc.version = 0; + rr->loc.size = 0x29; + rr->loc.horiz_pre = 0x34; + rr->loc.vert_pre = 0x53; + rr->loc.latitude = 2332887285; + rr->loc.longitude = 2146974024; + rr->loc.altitude = 10000000; + + check_answer_contains(packet, rr, DNS_ANSWER_SECTION_ANSWER | DNS_ANSWER_CACHEABLE); + dns_resource_record_unref(rr); +} + +TEST(packet_reply_loc_bad_version) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + DnsResourceRecord *rr = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* LOC */ 0x00, 0x1d, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x10, + /* rdata */ 0x00, 0x10, + /* version */ 0x01, + /* size */ 0x29, + /* horiz pre */ 0x34, + /* vert pre */ 0x53, + /* latitude */ 0x8b, 0x0d, 0x08, 0xf5, + /* longitude */ 0x7f, 0xf8, 0x39, 0x48, + /* altitude */ 0x00, 0x98, 0x96, 0x80 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + ASSERT_EQ(dns_question_size(packet->question), 0u); + ASSERT_EQ(dns_answer_size(packet->answer), 1u); + + rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_LOC, "example.com"); + ASSERT_NOT_NULL(rr); + rr->unparsable = true; + rr->generic.data_size = 16; + rr->generic.data = calloc(rr->generic.data_size, sizeof(uint8_t)); + ASSERT_NOT_NULL(rr->generic.data); + memcpy(rr->generic.data, data + 35, rr->generic.data_size); + + check_answer_contains(packet, rr, DNS_ANSWER_SECTION_ANSWER | DNS_ANSWER_CACHEABLE); + dns_resource_record_unref(rr); +} + /* ================================================================ * reply: SRV * ================================================================ */ From eedf263bd0c9afe49d2ed03667e0d1f028fc3092 Mon Sep 17 00:00:00 2001 From: James Coglan Date: Tue, 11 Jun 2024 14:44:26 +0100 Subject: [PATCH 18/40] resolved: tests for dns_packet_equal() --- src/resolve/test-dns-packet-extract.c | 52 +++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/resolve/test-dns-packet-extract.c b/src/resolve/test-dns-packet-extract.c index 9cca1c2981..e1cbb1ca71 100644 --- a/src/resolve/test-dns-packet-extract.c +++ b/src/resolve/test-dns-packet-extract.c @@ -3784,4 +3784,56 @@ TEST(packet_reply_svcb_service_mode_bad_ipv6hint) { ASSERT_EQ(dns_answer_size(packet->answer), 0u); } +/* ================================================================ + * dns_packet_equal() + * ================================================================ */ + +TEST(packet_equal_match) { + _cleanup_(dns_packet_unrefp) DnsPacket *p1 = NULL, *p2 = NULL; + + ASSERT_OK(dns_packet_new(&p1, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(p1); + dns_packet_truncate(p1, 0); + + ASSERT_OK(dns_packet_new(&p2, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(p2); + dns_packet_truncate(p2, 0); + + const uint8_t data[] = { + 0x00, 0x2a, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00 + }; + + ASSERT_OK(dns_packet_append_blob(p1, data, sizeof(data), NULL)); + ASSERT_OK(dns_packet_append_blob(p2, data, sizeof(data), NULL)); + ASSERT_TRUE(dns_packet_equal(p1, p2)); +} + +TEST(packet_equal_no_match) { + _cleanup_(dns_packet_unrefp) DnsPacket *p1 = NULL, *p2 = NULL; + + ASSERT_OK(dns_packet_new(&p1, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(p1); + dns_packet_truncate(p1, 0); + + const uint8_t data1[] = { + 0x00, 0x2a, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00 + }; + + ASSERT_OK(dns_packet_append_blob(p1, data1, sizeof(data1), NULL)); + + ASSERT_OK(dns_packet_new(&p2, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(p2); + dns_packet_truncate(p2, 0); + + const uint8_t data2[] = { + 0x00, 0x2a, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01 + }; + + ASSERT_OK(dns_packet_append_blob(p2, data2, sizeof(data2), NULL)); + ASSERT_FALSE(dns_packet_equal(p1, p2)); +} + DEFINE_TEST_MAIN(LOG_DEBUG) From 9728540e61be5035432c65a49d8dc04c275b3aae Mon Sep 17 00:00:00 2001 From: James Coglan Date: Tue, 11 Jun 2024 14:47:59 +0100 Subject: [PATCH 19/40] resolved: tests for dns_ede_rcode_is_dnssec() --- src/resolve/test-dns-packet-extract.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/resolve/test-dns-packet-extract.c b/src/resolve/test-dns-packet-extract.c index e1cbb1ca71..d52ee24420 100644 --- a/src/resolve/test-dns-packet-extract.c +++ b/src/resolve/test-dns-packet-extract.c @@ -3836,4 +3836,25 @@ TEST(packet_equal_no_match) { ASSERT_FALSE(dns_packet_equal(p1, p2)); } +/* ================================================================ + * dns_ede_rcode_is_dnssec() + * ================================================================ */ + +TEST(dns_ede_rcode_is_dnssec) { + ASSERT_TRUE(dns_ede_rcode_is_dnssec(DNS_EDE_RCODE_UNSUPPORTED_DNSKEY_ALG)); + ASSERT_TRUE(dns_ede_rcode_is_dnssec(DNS_EDE_RCODE_UNSUPPORTED_DS_DIGEST)); + ASSERT_TRUE(dns_ede_rcode_is_dnssec(DNS_EDE_RCODE_DNSSEC_INDETERMINATE)); + ASSERT_TRUE(dns_ede_rcode_is_dnssec(DNS_EDE_RCODE_DNSSEC_BOGUS)); + ASSERT_TRUE(dns_ede_rcode_is_dnssec(DNS_EDE_RCODE_SIG_EXPIRED)); + ASSERT_TRUE(dns_ede_rcode_is_dnssec(DNS_EDE_RCODE_SIG_NOT_YET_VALID)); + ASSERT_TRUE(dns_ede_rcode_is_dnssec(DNS_EDE_RCODE_DNSKEY_MISSING)); + ASSERT_TRUE(dns_ede_rcode_is_dnssec(DNS_EDE_RCODE_RRSIG_MISSING)); + ASSERT_TRUE(dns_ede_rcode_is_dnssec(DNS_EDE_RCODE_NO_ZONE_KEY_BIT)); + ASSERT_TRUE(dns_ede_rcode_is_dnssec(DNS_EDE_RCODE_NSEC_MISSING)); + + ASSERT_FALSE(dns_ede_rcode_is_dnssec(DNS_EDE_RCODE_BLOCKED)); + ASSERT_FALSE(dns_ede_rcode_is_dnssec(DNS_EDE_RCODE_CENSORED)); + ASSERT_FALSE(dns_ede_rcode_is_dnssec(DNS_EDE_RCODE_OTHER)); +} + DEFINE_TEST_MAIN(LOG_DEBUG) From d6c13c68177b1889508ddef29d5bf77be37e83a1 Mon Sep 17 00:00:00 2001 From: James Coglan Date: Tue, 11 Jun 2024 15:26:27 +0100 Subject: [PATCH 20/40] resolved: tests for dns_packet_ede_rcode() --- src/resolve/test-dns-packet-extract.c | 204 ++++++++++++++++++++++++++ 1 file changed, 204 insertions(+) diff --git a/src/resolve/test-dns-packet-extract.c b/src/resolve/test-dns-packet-extract.c index d52ee24420..1413ef17a4 100644 --- a/src/resolve/test-dns-packet-extract.c +++ b/src/resolve/test-dns-packet-extract.c @@ -2828,6 +2828,210 @@ TEST(packet_reply_opt_with_rfc6975_data) { ASSERT_NULL(packet->opt); } +/* ================================================================ + * dns_packet_ede_rcode() + * ================================================================ */ + +TEST(packet_ede_rcode_empty) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + int ret_ede_rcode; + char *ret_ede_msg; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + + /* name */ 0x00, + /* OPT */ 0x00, 0x29, + /* udp max */ 0x02, 0x01, + /* rcode */ 0x00, + /* version */ 0x00, + /* flags */ 0x80, 0x00, + /* rdata */ 0x00, 0x00 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + + ASSERT_ERROR(dns_packet_ede_rcode(packet, &ret_ede_rcode, &ret_ede_msg), ENOENT); +} + +TEST(packet_ede_rcode_ede_option_code) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + _cleanup_free_ char *ret_ede_msg; + int ret_ede_rcode; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + + /* name */ 0x00, + /* OPT */ 0x00, 0x29, + /* udp max */ 0x02, 0x01, + /* rcode */ 0x00, + /* version */ 0x00, + /* flags */ 0x80, 0x00, + /* rdata */ 0x00, 0x12, + 0x00, 0x0f, /* extended DNS error */ + 0x00, 0x0e, /* length */ + 0x00, 0x06, /* DNSSEC bogus */ + 'D', 'N', 'S', 'S', 'E', 'C', ' ', 'b', 'o', 'g', 'u', 's' + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + + ASSERT_EQ(dns_packet_ede_rcode(packet, &ret_ede_rcode, &ret_ede_msg), 0); + ASSERT_EQ(ret_ede_rcode, DNS_EDE_RCODE_DNSSEC_BOGUS); + ASSERT_STREQ(ret_ede_msg, "DNSSEC bogus"); +} + +TEST(packet_ede_rcode_ede_valid_utf8) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + _cleanup_free_ char *ret_ede_msg; + int ret_ede_rcode; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + + /* name */ 0x00, + /* OPT */ 0x00, 0x29, + /* udp max */ 0x02, 0x01, + /* rcode */ 0x00, + /* version */ 0x00, + /* flags */ 0x80, 0x00, + /* rdata */ 0x00, 0x0d, + 0x00, 0x0f, /* extended DNS error */ + 0x00, 0x09, /* length */ + 0x00, 0x06, /* DNSSEC bogus */ + 'b', 0xc3, 0xb8, 'g', 0xc3, 0xbc, 's' + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + + ASSERT_EQ(dns_packet_ede_rcode(packet, &ret_ede_rcode, &ret_ede_msg), 0); + ASSERT_EQ(ret_ede_rcode, DNS_EDE_RCODE_DNSSEC_BOGUS); + ASSERT_STREQ(ret_ede_msg, "bøgüs"); +} + +TEST(packet_ede_rcode_ede_invalid_utf8) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + _cleanup_free_ char *ret_ede_msg; + int ret_ede_rcode; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + + /* name */ 0x00, + /* OPT */ 0x00, 0x29, + /* udp max */ 0x02, 0x01, + /* rcode */ 0x00, + /* version */ 0x00, + /* flags */ 0x80, 0x00, + /* rdata */ 0x00, 0x0d, + 0x00, 0x0f, /* extended DNS error */ + 0x00, 0x09, /* length */ + 0x00, 0x06, /* DNSSEC bogus */ + 'b', 0xc3, 0xb8, 'g', 0xc3, 0xbc, 0xff + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + + ASSERT_EQ(dns_packet_ede_rcode(packet, &ret_ede_rcode, &ret_ede_msg), 0); + ASSERT_EQ(ret_ede_rcode, DNS_EDE_RCODE_DNSSEC_BOGUS); + ASSERT_STREQ(ret_ede_msg, "b\\303\\270g\\303\\274\\377"); +} + +TEST(packet_ede_rcode_non_ede_code) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + int ret_ede_rcode; + char *ret_ede_msg; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + + /* name */ 0x00, + /* OPT */ 0x00, 0x29, + /* udp max */ 0x02, 0x01, + /* rcode */ 0x00, + /* version */ 0x00, + /* flags */ 0x80, 0x00, + /* rdata */ 0x00, 0x12, + 0x00, 0x01, /* not EDE option code */ + 0x00, 0x0e, /* length */ + 0x00, 0x06, /* DNSSEC bogus */ + 'D', 'N', 'S', 'S', 'E', 'C', ' ', 'b', 'o', 'g', 'u', 's' + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + + ASSERT_ERROR(dns_packet_ede_rcode(packet, &ret_ede_rcode, &ret_ede_msg), ENOENT); +} + +TEST(packet_ede_rcode_malformed_ede_payload) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + int ret_ede_rcode; + char *ret_ede_msg; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + + /* name */ 0x00, + /* OPT */ 0x00, 0x29, + /* udp max */ 0x02, 0x01, + /* rcode */ 0x00, + /* version */ 0x00, + /* flags */ 0x80, 0x00, + /* rdata */ 0x00, 0x12, + 0x00, 0x0f, /* extended DNS error */ + 0x00, 0x0d, /* length */ + 0x00, 0x06, /* DNSSEC bogus */ + 'D', 'N', 'S', 'S', 'E', 'C', ' ', 'b', 'o', 'g', 'u', 's' + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + + ASSERT_ERROR(dns_packet_ede_rcode(packet, &ret_ede_rcode, &ret_ede_msg), ENOENT); +} + /* ================================================================ * reply: RRSIG * ================================================================ */ From 59e987a0b7cc8992f96db95d5e2027215662b90d Mon Sep 17 00:00:00 2001 From: James Coglan Date: Tue, 11 Jun 2024 15:48:30 +0100 Subject: [PATCH 21/40] resolved: tests for dns_packet_has_nsid_request() --- src/resolve/test-dns-packet-extract.c | 121 ++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) diff --git a/src/resolve/test-dns-packet-extract.c b/src/resolve/test-dns-packet-extract.c index 1413ef17a4..440eba3e9b 100644 --- a/src/resolve/test-dns-packet-extract.c +++ b/src/resolve/test-dns-packet-extract.c @@ -3032,6 +3032,127 @@ TEST(packet_ede_rcode_malformed_ede_payload) { ASSERT_ERROR(dns_packet_ede_rcode(packet, &ret_ede_rcode, &ret_ede_msg), ENOENT); } +/* ================================================================ + * dns_packet_has_nsid_request() + * ================================================================ */ + +TEST(packet_has_nsid_request_no_match) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + + /* name */ 0x00, + /* OPT */ 0x00, 0x29, + /* udp max */ 0x02, 0x01, + /* rcode */ 0x00, + /* version */ 0x00, + /* flags */ 0x80, 0x00, + /* rdata */ 0x00, 0x00 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + + ASSERT_FALSE(dns_packet_has_nsid_request(packet)); +} + +TEST(packet_has_nsid_request_match_empty_option) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + + /* name */ 0x00, + /* OPT */ 0x00, 0x29, + /* udp max */ 0x02, 0x01, + /* rcode */ 0x00, + /* version */ 0x00, + /* flags */ 0x80, 0x00, + /* rdata */ 0x00, 0x04, + 0x00, 0x03, /* NSID option code */ + 0x00, 0x00 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + + ASSERT_TRUE(dns_packet_has_nsid_request(packet)); +} + +TEST(packet_has_nsid_request_match_multiple) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + + /* name */ 0x00, + /* OPT */ 0x00, 0x29, + /* udp max */ 0x02, 0x01, + /* rcode */ 0x00, + /* version */ 0x00, + /* flags */ 0x80, 0x00, + /* rdata */ 0x00, 0x08, + 0x00, 0x03, /* NSID option code */ + 0x00, 0x00, + 0x00, 0x03, /* NSID option code */ + 0x00, 0x00 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + + ASSERT_ERROR(dns_packet_has_nsid_request(packet), EBADMSG); +} + +TEST(packet_has_nsid_request_match_not_empty) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + + /* name */ 0x00, + /* OPT */ 0x00, 0x29, + /* udp max */ 0x02, 0x01, + /* rcode */ 0x00, + /* version */ 0x00, + /* flags */ 0x80, 0x00, + /* rdata */ 0x00, 0x05, + 0x00, 0x03, /* NSID option code */ + 0x00, 0x01, + 0xff + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_OK(dns_packet_extract(packet)); + + ASSERT_ERROR(dns_packet_has_nsid_request(packet), EBADMSG); +} + /* ================================================================ * reply: RRSIG * ================================================================ */ From e7e2f01d7b01b552d8a067afd98cb6ec118749c6 Mon Sep 17 00:00:00 2001 From: James Coglan Date: Mon, 10 Jun 2024 10:15:19 +0100 Subject: [PATCH 22/40] resolved: tests for dns_packet_validate_{query,reply}() --- src/resolve/test-dns-packet-extract.c | 388 ++++++++++++++++++++++++++ 1 file changed, 388 insertions(+) diff --git a/src/resolve/test-dns-packet-extract.c b/src/resolve/test-dns-packet-extract.c index 440eba3e9b..0147add364 100644 --- a/src/resolve/test-dns-packet-extract.c +++ b/src/resolve/test-dns-packet-extract.c @@ -251,6 +251,265 @@ TEST(packet_header_reply_dnssec_bits) { ASSERT_EQ(DNS_PACKET_ARCOUNT(packet), 0); } +/* ================================================================ + * dns_packet_validate_query() + * ================================================================ */ + +TEST(packet_validate_query_qr_bit) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + 0x00, DNS_TYPE_A, + 0x00, DNS_CLASS_IN + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_FALSE(dns_packet_validate_query(packet)); +} + +TEST(packet_validate_query_no_qr_bit) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + 0x00, DNS_TYPE_A, + 0x00, DNS_CLASS_IN + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_TRUE(dns_packet_validate_query(packet)); +} + +TEST(packet_validate_query_bad_opcode) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, (1 << 3), 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + 0x00, DNS_TYPE_A, + 0x00, DNS_CLASS_IN + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_validate_query(packet), EBADMSG); +} + +TEST(packet_validate_query_truncated) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_TC, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + 0x00, DNS_TYPE_A, + 0x00, DNS_CLASS_IN + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_validate_query(packet), EBADMSG); + + packet->protocol = DNS_PROTOCOL_LLMNR; + ASSERT_ERROR(dns_packet_validate_query(packet), EBADMSG); +} + +TEST(packet_validate_query_no_questions) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_validate_query(packet), EBADMSG); + + packet->protocol = DNS_PROTOCOL_LLMNR; + ASSERT_ERROR(dns_packet_validate_query(packet), EBADMSG); +} + +TEST(packet_validate_query_too_many_questions) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + 0x00, DNS_TYPE_A, + 0x00, DNS_CLASS_IN, + + 0xc0, 0x0c, + 0x00, DNS_TYPE_AAAA, + 0x00, DNS_CLASS_IN + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_validate_query(packet), EBADMSG); + + packet->protocol = DNS_PROTOCOL_LLMNR; + ASSERT_ERROR(dns_packet_validate_query(packet), EBADMSG); +} + +TEST(packet_validate_query_with_anwser) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + 0x00, DNS_TYPE_A, + 0x00, DNS_CLASS_IN, + + 0xc0, 0x0c, + 0x00, DNS_TYPE_A, + 0x00, DNS_CLASS_IN, + 0x00, 0x00, 0x0e, 0x10, + 0x00, 0x04, + 0xc0, 0xa8, 0x01, 0x7f + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_validate_query(packet), EBADMSG); + + packet->protocol = DNS_PROTOCOL_LLMNR; + ASSERT_ERROR(dns_packet_validate_query(packet), EBADMSG); +} + +TEST(packet_validate_query_llmnr_with_authority) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_LLMNR, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + 0x00, DNS_TYPE_A, + 0x00, DNS_CLASS_IN, + + 0xc0, 0x0c, + 0x00, DNS_TYPE_NS, + 0x00, DNS_CLASS_IN, + 0x00, 0x00, 0x0e, 0x10, + 0x00, 0x06, + 0x03, 'n', 's', '1', + 0xc0, 0x0c + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_validate_query(packet), EBADMSG); +} + +TEST(packet_validate_query_mdns_valid_rcode) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_MDNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, 0x00, DNS_RCODE_SUCCESS, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + 0x00, DNS_TYPE_A, + 0x00, DNS_CLASS_IN + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_TRUE(dns_packet_validate_query(packet)); +} + +TEST(packet_validate_query_mdns_bad_rcode) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_MDNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, 0x00, DNS_RCODE_NXDOMAIN, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + 0x00, DNS_TYPE_A, + 0x00, DNS_CLASS_IN + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_validate_query(packet), EBADMSG); +} + /* ================================================================ * queries * ================================================================ */ @@ -959,6 +1218,135 @@ TEST(packet_query_bad_compression_6) { ASSERT_EQ(dns_answer_size(packet->answer), 0u); } +/* ================================================================ + * dns_packet_validate_reply() + * ================================================================ */ + +TEST(packet_validate_reply_qr_bit) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_TRUE(dns_packet_validate_reply(packet)); +} + +TEST(packet_validate_reply_no_qr_bit) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_FALSE(dns_packet_validate_reply(packet)); +} + +TEST(packet_validate_reply_bad_opcode) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | (1 << 3) | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_validate_reply(packet), EBADMSG); +} + +TEST(packet_validate_reply_mdns_success_rcode) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_MDNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_TRUE(dns_packet_validate_reply(packet)); +} + +TEST(packet_validate_reply_mdns_bad_rcode) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_MDNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_NXDOMAIN, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_validate_reply(packet), EBADMSG); +} + +TEST(packet_validate_reply_llmnr_with_questions) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_LLMNR, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + 0x00, DNS_TYPE_A, + 0x00, DNS_CLASS_IN + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_TRUE(dns_packet_validate_reply(packet)); +} + +TEST(packet_validate_reply_llmnr_no_questions) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_LLMNR, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + ASSERT_ERROR(dns_packet_validate_reply(packet), EBADMSG); +} + /* ================================================================ * reply: bad keys * ================================================================ */ From 6e85e2437681902ac2bdc459893e9a4ebf5bf172 Mon Sep 17 00:00:00 2001 From: James Coglan Date: Tue, 11 Jun 2024 10:54:18 +0100 Subject: [PATCH 23/40] resolved: tests for dns_packet_is_reply_for() --- src/resolve/test-dns-packet-extract.c | 138 ++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) diff --git a/src/resolve/test-dns-packet-extract.c b/src/resolve/test-dns-packet-extract.c index 0147add364..64e52006f9 100644 --- a/src/resolve/test-dns-packet-extract.c +++ b/src/resolve/test-dns-packet-extract.c @@ -1347,6 +1347,144 @@ TEST(packet_validate_reply_llmnr_no_questions) { ASSERT_ERROR(dns_packet_validate_reply(packet), EBADMSG); } +/* ================================================================ + * dns_packet_is_reply_for() + * ================================================================ */ + +TEST(packet_is_reply_for_no_question) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, "www.example.com"); + ASSERT_NOT_NULL(key); + ASSERT_FALSE(dns_packet_is_reply_for(packet, key)); +} + +TEST(packet_is_reply_for_too_many_questions) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x03, 'w', 'w', 'w', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* A */ 0x00, 0x01, + /* IN */ 0x00, 0x01, + + /* name */ 0x04, 'm', 'a', 'i', 'l', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* MX */ 0x00, 0x0f, + /* IN */ 0x00, 0x01 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, "www.example.com"); + ASSERT_NOT_NULL(key); + ASSERT_FALSE(dns_packet_is_reply_for(packet, key)); +} + +TEST(packet_is_reply_for_match_question) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x03, 'w', 'w', 'w', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* A */ 0x00, 0x01, + /* IN */ 0x00, 0x01 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, "www.example.com"); + ASSERT_NOT_NULL(key); + ASSERT_TRUE(dns_packet_is_reply_for(packet, key)); +} + +TEST(packet_is_reply_for_no_match_question) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x03, 'w', 'w', 'w', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* AAAA */ 0x00, 0x1c, + /* IN */ 0x00, 0x01 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, "www.example.com"); + ASSERT_NOT_NULL(key); + ASSERT_FALSE(dns_packet_is_reply_for(packet, key)); +} + +TEST(packet_is_reply_for_extract_failure) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_truncate(packet, 0); + + const uint8_t data[] = { + 0x00, 0x42, BIT_QR | BIT_AA, DNS_RCODE_SUCCESS, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x03, 'w', 'w', 'w', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0xc0, 0x0c, + /* A */ 0x00, 0x01, + /* IN */ 0x00, 0x01 + }; + + ASSERT_OK(dns_packet_append_blob(packet, data, sizeof(data), NULL)); + + key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, "www.example.com"); + ASSERT_NOT_NULL(key); + ASSERT_ERROR(dns_packet_is_reply_for(packet, key), EBADMSG); +} + /* ================================================================ * reply: bad keys * ================================================================ */ From ca93c4fe7548cf4078bc2bef1d8fd8a0fbc99060 Mon Sep 17 00:00:00 2001 From: James Coglan Date: Tue, 11 Jun 2024 16:14:09 +0100 Subject: [PATCH 24/40] resolved: tests for DNS parameter formatters --- src/resolve/test-dns-packet-extract.c | 69 +++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/src/resolve/test-dns-packet-extract.c b/src/resolve/test-dns-packet-extract.c index 64e52006f9..5cd5a83d49 100644 --- a/src/resolve/test-dns-packet-extract.c +++ b/src/resolve/test-dns-packet-extract.c @@ -4708,4 +4708,73 @@ TEST(dns_ede_rcode_is_dnssec) { ASSERT_FALSE(dns_ede_rcode_is_dnssec(DNS_EDE_RCODE_OTHER)); } +/* ================================================================ + * format_dns_rcode() + * ================================================================ */ + +TEST(format_dns_rcode) { + const char *str; + + str = FORMAT_DNS_RCODE(DNS_RCODE_SUCCESS); + ASSERT_STREQ(str, "SUCCESS"); + + str = FORMAT_DNS_RCODE(DNS_RCODE_NXDOMAIN); + ASSERT_STREQ(str, "NXDOMAIN"); + + str = FORMAT_DNS_RCODE(DNS_RCODE_SERVFAIL); + ASSERT_STREQ(str, "SERVFAIL"); + + str = FORMAT_DNS_RCODE(DNS_RCODE_REFUSED); + ASSERT_STREQ(str, "REFUSED"); + + str = FORMAT_DNS_RCODE(DNS_RCODE_BADTIME); + ASSERT_STREQ(str, "BADTIME"); +} + +/* ================================================================ + * format_dns_ede_rcode() + * ================================================================ */ + +TEST(format_dns_ede_rcode) { + const char *str; + + str = FORMAT_DNS_EDE_RCODE(DNS_EDE_RCODE_DNSSEC_BOGUS); + ASSERT_STREQ(str, "DNSSEC Bogus"); + + str = FORMAT_DNS_EDE_RCODE(DNS_EDE_RCODE_SIG_EXPIRED); + ASSERT_STREQ(str, "Signature Expired"); + + str = FORMAT_DNS_EDE_RCODE(DNS_EDE_RCODE_CENSORED); + ASSERT_STREQ(str, "Censored"); + + str = FORMAT_DNS_EDE_RCODE(DNS_EDE_RCODE_OTHER); + ASSERT_STREQ(str, "Other"); + + str = FORMAT_DNS_EDE_RCODE(DNS_EDE_RCODE_STALE_NXDOMAIN_ANSWER); + ASSERT_STREQ(str, "Stale NXDOMAIN Answer"); +} + +/* ================================================================ + * format_dns_svc_param_key() + * ================================================================ */ + +TEST(format_dns_svc_param_key) { + const char *str; + + str = FORMAT_DNS_SVC_PARAM_KEY(DNS_SVC_PARAM_KEY_ALPN); + ASSERT_STREQ(str, "alpn"); + + str = FORMAT_DNS_SVC_PARAM_KEY(DNS_SVC_PARAM_KEY_NO_DEFAULT_ALPN); + ASSERT_STREQ(str, "no-default-alpn"); + + str = FORMAT_DNS_SVC_PARAM_KEY(DNS_SVC_PARAM_KEY_PORT); + ASSERT_STREQ(str, "port"); + + str = FORMAT_DNS_SVC_PARAM_KEY(DNS_SVC_PARAM_KEY_IPV4HINT); + ASSERT_STREQ(str, "ipv4hint"); + + str = FORMAT_DNS_SVC_PARAM_KEY(DNS_SVC_PARAM_KEY_OHTTP); + ASSERT_STREQ(str, "ohttp"); +} + DEFINE_TEST_MAIN(LOG_DEBUG) From 6bfbacc9b456348e6a36514b5c52823ca36823a4 Mon Sep 17 00:00:00 2001 From: James Coglan Date: Mon, 10 Jun 2024 10:16:01 +0100 Subject: [PATCH 25/40] resolved: tests for dns_packet_set_flags() --- src/resolve/meson.build | 3 + src/resolve/test-dns-packet-append.c | 142 +++++++++++++++++++++++++++ 2 files changed, 145 insertions(+) create mode 100644 src/resolve/test-dns-packet-append.c diff --git a/src/resolve/meson.build b/src/resolve/meson.build index 47383feec3..b1fcb990af 100644 --- a/src/resolve/meson.build +++ b/src/resolve/meson.build @@ -165,6 +165,9 @@ executables += [ resolve_test_template + { 'sources' : files('test-dns-packet.c'), }, + resolve_test_template + { + 'sources' : files('test-dns-packet-append.c'), + }, resolve_test_template + { 'sources' : files('test-dns-packet-extract.c'), }, diff --git a/src/resolve/test-dns-packet-append.c b/src/resolve/test-dns-packet-append.c new file mode 100644 index 0000000000..c0c6a04601 --- /dev/null +++ b/src/resolve/test-dns-packet-append.c @@ -0,0 +1,142 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "dns-type.h" +#include "resolved-dns-packet.h" +#include "resolved-dns-rr.h" + +#include "log.h" +#include "tests.h" + +#define BIT_QR (1 << 7) +#define BIT_AA (1 << 2) +#define BIT_TC (1 << 1) +#define BIT_RD (1 << 0) + +#define BIT_RA (1 << 7) +#define BIT_AD (1 << 5) +#define BIT_CD (1 << 4) + +/* ================================================================ + * dns_packet_set_flags() + * ================================================================ */ + +TEST(packet_set_flags_dns_checking_enabled) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_set_flags(packet, /* dnssec_checking_disabled= */ false, /* truncated= */ false); + + ASSERT_EQ(DNS_PACKET_QR(packet), 0); + ASSERT_EQ(DNS_PACKET_OPCODE(packet), 0); + ASSERT_EQ(DNS_PACKET_AA(packet), 0); + ASSERT_EQ(DNS_PACKET_TC(packet), 0); + ASSERT_EQ(DNS_PACKET_RD(packet), 1); + + ASSERT_EQ(DNS_PACKET_RA(packet), 0); + ASSERT_EQ(DNS_PACKET_AD(packet), 0); + ASSERT_EQ(DNS_PACKET_CD(packet), 0); + ASSERT_EQ(DNS_PACKET_RCODE(packet), 0); +} + +TEST(packet_set_flags_dns_checking_disabled) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_set_flags(packet, /* dnssec_checking_disabled= */ true, /* truncated= */ false); + + ASSERT_EQ(DNS_PACKET_QR(packet), 0); + ASSERT_EQ(DNS_PACKET_OPCODE(packet), 0); + ASSERT_EQ(DNS_PACKET_AA(packet), 0); + ASSERT_EQ(DNS_PACKET_TC(packet), 0); + ASSERT_EQ(DNS_PACKET_RD(packet), 1); + + ASSERT_EQ(DNS_PACKET_RA(packet), 0); + ASSERT_EQ(DNS_PACKET_AD(packet), 0); + ASSERT_EQ(DNS_PACKET_CD(packet), 1); + ASSERT_EQ(DNS_PACKET_RCODE(packet), 0); +} + +TEST(packet_set_flags_llmnr) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_LLMNR, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_set_flags(packet, /* dnssec_checking_disabled= */ true, /* truncated= */ false); + + ASSERT_EQ(DNS_PACKET_QR(packet), 0); + ASSERT_EQ(DNS_PACKET_OPCODE(packet), 0); + ASSERT_EQ(DNS_PACKET_AA(packet), 0); + ASSERT_EQ(DNS_PACKET_TC(packet), 0); + ASSERT_EQ(DNS_PACKET_RD(packet), 0); + + ASSERT_EQ(DNS_PACKET_RA(packet), 0); + ASSERT_EQ(DNS_PACKET_AD(packet), 0); + ASSERT_EQ(DNS_PACKET_CD(packet), 0); + ASSERT_EQ(DNS_PACKET_RCODE(packet), 0); +} + +TEST(packet_set_flags_mdns_not_truncated) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_MDNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_set_flags(packet, /* dnssec_checking_disabled= */ true, /* truncated= */ false); + + ASSERT_EQ(DNS_PACKET_QR(packet), 0); + ASSERT_EQ(DNS_PACKET_OPCODE(packet), 0); + ASSERT_EQ(DNS_PACKET_AA(packet), 0); + ASSERT_EQ(DNS_PACKET_TC(packet), 0); + ASSERT_EQ(DNS_PACKET_RD(packet), 0); + + ASSERT_EQ(DNS_PACKET_RA(packet), 0); + ASSERT_EQ(DNS_PACKET_AD(packet), 0); + ASSERT_EQ(DNS_PACKET_CD(packet), 0); + ASSERT_EQ(DNS_PACKET_RCODE(packet), 0); +} + +TEST(packet_set_flags_mdns_truncated) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_MDNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + dns_packet_set_flags(packet, /* dnssec_checking_disabled= */ true, /* truncated= */ true); + + ASSERT_EQ(DNS_PACKET_QR(packet), 0); + ASSERT_EQ(DNS_PACKET_OPCODE(packet), 0); + ASSERT_EQ(DNS_PACKET_AA(packet), 0); + ASSERT_EQ(DNS_PACKET_TC(packet), 1); + ASSERT_EQ(DNS_PACKET_RD(packet), 0); + + ASSERT_EQ(DNS_PACKET_RA(packet), 0); + ASSERT_EQ(DNS_PACKET_AD(packet), 0); + ASSERT_EQ(DNS_PACKET_CD(packet), 0); + ASSERT_EQ(DNS_PACKET_RCODE(packet), 0); +} + +/* ================================================================ + * dns_packet_new_query() + * ================================================================ */ + +TEST(packet_new_query_checking_enabled) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new_query(&packet, DNS_PROTOCOL_DNS, 0, false)); + ASSERT_NOT_NULL(packet); + + ASSERT_EQ(DNS_PACKET_TC(packet), 0); + ASSERT_EQ(DNS_PACKET_CD(packet), 0); +} + +TEST(packet_new_query_checking_disabled) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new_query(&packet, DNS_PROTOCOL_DNS, 0, true)); + ASSERT_NOT_NULL(packet); + + ASSERT_EQ(DNS_PACKET_TC(packet), 0); + ASSERT_EQ(DNS_PACKET_CD(packet), 1); +} + +DEFINE_TEST_MAIN(LOG_DEBUG) From fc838bd42a6ab36caf318c00766fec7dc0297ffb Mon Sep 17 00:00:00 2001 From: James Coglan Date: Mon, 10 Jun 2024 11:12:51 +0100 Subject: [PATCH 26/40] resolved: tests for basic usage of dns_packet_append_key() --- src/resolve/test-dns-packet-append.c | 68 ++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/src/resolve/test-dns-packet-append.c b/src/resolve/test-dns-packet-append.c index c0c6a04601..388b43868a 100644 --- a/src/resolve/test-dns-packet-append.c +++ b/src/resolve/test-dns-packet-append.c @@ -139,4 +139,72 @@ TEST(packet_new_query_checking_disabled) { ASSERT_EQ(DNS_PACKET_CD(packet), 1); } +/* ================================================================ + * dns_packet_append_key() + * ================================================================ */ + +TEST(packet_append_key_single_a) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + DnsResourceKey *key = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + + DNS_PACKET_ID(packet) = htobe16(42); + DNS_PACKET_HEADER(packet)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0, 0, 0, 0, 1, 0, 0, 0, DNS_RCODE_SUCCESS)); + DNS_PACKET_HEADER(packet)->qdcount = htobe16(1); + + key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, "www.example.com"); + ASSERT_NOT_NULL(key); + ASSERT_OK(dns_packet_append_key(packet, key, 0, NULL)); + dns_resource_key_unref(key); + + const uint8_t data[] = { + 0x00, 0x2a, BIT_RD, DNS_RCODE_SUCCESS, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x03, 'w', 'w', 'w', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* A */ 0x00, 0x01, + /* IN */ 0x00, 0x01 + }; + + ASSERT_EQ(packet->size, sizeof(data)); + ASSERT_EQ(memcmp(DNS_PACKET_DATA(packet), data, sizeof(data)), 0); +} + +TEST(packet_append_key_single_soa_any_class) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + DnsResourceKey *key = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + + DNS_PACKET_ID(packet) = htobe16(42); + DNS_PACKET_HEADER(packet)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0, 0, 0, 0, 1, 0, 0, 0, DNS_RCODE_SUCCESS)); + DNS_PACKET_HEADER(packet)->qdcount = htobe16(1); + + key = dns_resource_key_new(DNS_CLASS_ANY, DNS_TYPE_SOA, "www.example.com"); + ASSERT_NOT_NULL(key); + ASSERT_OK(dns_packet_append_key(packet, key, 0, NULL)); + dns_resource_key_unref(key); + + const uint8_t data[] = { + 0x00, 0x2a, BIT_RD, DNS_RCODE_SUCCESS, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x03, 'w', 'w', 'w', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* SOA */ 0x00, 0x06, + /* ANY */ 0x00, 0xff + }; + + ASSERT_EQ(packet->size, sizeof(data)); + ASSERT_EQ(memcmp(DNS_PACKET_DATA(packet), data, sizeof(data)), 0); +} + DEFINE_TEST_MAIN(LOG_DEBUG) From 1ac8f468b60f194941d1c453e9eaca670ef9de38 Mon Sep 17 00:00:00 2001 From: James Coglan Date: Mon, 10 Jun 2024 12:30:48 +0100 Subject: [PATCH 27/40] resolved: tests for dns_packet_append_key() domain name compression --- src/resolve/test-dns-packet-append.c | 62 ++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/src/resolve/test-dns-packet-append.c b/src/resolve/test-dns-packet-append.c index 388b43868a..88bfa6fd64 100644 --- a/src/resolve/test-dns-packet-append.c +++ b/src/resolve/test-dns-packet-append.c @@ -207,4 +207,66 @@ TEST(packet_append_key_single_soa_any_class) { ASSERT_EQ(memcmp(DNS_PACKET_DATA(packet), data, sizeof(data)), 0); } +/* ================================================================ + * dns_packet_append_question() + * ================================================================ */ + +TEST(packet_append_question_compression) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL; + DnsResourceKey *key = NULL; + + question = dns_question_new(3); + 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_MX, "mail.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_SOA, "host.mail.example.com"); + ASSERT_NOT_NULL(key); + ASSERT_OK(dns_question_add(question, key, 0)); + dns_resource_key_unref(key); + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + + DNS_PACKET_ID(packet) = htobe16(42); + DNS_PACKET_HEADER(packet)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0, 0, 0, 0, 1, 0, 0, 0, DNS_RCODE_SUCCESS)); + DNS_PACKET_HEADER(packet)->qdcount = htobe16(dns_question_size(question)); + + ASSERT_OK(dns_packet_append_question(packet, question)); + + const uint8_t data[] = { + 0x00, 0x2a, BIT_RD, DNS_RCODE_SUCCESS, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x03, 'w', 'w', 'w', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* A */ 0x00, 0x01, + /* IN */ 0x00, 0x01, + + /* name */ 0x04, 'm', 'a', 'i', 'l', + 0xc0, 0x10, + /* MX */ 0x00, 0x0f, + /* IN */ 0x00, 0x01, + + /* name */ 0x04, 'h', 'o', 's', 't', + 0xc0, 0x21, + /* SOA */ 0x00, 0x06, + /* IN */ 0x00, 0x01 + }; + + ASSERT_EQ(packet->size, sizeof(data)); + ASSERT_EQ(memcmp(DNS_PACKET_DATA(packet), data, sizeof(data)), 0); +} + DEFINE_TEST_MAIN(LOG_DEBUG) From b6899784b5b201cf8ff2e157c3ad09fefc547261 Mon Sep 17 00:00:00 2001 From: James Coglan Date: Mon, 10 Jun 2024 13:15:53 +0100 Subject: [PATCH 28/40] resolved: tests for dns_packet_append_opt() --- src/resolve/test-dns-packet-append.c | 148 +++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) diff --git a/src/resolve/test-dns-packet-append.c b/src/resolve/test-dns-packet-append.c index 88bfa6fd64..a5b82025ae 100644 --- a/src/resolve/test-dns-packet-append.c +++ b/src/resolve/test-dns-packet-append.c @@ -269,4 +269,152 @@ TEST(packet_append_question_compression) { ASSERT_EQ(memcmp(DNS_PACKET_DATA(packet), data, sizeof(data)), 0); } +/* ================================================================ + * dns_packet_append_opt() + * ================================================================ */ + +TEST(packet_append_opt_basic) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + + DNS_PACKET_ID(packet) = htobe16(42); + DNS_PACKET_HEADER(packet)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0, 0, 0, 0, 1, 0, 0, 0, DNS_RCODE_SUCCESS)); + + ASSERT_OK(dns_packet_append_opt(packet, 512, false, false, NULL, 0, NULL)); + + const uint8_t data[] = { + 0x00, 0x2a, BIT_RD, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + + /* root */ 0x00, + /* OPT */ 0x00, 0x29, + /* udp max */ 0x02, 0x00, + /* rcode */ 0x00, + /* version */ 0x00, + /* flags */ 0x00, 0x00, + /* rdata */ 0x00, 0x00 + }; + + ASSERT_EQ(packet->size, sizeof(data)); + ASSERT_EQ(memcmp(DNS_PACKET_DATA(packet), data, sizeof(data)), 0); +} + +TEST(packet_append_opt_change_max_udp) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + + DNS_PACKET_ID(packet) = htobe16(42); + DNS_PACKET_HEADER(packet)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0, 0, 0, 0, 1, 0, 0, 0, DNS_RCODE_SUCCESS)); + + ASSERT_OK(dns_packet_append_opt(packet, 4100, false, false, NULL, 0, NULL)); + + const uint8_t data[] = { + 0x00, 0x2a, BIT_RD, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + + /* root */ 0x00, + /* OPT */ 0x00, 0x29, + /* udp max */ 0x10, 0x04, + /* rcode */ 0x00, + /* version */ 0x00, + /* flags */ 0x00, 0x00, + /* rdata */ 0x00, 0x00 + }; + + ASSERT_EQ(packet->size, sizeof(data)); + ASSERT_EQ(memcmp(DNS_PACKET_DATA(packet), data, sizeof(data)), 0); +} + +TEST(packet_append_opt_dnssec_ok) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + + DNS_PACKET_ID(packet) = htobe16(42); + DNS_PACKET_HEADER(packet)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0, 0, 0, 0, 1, 0, 0, 0, DNS_RCODE_SUCCESS)); + + ASSERT_OK(dns_packet_append_opt(packet, 512, true, false, NULL, 0, NULL)); + + const uint8_t data[] = { + 0x00, 0x2a, BIT_RD, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + + /* root */ 0x00, + /* OPT */ 0x00, 0x29, + /* udp max */ 0x02, 0x00, + /* rcode */ 0x00, + /* version */ 0x00, + /* flags */ 0x80, 0x00, + /* rdata */ 0x00, 0x00 + }; + + ASSERT_EQ(packet->size, sizeof(data)); + ASSERT_EQ(memcmp(DNS_PACKET_DATA(packet), data, sizeof(data)), 0); +} + +TEST(packet_append_opt_rcode) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + + DNS_PACKET_ID(packet) = htobe16(42); + DNS_PACKET_HEADER(packet)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0, 0, 0, 0, 1, 0, 0, 0, DNS_RCODE_SUCCESS)); + + ASSERT_OK(dns_packet_append_opt(packet, 512, false, false, NULL, 0x97a, NULL)); + + const uint8_t data[] = { + 0x00, 0x2a, BIT_RD, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + + /* root */ 0x00, + /* OPT */ 0x00, 0x29, + /* udp max */ 0x02, 0x00, + /* rcode */ 0x97, + /* version */ 0x00, + /* flags */ 0x00, 0x00, + /* rdata */ 0x00, 0x00 + }; + + ASSERT_EQ(packet->size, sizeof(data)); + ASSERT_EQ(memcmp(DNS_PACKET_DATA(packet), data, sizeof(data)), 0); +} + +TEST(packet_append_opt_nsid) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + + DNS_PACKET_ID(packet) = htobe16(42); + DNS_PACKET_HEADER(packet)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0, 0, 0, 0, 1, 0, 0, 0, DNS_RCODE_SUCCESS)); + + ASSERT_OK(dns_packet_append_opt(packet, 512, false, false, "nsid.example.com", 0, NULL)); + + const uint8_t data[] = { + 0x00, 0x2a, BIT_RD, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + + /* root */ 0x00, + /* OPT */ 0x00, 0x29, + /* udp max */ 0x02, 0x00, + /* rcode */ 0x00, + /* version */ 0x00, + /* flags */ 0x00, 0x00, + /* rdata */ 0x00, 0x14, + 0x00, 0x03, + 0x00, 0x10, + 'n', 's', 'i', 'd', '.', 'e', 'x', 'a', + 'm', 'p', 'l', 'e', '.', 'c', 'o', 'm' + }; + + ASSERT_EQ(packet->size, sizeof(data)); + ASSERT_EQ(memcmp(DNS_PACKET_DATA(packet), data, sizeof(data)), 0); +} + DEFINE_TEST_MAIN(LOG_DEBUG) From 2927f43d2b82a90136dea42cd17595f0495978f8 Mon Sep 17 00:00:00 2001 From: James Coglan Date: Mon, 10 Jun 2024 13:27:19 +0100 Subject: [PATCH 29/40] resolved: tests for dns_packet_truncate_opt() --- src/resolve/test-dns-packet-append.c | 74 ++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/src/resolve/test-dns-packet-append.c b/src/resolve/test-dns-packet-append.c index a5b82025ae..651be640cc 100644 --- a/src/resolve/test-dns-packet-append.c +++ b/src/resolve/test-dns-packet-append.c @@ -417,4 +417,78 @@ TEST(packet_append_opt_nsid) { ASSERT_EQ(memcmp(DNS_PACKET_DATA(packet), data, sizeof(data)), 0); } +TEST(packet_append_key_and_opt) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + + DNS_PACKET_ID(packet) = htobe16(42); + DNS_PACKET_HEADER(packet)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0, 0, 0, 0, 1, 0, 0, 0, DNS_RCODE_SUCCESS)); + DNS_PACKET_HEADER(packet)->qdcount = htobe16(1); + + key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, "example.com"); + ASSERT_NOT_NULL(key); + ASSERT_OK(dns_packet_append_key(packet, key, 0, NULL)); + + ASSERT_OK(dns_packet_append_opt(packet, 512, false, false, NULL, 0, NULL)); + + const uint8_t data[] = { + 0x00, 0x2a, BIT_RD, DNS_RCODE_SUCCESS, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + + /* name */ 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* A */ 0x00, 0x01, + /* IN */ 0x00, 0x01, + + /* root */ 0x00, + /* OPT */ 0x00, 0x29, + /* udp max */ 0x02, 0x00, + /* rcode */ 0x00, + /* version */ 0x00, + /* flags */ 0x00, 0x00, + /* rdata */ 0x00, 0x00 + }; + + ASSERT_EQ(packet->size, sizeof(data)); + ASSERT_EQ(memcmp(DNS_PACKET_DATA(packet), data, sizeof(data)), 0); +} + +TEST(packet_truncate_opt) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + + DNS_PACKET_ID(packet) = htobe16(42); + DNS_PACKET_HEADER(packet)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0, 0, 0, 0, 1, 0, 0, 0, DNS_RCODE_SUCCESS)); + DNS_PACKET_HEADER(packet)->qdcount = htobe16(1); + + key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, "example.com"); + ASSERT_NOT_NULL(key); + ASSERT_OK(dns_packet_append_key(packet, key, 0, NULL)); + + ASSERT_OK(dns_packet_append_opt(packet, 512, false, false, NULL, 0, NULL)); + + ASSERT_TRUE(dns_packet_truncate_opt(packet)); + + const uint8_t data[] = { + 0x00, 0x2a, BIT_RD, DNS_RCODE_SUCCESS, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* A */ 0x00, 0x01, + /* IN */ 0x00, 0x01 + }; + + ASSERT_EQ(packet->size, sizeof(data)); + ASSERT_EQ(memcmp(DNS_PACKET_DATA(packet), data, sizeof(data)), 0); +} + DEFINE_TEST_MAIN(LOG_DEBUG) From 1516ebfc023e7fc6506350a421b84d1859e31a3d Mon Sep 17 00:00:00 2001 From: James Coglan Date: Mon, 10 Jun 2024 14:16:50 +0100 Subject: [PATCH 30/40] resolved: tests for dns_packet_append_answer(); single A record --- src/resolve/test-dns-packet-append.c | 46 ++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/src/resolve/test-dns-packet-append.c b/src/resolve/test-dns-packet-append.c index 651be640cc..a9f2520dc0 100644 --- a/src/resolve/test-dns-packet-append.c +++ b/src/resolve/test-dns-packet-append.c @@ -491,4 +491,50 @@ TEST(packet_truncate_opt) { ASSERT_EQ(memcmp(DNS_PACKET_DATA(packet), data, sizeof(data)), 0); } +/* ================================================================ + * dns_packet_append_answer() + * ================================================================ */ + +TEST(packet_append_answer_single_a) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; + DnsResourceRecord *rr = NULL; + + answer = dns_answer_new(1); + ASSERT_NOT_NULL(answer); + + rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, "example.com"); + ASSERT_NOT_NULL(rr); + rr->ttl = 3601; + rr->a.in_addr.s_addr = htobe32(0xc0a8017f); + dns_answer_add(answer, rr, 1, 0, NULL); + dns_resource_record_unref(rr); + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + + DNS_PACKET_ID(packet) = htobe16(42); + DNS_PACKET_HEADER(packet)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(1, 0, 1, 0, 1, 1, 0, 0, DNS_RCODE_SUCCESS)); + DNS_PACKET_HEADER(packet)->ancount = htobe16(dns_answer_size(answer)); + + ASSERT_OK(dns_packet_append_answer(packet, answer, NULL)); + + const uint8_t data[] = { + 0x00, 0x2a, BIT_QR | BIT_AA | BIT_RD, BIT_RA | DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* A */ 0x00, 0x01, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x11, + /* rdata */ 0x00, 0x04, + /* ip */ 0xc0, 0xa8, 0x01, 0x7f + }; + + ASSERT_EQ(packet->size, sizeof(data)); + ASSERT_EQ(memcmp(DNS_PACKET_DATA(packet), data, sizeof(data)), 0); +} + DEFINE_TEST_MAIN(LOG_DEBUG) From bcd218151f2a612086e427fda6455d042c2035c4 Mon Sep 17 00:00:00 2001 From: James Coglan Date: Mon, 10 Jun 2024 16:21:32 +0100 Subject: [PATCH 31/40] resolved: tests for dns_packet_append_answer(); NS, CNAME, PTR and MX records --- src/resolve/test-dns-packet-append.c | 185 ++++++++++++++++++++++++++- 1 file changed, 182 insertions(+), 3 deletions(-) diff --git a/src/resolve/test-dns-packet-append.c b/src/resolve/test-dns-packet-append.c index a9f2520dc0..6eb2357074 100644 --- a/src/resolve/test-dns-packet-append.c +++ b/src/resolve/test-dns-packet-append.c @@ -500,13 +500,13 @@ TEST(packet_append_answer_single_a) { _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; DnsResourceRecord *rr = NULL; - answer = dns_answer_new(1); - ASSERT_NOT_NULL(answer); - rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, "example.com"); ASSERT_NOT_NULL(rr); rr->ttl = 3601; rr->a.in_addr.s_addr = htobe32(0xc0a8017f); + + answer = dns_answer_new(1); + ASSERT_NOT_NULL(answer); dns_answer_add(answer, rr, 1, 0, NULL); dns_resource_record_unref(rr); @@ -537,4 +537,183 @@ TEST(packet_append_answer_single_a) { ASSERT_EQ(memcmp(DNS_PACKET_DATA(packet), data, sizeof(data)), 0); } +TEST(packet_append_answer_single_ns) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; + DnsResourceRecord *rr = NULL; + + rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_NS, "example.com"); + ASSERT_NOT_NULL(rr); + rr->ttl = 3601; + rr->ns.name = strdup("ns1.example.com"); + + answer = dns_answer_new(1); + ASSERT_NOT_NULL(answer); + dns_answer_add(answer, rr, 1, 0, NULL); + dns_resource_record_unref(rr); + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + + DNS_PACKET_ID(packet) = htobe16(42); + DNS_PACKET_HEADER(packet)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(1, 0, 1, 0, 1, 1, 0, 0, DNS_RCODE_SUCCESS)); + DNS_PACKET_HEADER(packet)->ancount = htobe16(dns_answer_size(answer)); + + ASSERT_OK(dns_packet_append_answer(packet, answer, NULL)); + + const uint8_t data[] = { + 0x00, 0x2a, BIT_QR | BIT_AA | BIT_RD, BIT_RA | DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* NS */ 0x00, 0x02, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x11, + /* rdata */ 0x00, 0x06, + /* name */ 0x03, 'n', 's', '1', + 0xc0, 0x0c + }; + + ASSERT_EQ(packet->size, sizeof(data)); + ASSERT_EQ(memcmp(DNS_PACKET_DATA(packet), data, sizeof(data)), 0); +} + +TEST(packet_append_answer_single_cname) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; + DnsResourceRecord *rr = NULL; + + rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_CNAME, "www.example.com"); + ASSERT_NOT_NULL(rr); + rr->ttl = 3601; + rr->cname.name = strdup("example.com"); + + answer = dns_answer_new(1); + ASSERT_NOT_NULL(answer); + dns_answer_add(answer, rr, 1, 0, NULL); + dns_resource_record_unref(rr); + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + + DNS_PACKET_ID(packet) = htobe16(42); + DNS_PACKET_HEADER(packet)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(1, 0, 1, 0, 1, 1, 0, 0, DNS_RCODE_SUCCESS)); + DNS_PACKET_HEADER(packet)->ancount = htobe16(dns_answer_size(answer)); + + ASSERT_OK(dns_packet_append_answer(packet, answer, NULL)); + + const uint8_t data[] = { + 0x00, 0x2a, BIT_QR | BIT_AA | BIT_RD, BIT_RA | DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x03, 'w', 'w', 'w', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* CNAME */ 0x00, 0x05, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x11, + /* rdata */ 0x00, 0x02, + /* name */ 0xc0, 0x10 + }; + + ASSERT_EQ(packet->size, sizeof(data)); + ASSERT_EQ(memcmp(DNS_PACKET_DATA(packet), data, sizeof(data)), 0); +} + +TEST(packet_append_answer_single_ptr) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; + DnsResourceRecord *rr = NULL; + + rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_PTR, "127.1.168.192.in-addr.arpa"); + ASSERT_NOT_NULL(rr); + rr->ttl = 3601; + rr->ptr.name = strdup("example.com"); + + answer = dns_answer_new(1); + ASSERT_NOT_NULL(answer); + dns_answer_add(answer, rr, 1, 0, NULL); + dns_resource_record_unref(rr); + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + + DNS_PACKET_ID(packet) = htobe16(42); + DNS_PACKET_HEADER(packet)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(1, 0, 1, 0, 1, 1, 0, 0, DNS_RCODE_SUCCESS)); + DNS_PACKET_HEADER(packet)->ancount = htobe16(dns_answer_size(answer)); + + ASSERT_OK(dns_packet_append_answer(packet, answer, NULL)); + + const uint8_t data[] = { + 0x00, 0x2a, BIT_QR | BIT_AA | BIT_RD, BIT_RA | DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x03, '1', '2', '7', + 0x01, '1', + 0x03, '1', '6', '8', + 0x03, '1', '9', '2', + 0x07, 'i', 'n', '-', 'a', 'd', 'd', 'r', + 0x04, 'a', 'r', 'p', 'a', + 0x00, + /* PTR */ 0x00, 0x0c, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x11, + /* rdata */ 0x00, 0x0d, + /* name */ 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00 + }; + + ASSERT_EQ(packet->size, sizeof(data)); + ASSERT_EQ(memcmp(DNS_PACKET_DATA(packet), data, sizeof(data)), 0); +} + +TEST(packet_append_answer_single_mx) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; + DnsResourceRecord *rr = NULL; + + rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_MX, "example.com"); + ASSERT_NOT_NULL(rr); + rr->ttl = 3601; + rr->mx.priority = 9; + rr->mx.exchange = strdup("mail.example.com"); + + answer = dns_answer_new(1); + ASSERT_NOT_NULL(answer); + dns_answer_add(answer, rr, 1, 0, NULL); + dns_resource_record_unref(rr); + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + + DNS_PACKET_ID(packet) = htobe16(42); + DNS_PACKET_HEADER(packet)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(1, 0, 1, 0, 1, 1, 0, 0, DNS_RCODE_SUCCESS)); + DNS_PACKET_HEADER(packet)->ancount = htobe16(dns_answer_size(answer)); + + ASSERT_OK(dns_packet_append_answer(packet, answer, NULL)); + + const uint8_t data[] = { + 0x00, 0x2a, BIT_QR | BIT_AA | BIT_RD, BIT_RA | DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* MX */ 0x00, 0x0f, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x11, + /* rdata */ 0x00, 0x09, + /* priority */ 0x00, 0x09, + /* name */ 0x04, 'm', 'a', 'i', 'l', + 0xc0, 0x0c + }; + + ASSERT_EQ(packet->size, sizeof(data)); + ASSERT_EQ(memcmp(DNS_PACKET_DATA(packet), data, sizeof(data)), 0); +} + DEFINE_TEST_MAIN(LOG_DEBUG) From 1f66bd238f9897c4e1911627af038bc4a3924eac Mon Sep 17 00:00:00 2001 From: James Coglan Date: Mon, 10 Jun 2024 16:21:40 +0100 Subject: [PATCH 32/40] resolved: tests for dns_packet_append_answer(); SRV records --- src/resolve/test-dns-packet-append.c | 53 ++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/src/resolve/test-dns-packet-append.c b/src/resolve/test-dns-packet-append.c index 6eb2357074..e55ce35273 100644 --- a/src/resolve/test-dns-packet-append.c +++ b/src/resolve/test-dns-packet-append.c @@ -716,4 +716,57 @@ TEST(packet_append_answer_single_mx) { ASSERT_EQ(memcmp(DNS_PACKET_DATA(packet), data, sizeof(data)), 0); } +TEST(packet_append_answer_single_srv) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; + DnsResourceRecord *rr = NULL; + + rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_SRV, "_ldap._tcp.example.com"); + ASSERT_NOT_NULL(rr); + rr->ttl = 3601; + rr->srv.priority = 17185; + rr->srv.weight = 25976; + rr->srv.port = 389; + rr->srv.name = strdup("cloud.example.com"); + + answer = dns_answer_new(1); + ASSERT_NOT_NULL(answer); + dns_answer_add(answer, rr, 1, 0, NULL); + dns_resource_record_unref(rr); + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + + DNS_PACKET_ID(packet) = htobe16(42); + DNS_PACKET_HEADER(packet)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(1, 0, 1, 0, 1, 1, 0, 0, DNS_RCODE_SUCCESS)); + DNS_PACKET_HEADER(packet)->ancount = htobe16(dns_answer_size(answer)); + + ASSERT_OK(dns_packet_append_answer(packet, answer, NULL)); + + const uint8_t data[] = { + 0x00, 0x2a, BIT_QR | BIT_AA | BIT_RD, BIT_RA | DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x05, '_', 'l', 'd', 'a', 'p', + 0x04, '_', 't', 'c', 'p', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* SRV */ 0x00, 0x21, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x11, + /* rdata */ 0x00, 0x19, + /* priority */ 0x43, 0x21, + /* weight */ 0x65, 0x78, + /* port */ 0x01, 0x85, + /* name */ 0x05, 'c', 'l', 'o', 'u', 'd', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00 + }; + + ASSERT_EQ(packet->size, sizeof(data)); + ASSERT_EQ(memcmp(DNS_PACKET_DATA(packet), data, sizeof(data)), 0); +} + DEFINE_TEST_MAIN(LOG_DEBUG) From 945a75c88c8ace8bfe69c7a83ecc110cf88b77a7 Mon Sep 17 00:00:00 2001 From: James Coglan Date: Mon, 10 Jun 2024 16:41:12 +0100 Subject: [PATCH 33/40] resolved: tests for dns_packet_append_answer(); RRSIG records --- src/resolve/test-dns-packet-append.c | 82 ++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/src/resolve/test-dns-packet-append.c b/src/resolve/test-dns-packet-append.c index e55ce35273..cbb70a8218 100644 --- a/src/resolve/test-dns-packet-append.c +++ b/src/resolve/test-dns-packet-append.c @@ -769,4 +769,86 @@ TEST(packet_append_answer_single_srv) { ASSERT_EQ(memcmp(DNS_PACKET_DATA(packet), data, sizeof(data)), 0); } +TEST(packet_append_answer_rrsig_with_a) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; + DnsResourceRecord *rr = NULL; + + answer = dns_answer_new(2); + ASSERT_NOT_NULL(answer); + + rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, "www.example.com"); + ASSERT_NOT_NULL(rr); + rr->ttl = 3601; + rr->a.in_addr.s_addr = htobe32(0xc0a8017f); + + dns_answer_add(answer, rr, 1, 0, NULL); + dns_resource_record_unref(rr); + + rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_RRSIG, "www.example.com"); + ASSERT_NOT_NULL(rr); + rr->ttl = 3601; + rr->rrsig.type_covered = DNS_TYPE_A; + rr->rrsig.algorithm = DNSSEC_ALGORITHM_ECC; + rr->rrsig.labels = 3; + rr->rrsig.original_ttl = 3600; + rr->rrsig.expiration = 1720361303; + rr->rrsig.inception = 1717769303; + rr->rrsig.key_tag = 0x1234; + rr->rrsig.signer = strdup("example.com"); + + const uint8_t signature[] = { + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 + }; + rr->rrsig.signature_size = sizeof(signature); + rr->rrsig.signature = memdup(signature, rr->rrsig.signature_size); + + dns_answer_add(answer, rr, 1, 0, NULL); + dns_resource_record_unref(rr); + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + + DNS_PACKET_ID(packet) = htobe16(42); + DNS_PACKET_HEADER(packet)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(1, 0, 1, 0, 1, 1, 0, 0, DNS_RCODE_SUCCESS)); + DNS_PACKET_HEADER(packet)->ancount = htobe16(dns_answer_size(answer)); + + ASSERT_OK(dns_packet_append_answer(packet, answer, NULL)); + + const uint8_t data[] = { + 0x00, 0x2a, BIT_QR | BIT_AA | BIT_RD, BIT_RA | DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x03, 'w', 'w', 'w', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* A */ 0x00, 0x01, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x11, + /* rdata */ 0x00, 0x04, + /* ip */ 0xc0, 0xa8, 0x01, 0x7f, + + /* name */ 0xc0, 0x0c, + /* RRSIG */ 0x00, 0x2e, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x11, + /* rdata */ 0x00, 0x27, + /* type */ 0x00, 0x01, + /* algo */ 0x04, + /* labels */ 0x03, + /* orig ttl */ 0x00, 0x00, 0x0e, 0x10, + /* expiry */ 0x66, 0x8a, 0xa1, 0x57, + /* inception */ 0x66, 0x63, 0x14, 0x57, + /* key tag */ 0x12, 0x34, + /* signer */ 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* signature */ 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 + }; + + ASSERT_EQ(packet->size, sizeof(data)); + ASSERT_EQ(memcmp(DNS_PACKET_DATA(packet), data, sizeof(data)), 0); +} + DEFINE_TEST_MAIN(LOG_DEBUG) From 6ff5ca8e092a60adcc4ab1df4497dadf85bba8c3 Mon Sep 17 00:00:00 2001 From: James Coglan Date: Mon, 10 Jun 2024 17:05:13 +0100 Subject: [PATCH 34/40] resolved: tests for dns_packet_append_answer(); HINFO records --- src/resolve/test-dns-packet-append.c | 44 ++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/src/resolve/test-dns-packet-append.c b/src/resolve/test-dns-packet-append.c index cbb70a8218..3198698729 100644 --- a/src/resolve/test-dns-packet-append.c +++ b/src/resolve/test-dns-packet-append.c @@ -623,6 +623,50 @@ TEST(packet_append_answer_single_cname) { ASSERT_EQ(memcmp(DNS_PACKET_DATA(packet), data, sizeof(data)), 0); } +TEST(packet_append_answer_single_hinfo) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; + DnsResourceRecord *rr = NULL; + + rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_HINFO, "example.com"); + ASSERT_NOT_NULL(rr); + rr->ttl = 3601; + rr->hinfo.cpu = strdup("x64"); + rr->hinfo.os = strdup("GNU/Linux"); + + answer = dns_answer_new(1); + ASSERT_NOT_NULL(answer); + dns_answer_add(answer, rr, 1, 0, NULL); + dns_resource_record_unref(rr); + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + + DNS_PACKET_ID(packet) = htobe16(42); + DNS_PACKET_HEADER(packet)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(1, 0, 1, 0, 1, 1, 0, 0, DNS_RCODE_SUCCESS)); + DNS_PACKET_HEADER(packet)->ancount = htobe16(dns_answer_size(answer)); + + ASSERT_OK(dns_packet_append_answer(packet, answer, NULL)); + + const uint8_t data[] = { + 0x00, 0x2a, BIT_QR | BIT_AA | BIT_RD, BIT_RA | DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* HINFO */ 0x00, 0x0d, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x11, + /* rdata */ 0x00, 0x0e, + /* cpu */ 0x03, 'x', '6', '4', + /* os */ 0x09, 'G', 'N', 'U', '/', 'L', 'i', 'n', 'u', 'x' + }; + + ASSERT_EQ(packet->size, sizeof(data)); + ASSERT_EQ(memcmp(DNS_PACKET_DATA(packet), data, sizeof(data)), 0); +} + TEST(packet_append_answer_single_ptr) { _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; From 3c7ede7b889407aaa4785391a19061051f1425e0 Mon Sep 17 00:00:00 2001 From: James Coglan Date: Mon, 10 Jun 2024 17:28:37 +0100 Subject: [PATCH 35/40] resolved: tests for dns_packet_append_answer(); SVCB and HTTPS records --- src/resolve/test-dns-packet-append.c | 96 ++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/src/resolve/test-dns-packet-append.c b/src/resolve/test-dns-packet-append.c index 3198698729..0bb7266fc7 100644 --- a/src/resolve/test-dns-packet-append.c +++ b/src/resolve/test-dns-packet-append.c @@ -4,6 +4,7 @@ #include "resolved-dns-packet.h" #include "resolved-dns-rr.h" +#include "list.h" #include "log.h" #include "tests.h" @@ -895,4 +896,99 @@ TEST(packet_append_answer_rrsig_with_a) { ASSERT_EQ(memcmp(DNS_PACKET_DATA(packet), data, sizeof(data)), 0); } +static DnsSvcParam* add_svcb_param(DnsResourceRecord *rr, uint16_t key, const char *value, size_t len) { + DnsSvcParam *param = calloc(1, offsetof(DnsSvcParam, value) + len); + ASSERT_NOT_NULL(param); + + param->key = key; + param->length = len; + + if (value != NULL) + memcpy(param->value, value, len); + + LIST_APPEND(params, rr->svcb.params, param); + return param; +} + +TEST(packet_append_answer_single_svcb) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; + DnsResourceRecord *rr = NULL; + DnsSvcParam *param = NULL; + + rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_SVCB, "_443._wss.example.com"); + ASSERT_NOT_NULL(rr); + rr->ttl = 3601; + rr->svcb.priority = 9; + rr->svcb.target_name = strdup("sock.example.com"); + + add_svcb_param(rr, DNS_SVC_PARAM_KEY_MANDATORY, "\x00\x01\x00\x03", 4); + add_svcb_param(rr, DNS_SVC_PARAM_KEY_ALPN, "\x09websocket", 10); + add_svcb_param(rr, DNS_SVC_PARAM_KEY_NO_DEFAULT_ALPN, NULL, 0); + add_svcb_param(rr, DNS_SVC_PARAM_KEY_PORT, "\x01\xbb", 2); + + param = add_svcb_param(rr, DNS_SVC_PARAM_KEY_IPV4HINT, NULL, 2 * sizeof(struct in_addr)); + param->value_in_addr[0].s_addr = htobe32(0x7284fd3a); + param->value_in_addr[1].s_addr = htobe32(0x48bcc7c0); + + param = add_svcb_param(rr, DNS_SVC_PARAM_KEY_IPV6HINT, NULL, sizeof(struct in6_addr)); + param->value_in6_addr[0] = (struct in6_addr) { .s6_addr = { 0xf2, 0x34, 0x32, 0x2e, 0xb8, 0x25, 0x38, 0x35, 0x2f, 0xd7, 0xdb, 0x7b, 0x28, 0x7e, 0x60, 0xbb } }; + + answer = dns_answer_new(1); + ASSERT_NOT_NULL(answer); + dns_answer_add(answer, rr, 1, 0, NULL); + dns_resource_record_unref(rr); + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + + DNS_PACKET_ID(packet) = htobe16(42); + DNS_PACKET_HEADER(packet)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(1, 0, 1, 0, 1, 1, 0, 0, DNS_RCODE_SUCCESS)); + DNS_PACKET_HEADER(packet)->ancount = htobe16(dns_answer_size(answer)); + + ASSERT_OK(dns_packet_append_answer(packet, answer, NULL)); + + const uint8_t data[] = { + 0x00, 0x2a, BIT_QR | BIT_AA | BIT_RD, BIT_RA | DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x04, '_', '4', '4', '3', + 0x04, '_', 'w', 's', 's', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* SVCB */ 0x00, 0x40, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x11, + /* rdata */ 0x00, 0x54, + /* priority */ 0x00, 0x09, + /* target */ 0x04, 's', 'o', 'c', 'k', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* mandatory */ 0x00, 0x00, + 0x00, 0x04, + 0x00, 0x01, 0x00, 0x03, + /* alpn */ 0x00, 0x01, + 0x00, 0x0a, + 0x09, 'w', 'e', 'b', 's', 'o', 'c', 'k', 'e', 't', + /* no-deflt */ 0x00, 0x02, + 0x00, 0x00, + /* port */ 0x00, 0x03, + 0x00, 0x02, + 0x01, 0xbb, + /* ipv4hint */ 0x00, 0x04, + 0x00, 0x08, + 0x72, 0x84, 0xfd, 0x3a, + 0x48, 0xbc, 0xc7, 0xc0, + /* ipv6hint */ 0x00, 0x06, + 0x00, 0x10, + 0xf2, 0x34, 0x32, 0x2e, 0xb8, 0x25, 0x38, 0x35, + 0x2f, 0xd7, 0xdb, 0x7b, 0x28, 0x7e, 0x60, 0xbb + }; + + ASSERT_EQ(packet->size, sizeof(data)); + ASSERT_EQ(memcmp(DNS_PACKET_DATA(packet), data, sizeof(data)), 0); +} + DEFINE_TEST_MAIN(LOG_DEBUG) From 053ec2c5a203708f5b81de057965504b6a97622d Mon Sep 17 00:00:00 2001 From: James Coglan Date: Mon, 10 Jun 2024 17:45:58 +0100 Subject: [PATCH 36/40] resolved: tests for dns_packet_append_answer(); NAPTR records --- src/resolve/test-dns-packet-append.c | 64 ++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/src/resolve/test-dns-packet-append.c b/src/resolve/test-dns-packet-append.c index 0bb7266fc7..d826ce8fb5 100644 --- a/src/resolve/test-dns-packet-append.c +++ b/src/resolve/test-dns-packet-append.c @@ -814,6 +814,70 @@ TEST(packet_append_answer_single_srv) { ASSERT_EQ(memcmp(DNS_PACKET_DATA(packet), data, sizeof(data)), 0); } +TEST(packet_append_answer_single_naptr) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; + DnsResourceRecord *rr = NULL; + + rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_NAPTR, "4.3.2.1.5.5.5.0.0.8.1.e164.arpa"); + ASSERT_NOT_NULL(rr); + rr->ttl = 3601; + rr->naptr.order = 102; + rr->naptr.preference = 10; + rr->naptr.flags = strdup("U"); + rr->naptr.services = strdup("E2U+sip"); + rr->naptr.regexp = strdup("!^.*$!sip:customer-service@example.com!"); + rr->naptr.replacement = strdup("_sip._udp.example.com"); + + answer = dns_answer_new(1); + ASSERT_NOT_NULL(answer); + dns_answer_add(answer, rr, 1, 0, NULL); + dns_resource_record_unref(rr); + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + + DNS_PACKET_ID(packet) = htobe16(42); + DNS_PACKET_HEADER(packet)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(1, 0, 1, 0, 1, 1, 0, 0, DNS_RCODE_SUCCESS)); + DNS_PACKET_HEADER(packet)->ancount = htobe16(dns_answer_size(answer)); + + ASSERT_OK(dns_packet_append_answer(packet, answer, NULL)); + + const uint8_t data[] = { + 0x00, 0x2a, BIT_QR | BIT_AA | BIT_RD, BIT_RA | DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x01, '4', 0x01, '3', 0x01, '2', 0x01, '1', + 0x01, '5', 0x01, '5', 0x01, '5', + 0x01, '0', 0x01, '0', 0x01, '8', 0x01, '1', + 0x04, 'e', '1', '6', '4', + 0x04, 'a', 'r', 'p', 'a', + 0x00, + /* NAPTR */ 0x00, 0x23, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x11, + /* rdata */ 0x00, 0x4d, + /* order */ 0x00, 0x66, + /* pref */ 0x00, 0x0a, + /* flags */ 0x01, 'U', + /* services */ 0x07, 'E', '2', 'U', '+', 's', 'i', 'p', + /* regexp */ 0x27, + '!', '^', '.', '*', '$', '!', 's', 'i', + 'p', ':', 'c', 'u', 's', 't', 'o', 'm', + 'e', 'r', '-', 's', 'e', 'r', 'v', 'i', + 'c', 'e', '@', 'e', 'x', 'a', 'm', 'p', + 'l', 'e', '.', 'c', 'o', 'm', '!', + /* replace */ 0x04, '_', 's', 'i', 'p', + 0x04, '_', 'u', 'd', 'p', + 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00 + }; + + ASSERT_EQ(packet->size, sizeof(data)); + ASSERT_EQ(memcmp(DNS_PACKET_DATA(packet), data, sizeof(data)), 0); +} + TEST(packet_append_answer_rrsig_with_a) { _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; From 346b0d3b183a7f8509b5012482af109b07da2c4e Mon Sep 17 00:00:00 2001 From: James Coglan Date: Wed, 12 Jun 2024 13:31:12 +0100 Subject: [PATCH 37/40] resolved: tests for dns_packet_append_answer(); TXT records --- src/resolve/test-dns-packet-append.c | 55 ++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/src/resolve/test-dns-packet-append.c b/src/resolve/test-dns-packet-append.c index d826ce8fb5..6a8f8325a4 100644 --- a/src/resolve/test-dns-packet-append.c +++ b/src/resolve/test-dns-packet-append.c @@ -761,6 +761,61 @@ TEST(packet_append_answer_single_mx) { ASSERT_EQ(memcmp(DNS_PACKET_DATA(packet), data, sizeof(data)), 0); } +TEST(packet_append_answer_single_txt) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; + DnsResourceRecord *rr = NULL; + DnsTxtItem *item = NULL; + + rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_TXT, "example.com"); + ASSERT_NOT_NULL(rr); + rr->ttl = 3601; + + item = calloc(1, offsetof(DnsTxtItem, data) + 3); + ASSERT_NOT_NULL(item); + item->length = 2; + memcpy(item->data, "hi", 3); + LIST_APPEND(items, rr->txt.items, item); + + item = calloc(1, offsetof(DnsTxtItem, data) + 6); + ASSERT_NOT_NULL(item); + item->length = 5; + memcpy(item->data, "world", 6); + LIST_APPEND(items, rr->txt.items, item); + + answer = dns_answer_new(1); + ASSERT_NOT_NULL(answer); + dns_answer_add(answer, rr, 1, 0, NULL); + dns_resource_record_unref(rr); + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + + DNS_PACKET_ID(packet) = htobe16(42); + DNS_PACKET_HEADER(packet)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(1, 0, 1, 0, 1, 1, 0, 0, DNS_RCODE_SUCCESS)); + DNS_PACKET_HEADER(packet)->ancount = htobe16(dns_answer_size(answer)); + + ASSERT_OK(dns_packet_append_answer(packet, answer, NULL)); + + const uint8_t data[] = { + 0x00, 0x2a, BIT_QR | BIT_AA | BIT_RD, BIT_RA | DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* TXT */ 0x00, 0x10, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x11, + /* rdata */ 0x00, 0x09, + 0x02, 'h', 'i', + 0x05, 'w', 'o', 'r', 'l', 'd' + }; + + ASSERT_EQ(packet->size, sizeof(data)); + ASSERT_EQ(memcmp(DNS_PACKET_DATA(packet), data, sizeof(data)), 0); +} + TEST(packet_append_answer_single_srv) { _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; From b81b8faa4301240992f8effb879ebae9b108d53f Mon Sep 17 00:00:00 2001 From: James Coglan Date: Wed, 12 Jun 2024 18:47:04 +0100 Subject: [PATCH 38/40] resolved: tests for dns_packet_append_answer(); LOC records --- src/resolve/test-dns-packet-append.c | 54 ++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/src/resolve/test-dns-packet-append.c b/src/resolve/test-dns-packet-append.c index 6a8f8325a4..b87e7de30c 100644 --- a/src/resolve/test-dns-packet-append.c +++ b/src/resolve/test-dns-packet-append.c @@ -816,6 +816,60 @@ TEST(packet_append_answer_single_txt) { ASSERT_EQ(memcmp(DNS_PACKET_DATA(packet), data, sizeof(data)), 0); } +TEST(packet_append_answer_single_loc) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; + DnsResourceRecord *rr = NULL; + + rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_LOC, "example.com"); + ASSERT_NOT_NULL(rr); + rr->ttl = 3601; + rr->loc.version = 0; + rr->loc.size = 0x29; + rr->loc.horiz_pre = 0x34; + rr->loc.vert_pre = 0x53; + rr->loc.latitude = 2332887285; + rr->loc.longitude = 2146974024; + rr->loc.altitude = 10000000; + + answer = dns_answer_new(1); + ASSERT_NOT_NULL(answer); + dns_answer_add(answer, rr, 1, 0, NULL); + dns_resource_record_unref(rr); + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + + DNS_PACKET_ID(packet) = htobe16(42); + DNS_PACKET_HEADER(packet)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(1, 0, 1, 0, 1, 1, 0, 0, DNS_RCODE_SUCCESS)); + DNS_PACKET_HEADER(packet)->ancount = htobe16(dns_answer_size(answer)); + + ASSERT_OK(dns_packet_append_answer(packet, answer, NULL)); + + const uint8_t data[] = { + 0x00, 0x2a, BIT_QR | BIT_AA | BIT_RD, BIT_RA | DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* LOC */ 0x00, 0x1d, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x11, + /* rdata */ 0x00, 0x10, + /* version */ 0x00, + /* size */ 0x29, + /* horiz pre */ 0x34, + /* vert pre */ 0x53, + /* latitude */ 0x8b, 0x0d, 0x08, 0xf5, + /* longitude */ 0x7f, 0xf8, 0x39, 0x48, + /* altitude */ 0x00, 0x98, 0x96, 0x80 + }; + + ASSERT_EQ(packet->size, sizeof(data)); + ASSERT_EQ(memcmp(DNS_PACKET_DATA(packet), data, sizeof(data)), 0); +} + TEST(packet_append_answer_single_srv) { _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; From d6f1f962fe3ca20a48d8a9404249cec02a965110 Mon Sep 17 00:00:00 2001 From: James Coglan Date: Tue, 11 Jun 2024 14:08:15 +0100 Subject: [PATCH 39/40] resolved: tests for dns_packet_patch_max_udp_size() --- src/resolve/test-dns-packet-append.c | 54 ++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/src/resolve/test-dns-packet-append.c b/src/resolve/test-dns-packet-append.c index b87e7de30c..3aed1a754f 100644 --- a/src/resolve/test-dns-packet-append.c +++ b/src/resolve/test-dns-packet-append.c @@ -492,6 +492,60 @@ TEST(packet_truncate_opt) { ASSERT_EQ(memcmp(DNS_PACKET_DATA(packet), data, sizeof(data)), 0); } +/* ================================================================ + * dns_packet_patch_max_udp_size() + * ================================================================ */ + +TEST(packet_patch_max_udp_size) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + + DNS_PACKET_ID(packet) = htobe16(42); + DNS_PACKET_HEADER(packet)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0, 0, 0, 0, 1, 0, 0, 0, DNS_RCODE_SUCCESS)); + + ASSERT_OK(dns_packet_append_opt(packet, 512, false, false, NULL, 0, NULL)); + + ASSERT_TRUE(dns_packet_patch_max_udp_size(packet, 4097)); + + const uint8_t data[] = { + 0x00, 0x2a, BIT_RD, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + + /* root */ 0x00, + /* OPT */ 0x00, 0x29, + /* udp max */ 0x10, 0x01, + /* rcode */ 0x00, + /* version */ 0x00, + /* flags */ 0x00, 0x00, + /* rdata */ 0x00, 0x00 + }; + + ASSERT_EQ(packet->size, sizeof(data)); + ASSERT_EQ(memcmp(DNS_PACKET_DATA(packet), data, sizeof(data)), 0); +} + +TEST(packet_patch_max_udp_size_no_opt) { + _cleanup_(dns_packet_unrefp) DnsPacket *packet = NULL; + + ASSERT_OK(dns_packet_new(&packet, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(packet); + + DNS_PACKET_ID(packet) = htobe16(42); + DNS_PACKET_HEADER(packet)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0, 0, 0, 0, 1, 0, 0, 0, DNS_RCODE_SUCCESS)); + + ASSERT_FALSE(dns_packet_patch_max_udp_size(packet, 4097)); + + const uint8_t data[] = { + 0x00, 0x2a, BIT_RD, DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + ASSERT_EQ(packet->size, sizeof(data)); + ASSERT_EQ(memcmp(DNS_PACKET_DATA(packet), data, sizeof(data)), 0); +} + /* ================================================================ * dns_packet_append_answer() * ================================================================ */ From ce9b6819d618dcfb7a7e186a4871fc4bc6ca8254 Mon Sep 17 00:00:00 2001 From: James Coglan Date: Tue, 11 Jun 2024 16:32:28 +0100 Subject: [PATCH 40/40] resolved: tests for dns_packet_dup() --- src/resolve/test-dns-packet-append.c | 49 ++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/resolve/test-dns-packet-append.c b/src/resolve/test-dns-packet-append.c index 3aed1a754f..9ef77b3b98 100644 --- a/src/resolve/test-dns-packet-append.c +++ b/src/resolve/test-dns-packet-append.c @@ -546,6 +546,55 @@ TEST(packet_patch_max_udp_size_no_opt) { ASSERT_EQ(memcmp(DNS_PACKET_DATA(packet), data, sizeof(data)), 0); } +/* ================================================================ + * dns_packet_dup() + * ================================================================ */ + +TEST(packet_dup) { + _cleanup_(dns_packet_unrefp) DnsPacket *p1 = NULL, *p2 = NULL; + _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; + DnsResourceRecord *rr = NULL; + + rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, "example.com"); + ASSERT_NOT_NULL(rr); + rr->ttl = 3601; + rr->a.in_addr.s_addr = htobe32(0xc0a8017f); + + answer = dns_answer_new(1); + ASSERT_NOT_NULL(answer); + dns_answer_add(answer, rr, 1, 0, NULL); + dns_resource_record_unref(rr); + + ASSERT_OK(dns_packet_new(&p1, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX)); + ASSERT_NOT_NULL(p1); + + DNS_PACKET_ID(p1) = htobe16(42); + DNS_PACKET_HEADER(p1)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(1, 0, 1, 0, 1, 1, 0, 0, DNS_RCODE_SUCCESS)); + DNS_PACKET_HEADER(p1)->ancount = htobe16(dns_answer_size(answer)); + + ASSERT_OK(dns_packet_append_answer(p1, answer, NULL)); + + const uint8_t data[] = { + 0x00, 0x2a, BIT_QR | BIT_AA | BIT_RD, BIT_RA | DNS_RCODE_SUCCESS, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + + /* name */ 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x03, 'c', 'o', 'm', + 0x00, + /* A */ 0x00, 0x01, + /* IN */ 0x00, 0x01, + /* ttl */ 0x00, 0x00, 0x0e, 0x11, + /* rdata */ 0x00, 0x04, + /* ip */ 0xc0, 0xa8, 0x01, 0x7f + }; + + ASSERT_OK(dns_packet_dup(&p2, p1)); + ASSERT_NOT_NULL(p2); + + ASSERT_EQ(p2->size, sizeof(data)); + ASSERT_EQ(memcmp(DNS_PACKET_DATA(p2), data, sizeof(data)), 0); +} + /* ================================================================ * dns_packet_append_answer() * ================================================================ */