xref: /netbsd-src/external/mpl/bind/dist/tests/dns/name_test.c (revision bcda20f65a8566e103791ec395f7f499ef322704)
1 /*	$NetBSD: name_test.c,v 1.4 2025/01/26 16:25:47 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/commandline.h>
31 #include <isc/mem.h>
32 #include <isc/os.h>
33 #include <isc/thread.h>
34 #include <isc/util.h>
35 
36 #include <dns/compress.h>
37 #include <dns/fixedname.h>
38 #include <dns/name.h>
39 
40 #include <tests/dns.h>
41 
42 /* Set to true (or use -v option) for verbose output */
43 static bool verbose = false;
44 
45 /* dns_name_fullcompare test */
46 ISC_RUN_TEST_IMPL(fullcompare) {
47 	dns_fixedname_t fixed1;
48 	dns_fixedname_t fixed2;
49 	dns_name_t *name1;
50 	dns_name_t *name2;
51 	dns_namereln_t relation;
52 	int i;
53 	isc_result_t result;
54 	struct {
55 		const char *name1;
56 		const char *name2;
57 		dns_namereln_t relation;
58 		int order;
59 		unsigned int nlabels;
60 	} data[] = {
61 		/* relative */
62 		{ "", "", dns_namereln_equal, 0, 0 },
63 		{ "foo", "", dns_namereln_subdomain, 1, 0 },
64 		{ "", "foo", dns_namereln_contains, -1, 0 },
65 		{ "foo", "bar", dns_namereln_none, 1, 0 },
66 		{ "bar", "foo", dns_namereln_none, -1, 0 },
67 		{ "bar.foo", "foo", dns_namereln_subdomain, 1, 1 },
68 		{ "foo", "bar.foo", dns_namereln_contains, -1, 1 },
69 		{ "baz.bar.foo", "bar.foo", dns_namereln_subdomain, 1, 2 },
70 		{ "bar.foo", "baz.bar.foo", dns_namereln_contains, -1, 2 },
71 		{ "foo.example", "bar.example", dns_namereln_commonancestor, 1,
72 		  1 },
73 
74 		/* absolute */
75 		{ ".", ".", dns_namereln_equal, 0, 1 },
76 		{ "foo.", "bar.", dns_namereln_commonancestor, 1, 1 },
77 		{ "bar.", "foo.", dns_namereln_commonancestor, -1, 1 },
78 		{ "foo.example.", "bar.example.", dns_namereln_commonancestor,
79 		  1, 2 },
80 		{ "bar.foo.", "foo.", dns_namereln_subdomain, 1, 2 },
81 		{ "foo.", "bar.foo.", dns_namereln_contains, -1, 2 },
82 		{ "baz.bar.foo.", "bar.foo.", dns_namereln_subdomain, 1, 3 },
83 		{ "bar.foo.", "baz.bar.foo.", dns_namereln_contains, -1, 3 },
84 		{ NULL, NULL, dns_namereln_none, 0, 0 }
85 	};
86 
87 	UNUSED(state);
88 
89 	name1 = dns_fixedname_initname(&fixed1);
90 	name2 = dns_fixedname_initname(&fixed2);
91 	for (i = 0; data[i].name1 != NULL; i++) {
92 		int order = 3000;
93 		unsigned int nlabels = 3000;
94 
95 		if (data[i].name1[0] == 0) {
96 			dns_fixedname_init(&fixed1);
97 		} else {
98 			result = dns_name_fromstring(name1, data[i].name1, NULL,
99 						     0, NULL);
100 			assert_int_equal(result, ISC_R_SUCCESS);
101 		}
102 		if (data[i].name2[0] == 0) {
103 			dns_fixedname_init(&fixed2);
104 		} else {
105 			result = dns_name_fromstring(name2, data[i].name2, NULL,
106 						     0, NULL);
107 			assert_int_equal(result, ISC_R_SUCCESS);
108 		}
109 		relation = dns_name_fullcompare(name1, name1, &order, &nlabels);
110 		assert_int_equal(relation, dns_namereln_equal);
111 		assert_int_equal(order, 0);
112 		assert_int_equal(nlabels, name1->labels);
113 
114 		/* Some random initializer */
115 		order = 3001;
116 		nlabels = 3001;
117 
118 		relation = dns_name_fullcompare(name1, name2, &order, &nlabels);
119 		assert_int_equal(relation, data[i].relation);
120 		assert_int_equal(order, data[i].order);
121 		assert_int_equal(nlabels, data[i].nlabels);
122 	}
123 }
124 
125 static void
126 compress_test(const dns_name_t *name1, const dns_name_t *name2,
127 	      const dns_name_t *name3, unsigned char *compressed,
128 	      unsigned int compressed_length, unsigned char *expanded,
129 	      unsigned int expanded_length, dns_compress_t *cctx,
130 	      dns_decompress_t dctx, bool rdata) {
131 	isc_buffer_t source;
132 	isc_buffer_t target;
133 	dns_name_t name;
134 	unsigned char buf1[1024];
135 	unsigned char buf2[1024];
136 
137 	isc_buffer_init(&source, buf1, sizeof(buf1));
138 	isc_buffer_init(&target, buf2, sizeof(buf2));
139 
140 	/*
141 	 * compression offsets are not allowed to be zero so our
142 	 * names need to start after a little fake header
143 	 */
144 	isc_buffer_putuint16(&source, 0xEAD);
145 	isc_buffer_putuint16(&target, 0xEAD);
146 
147 	if (rdata) {
148 		/* RDATA compression */
149 		assert_int_equal(dns_name_towire(name1, cctx, &source, NULL),
150 				 ISC_R_SUCCESS);
151 		assert_int_equal(dns_name_towire(name2, cctx, &source, NULL),
152 				 ISC_R_SUCCESS);
153 		assert_int_equal(dns_name_towire(name2, cctx, &source, NULL),
154 				 ISC_R_SUCCESS);
155 		assert_int_equal(dns_name_towire(name3, cctx, &source, NULL),
156 				 ISC_R_SUCCESS);
157 	} else {
158 		/* Owner name compression */
159 		uint16_t offset = 0xffff;
160 		assert_int_equal(dns_name_towire(name1, cctx, &source, &offset),
161 				 ISC_R_SUCCESS);
162 
163 		offset = 0xffff;
164 		assert_int_equal(dns_name_towire(name2, cctx, &source, &offset),
165 				 ISC_R_SUCCESS);
166 		assert_int_equal(dns_name_towire(name2, cctx, &source, &offset),
167 				 ISC_R_SUCCESS);
168 
169 		offset = 0xffff;
170 		assert_int_equal(dns_name_towire(name3, cctx, &source, &offset),
171 				 ISC_R_SUCCESS);
172 	}
173 	assert_int_equal(source.used, compressed_length);
174 	assert_true(memcmp(source.base, compressed, source.used) == 0);
175 
176 	isc_buffer_setactive(&source, source.used);
177 
178 	dns_name_init(&name, NULL);
179 	RUNTIME_CHECK(isc_buffer_getuint16(&source) == 0xEAD);
180 	RUNTIME_CHECK(dns_name_fromwire(&name, &source, dctx, &target) ==
181 		      ISC_R_SUCCESS);
182 	RUNTIME_CHECK(dns_name_fromwire(&name, &source, dctx, &target) ==
183 		      ISC_R_SUCCESS);
184 	RUNTIME_CHECK(dns_name_fromwire(&name, &source, dctx, &target) ==
185 		      ISC_R_SUCCESS);
186 	RUNTIME_CHECK(dns_name_fromwire(&name, &source, dctx, &target) ==
187 		      ISC_R_SUCCESS);
188 
189 	assert_int_equal(target.used, expanded_length);
190 	assert_true(memcmp(target.base, expanded, target.used) == 0);
191 }
192 
193 /* name compression test */
194 ISC_RUN_TEST_IMPL(compression) {
195 	bool permitted;
196 	dns_compress_t cctx;
197 	dns_decompress_t dctx;
198 	dns_name_t name1;
199 	dns_name_t name2;
200 	dns_name_t name3;
201 	dns_name_t name4;
202 	isc_region_t r;
203 	unsigned char plain1[] = "\003yyy\003foo";
204 	unsigned char plain2[] = "\003bar\003yyy\003foo";
205 	unsigned char plain3[] = "\003xxx\003bar\003foo";
206 	unsigned char plain4[] = "\003xxx\003bar\003zzz";
207 
208 	unsigned char plain[] = "\x0E\xAD"
209 				"\003yyy\003foo\0"
210 				"\003bar\003yyy\003foo\0"
211 				"\003bar\003yyy\003foo\0"
212 				"\003xxx\003bar\003foo";
213 
214 	unsigned char compressed[29] = "\x0E\xAD"
215 				       "\003yyy\003foo\0"
216 				       "\003bar\xc0\x02"
217 				       "\xc0\x0B"
218 				       "\003xxx\003bar\xc0\x06";
219 	/*
220 	 * Only the second owner name is compressed.
221 	 */
222 	unsigned char disabled_owner[] = "\x0E\xAD"
223 					 "\003yyy\003foo\0"
224 					 "\003bar\003yyy\003foo\0"
225 					 "\xc0\x0B"
226 					 "\003xxx\003bar\003foo";
227 
228 	unsigned char root_plain[] = "\x0E\xAD"
229 				     "\003yyy\003foo\0"
230 				     "\0\0"
231 				     "\003xxx\003bar\003zzz";
232 
233 	UNUSED(state);
234 
235 	dns_name_init(&name1, NULL);
236 	r.base = plain1;
237 	r.length = sizeof(plain1);
238 	dns_name_fromregion(&name1, &r);
239 
240 	dns_name_init(&name2, NULL);
241 	r.base = plain2;
242 	r.length = sizeof(plain2);
243 	dns_name_fromregion(&name2, &r);
244 
245 	dns_name_init(&name3, NULL);
246 	r.base = plain3;
247 	r.length = sizeof(plain3);
248 	dns_name_fromregion(&name3, &r);
249 
250 	dns_name_init(&name4, NULL);
251 	r.base = plain4;
252 	r.length = sizeof(plain3);
253 	dns_name_fromregion(&name4, &r);
254 
255 	/* Test 1: off, rdata */
256 	permitted = false;
257 	dns_compress_init(&cctx, mctx, 0);
258 	dns_compress_setpermitted(&cctx, permitted);
259 	dctx = dns_decompress_setpermitted(DNS_DECOMPRESS_DEFAULT, permitted);
260 
261 	compress_test(&name1, &name2, &name3, plain, sizeof(plain), plain,
262 		      sizeof(plain), &cctx, dctx, true);
263 
264 	dns_compress_rollback(&cctx, 0);
265 	dns_compress_invalidate(&cctx);
266 
267 	/* Test2: on, rdata */
268 	permitted = true;
269 	dns_compress_init(&cctx, mctx, 0);
270 	dns_compress_setpermitted(&cctx, permitted);
271 	dctx = dns_decompress_setpermitted(DNS_DECOMPRESS_DEFAULT, permitted);
272 
273 	compress_test(&name1, &name2, &name3, compressed, sizeof(compressed),
274 		      plain, sizeof(plain), &cctx, dctx, true);
275 
276 	dns_compress_rollback(&cctx, 0);
277 	dns_compress_invalidate(&cctx);
278 
279 	/* Test3: off, disabled, rdata */
280 	permitted = false;
281 	dns_compress_init(&cctx, mctx, DNS_COMPRESS_DISABLED);
282 	dns_compress_setpermitted(&cctx, permitted);
283 	dctx = dns_decompress_setpermitted(DNS_DECOMPRESS_DEFAULT, permitted);
284 
285 	compress_test(&name1, &name2, &name3, plain, sizeof(plain), plain,
286 		      sizeof(plain), &cctx, dctx, true);
287 
288 	dns_compress_rollback(&cctx, 0);
289 	dns_compress_invalidate(&cctx);
290 
291 	/* Test4: on, disabled, rdata */
292 	permitted = true;
293 	dns_compress_init(&cctx, mctx, DNS_COMPRESS_DISABLED);
294 	dns_compress_setpermitted(&cctx, permitted);
295 	dctx = dns_decompress_setpermitted(DNS_DECOMPRESS_DEFAULT, permitted);
296 
297 	compress_test(&name1, &name2, &name3, plain, sizeof(plain), plain,
298 		      sizeof(plain), &cctx, dctx, true);
299 
300 	dns_compress_rollback(&cctx, 0);
301 	dns_compress_invalidate(&cctx);
302 
303 	/* Test5: on, rdata */
304 	permitted = true;
305 	dns_compress_init(&cctx, mctx, 0);
306 	dns_compress_setpermitted(&cctx, permitted);
307 	dctx = dns_decompress_setpermitted(DNS_DECOMPRESS_DEFAULT, permitted);
308 
309 	compress_test(&name1, dns_rootname, &name4, root_plain,
310 		      sizeof(root_plain), root_plain, sizeof(root_plain), &cctx,
311 		      dctx, true);
312 
313 	dns_compress_rollback(&cctx, 0);
314 	dns_compress_invalidate(&cctx);
315 
316 	/* Test 6: off, owner */
317 	permitted = false;
318 	dns_compress_init(&cctx, mctx, 0);
319 	dns_compress_setpermitted(&cctx, permitted);
320 	dctx = dns_decompress_setpermitted(DNS_DECOMPRESS_DEFAULT, permitted);
321 
322 	compress_test(&name1, &name2, &name3, plain, sizeof(plain), plain,
323 		      sizeof(plain), &cctx, dctx, false);
324 
325 	dns_compress_rollback(&cctx, 0);
326 	dns_compress_invalidate(&cctx);
327 
328 	/* Test7: on, owner */
329 	permitted = true;
330 	dns_compress_init(&cctx, mctx, 0);
331 	dns_compress_setpermitted(&cctx, permitted);
332 	dctx = dns_decompress_setpermitted(DNS_DECOMPRESS_DEFAULT, permitted);
333 
334 	compress_test(&name1, &name2, &name3, compressed, sizeof(compressed),
335 		      plain, sizeof(plain), &cctx, dctx, false);
336 
337 	dns_compress_rollback(&cctx, 0);
338 	dns_compress_invalidate(&cctx);
339 
340 	/* Test8: off, disabled, owner */
341 	permitted = false;
342 	dns_compress_init(&cctx, mctx, DNS_COMPRESS_DISABLED);
343 	dns_compress_setpermitted(&cctx, permitted);
344 	dctx = dns_decompress_setpermitted(DNS_DECOMPRESS_DEFAULT, permitted);
345 
346 	compress_test(&name1, &name2, &name3, plain, sizeof(plain), plain,
347 		      sizeof(plain), &cctx, dctx, false);
348 
349 	dns_compress_rollback(&cctx, 0);
350 	dns_compress_invalidate(&cctx);
351 
352 	/* Test9: on, disabled, owner */
353 	permitted = true;
354 	dns_compress_init(&cctx, mctx, DNS_COMPRESS_DISABLED);
355 	dns_compress_setpermitted(&cctx, permitted);
356 	dctx = dns_decompress_setpermitted(DNS_DECOMPRESS_DEFAULT, permitted);
357 
358 	compress_test(&name1, &name2, &name3, disabled_owner,
359 		      sizeof(disabled_owner), plain, sizeof(plain), &cctx, dctx,
360 		      false);
361 
362 	dns_compress_rollback(&cctx, 0);
363 	dns_compress_invalidate(&cctx);
364 
365 	/* Test10: on, owner */
366 	permitted = true;
367 	dns_compress_init(&cctx, mctx, 0);
368 	dns_compress_setpermitted(&cctx, permitted);
369 	dctx = dns_decompress_setpermitted(DNS_DECOMPRESS_DEFAULT, permitted);
370 
371 	compress_test(&name1, dns_rootname, &name4, root_plain,
372 		      sizeof(root_plain), root_plain, sizeof(root_plain), &cctx,
373 		      dctx, false);
374 
375 	dns_compress_rollback(&cctx, 0);
376 	dns_compress_invalidate(&cctx);
377 }
378 
379 #define NAME_LO 25
380 #define NAME_HI 250000
381 
382 /*
383  * test compression context hash set collisions and rollbacks
384  */
385 ISC_RUN_TEST_IMPL(collision) {
386 	isc_result_t result;
387 	isc_region_t r;
388 	dns_compress_t cctx;
389 	isc_buffer_t message;
390 	uint8_t msgbuf[65536];
391 	dns_name_t name;
392 	char namebuf[256];
393 	uint8_t offsets[128];
394 
395 	dns_compress_init(&cctx, mctx, DNS_COMPRESS_LARGE);
396 	isc_buffer_init(&message, msgbuf, sizeof(msgbuf));
397 	dns_name_init(&name, offsets);
398 
399 	/*
400 	 * compression offsets are not allowed to be zero so our
401 	 * names need to start after a little fake header
402 	 */
403 	isc_buffer_putuint16(&message, 0xEAD);
404 
405 	static const char zone[] = "test";
406 	const int zonelen = sizeof(zone) - 1;
407 	unsigned int zone_coff = 0;
408 
409 	for (int i = NAME_LO; i < NAME_HI; i++) {
410 		unsigned int prefix_len, suffix_coff;
411 		unsigned int coff = isc_buffer_usedlength(&message);
412 
413 		int len = snprintf(namebuf, sizeof(namebuf), ".%d%c%s", i,
414 				   zonelen, zone);
415 		namebuf[0] = len - zonelen - 2;
416 		r = (isc_region_t){ .base = (uint8_t *)namebuf,
417 				    .length = len + 1 };
418 		dns_name_fromregion(&name, &r);
419 
420 		/* the name we are about to add must partially match */
421 		prefix_len = name.length;
422 		suffix_coff = 0;
423 		dns_compress_name(&cctx, &message, &name, &prefix_len,
424 				  &suffix_coff);
425 		if (i == NAME_LO) {
426 			assert_int_equal(prefix_len, name.length);
427 			assert_int_equal(suffix_coff, 0);
428 			zone_coff = 2 + len - zonelen - 1;
429 		} else {
430 			assert_int_equal(prefix_len, len - zonelen - 1);
431 			assert_int_equal(suffix_coff, zone_coff);
432 		}
433 		dns_compress_rollback(&cctx, coff);
434 
435 		result = dns_name_towire(&name, &cctx, &message, NULL);
436 		assert_int_equal(result, ISC_R_SUCCESS);
437 
438 		/* we must be able to find the name we just added */
439 		prefix_len = name.length;
440 		suffix_coff = 0;
441 		dns_compress_name(&cctx, &message, &name, &prefix_len,
442 				  &suffix_coff);
443 		assert_int_equal(prefix_len, 0);
444 		assert_int_equal(suffix_coff, coff);
445 
446 		/* don't let the hash set get too full */
447 		if (cctx.count > cctx.mask * 3 / 5) {
448 			dns_compress_rollback(&cctx, zone_coff + zonelen + 2);
449 			isc_buffer_clear(&message);
450 			isc_buffer_add(&message, zone_coff + zonelen + 2);
451 		}
452 	}
453 
454 	dns_compress_invalidate(&cctx);
455 }
456 
457 ISC_RUN_TEST_IMPL(fromregion) {
458 	dns_name_t name;
459 	isc_buffer_t b;
460 	isc_region_t r;
461 	/*
462 	 * target and source need to be bigger than DNS_NAME_MAXWIRE to
463 	 * exercise 'len > DNS_NAME_MAXWIRE' test in dns_name_fromwire
464 	 */
465 	unsigned char target[DNS_NAME_MAXWIRE + 10];
466 	unsigned char source[DNS_NAME_MAXWIRE + 10] = { '\007', 'e', 'x', 'a',
467 							'm',	'p', 'l', 'e' };
468 	/*
469 	 * Extract the fully qualified name at the beginning of 'source'
470 	 * into 'name' where 'name.ndata' points to the buffer 'target'.
471 	 */
472 	isc_buffer_init(&b, target, sizeof(target));
473 	dns_name_init(&name, NULL);
474 	dns_name_setbuffer(&name, &b);
475 	r.base = source;
476 	r.length = sizeof(source);
477 	dns_name_fromregion(&name, &r);
478 	assert_int_equal(9, name.length);
479 	assert_ptr_equal(target, name.ndata);
480 	assert_true(dns_name_isabsolute(&name));
481 
482 	/*
483 	 * Extract the fully qualified name at the beginning of 'source'
484 	 * into 'name' where 'name.ndata' points to the source.
485 	 */
486 	isc_buffer_init(&b, target, sizeof(target));
487 	dns_name_init(&name, NULL);
488 	r.base = source;
489 	r.length = sizeof(source);
490 	dns_name_fromregion(&name, &r);
491 	assert_int_equal(9, name.length);
492 	assert_ptr_equal(source, name.ndata);
493 	assert_true(dns_name_isabsolute(&name));
494 
495 	/*
496 	 * Extract the partially qualified name in 'source' into 'name'
497 	 * where 'name.ndata' points to the source.
498 	 */
499 	isc_buffer_init(&b, target, sizeof(target));
500 	dns_name_init(&name, NULL);
501 	r.base = source;
502 	r.length = 8;
503 	dns_name_fromregion(&name, &r);
504 	assert_int_equal(8, name.length);
505 	assert_ptr_equal(source, name.ndata);
506 	assert_false(dns_name_isabsolute(&name));
507 
508 	/*
509 	 * Extract empty name in 'source' into 'name'.
510 	 */
511 	isc_buffer_init(&b, target, sizeof(target));
512 	dns_name_init(&name, NULL);
513 	r.base = source;
514 	r.length = 0;
515 	dns_name_fromregion(&name, &r);
516 	assert_int_equal(0, name.length);
517 	assert_ptr_equal(source, name.ndata);
518 	assert_false(dns_name_isabsolute(&name));
519 }
520 
521 /* is trust-anchor-telemetry test */
522 ISC_RUN_TEST_IMPL(istat) {
523 	dns_fixedname_t fixed;
524 	dns_name_t *name;
525 	isc_result_t result;
526 	size_t i;
527 	struct {
528 		const char *name;
529 		bool istat;
530 	} data[] = { { ".", false },
531 		     { "_ta-", false },
532 		     { "_ta-1234", true },
533 		     { "_TA-1234", true },
534 		     { "+TA-1234", false },
535 		     { "_fa-1234", false },
536 		     { "_td-1234", false },
537 		     { "_ta_1234", false },
538 		     { "_ta-g234", false },
539 		     { "_ta-1h34", false },
540 		     { "_ta-12i4", false },
541 		     { "_ta-123j", false },
542 		     { "_ta-1234-abcf", true },
543 		     { "_ta-1234-abcf-ED89", true },
544 		     { "_ta-12345-abcf-ED89", false },
545 		     { "_ta-.example", false },
546 		     { "_ta-1234.example", true },
547 		     { "_ta-1234-abcf.example", true },
548 		     { "_ta-1234-abcf-ED89.example", true },
549 		     { "_ta-12345-abcf-ED89.example", false },
550 		     { "_ta-1234-abcfe-ED89.example", false },
551 		     { "_ta-1234-abcf-EcD89.example", false } };
552 
553 	UNUSED(state);
554 
555 	name = dns_fixedname_initname(&fixed);
556 
557 	for (i = 0; i < (sizeof(data) / sizeof(data[0])); i++) {
558 		result = dns_name_fromstring(name, data[i].name, dns_rootname,
559 					     0, NULL);
560 		assert_int_equal(result, ISC_R_SUCCESS);
561 		assert_int_equal(dns_name_istat(name), data[i].istat);
562 	}
563 }
564 
565 static bool
566 name_attr_zero(struct dns_name_attrs attributes) {
567 	return !(attributes.absolute | attributes.readonly |
568 		 attributes.dynamic | attributes.dynoffsets |
569 		 attributes.nocompress | attributes.cache | attributes.answer |
570 		 attributes.ncache | attributes.chaining | attributes.chase |
571 		 attributes.wildcard | attributes.prerequisite |
572 		 attributes.update | attributes.hasupdaterec);
573 }
574 
575 /* dns_name_init */
576 ISC_RUN_TEST_IMPL(init) {
577 	dns_name_t name;
578 	unsigned char offsets[1];
579 
580 	UNUSED(state);
581 
582 	dns_name_init(&name, offsets);
583 
584 	assert_null(name.ndata);
585 	assert_int_equal(name.length, 0);
586 	assert_int_equal(name.labels, 0);
587 	assert_ptr_equal(name.offsets, offsets);
588 	assert_null(name.buffer);
589 	assert_true(name_attr_zero(name.attributes));
590 }
591 
592 /* dns_name_invalidate */
593 ISC_RUN_TEST_IMPL(invalidate) {
594 	dns_name_t name;
595 	unsigned char offsets[1];
596 
597 	UNUSED(state);
598 
599 	dns_name_init(&name, offsets);
600 	dns_name_invalidate(&name);
601 
602 	assert_null(name.ndata);
603 	assert_int_equal(name.length, 0);
604 	assert_int_equal(name.labels, 0);
605 	assert_null(name.offsets);
606 	assert_null(name.buffer);
607 	assert_true(name_attr_zero(name.attributes));
608 }
609 
610 /* dns_name_setbuffer/hasbuffer */
611 ISC_RUN_TEST_IMPL(buffer) {
612 	dns_name_t name;
613 	unsigned char buf[BUFSIZ];
614 	isc_buffer_t b;
615 
616 	UNUSED(state);
617 
618 	isc_buffer_init(&b, buf, BUFSIZ);
619 	dns_name_init(&name, NULL);
620 	dns_name_setbuffer(&name, &b);
621 	assert_ptr_equal(name.buffer, &b);
622 	assert_true(dns_name_hasbuffer(&name));
623 }
624 
625 /* dns_name_isabsolute */
626 ISC_RUN_TEST_IMPL(isabsolute) {
627 	struct {
628 		const char *namestr;
629 		bool expect;
630 	} testcases[] = { { "x", false },
631 			  { "a.b.c.d.", true },
632 			  { "x.z", false } };
633 	unsigned int i;
634 
635 	UNUSED(state);
636 
637 	for (i = 0; i < (sizeof(testcases) / sizeof(testcases[0])); i++) {
638 		isc_result_t result;
639 		dns_name_t name;
640 		unsigned char data[BUFSIZ];
641 		isc_buffer_t b, nb;
642 		size_t len;
643 
644 		len = strlen(testcases[i].namestr);
645 		isc_buffer_constinit(&b, testcases[i].namestr, len);
646 		isc_buffer_add(&b, len);
647 
648 		dns_name_init(&name, NULL);
649 		isc_buffer_init(&nb, data, BUFSIZ);
650 		dns_name_setbuffer(&name, &nb);
651 		result = dns_name_fromtext(&name, &b, NULL, 0, NULL);
652 		assert_int_equal(result, ISC_R_SUCCESS);
653 
654 		assert_int_equal(dns_name_isabsolute(&name),
655 				 testcases[i].expect);
656 	}
657 }
658 
659 /* dns_name_hash */
660 ISC_RUN_TEST_IMPL(hash) {
661 	struct {
662 		const char *name1;
663 		const char *name2;
664 		bool expect;
665 		bool expecti;
666 	} testcases[] = {
667 		{ "a.b.c.d", "A.B.C.D", true, false },
668 		{ "a.b.c.d.", "A.B.C.D.", true, false },
669 		{ "a.b.c.d", "a.b.c.d", true, true },
670 		{ "A.B.C.D.", "A.B.C.D.", true, false },
671 		{ "x.y.z.w", "a.b.c.d", false, false },
672 		{ "x.y.z.w.", "a.b.c.d.", false, false },
673 	};
674 	unsigned int i;
675 
676 	UNUSED(state);
677 
678 	for (i = 0; i < (sizeof(testcases) / sizeof(testcases[0])); i++) {
679 		isc_result_t result;
680 		dns_fixedname_t f1, f2;
681 		dns_name_t *n1, *n2;
682 		unsigned int h1, h2;
683 
684 		n1 = dns_fixedname_initname(&f1);
685 		n2 = dns_fixedname_initname(&f2);
686 
687 		result = dns_name_fromstring(n1, testcases[i].name1, NULL, 0,
688 					     NULL);
689 		assert_int_equal(result, ISC_R_SUCCESS);
690 		result = dns_name_fromstring(n2, testcases[i].name2, NULL, 0,
691 					     NULL);
692 		assert_int_equal(result, ISC_R_SUCCESS);
693 
694 		/* Check case-insensitive hashing first */
695 		h1 = dns_name_hash(n1);
696 		h2 = dns_name_hash(n2);
697 
698 		if (verbose) {
699 			print_message("# %s hashes to %u, "
700 				      "%s to %u, case insensitive\n",
701 				      testcases[i].name1, h1,
702 				      testcases[i].name2, h2);
703 		}
704 
705 		assert_int_equal((h1 == h2), testcases[i].expect);
706 
707 		/* Now case-sensitive */
708 		h1 = dns_name_hash(n1);
709 		h2 = dns_name_hash(n2);
710 
711 		if (verbose) {
712 			print_message("# %s hashes to %u, "
713 				      "%s to %u, case sensitive\n",
714 				      testcases[i].name1, h1,
715 				      testcases[i].name2, h2);
716 		}
717 
718 		assert_int_equal((h1 == h2), testcases[i].expect);
719 	}
720 }
721 
722 /* dns_name_issubdomain */
723 ISC_RUN_TEST_IMPL(issubdomain) {
724 	struct {
725 		const char *name1;
726 		const char *name2;
727 		bool expect;
728 	} testcases[] = {
729 		{ "c.d", "a.b.c.d", false }, { "c.d.", "a.b.c.d.", false },
730 		{ "b.c.d", "c.d", true },    { "a.b.c.d.", "c.d.", true },
731 		{ "a.b.c", "a.b.c", true },  { "a.b.c.", "a.b.c.", true },
732 		{ "x.y.z", "a.b.c", false }
733 	};
734 	unsigned int i;
735 
736 	UNUSED(state);
737 
738 	for (i = 0; i < (sizeof(testcases) / sizeof(testcases[0])); i++) {
739 		isc_result_t result;
740 		dns_fixedname_t f1, f2;
741 		dns_name_t *n1, *n2;
742 
743 		n1 = dns_fixedname_initname(&f1);
744 		n2 = dns_fixedname_initname(&f2);
745 
746 		result = dns_name_fromstring(n1, testcases[i].name1, NULL, 0,
747 					     NULL);
748 		assert_int_equal(result, ISC_R_SUCCESS);
749 		result = dns_name_fromstring(n2, testcases[i].name2, NULL, 0,
750 					     NULL);
751 		assert_int_equal(result, ISC_R_SUCCESS);
752 
753 		if (verbose) {
754 			print_message("# check: %s %s a subdomain of %s\n",
755 				      testcases[i].name1,
756 				      testcases[i].expect ? "is" : "is not",
757 				      testcases[i].name2);
758 		}
759 
760 		assert_int_equal(dns_name_issubdomain(n1, n2),
761 				 testcases[i].expect);
762 	}
763 }
764 
765 /* dns_name_countlabels */
766 ISC_RUN_TEST_IMPL(countlabels) {
767 	struct {
768 		const char *namestr;
769 		unsigned int expect;
770 	} testcases[] = {
771 		{ "c.d", 2 },
772 		{ "c.d.", 3 },
773 		{ "a.b.c.d.", 5 },
774 		{ "a.b.c.d", 4 },
775 		{ "a.b.c", 3 },
776 		{ ".", 1 },
777 		{ "a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y."
778 		  "a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y."
779 		  "a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y."
780 		  "a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y."
781 		  "a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y."
782 		  "a.b.",
783 		  128 },
784 	};
785 	unsigned int i;
786 
787 	UNUSED(state);
788 
789 	for (i = 0; i < (sizeof(testcases) / sizeof(testcases[0])); i++) {
790 		isc_result_t result;
791 		dns_fixedname_t fname;
792 		dns_name_t *name;
793 
794 		name = dns_fixedname_initname(&fname);
795 
796 		result = dns_name_fromstring(name, testcases[i].namestr, NULL,
797 					     0, NULL);
798 		assert_int_equal(result, ISC_R_SUCCESS);
799 
800 		if (verbose) {
801 			print_message("# %s: expect %u labels\n",
802 				      testcases[i].namestr,
803 				      testcases[i].expect);
804 		}
805 
806 		assert_int_equal(dns_name_countlabels(name),
807 				 testcases[i].expect);
808 	}
809 }
810 
811 /* dns_name_getlabel */
812 ISC_RUN_TEST_IMPL(getlabel) {
813 	struct {
814 		const char *name1;
815 		unsigned int pos1;
816 		const char *name2;
817 		unsigned int pos2;
818 	} testcases[] = {
819 		{ "c.d", 1, "a.b.c.d", 3 },
820 		{ "a.b.c.d", 3, "c.d", 1 },
821 		{ "a.b.c.", 3, "A.B.C.", 3 },
822 	};
823 	unsigned int i;
824 
825 	UNUSED(state);
826 
827 	for (i = 0; i < (sizeof(testcases) / sizeof(testcases[0])); i++) {
828 		isc_result_t result;
829 		dns_fixedname_t f1, f2;
830 		dns_name_t *n1, *n2;
831 		dns_label_t l1, l2;
832 		unsigned int j;
833 
834 		n1 = dns_fixedname_initname(&f1);
835 		n2 = dns_fixedname_initname(&f2);
836 
837 		result = dns_name_fromstring(n1, testcases[i].name1, NULL, 0,
838 					     NULL);
839 		assert_int_equal(result, ISC_R_SUCCESS);
840 		result = dns_name_fromstring(n2, testcases[i].name2, NULL, 0,
841 					     NULL);
842 		assert_int_equal(result, ISC_R_SUCCESS);
843 
844 		dns_name_getlabel(n1, testcases[i].pos1, &l1);
845 		dns_name_getlabel(n2, testcases[i].pos2, &l2);
846 		assert_int_equal(l1.length, l2.length);
847 
848 		for (j = 0; j < l1.length; j++) {
849 			assert_int_equal(l1.base[j], l2.base[j]);
850 		}
851 	}
852 }
853 
854 /* dns_name_getlabelsequence */
855 ISC_RUN_TEST_IMPL(getlabelsequence) {
856 	struct {
857 		const char *name1;
858 		unsigned int pos1;
859 		const char *name2;
860 		unsigned int pos2;
861 		unsigned int range;
862 	} testcases[] = {
863 		{ "c.d", 1, "a.b.c.d", 3, 1 },
864 		{ "a.b.c.d.e", 2, "c.d", 0, 2 },
865 		{ "a.b.c", 0, "a.b.c", 0, 3 },
866 	};
867 	unsigned int i;
868 
869 	UNUSED(state);
870 
871 	for (i = 0; i < (sizeof(testcases) / sizeof(testcases[0])); i++) {
872 		isc_result_t result;
873 		dns_name_t t1, t2;
874 		dns_fixedname_t f1, f2;
875 		dns_name_t *n1, *n2;
876 
877 		/* target names */
878 		dns_name_init(&t1, NULL);
879 		dns_name_init(&t2, NULL);
880 
881 		/* source names */
882 		n1 = dns_fixedname_initname(&f1);
883 		n2 = dns_fixedname_initname(&f2);
884 
885 		result = dns_name_fromstring(n1, testcases[i].name1, NULL, 0,
886 					     NULL);
887 		assert_int_equal(result, ISC_R_SUCCESS);
888 		result = dns_name_fromstring(n2, testcases[i].name2, NULL, 0,
889 					     NULL);
890 		assert_int_equal(result, ISC_R_SUCCESS);
891 
892 		dns_name_getlabelsequence(n1, testcases[i].pos1,
893 					  testcases[i].range, &t1);
894 		dns_name_getlabelsequence(n2, testcases[i].pos2,
895 					  testcases[i].range, &t2);
896 
897 		assert_true(dns_name_equal(&t1, &t2));
898 	}
899 }
900 
901 ISC_RUN_TEST_IMPL(maxlabels) {
902 	isc_result_t result;
903 	dns_fixedname_t fixed;
904 	dns_name_t *name = NULL;
905 
906 	const char one_too_many[] =
907 		"a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y."
908 		"a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y."
909 		"a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y."
910 		"a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y."
911 		"a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y."
912 		"a.b.c.";
913 
914 	name = dns_fixedname_initname(&fixed);
915 	result = dns_name_fromstring(name, one_too_many, dns_rootname, 0, NULL);
916 	assert_int_equal(result, ISC_R_NOSPACE);
917 
918 	name = dns_fixedname_initname(&fixed);
919 	result = dns_name_fromstring(name, one_too_many + 2, dns_rootname, 0,
920 				     NULL);
921 	assert_int_equal(result, ISC_R_SUCCESS);
922 	assert_true(dns_name_isvalid(name));
923 	assert_int_equal(dns_name_countlabels(name), DNS_NAME_MAXLABELS);
924 }
925 
926 #ifdef DNS_BENCHMARK_TESTS
927 
928 /*
929  * XXXMUKS: Don't delete this code. It is useful in benchmarking the
930  * name parser, but we don't require it as part of the unit test runs.
931  */
932 
933 /* Benchmark dns_name_fromwire() implementation */
934 
935 ISC_RUN_TEST_IMPL(fromwire_thread(void *arg) {
936 	unsigned int maxval = 32000000;
937 	uint8_t data[] = { 3,	'w', 'w', 'w', 7,   'e', 'x',
938 			   'a', 'm', 'p', 'l', 'e', 7,	 'i',
939 			   'n', 'v', 'a', 'l', 'i', 'd', 0 };
940 	unsigned char output_data[DNS_NAME_MAXWIRE];
941 	isc_buffer_t source, target;
942 	unsigned int i;
943 	dns_decompress_t dctx;
944 
945 	UNUSED(arg);
946 
947 	dns_decompress_init(&dctx, DNS_DECOMPRESS_STRICT);
948 	dns_decompress_setmethods(&dctx, DNS_COMPRESS_NONE);
949 
950 	isc_buffer_init(&source, data, sizeof(data));
951 	isc_buffer_add(&source, sizeof(data));
952 	isc_buffer_init(&target, output_data, sizeof(output_data));
953 
954 	/* Parse 32 million names in each thread */
955 	for (i = 0; i < maxval; i++) {
956 		dns_name_t name;
957 
958 		isc_buffer_clear(&source);
959 		isc_buffer_clear(&target);
960 		isc_buffer_add(&source, sizeof(data));
961 		isc_buffer_setactive(&source, sizeof(data));
962 
963 		dns_name_init(&name, NULL);
964 		(void)dns_name_fromwire(&name, &source, &dctx, &target);
965 	}
966 
967 	return NULL;
968 }
969 
970 ISC_RUN_TEST_IMPL(benchmark) {
971 	isc_result_t result;
972 	unsigned int i;
973 	isc_time_t ts1, ts2;
974 	double t;
975 	unsigned int nthreads;
976 	isc_thread_t threads[32];
977 
978 	UNUSED(state);
979 
980 	debug_mem_record = false;
981 
982 	result = isc_time_now(&ts1);
983 	assert_int_equal(result, ISC_R_SUCCESS);
984 
985 	nthreads = ISC_MIN(isc_os_ncpus(), 32);
986 	nthreads = ISC_MAX(nthreads, 1);
987 	for (i = 0; i < nthreads; i++) {
988 		isc_thread_create(fromwire_thread, NULL, &threads[i]);
989 	}
990 
991 	for (i = 0; i < nthreads; i++) {
992 		isc_thread_join(threads[i], NULL);
993 	}
994 
995 	result = isc_time_now(&ts2);
996 	assert_int_equal(result, ISC_R_SUCCESS);
997 
998 	t = isc_time_microdiff(&ts2, &ts1);
999 
1000 	printf("%u dns_name_fromwire() calls, %f seconds, %f calls/second\n",
1001 	       nthreads * 32000000, t / 1000000.0,
1002 	       (nthreads * 32000000) / (t / 1000000.0));
1003 }
1004 
1005 #endif /* DNS_BENCHMARK_TESTS */
1006 
1007 ISC_TEST_LIST_START
1008 ISC_TEST_ENTRY(fullcompare)
1009 ISC_TEST_ENTRY(compression)
1010 ISC_TEST_ENTRY(collision)
1011 ISC_TEST_ENTRY(fromregion)
1012 ISC_TEST_ENTRY(istat)
1013 ISC_TEST_ENTRY(init)
1014 ISC_TEST_ENTRY(invalidate)
1015 ISC_TEST_ENTRY(buffer)
1016 ISC_TEST_ENTRY(isabsolute)
1017 ISC_TEST_ENTRY(hash)
1018 ISC_TEST_ENTRY(issubdomain)
1019 ISC_TEST_ENTRY(countlabels)
1020 ISC_TEST_ENTRY(getlabel)
1021 ISC_TEST_ENTRY(getlabelsequence)
1022 ISC_TEST_ENTRY(maxlabels)
1023 #ifdef DNS_BENCHMARK_TESTS
1024 ISC_TEST_ENTRY(benchmark)
1025 #endif /* DNS_BENCHMARK_TESTS */
1026 ISC_TEST_LIST_END
1027 
1028 ISC_TEST_MAIN
1029