Home | History | Annotate | Line # | Download | only in dns
      1 /*	$NetBSD: message_test.c,v 1.1.1.1 2026/09/17 17:45:09 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
      5  *
      6  * SPDX-License-Identifier: MPL-2.0
      7  *
      8  * This Source Code Form is subject to the terms of the Mozilla Public
      9  * License, v. 2.0. If a copy of the MPL was not distributed with this
     10  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
     11  *
     12  * See the COPYRIGHT file distributed with this work for additional
     13  * information regarding copyright ownership.
     14  */
     15 
     16 #include <inttypes.h>
     17 #include <sched.h> /* IWYU pragma: keep */
     18 #include <setjmp.h>
     19 #include <stdarg.h>
     20 #include <stdbool.h>
     21 #include <stddef.h>
     22 #include <stdlib.h>
     23 #include <string.h>
     24 #include <unistd.h>
     25 
     26 #define UNIT_TESTING
     27 #include <cmocka.h>
     28 
     29 #include <isc/buffer.h>
     30 #include <isc/region.h>
     31 #include <isc/result.h>
     32 #include <isc/util.h>
     33 
     34 #include <dns/fixedname.h>
     35 #include <dns/message.h>
     36 #include <dns/name.h>
     37 #include <dns/rdata.h>
     38 #include <dns/rdataclass.h>
     39 #include <dns/rdataset.h>
     40 #include <dns/rdatatype.h>
     41 
     42 #include <tests/dns.h>
     43 
     44 #define TTL 300
     45 
     46 /*
     47  * Helpers for assembling a DNS message in wire format by hand, so that
     48  * it can contain things dns_message_rendersection() would never produce,
     49  * such as the same RR listed several times.
     50  */
     51 
     52 static void
     53 put_name(isc_buffer_t *wire, const char *namestr) {
     54 	dns_fixedname_t fname;
     55 	isc_region_t r;
     56 
     57 	dns_test_namefromstring(namestr, &fname);
     58 	dns_name_toregion(dns_fixedname_name(&fname), &r);
     59 	isc_buffer_putmem(wire, r.base, r.length);
     60 }
     61 
     62 static void
     63 put_header(isc_buffer_t *wire, unsigned int ancount, unsigned int nscount) {
     64 	isc_buffer_putuint16(wire, 0x1234); /* ID */
     65 	isc_buffer_putuint16(wire, DNS_MESSAGEFLAG_QR);
     66 	isc_buffer_putuint16(wire, 1); /* QDCOUNT */
     67 	isc_buffer_putuint16(wire, ancount);
     68 	isc_buffer_putuint16(wire, nscount);
     69 	isc_buffer_putuint16(wire, 0); /* ARCOUNT */
     70 }
     71 
     72 static void
     73 put_question(isc_buffer_t *wire, const char *qname, dns_rdatatype_t qtype) {
     74 	put_name(wire, qname);
     75 	isc_buffer_putuint16(wire, qtype);
     76 	isc_buffer_putuint16(wire, dns_rdataclass_in);
     77 }
     78 
     79 static void
     80 put_rr_with_ttl(isc_buffer_t *wire, const char *owner, dns_rdatatype_t type,
     81 		dns_ttl_t ttl, const char *rdatatext) {
     82 	unsigned char rdatabuf[512];
     83 	dns_rdata_t rdata = DNS_RDATA_INIT;
     84 	isc_result_t result;
     85 
     86 	result = dns_test_rdatafromstring(&rdata, dns_rdataclass_in, type,
     87 					  rdatabuf, sizeof(rdatabuf), rdatatext,
     88 					  false);
     89 	assert_int_equal(result, ISC_R_SUCCESS);
     90 
     91 	put_name(wire, owner);
     92 	isc_buffer_putuint16(wire, type);
     93 	isc_buffer_putuint16(wire, dns_rdataclass_in);
     94 	isc_buffer_putuint32(wire, ttl);
     95 	isc_buffer_putuint16(wire, rdata.length);
     96 	isc_buffer_putmem(wire, rdata.data, rdata.length);
     97 }
     98 
     99 static void
    100 put_rr(isc_buffer_t *wire, const char *owner, dns_rdatatype_t type,
    101        const char *rdatatext) {
    102 	put_rr_with_ttl(wire, owner, type, TTL, rdatatext);
    103 }
    104 
    105 static isc_result_t
    106 parse(isc_buffer_t *wire, unsigned int options, dns_message_t **msgp) {
    107 	dns_message_create(mctx, NULL, NULL, DNS_MESSAGE_INTENTPARSE, msgp);
    108 	return dns_message_parse(*msgp, wire, options);
    109 }
    110 
    111 /*
    112  * Get the rdataset of the given type at 'owner' in 'section'.
    113  */
    114 static dns_rdataset_t *
    115 get_rdataset(dns_message_t *msg, dns_section_t section, const char *owner,
    116 	     dns_rdatatype_t type) {
    117 	dns_fixedname_t fname;
    118 	dns_rdataset_t *rdataset = NULL;
    119 	isc_result_t result;
    120 
    121 	dns_test_namefromstring(owner, &fname);
    122 	result = dns_message_findname(msg, section, dns_fixedname_name(&fname),
    123 				      type, 0, NULL, &rdataset);
    124 	assert_int_equal(result, ISC_R_SUCCESS);
    125 
    126 	return rdataset;
    127 }
    128 
    129 /*
    130  * A record of a singleton type repeated with identical RDATA is kept once;
    131  * repeats of other types are all retained, as before.
    132  */
    133 ISC_RUN_TEST_IMPL(parse_duplicate_singleton) {
    134 	unsigned char wirebuf[1024];
    135 	isc_buffer_t wire;
    136 	dns_message_t *msg = NULL;
    137 	isc_result_t result;
    138 	dns_rdataset_t *rdataset = NULL;
    139 
    140 	isc_buffer_init(&wire, wirebuf, sizeof(wirebuf));
    141 	put_header(&wire, 4, 2);
    142 	put_question(&wire, "dup.example.", dns_rdatatype_a);
    143 	put_rr_with_ttl(&wire, "dup.example.", dns_rdatatype_cname, 600,
    144 			"target.example.");
    145 	put_rr_with_ttl(&wire, "dup.example.", dns_rdatatype_cname, 300,
    146 			"target.example.");
    147 	put_rr_with_ttl(&wire, "target.example.", dns_rdatatype_a, 600,
    148 			"10.0.0.1");
    149 	put_rr_with_ttl(&wire, "target.example.", dns_rdatatype_a, 1200,
    150 			"10.0.0.1");
    151 	put_rr_with_ttl(&wire, "example.", dns_rdatatype_soa, 0,
    152 			"ns.example. hostmaster.example. 1 3600 600 86400 300");
    153 	put_rr_with_ttl(&wire, "example.", dns_rdatatype_soa, 1200,
    154 			"ns.example. hostmaster.example. 1 3600 600 86400 300");
    155 
    156 	result = parse(&wire, 0, &msg);
    157 	assert_int_equal(result, ISC_R_SUCCESS);
    158 
    159 	rdataset = get_rdataset(msg, DNS_SECTION_ANSWER, "dup.example.",
    160 				dns_rdatatype_cname);
    161 	assert_non_null(rdataset);
    162 	assert_int_equal(dns_rdataset_count(rdataset), 1);
    163 	assert_int_equal(rdataset->ttl, 300);
    164 
    165 	rdataset = get_rdataset(msg, DNS_SECTION_ANSWER, "target.example.",
    166 				dns_rdatatype_a);
    167 	assert_non_null(rdataset);
    168 	assert_int_equal(dns_rdataset_count(rdataset), 2);
    169 	assert_int_equal(rdataset->ttl, 600);
    170 
    171 	rdataset = get_rdataset(msg, DNS_SECTION_AUTHORITY, "example.",
    172 				dns_rdatatype_soa);
    173 	assert_non_null(rdataset);
    174 	assert_int_equal(dns_rdataset_count(rdataset), 1);
    175 	assert_int_equal(rdataset->ttl, 0);
    176 
    177 	dns_message_detach(&msg);
    178 }
    179 
    180 /*
    181  * A singleton type with two different RDATA is still a malformed message.
    182  */
    183 ISC_RUN_TEST_IMPL(parse_conflicting_singleton) {
    184 	unsigned char wirebuf[1024];
    185 	isc_buffer_t wire;
    186 	dns_message_t *msg = NULL;
    187 	isc_result_t result;
    188 	dns_rdataset_t *rdataset = NULL;
    189 
    190 	isc_buffer_init(&wire, wirebuf, sizeof(wirebuf));
    191 	put_header(&wire, 2, 0);
    192 	put_question(&wire, "dup.example.", dns_rdatatype_a);
    193 	put_rr(&wire, "dup.example.", dns_rdatatype_cname, "target.example.");
    194 	put_rr(&wire, "dup.example.", dns_rdatatype_cname, "other.example.");
    195 
    196 	result = parse(&wire, 0, &msg);
    197 	assert_int_equal(result, DNS_R_FORMERR);
    198 	dns_message_detach(&msg);
    199 
    200 	/*
    201 	 * With best-effort parsing the problem is reported but the message
    202 	 * is still usable, and only the first CNAME survives.
    203 	 */
    204 	isc_buffer_first(&wire);
    205 	result = parse(&wire, DNS_MESSAGEPARSE_BESTEFFORT, &msg);
    206 	assert_int_equal(result, DNS_R_RECOVERABLE);
    207 
    208 	rdataset = get_rdataset(msg, DNS_SECTION_ANSWER, "dup.example.",
    209 				dns_rdatatype_cname);
    210 	assert_non_null(rdataset);
    211 	assert_int_equal(dns_rdataset_count(rdataset), 2);
    212 
    213 	dns_message_detach(&msg);
    214 }
    215 
    216 ISC_TEST_LIST_START
    217 ISC_TEST_ENTRY(parse_duplicate_singleton)
    218 ISC_TEST_ENTRY(parse_conflicting_singleton)
    219 ISC_TEST_LIST_END
    220 
    221 ISC_TEST_MAIN
    222