1 /* $NetBSD: svcb_64.c,v 1.6 2025/01/26 16:25:35 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 /* draft-ietf-dnsop-svcb-https-02 */ 17 18 #ifndef RDATA_IN_1_SVCB_64_C 19 #define RDATA_IN_1_SVCB_64_C 20 21 #define RRTYPE_SVCB_ATTRIBUTES (DNS_RDATATYPEATTR_FOLLOWADDITIONAL) 22 23 #define SVCB_MAN_KEY 0 24 #define SVCB_ALPN_KEY 1 25 #define SVCB_NO_DEFAULT_ALPN_KEY 2 26 #define SVCB_DOHPATH_KEY 7 27 #define MAX_CNAMES 16 /* See ns/query.c MAX_RESTARTS */ 28 29 /* 30 * Service Binding Parameter Registry 31 */ 32 enum encoding { 33 sbpr_text, 34 sbpr_port, 35 sbpr_ipv4s, 36 sbpr_ipv6s, 37 sbpr_base64, 38 sbpr_empty, 39 sbpr_alpn, 40 sbpr_keylist, 41 sbpr_dohpath 42 }; 43 static const struct { 44 const char *name; /* Restricted to lowercase LDH by registry. */ 45 unsigned int value; 46 enum encoding encoding; 47 bool initial; /* Part of the first defined set of encodings. */ 48 } sbpr[] = { 49 { "mandatory", 0, sbpr_keylist, true }, 50 { "alpn", 1, sbpr_alpn, true }, 51 { "no-default-alpn", 2, sbpr_empty, true }, 52 { "port", 3, sbpr_port, true }, 53 { "ipv4hint", 4, sbpr_ipv4s, true }, 54 { "ech", 5, sbpr_base64, true }, 55 { "ipv6hint", 6, sbpr_ipv6s, true }, 56 { "dohpath", 7, sbpr_dohpath, false }, 57 }; 58 59 static isc_result_t 60 alpn_fromtxt(isc_textregion_t *source, isc_buffer_t *target) { 61 isc_textregion_t source0 = *source; 62 do { 63 RETERR(commatxt_fromtext(&source0, true, target)); 64 } while (source0.length != 0); 65 return ISC_R_SUCCESS; 66 } 67 68 static int 69 svckeycmp(const void *a1, const void *a2) { 70 const unsigned char *u1 = a1, *u2 = a2; 71 if (*u1 != *u2) { 72 return *u1 - *u2; 73 } 74 return *(++u1) - *(++u2); 75 } 76 77 static isc_result_t 78 svcsortkeylist(isc_buffer_t *target, unsigned int used) { 79 isc_region_t region; 80 81 isc_buffer_usedregion(target, ®ion); 82 isc_region_consume(®ion, used); 83 INSIST(region.length > 0U); 84 qsort(region.base, region.length / 2, 2, svckeycmp); 85 /* Reject duplicates. */ 86 while (region.length >= 4) { 87 if (region.base[0] == region.base[2] && 88 region.base[1] == region.base[3]) 89 { 90 return DNS_R_SYNTAX; 91 } 92 isc_region_consume(®ion, 2); 93 } 94 return ISC_R_SUCCESS; 95 } 96 97 static isc_result_t 98 svcb_validate(uint16_t key, isc_region_t *region) { 99 size_t i; 100 101 for (i = 0; i < ARRAY_SIZE(sbpr); i++) { 102 if (sbpr[i].value == key) { 103 switch (sbpr[i].encoding) { 104 case sbpr_port: 105 if (region->length != 2) { 106 return DNS_R_FORMERR; 107 } 108 break; 109 case sbpr_ipv4s: 110 if ((region->length % 4) != 0 || 111 region->length == 0) 112 { 113 return DNS_R_FORMERR; 114 } 115 break; 116 case sbpr_ipv6s: 117 if ((region->length % 16) != 0 || 118 region->length == 0) 119 { 120 return DNS_R_FORMERR; 121 } 122 break; 123 case sbpr_alpn: { 124 if (region->length == 0) { 125 return DNS_R_FORMERR; 126 } 127 while (region->length != 0) { 128 size_t l = *region->base + 1; 129 if (l == 1U || l > region->length) { 130 return DNS_R_FORMERR; 131 } 132 isc_region_consume(region, l); 133 } 134 break; 135 } 136 case sbpr_keylist: { 137 if ((region->length % 2) != 0 || 138 region->length == 0) 139 { 140 return DNS_R_FORMERR; 141 } 142 /* In order? */ 143 while (region->length >= 4) { 144 if (region->base[0] > region->base[2] || 145 (region->base[0] == 146 region->base[2] && 147 region->base[1] >= 148 region->base[3])) 149 { 150 return DNS_R_FORMERR; 151 } 152 isc_region_consume(region, 2); 153 } 154 break; 155 } 156 case sbpr_text: 157 case sbpr_base64: 158 break; 159 case sbpr_dohpath: 160 if (!validate_dohpath(region)) { 161 return DNS_R_FORMERR; 162 } 163 break; 164 case sbpr_empty: 165 if (region->length != 0) { 166 return DNS_R_FORMERR; 167 } 168 break; 169 } 170 } 171 } 172 return ISC_R_SUCCESS; 173 } 174 175 /* 176 * Parse keyname from region. 177 */ 178 static isc_result_t 179 svc_keyfromregion(isc_textregion_t *region, char sep, uint16_t *value, 180 isc_buffer_t *target) { 181 char *e = NULL; 182 size_t i; 183 unsigned long ul; 184 185 /* Look for known key names. */ 186 for (i = 0; i < ARRAY_SIZE(sbpr); i++) { 187 size_t len = strlen(sbpr[i].name); 188 if (strncasecmp(region->base, sbpr[i].name, len) != 0 || 189 (region->base[len] != 0 && region->base[len] != sep)) 190 { 191 continue; 192 } 193 isc_textregion_consume(region, len); 194 ul = sbpr[i].value; 195 goto finish; 196 } 197 /* Handle keyXXXXX form. */ 198 if (strncmp(region->base, "key", 3) != 0) { 199 return DNS_R_SYNTAX; 200 } 201 isc_textregion_consume(region, 3); 202 /* Disallow [+-]XXXXX which is allowed by strtoul. */ 203 if (region->length == 0 || *region->base == '-' || *region->base == '+') 204 { 205 return DNS_R_SYNTAX; 206 } 207 /* No zero padding. */ 208 if (region->length > 1 && *region->base == '0' && 209 region->base[1] != sep) 210 { 211 return DNS_R_SYNTAX; 212 } 213 ul = strtoul(region->base, &e, 10); 214 /* Valid number? */ 215 if (e == region->base || (*e != sep && *e != 0)) { 216 return DNS_R_SYNTAX; 217 } 218 if (ul > 0xffff) { 219 return ISC_R_RANGE; 220 } 221 isc_textregion_consume(region, e - region->base); 222 finish: 223 if (sep == ',' && region->length == 1) { 224 return DNS_R_SYNTAX; 225 } 226 /* Consume separator. */ 227 if (region->length != 0) { 228 isc_textregion_consume(region, 1); 229 } 230 RETERR(uint16_tobuffer(ul, target)); 231 SET_IF_NOT_NULL(value, ul); 232 return ISC_R_SUCCESS; 233 } 234 235 static isc_result_t 236 svc_fromtext(isc_textregion_t *region, isc_buffer_t *target) { 237 char *e = NULL; 238 char abuf[16]; 239 char tbuf[sizeof("aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:255.255.255.255,")]; 240 isc_buffer_t sb; 241 isc_region_t keyregion; 242 size_t len; 243 uint16_t key; 244 unsigned int i; 245 unsigned int used; 246 unsigned long ul; 247 248 for (i = 0; i < ARRAY_SIZE(sbpr); i++) { 249 len = strlen(sbpr[i].name); 250 if (strncmp(region->base, sbpr[i].name, len) != 0 || 251 (region->base[len] != 0 && region->base[len] != '=')) 252 { 253 continue; 254 } 255 256 if (region->base[len] == '=') { 257 len++; 258 } 259 260 RETERR(uint16_tobuffer(sbpr[i].value, target)); 261 isc_textregion_consume(region, len); 262 263 sb = *target; 264 RETERR(uint16_tobuffer(0, target)); /* length */ 265 266 switch (sbpr[i].encoding) { 267 case sbpr_text: 268 case sbpr_dohpath: 269 RETERR(multitxt_fromtext(region, target)); 270 break; 271 case sbpr_alpn: 272 RETERR(alpn_fromtxt(region, target)); 273 break; 274 case sbpr_port: 275 if (!isdigit((unsigned char)*region->base)) { 276 return DNS_R_SYNTAX; 277 } 278 ul = strtoul(region->base, &e, 10); 279 if (*e != '\0') { 280 return DNS_R_SYNTAX; 281 } 282 if (ul > 0xffff) { 283 return ISC_R_RANGE; 284 } 285 RETERR(uint16_tobuffer(ul, target)); 286 break; 287 case sbpr_ipv4s: 288 do { 289 snprintf(tbuf, sizeof(tbuf), "%*s", 290 (int)(region->length), region->base); 291 e = strchr(tbuf, ','); 292 if (e != NULL) { 293 *e++ = 0; 294 isc_textregion_consume(region, 295 e - tbuf); 296 } 297 if (inet_pton(AF_INET, tbuf, abuf) != 1) { 298 return DNS_R_SYNTAX; 299 } 300 mem_tobuffer(target, abuf, 4); 301 } while (e != NULL); 302 break; 303 case sbpr_ipv6s: 304 do { 305 snprintf(tbuf, sizeof(tbuf), "%*s", 306 (int)(region->length), region->base); 307 e = strchr(tbuf, ','); 308 if (e != NULL) { 309 *e++ = 0; 310 isc_textregion_consume(region, 311 e - tbuf); 312 } 313 if (inet_pton(AF_INET6, tbuf, abuf) != 1) { 314 return DNS_R_SYNTAX; 315 } 316 mem_tobuffer(target, abuf, 16); 317 } while (e != NULL); 318 break; 319 case sbpr_base64: 320 RETERR(isc_base64_decodestring(region->base, target)); 321 break; 322 case sbpr_empty: 323 if (region->length != 0) { 324 return DNS_R_SYNTAX; 325 } 326 break; 327 case sbpr_keylist: 328 if (region->length == 0) { 329 return DNS_R_SYNTAX; 330 } 331 used = isc_buffer_usedlength(target); 332 while (region->length != 0) { 333 RETERR(svc_keyfromregion(region, ',', NULL, 334 target)); 335 } 336 RETERR(svcsortkeylist(target, used)); 337 break; 338 default: 339 UNREACHABLE(); 340 } 341 342 len = isc_buffer_usedlength(target) - 343 isc_buffer_usedlength(&sb) - 2; 344 RETERR(uint16_tobuffer(len, &sb)); /* length */ 345 switch (sbpr[i].encoding) { 346 case sbpr_dohpath: 347 /* 348 * Apply constraints not applied by multitxt_fromtext. 349 */ 350 keyregion.base = isc_buffer_used(&sb); 351 keyregion.length = isc_buffer_usedlength(target) - 352 isc_buffer_usedlength(&sb); 353 RETERR(svcb_validate(sbpr[i].value, &keyregion)); 354 break; 355 default: 356 break; 357 } 358 return ISC_R_SUCCESS; 359 } 360 361 RETERR(svc_keyfromregion(region, '=', &key, target)); 362 if (region->length == 0) { 363 RETERR(uint16_tobuffer(0, target)); /* length */ 364 /* Sanity check keyXXXXX form. */ 365 keyregion.base = isc_buffer_used(target); 366 keyregion.length = 0; 367 return svcb_validate(key, &keyregion); 368 } 369 sb = *target; 370 RETERR(uint16_tobuffer(0, target)); /* dummy length */ 371 RETERR(multitxt_fromtext(region, target)); 372 len = isc_buffer_usedlength(target) - isc_buffer_usedlength(&sb) - 2; 373 RETERR(uint16_tobuffer(len, &sb)); /* length */ 374 /* Sanity check keyXXXXX form. */ 375 keyregion.base = isc_buffer_used(&sb); 376 keyregion.length = len; 377 return svcb_validate(key, &keyregion); 378 } 379 380 static const char * 381 svcparamkey(unsigned short value, enum encoding *encoding, char *buf, 382 size_t len) { 383 size_t i; 384 int n; 385 386 for (i = 0; i < ARRAY_SIZE(sbpr); i++) { 387 if (sbpr[i].value == value && sbpr[i].initial) { 388 *encoding = sbpr[i].encoding; 389 return sbpr[i].name; 390 } 391 } 392 n = snprintf(buf, len, "key%u", value); 393 INSIST(n > 0 && (unsigned int)n < len); 394 *encoding = sbpr_text; 395 return buf; 396 } 397 398 static isc_result_t 399 svcsortkeys(isc_buffer_t *target, unsigned int used) { 400 isc_region_t r1, r2, man = { .base = NULL, .length = 0 }; 401 unsigned char buf[1024]; 402 uint16_t mankey = 0; 403 bool have_alpn = false; 404 405 if (isc_buffer_usedlength(target) == used) { 406 return ISC_R_SUCCESS; 407 } 408 409 /* 410 * Get the parameters into r1. 411 */ 412 isc_buffer_usedregion(target, &r1); 413 isc_region_consume(&r1, used); 414 415 while (1) { 416 uint16_t key1, len1, key2, len2; 417 unsigned char *base1, *base2; 418 419 r2 = r1; 420 421 /* 422 * Get the first parameter. 423 */ 424 base1 = r1.base; 425 key1 = uint16_fromregion(&r1); 426 isc_region_consume(&r1, 2); 427 len1 = uint16_fromregion(&r1); 428 isc_region_consume(&r1, 2); 429 isc_region_consume(&r1, len1); 430 431 /* 432 * Was there only one key left? 433 */ 434 if (r1.length == 0) { 435 if (mankey != 0) { 436 /* Is this the last mandatory key? */ 437 if (key1 != mankey || man.length != 0) { 438 return DNS_R_INCONSISTENTRR; 439 } 440 } else if (key1 == SVCB_MAN_KEY) { 441 /* Lone mandatory field. */ 442 return DNS_R_DISALLOWED; 443 } else if (key1 == SVCB_NO_DEFAULT_ALPN_KEY && 444 !have_alpn) 445 { 446 /* Missing required ALPN field. */ 447 return DNS_R_DISALLOWED; 448 } 449 return ISC_R_SUCCESS; 450 } 451 452 /* 453 * Find the smallest parameter. 454 */ 455 while (r1.length != 0) { 456 base2 = r1.base; 457 key2 = uint16_fromregion(&r1); 458 isc_region_consume(&r1, 2); 459 len2 = uint16_fromregion(&r1); 460 isc_region_consume(&r1, 2); 461 isc_region_consume(&r1, len2); 462 if (key2 == key1) { 463 return DNS_R_DUPLICATE; 464 } 465 if (key2 < key1) { 466 base1 = base2; 467 key1 = key2; 468 len1 = len2; 469 } 470 } 471 472 /* 473 * Do we need to move the smallest parameter to the start? 474 */ 475 if (base1 != r2.base) { 476 size_t offset = 0; 477 size_t bytes = len1 + 4; 478 size_t length = base1 - r2.base; 479 480 /* 481 * Move the smallest parameter to the start. 482 */ 483 while (bytes > 0) { 484 size_t count; 485 486 if (bytes > sizeof(buf)) { 487 count = sizeof(buf); 488 } else { 489 count = bytes; 490 } 491 memmove(buf, base1, count); 492 memmove(r2.base + offset + count, 493 r2.base + offset, length); 494 memmove(r2.base + offset, buf, count); 495 base1 += count; 496 bytes -= count; 497 offset += count; 498 } 499 } 500 501 /* 502 * Check ALPN is present when NO-DEFAULT-ALPN is set. 503 */ 504 if (key1 == SVCB_ALPN_KEY) { 505 have_alpn = true; 506 } else if (key1 == SVCB_NO_DEFAULT_ALPN_KEY && !have_alpn) { 507 /* Missing required ALPN field. */ 508 return DNS_R_DISALLOWED; 509 } 510 511 /* 512 * Check key against mandatory key list. 513 */ 514 if (mankey != 0) { 515 if (key1 > mankey) { 516 return DNS_R_INCONSISTENTRR; 517 } 518 if (key1 == mankey) { 519 if (man.length >= 2) { 520 mankey = uint16_fromregion(&man); 521 isc_region_consume(&man, 2); 522 } else { 523 mankey = 0; 524 } 525 } 526 } 527 528 /* 529 * Is this the mandatory key? 530 */ 531 if (key1 == SVCB_MAN_KEY) { 532 man = r2; 533 man.length = len1 + 4; 534 isc_region_consume(&man, 4); 535 if (man.length >= 2) { 536 mankey = uint16_fromregion(&man); 537 isc_region_consume(&man, 2); 538 if (mankey == SVCB_MAN_KEY) { 539 return DNS_R_DISALLOWED; 540 } 541 } else { 542 return DNS_R_SYNTAX; 543 } 544 } 545 546 /* 547 * Consume the smallest parameter. 548 */ 549 isc_region_consume(&r2, len1 + 4); 550 r1 = r2; 551 } 552 } 553 554 static isc_result_t 555 generic_fromtext_in_svcb(ARGS_FROMTEXT) { 556 isc_token_t token; 557 dns_name_t name; 558 isc_buffer_t buffer; 559 bool alias; 560 bool ok = true; 561 unsigned int used; 562 563 UNUSED(type); 564 UNUSED(rdclass); 565 UNUSED(callbacks); 566 567 /* 568 * SvcPriority. 569 */ 570 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number, 571 false)); 572 if (token.value.as_ulong > 0xffffU) { 573 RETTOK(ISC_R_RANGE); 574 } 575 RETERR(uint16_tobuffer(token.value.as_ulong, target)); 576 577 alias = token.value.as_ulong == 0; 578 579 /* 580 * TargetName. 581 */ 582 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_qstring, 583 false)); 584 dns_name_init(&name, NULL); 585 buffer_fromregion(&buffer, &token.value.as_region); 586 if (origin == NULL) { 587 origin = dns_rootname; 588 } 589 RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target)); 590 if (!alias && (options & DNS_RDATA_CHECKNAMES) != 0) { 591 ok = dns_name_ishostname(&name, false); 592 } 593 if (!ok && (options & DNS_RDATA_CHECKNAMESFAIL) != 0) { 594 RETTOK(DNS_R_BADNAME); 595 } 596 if (!ok && callbacks != NULL) { 597 warn_badname(&name, lexer, callbacks); 598 } 599 600 /* 601 * SvcParams 602 */ 603 used = isc_buffer_usedlength(target); 604 while (1) { 605 RETERR(isc_lex_getmastertoken(lexer, &token, 606 isc_tokentype_qvpair, true)); 607 if (token.type == isc_tokentype_eol || 608 token.type == isc_tokentype_eof) 609 { 610 isc_lex_ungettoken(lexer, &token); 611 return svcsortkeys(target, used); 612 } 613 614 if (token.type != isc_tokentype_string && /* key only */ 615 token.type != isc_tokentype_qvpair && 616 token.type != isc_tokentype_vpair) 617 { 618 RETTOK(DNS_R_SYNTAX); 619 } 620 RETTOK(svc_fromtext(&token.value.as_textregion, target)); 621 } 622 } 623 624 static isc_result_t 625 fromtext_in_svcb(ARGS_FROMTEXT) { 626 REQUIRE(type == dns_rdatatype_svcb); 627 REQUIRE(rdclass == dns_rdataclass_in); 628 UNUSED(type); 629 UNUSED(rdclass); 630 UNUSED(callbacks); 631 632 return generic_fromtext_in_svcb(CALL_FROMTEXT); 633 } 634 635 static isc_result_t 636 generic_totext_in_svcb(ARGS_TOTEXT) { 637 isc_region_t region; 638 dns_name_t name; 639 dns_name_t prefix; 640 unsigned int opts; 641 char buf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255")]; 642 unsigned short num; 643 int n; 644 645 REQUIRE(rdata->length != 0); 646 647 dns_name_init(&name, NULL); 648 dns_name_init(&prefix, NULL); 649 650 dns_rdata_toregion(rdata, ®ion); 651 652 /* 653 * SvcPriority. 654 */ 655 num = uint16_fromregion(®ion); 656 isc_region_consume(®ion, 2); 657 n = snprintf(buf, sizeof(buf), "%u ", num); 658 INSIST(n > 0 && (unsigned int)n < sizeof(buf)); 659 RETERR(str_totext(buf, target)); 660 661 /* 662 * TargetName. 663 */ 664 dns_name_fromregion(&name, ®ion); 665 isc_region_consume(®ion, name_length(&name)); 666 opts = name_prefix(&name, tctx->origin, &prefix) ? DNS_NAME_OMITFINALDOT 667 : 0; 668 RETERR(dns_name_totext(&prefix, opts, target)); 669 670 while (region.length > 0) { 671 isc_region_t r; 672 enum encoding encoding; 673 674 RETERR(str_totext(" ", target)); 675 676 INSIST(region.length >= 2); 677 num = uint16_fromregion(®ion); 678 isc_region_consume(®ion, 2); 679 RETERR(str_totext(svcparamkey(num, &encoding, buf, sizeof(buf)), 680 target)); 681 682 INSIST(region.length >= 2); 683 num = uint16_fromregion(®ion); 684 isc_region_consume(®ion, 2); 685 686 INSIST(region.length >= num); 687 r = region; 688 r.length = num; 689 isc_region_consume(®ion, num); 690 if (num == 0) { 691 continue; 692 } 693 if (encoding != sbpr_empty) { 694 RETERR(str_totext("=", target)); 695 } 696 switch (encoding) { 697 case sbpr_text: 698 RETERR(multitxt_totext(&r, target)); 699 break; 700 case sbpr_port: 701 num = uint16_fromregion(&r); 702 isc_region_consume(&r, 2); 703 n = snprintf(buf, sizeof(buf), "%u", num); 704 INSIST(n > 0 && (unsigned int)n < sizeof(buf)); 705 RETERR(str_totext(buf, target)); 706 INSIST(r.length == 0U); 707 break; 708 case sbpr_ipv4s: 709 while (r.length > 0U) { 710 INSIST(r.length >= 4U); 711 inet_ntop(AF_INET, r.base, buf, sizeof(buf)); 712 RETERR(str_totext(buf, target)); 713 isc_region_consume(&r, 4); 714 if (r.length != 0U) { 715 RETERR(str_totext(",", target)); 716 } 717 } 718 break; 719 case sbpr_ipv6s: 720 while (r.length > 0U) { 721 INSIST(r.length >= 16U); 722 inet_ntop(AF_INET6, r.base, buf, sizeof(buf)); 723 RETERR(str_totext(buf, target)); 724 isc_region_consume(&r, 16); 725 if (r.length != 0U) { 726 RETERR(str_totext(",", target)); 727 } 728 } 729 break; 730 case sbpr_base64: 731 RETERR(isc_base64_totext(&r, 0, "", target)); 732 break; 733 case sbpr_alpn: 734 INSIST(r.length != 0U); 735 RETERR(str_totext("\"", target)); 736 while (r.length != 0) { 737 commatxt_totext(&r, false, true, target); 738 if (r.length != 0) { 739 RETERR(str_totext(",", target)); 740 } 741 } 742 RETERR(str_totext("\"", target)); 743 break; 744 case sbpr_empty: 745 INSIST(r.length == 0U); 746 break; 747 case sbpr_keylist: 748 while (r.length > 0) { 749 num = uint16_fromregion(&r); 750 isc_region_consume(&r, 2); 751 RETERR(str_totext(svcparamkey(num, &encoding, 752 buf, sizeof(buf)), 753 target)); 754 if (r.length != 0) { 755 RETERR(str_totext(",", target)); 756 } 757 } 758 break; 759 default: 760 UNREACHABLE(); 761 } 762 } 763 return ISC_R_SUCCESS; 764 } 765 766 static isc_result_t 767 totext_in_svcb(ARGS_TOTEXT) { 768 REQUIRE(rdata->type == dns_rdatatype_svcb); 769 REQUIRE(rdata->rdclass == dns_rdataclass_in); 770 REQUIRE(rdata->length != 0); 771 772 return generic_totext_in_svcb(CALL_TOTEXT); 773 } 774 775 static isc_result_t 776 generic_fromwire_in_svcb(ARGS_FROMWIRE) { 777 dns_name_t name; 778 isc_region_t region, man = { .base = NULL, .length = 0 }; 779 bool first = true, have_alpn = false; 780 uint16_t lastkey = 0, mankey = 0; 781 782 UNUSED(type); 783 UNUSED(rdclass); 784 785 dctx = dns_decompress_setpermitted(dctx, false); 786 787 dns_name_init(&name, NULL); 788 789 /* 790 * SvcPriority. 791 */ 792 isc_buffer_activeregion(source, ®ion); 793 if (region.length < 2) { 794 return ISC_R_UNEXPECTEDEND; 795 } 796 RETERR(mem_tobuffer(target, region.base, 2)); 797 isc_buffer_forward(source, 2); 798 799 /* 800 * TargetName. 801 */ 802 RETERR(dns_name_fromwire(&name, source, dctx, target)); 803 804 /* 805 * SvcParams. 806 */ 807 isc_buffer_activeregion(source, ®ion); 808 while (region.length > 0U) { 809 isc_region_t keyregion; 810 uint16_t key, len; 811 812 /* 813 * SvcParamKey 814 */ 815 if (region.length < 2U) { 816 return ISC_R_UNEXPECTEDEND; 817 } 818 RETERR(mem_tobuffer(target, region.base, 2)); 819 key = uint16_fromregion(®ion); 820 isc_region_consume(®ion, 2); 821 822 /* 823 * Keys must be unique and in order. 824 */ 825 if (!first && key <= lastkey) { 826 return DNS_R_FORMERR; 827 } 828 829 /* 830 * Check mandatory keys. 831 */ 832 if (mankey != 0) { 833 /* Missing mandatory key? */ 834 if (key > mankey) { 835 return DNS_R_FORMERR; 836 } 837 if (key == mankey) { 838 /* Get next mandatory key. */ 839 if (man.length >= 2) { 840 mankey = uint16_fromregion(&man); 841 isc_region_consume(&man, 2); 842 } else { 843 mankey = 0; 844 } 845 } 846 } 847 848 /* 849 * Check alpn present when no-default-alpn is set. 850 */ 851 if (key == SVCB_ALPN_KEY) { 852 have_alpn = true; 853 } else if (key == SVCB_NO_DEFAULT_ALPN_KEY && !have_alpn) { 854 return DNS_R_FORMERR; 855 } 856 857 first = false; 858 lastkey = key; 859 860 /* 861 * SvcParamValue length. 862 */ 863 if (region.length < 2U) { 864 return ISC_R_UNEXPECTEDEND; 865 } 866 RETERR(mem_tobuffer(target, region.base, 2)); 867 len = uint16_fromregion(®ion); 868 isc_region_consume(®ion, 2); 869 870 /* 871 * SvcParamValue. 872 */ 873 if (region.length < len) { 874 return ISC_R_UNEXPECTEDEND; 875 } 876 877 /* 878 * Remember manatory key. 879 */ 880 if (key == SVCB_MAN_KEY) { 881 man = region; 882 man.length = len; 883 /* Get first mandatory key */ 884 if (man.length >= 2) { 885 mankey = uint16_fromregion(&man); 886 isc_region_consume(&man, 2); 887 if (mankey == SVCB_MAN_KEY) { 888 return DNS_R_FORMERR; 889 } 890 } else { 891 return DNS_R_FORMERR; 892 } 893 } 894 keyregion = region; 895 keyregion.length = len; 896 RETERR(svcb_validate(key, &keyregion)); 897 RETERR(mem_tobuffer(target, region.base, len)); 898 isc_region_consume(®ion, len); 899 isc_buffer_forward(source, len + 4); 900 } 901 902 /* 903 * Do we have an outstanding mandatory key? 904 */ 905 if (mankey != 0) { 906 return DNS_R_FORMERR; 907 } 908 909 return ISC_R_SUCCESS; 910 } 911 912 static isc_result_t 913 fromwire_in_svcb(ARGS_FROMWIRE) { 914 REQUIRE(type == dns_rdatatype_svcb); 915 REQUIRE(rdclass == dns_rdataclass_in); 916 917 return generic_fromwire_in_svcb(CALL_FROMWIRE); 918 } 919 920 static isc_result_t 921 generic_towire_in_svcb(ARGS_TOWIRE) { 922 dns_name_t name; 923 dns_offsets_t offsets; 924 isc_region_t region; 925 926 REQUIRE(rdata->length != 0); 927 928 dns_compress_setpermitted(cctx, false); 929 930 /* 931 * SvcPriority. 932 */ 933 dns_rdata_toregion(rdata, ®ion); 934 RETERR(mem_tobuffer(target, region.base, 2)); 935 isc_region_consume(®ion, 2); 936 937 /* 938 * TargetName. 939 */ 940 dns_name_init(&name, offsets); 941 dns_name_fromregion(&name, ®ion); 942 RETERR(dns_name_towire(&name, cctx, target, NULL)); 943 isc_region_consume(®ion, name_length(&name)); 944 945 /* 946 * SvcParams. 947 */ 948 return mem_tobuffer(target, region.base, region.length); 949 } 950 951 static isc_result_t 952 towire_in_svcb(ARGS_TOWIRE) { 953 REQUIRE(rdata->type == dns_rdatatype_svcb); 954 REQUIRE(rdata->length != 0); 955 956 return generic_towire_in_svcb(CALL_TOWIRE); 957 } 958 959 static int 960 compare_in_svcb(ARGS_COMPARE) { 961 isc_region_t region1; 962 isc_region_t region2; 963 964 REQUIRE(rdata1->type == rdata2->type); 965 REQUIRE(rdata1->rdclass == rdata2->rdclass); 966 REQUIRE(rdata1->type == dns_rdatatype_svcb); 967 REQUIRE(rdata1->rdclass == dns_rdataclass_in); 968 REQUIRE(rdata1->length != 0); 969 REQUIRE(rdata2->length != 0); 970 971 dns_rdata_toregion(rdata1, ®ion1); 972 dns_rdata_toregion(rdata2, ®ion2); 973 974 return isc_region_compare(®ion1, ®ion2); 975 } 976 977 static isc_result_t 978 generic_fromstruct_in_svcb(ARGS_FROMSTRUCT) { 979 dns_rdata_in_svcb_t *svcb = source; 980 isc_region_t region; 981 982 REQUIRE(svcb != NULL); 983 REQUIRE(svcb->common.rdtype == type); 984 REQUIRE(svcb->common.rdclass == rdclass); 985 986 UNUSED(type); 987 UNUSED(rdclass); 988 989 RETERR(uint16_tobuffer(svcb->priority, target)); 990 dns_name_toregion(&svcb->svcdomain, ®ion); 991 RETERR(isc_buffer_copyregion(target, ®ion)); 992 993 return mem_tobuffer(target, svcb->svc, svcb->svclen); 994 } 995 996 static isc_result_t 997 fromstruct_in_svcb(ARGS_FROMSTRUCT) { 998 dns_rdata_in_svcb_t *svcb = source; 999 1000 REQUIRE(type == dns_rdatatype_svcb); 1001 REQUIRE(rdclass == dns_rdataclass_in); 1002 REQUIRE(svcb != NULL); 1003 REQUIRE(svcb->common.rdtype == type); 1004 REQUIRE(svcb->common.rdclass == rdclass); 1005 1006 return generic_fromstruct_in_svcb(CALL_FROMSTRUCT); 1007 } 1008 1009 static isc_result_t 1010 generic_tostruct_in_svcb(ARGS_TOSTRUCT) { 1011 isc_region_t region; 1012 dns_rdata_in_svcb_t *svcb = target; 1013 dns_name_t name; 1014 1015 REQUIRE(svcb != NULL); 1016 REQUIRE(rdata->length != 0); 1017 1018 svcb->common.rdclass = rdata->rdclass; 1019 svcb->common.rdtype = rdata->type; 1020 ISC_LINK_INIT(&svcb->common, link); 1021 1022 dns_rdata_toregion(rdata, ®ion); 1023 1024 svcb->priority = uint16_fromregion(®ion); 1025 isc_region_consume(®ion, 2); 1026 1027 dns_name_init(&svcb->svcdomain, NULL); 1028 dns_name_init(&name, NULL); 1029 dns_name_fromregion(&name, ®ion); 1030 isc_region_consume(®ion, name_length(&name)); 1031 1032 name_duporclone(&name, mctx, &svcb->svcdomain); 1033 svcb->svclen = region.length; 1034 svcb->svc = mem_maybedup(mctx, region.base, region.length); 1035 1036 svcb->offset = 0; 1037 svcb->mctx = mctx; 1038 1039 return ISC_R_SUCCESS; 1040 } 1041 1042 static isc_result_t 1043 tostruct_in_svcb(ARGS_TOSTRUCT) { 1044 dns_rdata_in_svcb_t *svcb = target; 1045 1046 REQUIRE(rdata->rdclass == dns_rdataclass_in); 1047 REQUIRE(rdata->type == dns_rdatatype_svcb); 1048 REQUIRE(svcb != NULL); 1049 REQUIRE(rdata->length != 0); 1050 1051 return generic_tostruct_in_svcb(CALL_TOSTRUCT); 1052 } 1053 1054 static void 1055 generic_freestruct_in_svcb(ARGS_FREESTRUCT) { 1056 dns_rdata_in_svcb_t *svcb = source; 1057 1058 REQUIRE(svcb != NULL); 1059 1060 if (svcb->mctx == NULL) { 1061 return; 1062 } 1063 1064 dns_name_free(&svcb->svcdomain, svcb->mctx); 1065 isc_mem_free(svcb->mctx, svcb->svc); 1066 svcb->mctx = NULL; 1067 } 1068 1069 static void 1070 freestruct_in_svcb(ARGS_FREESTRUCT) { 1071 dns_rdata_in_svcb_t *svcb = source; 1072 1073 REQUIRE(svcb != NULL); 1074 REQUIRE(svcb->common.rdclass == dns_rdataclass_in); 1075 REQUIRE(svcb->common.rdtype == dns_rdatatype_svcb); 1076 1077 generic_freestruct_in_svcb(CALL_FREESTRUCT); 1078 } 1079 1080 static isc_result_t 1081 generic_additionaldata_in_svcb(ARGS_ADDLDATA) { 1082 bool alias, done = false; 1083 dns_fixedname_t fixed; 1084 dns_name_t name, *fname = NULL; 1085 dns_offsets_t offsets; 1086 dns_rdataset_t rdataset; 1087 isc_region_t region; 1088 unsigned int cnames = 0; 1089 1090 dns_name_init(&name, offsets); 1091 dns_rdata_toregion(rdata, ®ion); 1092 alias = uint16_fromregion(®ion) == 0; 1093 isc_region_consume(®ion, 2); 1094 1095 dns_name_fromregion(&name, ®ion); 1096 1097 if (dns_name_equal(&name, dns_rootname)) { 1098 /* 1099 * "." only means owner name in service form. 1100 */ 1101 if (alias || dns_name_equal(owner, dns_rootname) || 1102 !dns_name_ishostname(owner, false)) 1103 { 1104 return ISC_R_SUCCESS; 1105 } 1106 /* Only lookup address records */ 1107 return (add)(arg, owner, dns_rdatatype_a, 1108 NULL DNS__DB_FILELINE); 1109 } 1110 1111 /* 1112 * Follow CNAME chains when processing HTTPS and SVCB records. 1113 */ 1114 dns_rdataset_init(&rdataset); 1115 fname = dns_fixedname_initname(&fixed); 1116 do { 1117 RETERR((add)(arg, &name, dns_rdatatype_cname, 1118 &rdataset DNS__DB_FILELINE)); 1119 if (dns_rdataset_isassociated(&rdataset)) { 1120 isc_result_t result; 1121 result = dns_rdataset_first(&rdataset); 1122 if (result == ISC_R_SUCCESS) { 1123 dns_rdata_t current = DNS_RDATA_INIT; 1124 dns_rdata_cname_t cname; 1125 1126 dns_rdataset_current(&rdataset, ¤t); 1127 1128 result = dns_rdata_tostruct(¤t, &cname, 1129 NULL); 1130 RUNTIME_CHECK(result == ISC_R_SUCCESS); 1131 dns_name_copy(&cname.cname, fname); 1132 dns_name_clone(fname, &name); 1133 } else { 1134 done = true; 1135 } 1136 dns_rdataset_disassociate(&rdataset); 1137 } else { 1138 done = true; 1139 } 1140 /* 1141 * Stop following a potentially infinite CNAME chain. 1142 */ 1143 if (!done && cnames++ > MAX_CNAMES) { 1144 return ISC_R_SUCCESS; 1145 } 1146 } while (!done); 1147 1148 /* 1149 * Look up HTTPS/SVCB records when processing the alias form. 1150 */ 1151 if (alias) { 1152 RETERR((add)(arg, &name, rdata->type, 1153 &rdataset DNS__DB_FILELINE)); 1154 /* 1155 * Don't return A or AAAA if this is not the last element 1156 * in the HTTP / SVCB chain. 1157 */ 1158 if (dns_rdataset_isassociated(&rdataset)) { 1159 dns_rdataset_disassociate(&rdataset); 1160 return ISC_R_SUCCESS; 1161 } 1162 } 1163 return (add)(arg, &name, dns_rdatatype_a, NULL DNS__DB_FILELINE); 1164 } 1165 1166 static isc_result_t 1167 additionaldata_in_svcb(ARGS_ADDLDATA) { 1168 REQUIRE(rdata->type == dns_rdatatype_svcb); 1169 REQUIRE(rdata->rdclass == dns_rdataclass_in); 1170 1171 return generic_additionaldata_in_svcb(CALL_ADDLDATA); 1172 } 1173 1174 static isc_result_t 1175 digest_in_svcb(ARGS_DIGEST) { 1176 isc_region_t region1; 1177 1178 REQUIRE(rdata->type == dns_rdatatype_svcb); 1179 REQUIRE(rdata->rdclass == dns_rdataclass_in); 1180 1181 dns_rdata_toregion(rdata, ®ion1); 1182 return (digest)(arg, ®ion1); 1183 } 1184 1185 static bool 1186 checkowner_in_svcb(ARGS_CHECKOWNER) { 1187 REQUIRE(type == dns_rdatatype_svcb); 1188 REQUIRE(rdclass == dns_rdataclass_in); 1189 1190 UNUSED(name); 1191 UNUSED(type); 1192 UNUSED(rdclass); 1193 UNUSED(wildcard); 1194 1195 return true; 1196 } 1197 1198 static bool 1199 generic_checknames_in_svcb(ARGS_CHECKNAMES) { 1200 isc_region_t region; 1201 dns_name_t name; 1202 bool alias; 1203 1204 UNUSED(owner); 1205 1206 dns_rdata_toregion(rdata, ®ion); 1207 INSIST(region.length > 1); 1208 alias = uint16_fromregion(®ion) == 0; 1209 isc_region_consume(®ion, 2); 1210 dns_name_init(&name, NULL); 1211 dns_name_fromregion(&name, ®ion); 1212 if (!alias && !dns_name_ishostname(&name, false)) { 1213 if (bad != NULL) { 1214 dns_name_clone(&name, bad); 1215 } 1216 return false; 1217 } 1218 return true; 1219 } 1220 1221 static bool 1222 checknames_in_svcb(ARGS_CHECKNAMES) { 1223 REQUIRE(rdata->type == dns_rdatatype_svcb); 1224 REQUIRE(rdata->rdclass == dns_rdataclass_in); 1225 1226 return generic_checknames_in_svcb(CALL_CHECKNAMES); 1227 } 1228 1229 static int 1230 casecompare_in_svcb(ARGS_COMPARE) { 1231 return compare_in_svcb(rdata1, rdata2); 1232 } 1233 1234 static isc_result_t 1235 generic_rdata_in_svcb_first(dns_rdata_in_svcb_t *svcb) { 1236 if (svcb->svclen == 0) { 1237 return ISC_R_NOMORE; 1238 } 1239 svcb->offset = 0; 1240 return ISC_R_SUCCESS; 1241 } 1242 1243 static isc_result_t 1244 generic_rdata_in_svcb_next(dns_rdata_in_svcb_t *svcb) { 1245 isc_region_t region; 1246 size_t len; 1247 1248 if (svcb->offset >= svcb->svclen) { 1249 return ISC_R_NOMORE; 1250 } 1251 1252 region.base = svcb->svc + svcb->offset; 1253 region.length = svcb->svclen - svcb->offset; 1254 INSIST(region.length >= 4); 1255 isc_region_consume(®ion, 2); 1256 len = uint16_fromregion(®ion); 1257 INSIST(region.length >= len + 2); 1258 svcb->offset += len + 4; 1259 return svcb->offset >= svcb->svclen ? ISC_R_NOMORE : ISC_R_SUCCESS; 1260 } 1261 1262 static void 1263 generic_rdata_in_svcb_current(dns_rdata_in_svcb_t *svcb, isc_region_t *region) { 1264 size_t len; 1265 1266 INSIST(svcb->offset <= svcb->svclen); 1267 1268 region->base = svcb->svc + svcb->offset; 1269 region->length = svcb->svclen - svcb->offset; 1270 INSIST(region->length >= 4); 1271 isc_region_consume(region, 2); 1272 len = uint16_fromregion(region); 1273 INSIST(region->length >= len + 2); 1274 region->base = svcb->svc + svcb->offset; 1275 region->length = len + 4; 1276 } 1277 1278 isc_result_t 1279 dns_rdata_in_svcb_first(dns_rdata_in_svcb_t *svcb) { 1280 REQUIRE(svcb != NULL); 1281 REQUIRE(svcb->common.rdtype == dns_rdatatype_svcb); 1282 REQUIRE(svcb->common.rdclass == dns_rdataclass_in); 1283 1284 return generic_rdata_in_svcb_first(svcb); 1285 } 1286 1287 isc_result_t 1288 dns_rdata_in_svcb_next(dns_rdata_in_svcb_t *svcb) { 1289 REQUIRE(svcb != NULL); 1290 REQUIRE(svcb->common.rdtype == dns_rdatatype_svcb); 1291 REQUIRE(svcb->common.rdclass == dns_rdataclass_in); 1292 1293 return generic_rdata_in_svcb_next(svcb); 1294 } 1295 1296 void 1297 dns_rdata_in_svcb_current(dns_rdata_in_svcb_t *svcb, isc_region_t *region) { 1298 REQUIRE(svcb != NULL); 1299 REQUIRE(svcb->common.rdtype == dns_rdatatype_svcb); 1300 REQUIRE(svcb->common.rdclass == dns_rdataclass_in); 1301 REQUIRE(region != NULL); 1302 1303 generic_rdata_in_svcb_current(svcb, region); 1304 } 1305 1306 #endif /* RDATA_IN_1_SVCB_64_C */ 1307