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