1 /* $NetBSD: rdata.c,v 1.19 2026/01/29 18:37:49 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 /*! \file */ 17 18 #include <ctype.h> 19 #include <inttypes.h> 20 #include <stdbool.h> 21 22 #include <openssl/err.h> 23 #include <openssl/objects.h> 24 25 #include <isc/ascii.h> 26 #include <isc/base64.h> 27 #include <isc/hex.h> 28 #include <isc/lex.h> 29 #include <isc/mem.h> 30 #include <isc/parseint.h> 31 #include <isc/result.h> 32 #include <isc/string.h> 33 #include <isc/utf8.h> 34 #include <isc/util.h> 35 36 #include <dns/callbacks.h> 37 #include <dns/cert.h> 38 #include <dns/compress.h> 39 #include <dns/db.h> 40 #include <dns/dsdigest.h> 41 #include <dns/enumtype.h> 42 #include <dns/fixedname.h> 43 #include <dns/keyflags.h> 44 #include <dns/keyvalues.h> 45 #include <dns/message.h> 46 #include <dns/rcode.h> 47 #include <dns/rdata.h> 48 #include <dns/rdataclass.h> 49 #include <dns/rdataset.h> 50 #include <dns/rdatastruct.h> 51 #include <dns/rdatatype.h> 52 #include <dns/secalg.h> 53 #include <dns/secproto.h> 54 #include <dns/time.h> 55 #include <dns/ttl.h> 56 57 #define RETTOK(x) \ 58 do { \ 59 isc_result_t _r = (x); \ 60 if (_r != ISC_R_SUCCESS) { \ 61 isc_lex_ungettoken(lexer, &token); \ 62 return (_r); \ 63 } \ 64 } while (0) 65 66 #define CHECKTOK(op) \ 67 do { \ 68 result = (op); \ 69 if (result != ISC_R_SUCCESS) { \ 70 isc_lex_ungettoken(lexer, &token); \ 71 goto cleanup; \ 72 } \ 73 } while (0) 74 75 #define DNS_AS_STR(t) ((t).value.as_textregion.base) 76 77 #define ARGS_FROMTEXT \ 78 int rdclass, dns_rdatatype_t type, isc_lex_t *lexer, \ 79 const dns_name_t *origin, unsigned int options, \ 80 isc_buffer_t *target, dns_rdatacallbacks_t *callbacks 81 82 #define CALL_FROMTEXT rdclass, type, lexer, origin, options, target, callbacks 83 84 #define ARGS_TOTEXT \ 85 dns_rdata_t *rdata, dns_rdata_textctx_t *tctx, isc_buffer_t *target 86 87 #define CALL_TOTEXT rdata, tctx, target 88 89 #define ARGS_FROMWIRE \ 90 int rdclass, dns_rdatatype_t type, isc_buffer_t *source, \ 91 dns_decompress_t dctx, isc_buffer_t *target 92 93 #define CALL_FROMWIRE rdclass, type, source, dctx, target 94 95 #define ARGS_TOWIRE \ 96 dns_rdata_t *rdata, dns_compress_t *cctx, isc_buffer_t *target 97 98 #define CALL_TOWIRE rdata, cctx, target 99 100 #define ARGS_COMPARE const dns_rdata_t *rdata1, const dns_rdata_t *rdata2 101 102 #define CALL_COMPARE rdata1, rdata2 103 104 #define ARGS_FROMSTRUCT \ 105 int rdclass, dns_rdatatype_t type, void *source, isc_buffer_t *target 106 107 #define CALL_FROMSTRUCT rdclass, type, source, target 108 109 #define ARGS_TOSTRUCT const dns_rdata_t *rdata, void *target, isc_mem_t *mctx 110 111 #define CALL_TOSTRUCT rdata, target, mctx 112 113 #define ARGS_FREESTRUCT void *source 114 115 #define CALL_FREESTRUCT source 116 117 #define ARGS_ADDLDATA \ 118 dns_rdata_t *rdata, const dns_name_t *owner, \ 119 dns_additionaldatafunc_t add, void *arg 120 121 #define CALL_ADDLDATA rdata, owner, add, arg 122 123 #define ARGS_DIGEST dns_rdata_t *rdata, dns_digestfunc_t digest, void *arg 124 125 #define CALL_DIGEST rdata, digest, arg 126 127 #define ARGS_CHECKOWNER \ 128 const dns_name_t *name, dns_rdataclass_t rdclass, \ 129 dns_rdatatype_t type, bool wildcard 130 131 #define CALL_CHECKOWNER name, rdclass, type, wildcard 132 133 #define ARGS_CHECKNAMES \ 134 dns_rdata_t *rdata, const dns_name_t *owner, dns_name_t *bad 135 136 #define CALL_CHECKNAMES rdata, owner, bad 137 138 /*% 139 * Context structure for the totext_ functions. 140 * Contains formatting options for rdata-to-text 141 * conversion. 142 */ 143 typedef struct dns_rdata_textctx { 144 const dns_name_t *origin; /*%< Current origin, or NULL. */ 145 dns_masterstyle_flags_t flags; /*%< DNS_STYLEFLAG_* */ 146 unsigned int width; /*%< Width of rdata column. */ 147 const char *linebreak; /*%< Line break string. */ 148 } dns_rdata_textctx_t; 149 150 static isc_result_t 151 txt_totext(isc_region_t *source, bool quote, isc_buffer_t *target); 152 153 static isc_result_t 154 txt_fromtext(isc_textregion_t *source, isc_buffer_t *target); 155 156 static isc_result_t 157 txt_fromwire(isc_buffer_t *source, isc_buffer_t *target); 158 159 static isc_result_t 160 commatxt_fromtext(isc_textregion_t *source, bool comma, isc_buffer_t *target); 161 162 static isc_result_t 163 commatxt_totext(isc_region_t *source, bool quote, bool comma, 164 isc_buffer_t *target); 165 166 static isc_result_t 167 multitxt_totext(isc_region_t *source, isc_buffer_t *target); 168 169 static isc_result_t 170 multitxt_fromtext(isc_textregion_t *source, isc_buffer_t *target); 171 172 static bool 173 name_prefix(dns_name_t *name, const dns_name_t *origin, dns_name_t *target); 174 175 static unsigned int 176 name_length(const dns_name_t *name); 177 178 static isc_result_t 179 str_totext(const char *source, isc_buffer_t *target); 180 181 static isc_result_t 182 inet_totext(int af, uint32_t flags, isc_region_t *src, isc_buffer_t *target); 183 184 static bool 185 buffer_empty(isc_buffer_t *source); 186 187 static void 188 buffer_fromregion(isc_buffer_t *buffer, isc_region_t *region); 189 190 static isc_result_t 191 uint32_tobuffer(uint32_t, isc_buffer_t *target); 192 193 static isc_result_t 194 uint16_tobuffer(uint32_t, isc_buffer_t *target); 195 196 static isc_result_t 197 uint8_tobuffer(uint32_t, isc_buffer_t *target); 198 199 static isc_result_t 200 name_tobuffer(const dns_name_t *name, isc_buffer_t *target); 201 202 static uint32_t 203 uint32_fromregion(isc_region_t *region); 204 205 static uint16_t 206 uint16_fromregion(isc_region_t *region); 207 208 static uint8_t 209 uint8_fromregion(isc_region_t *region); 210 211 static uint8_t 212 uint8_consume_fromregion(isc_region_t *region); 213 214 static isc_result_t 215 mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length); 216 217 static int 218 hexvalue(char value); 219 220 static int 221 decvalue(char value); 222 223 static void 224 default_fromtext_callback(dns_rdatacallbacks_t *callbacks, const char *, ...) 225 ISC_FORMAT_PRINTF(2, 3); 226 227 static void 228 fromtext_error(void (*callback)(dns_rdatacallbacks_t *, const char *, ...), 229 dns_rdatacallbacks_t *callbacks, const char *name, 230 unsigned long line, isc_token_t *token, isc_result_t result); 231 232 static void 233 fromtext_warneof(isc_lex_t *lexer, dns_rdatacallbacks_t *callbacks); 234 235 static isc_result_t 236 rdata_totext(dns_rdata_t *rdata, dns_rdata_textctx_t *tctx, 237 isc_buffer_t *target); 238 239 static void 240 warn_badname(const dns_name_t *name, isc_lex_t *lexer, 241 dns_rdatacallbacks_t *callbacks); 242 243 static void 244 warn_badmx(isc_token_t *token, isc_lex_t *lexer, 245 dns_rdatacallbacks_t *callbacks); 246 247 static uint16_t 248 uint16_consume_fromregion(isc_region_t *region); 249 250 static isc_result_t 251 unknown_totext(dns_rdata_t *rdata, dns_rdata_textctx_t *tctx, 252 isc_buffer_t *target); 253 254 static isc_result_t generic_fromtext_key(ARGS_FROMTEXT); 255 256 static isc_result_t generic_totext_key(ARGS_TOTEXT); 257 258 static isc_result_t generic_fromwire_key(ARGS_FROMWIRE); 259 260 static isc_result_t generic_fromstruct_key(ARGS_FROMSTRUCT); 261 262 static isc_result_t generic_tostruct_key(ARGS_TOSTRUCT); 263 264 static void generic_freestruct_key(ARGS_FREESTRUCT); 265 266 static isc_result_t generic_fromtext_txt(ARGS_FROMTEXT); 267 268 static isc_result_t generic_totext_txt(ARGS_TOTEXT); 269 270 static isc_result_t generic_fromwire_txt(ARGS_FROMWIRE); 271 272 static isc_result_t generic_fromstruct_txt(ARGS_FROMSTRUCT); 273 274 static isc_result_t generic_tostruct_txt(ARGS_TOSTRUCT); 275 276 static void generic_freestruct_txt(ARGS_FREESTRUCT); 277 278 static isc_result_t 279 generic_txt_first(dns_rdata_txt_t *txt); 280 281 static isc_result_t 282 generic_txt_next(dns_rdata_txt_t *txt); 283 284 static isc_result_t 285 generic_txt_current(dns_rdata_txt_t *txt, dns_rdata_txt_string_t *string); 286 287 static isc_result_t generic_totext_ds(ARGS_TOTEXT); 288 289 static isc_result_t generic_tostruct_ds(ARGS_TOSTRUCT); 290 291 static isc_result_t generic_fromtext_ds(ARGS_FROMTEXT); 292 293 static isc_result_t generic_fromwire_ds(ARGS_FROMWIRE); 294 295 static isc_result_t generic_fromstruct_ds(ARGS_FROMSTRUCT); 296 297 static isc_result_t generic_fromtext_tlsa(ARGS_FROMTEXT); 298 299 static isc_result_t generic_totext_tlsa(ARGS_TOTEXT); 300 301 static isc_result_t generic_fromwire_tlsa(ARGS_FROMWIRE); 302 303 static isc_result_t generic_fromstruct_tlsa(ARGS_FROMSTRUCT); 304 305 static isc_result_t generic_tostruct_tlsa(ARGS_TOSTRUCT); 306 307 static void generic_freestruct_tlsa(ARGS_FREESTRUCT); 308 309 static isc_result_t generic_fromtext_in_svcb(ARGS_FROMTEXT); 310 static isc_result_t generic_totext_in_svcb(ARGS_TOTEXT); 311 static isc_result_t generic_fromwire_in_svcb(ARGS_FROMWIRE); 312 static isc_result_t generic_towire_in_svcb(ARGS_TOWIRE); 313 static isc_result_t generic_fromstruct_in_svcb(ARGS_FROMSTRUCT); 314 static isc_result_t generic_tostruct_in_svcb(ARGS_TOSTRUCT); 315 static void generic_freestruct_in_svcb(ARGS_FREESTRUCT); 316 static isc_result_t generic_additionaldata_in_svcb(ARGS_ADDLDATA); 317 static bool generic_checknames_in_svcb(ARGS_CHECKNAMES); 318 static isc_result_t 319 generic_rdata_in_svcb_first(dns_rdata_in_svcb_t *); 320 static isc_result_t 321 generic_rdata_in_svcb_next(dns_rdata_in_svcb_t *); 322 static void 323 generic_rdata_in_svcb_current(dns_rdata_in_svcb_t *, isc_region_t *); 324 325 /*% INT16 Size */ 326 #define NS_INT16SZ 2 327 /*% IPv6 Address Size */ 328 #define NS_LOCATORSZ 8 329 330 /* 331 * Active Directory gc._msdcs.<forest> prefix. 332 */ 333 static unsigned char gc_msdcs_data[] = "\002gc\006_msdcs"; 334 static unsigned char gc_msdcs_offset[] = { 0, 3 }; 335 336 static dns_name_t const gc_msdcs = DNS_NAME_INITNONABSOLUTE(gc_msdcs_data, 337 gc_msdcs_offset); 338 339 /*% 340 * convert presentation level address to network order binary form. 341 * \return 342 * 1 if `src' is a valid [RFC1884 2.2] address, else 0. 343 * \note 344 * (1) does not touch `dst' unless it's returning 1. 345 */ 346 static int 347 locator_pton(const char *src, unsigned char *dst) { 348 unsigned char tmp[NS_LOCATORSZ]; 349 unsigned char *tp = tmp, *endp; 350 int ch, seen_xdigits; 351 unsigned int val, hexval; 352 353 memset(tp, '\0', NS_LOCATORSZ); 354 endp = tp + NS_LOCATORSZ; 355 seen_xdigits = 0; 356 val = 0; 357 while ((ch = *src++) != '\0') { 358 hexval = isc_hex_char(ch); 359 if (hexval != 0) { 360 val <<= 4; 361 val |= (ch - hexval); 362 if (++seen_xdigits > 4) { 363 return 0; 364 } 365 continue; 366 } 367 if (ch == ':') { 368 if (!seen_xdigits) { 369 return 0; 370 } 371 if (tp + NS_INT16SZ > endp) { 372 return 0; 373 } 374 *tp++ = (unsigned char)(val >> 8) & 0xff; 375 *tp++ = (unsigned char)val & 0xff; 376 seen_xdigits = 0; 377 val = 0; 378 continue; 379 } 380 return 0; 381 } 382 if (seen_xdigits) { 383 if (tp + NS_INT16SZ > endp) { 384 return 0; 385 } 386 *tp++ = (unsigned char)(val >> 8) & 0xff; 387 *tp++ = (unsigned char)val & 0xff; 388 } 389 if (tp != endp) { 390 return 0; 391 } 392 memmove(dst, tmp, NS_LOCATORSZ); 393 return 1; 394 } 395 396 static void 397 name_duporclone(const dns_name_t *source, isc_mem_t *mctx, dns_name_t *target) { 398 if (mctx != NULL) { 399 dns_name_dup(source, mctx, target); 400 } else { 401 dns_name_clone(source, target); 402 } 403 } 404 405 static void * 406 mem_maybedup(isc_mem_t *mctx, void *source, size_t length) { 407 void *copy = NULL; 408 409 REQUIRE(source != NULL); 410 411 if (mctx == NULL) { 412 return source; 413 } 414 415 copy = isc_mem_allocate(mctx, length); 416 memmove(copy, source, length); 417 418 return copy; 419 } 420 421 static isc_result_t 422 typemap_fromtext(isc_lex_t *lexer, isc_buffer_t *target, bool allow_empty) { 423 isc_token_t token; 424 unsigned char bm[8 * 1024]; /* 64k bits */ 425 dns_rdatatype_t covered, max_used; 426 int octet; 427 unsigned int max_octet, newend, end; 428 int window; 429 bool first = true; 430 431 max_used = 0; 432 bm[0] = 0; 433 end = 0; 434 435 do { 436 RETERR(isc_lex_getmastertoken(lexer, &token, 437 isc_tokentype_string, true)); 438 if (token.type != isc_tokentype_string) { 439 break; 440 } 441 RETTOK(dns_rdatatype_fromtext(&covered, 442 &token.value.as_textregion)); 443 if (covered > max_used) { 444 newend = covered / 8; 445 if (newend > end) { 446 memset(&bm[end + 1], 0, newend - end); 447 end = newend; 448 } 449 max_used = covered; 450 } 451 bm[covered / 8] |= (0x80 >> (covered % 8)); 452 first = false; 453 } while (1); 454 isc_lex_ungettoken(lexer, &token); 455 if (!allow_empty && first) { 456 return DNS_R_FORMERR; 457 } 458 459 for (window = 0; window < 256; window++) { 460 if (max_used < window * 256) { 461 break; 462 } 463 464 max_octet = max_used - (window * 256); 465 if (max_octet >= 256) { 466 max_octet = 31; 467 } else { 468 max_octet /= 8; 469 } 470 471 /* 472 * Find if we have a type in this window. 473 */ 474 for (octet = max_octet; octet >= 0; octet--) { 475 if (bm[window * 32 + octet] != 0) { 476 break; 477 } 478 } 479 if (octet < 0) { 480 continue; 481 } 482 RETERR(uint8_tobuffer(window, target)); 483 RETERR(uint8_tobuffer(octet + 1, target)); 484 RETERR(mem_tobuffer(target, &bm[window * 32], octet + 1)); 485 } 486 return ISC_R_SUCCESS; 487 } 488 489 static isc_result_t 490 typemap_totext(isc_region_t *sr, dns_rdata_textctx_t *tctx, 491 isc_buffer_t *target) { 492 unsigned int i, j, k; 493 unsigned int window, len; 494 bool first = true; 495 496 for (i = 0; i < sr->length; i += len) { 497 if (tctx != NULL && 498 (tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) 499 { 500 RETERR(str_totext(tctx->linebreak, target)); 501 first = true; 502 } 503 INSIST(i + 2 <= sr->length); 504 window = sr->base[i]; 505 len = sr->base[i + 1]; 506 INSIST(len > 0 && len <= 32); 507 i += 2; 508 INSIST(i + len <= sr->length); 509 for (j = 0; j < len; j++) { 510 dns_rdatatype_t t; 511 if (sr->base[i + j] == 0) { 512 continue; 513 } 514 for (k = 0; k < 8; k++) { 515 if ((sr->base[i + j] & (0x80 >> k)) == 0) { 516 continue; 517 } 518 t = window * 256 + j * 8 + k; 519 if (!first) { 520 RETERR(str_totext(" ", target)); 521 } 522 first = false; 523 if (dns_rdatatype_isknown(t)) { 524 RETERR(dns_rdatatype_totext(t, target)); 525 } else { 526 char buf[sizeof("TYPE65535")]; 527 snprintf(buf, sizeof(buf), "TYPE%u", t); 528 RETERR(str_totext(buf, target)); 529 } 530 } 531 } 532 } 533 return ISC_R_SUCCESS; 534 } 535 536 static isc_result_t 537 typemap_test(isc_region_t *sr, bool allow_empty) { 538 unsigned int window, lastwindow = 0; 539 unsigned int len; 540 bool first = true; 541 unsigned int i; 542 543 for (i = 0; i < sr->length; i += len) { 544 /* 545 * Check for overflow. 546 */ 547 if (i + 2 > sr->length) { 548 RETERR(DNS_R_FORMERR); 549 } 550 window = sr->base[i]; 551 len = sr->base[i + 1]; 552 i += 2; 553 /* 554 * Check that bitmap windows are in the correct order. 555 */ 556 if (!first && window <= lastwindow) { 557 RETERR(DNS_R_FORMERR); 558 } 559 /* 560 * Check for legal lengths. 561 */ 562 if (len < 1 || len > 32) { 563 RETERR(DNS_R_FORMERR); 564 } 565 /* 566 * Check for overflow. 567 */ 568 if (i + len > sr->length) { 569 RETERR(DNS_R_FORMERR); 570 } 571 /* 572 * The last octet of the bitmap must be non zero. 573 */ 574 if (sr->base[i + len - 1] == 0) { 575 RETERR(DNS_R_FORMERR); 576 } 577 lastwindow = window; 578 first = false; 579 } 580 if (i != sr->length) { 581 return DNS_R_EXTRADATA; 582 } 583 if (!allow_empty && first) { 584 RETERR(DNS_R_FORMERR); 585 } 586 return ISC_R_SUCCESS; 587 } 588 589 static isc_result_t 590 check_private(isc_buffer_t *source, dns_secalg_t alg) { 591 isc_region_t sr; 592 if (alg == DNS_KEYALG_PRIVATEDNS) { 593 dns_fixedname_t fixed; 594 595 RETERR(dns_name_fromwire(dns_fixedname_initname(&fixed), source, 596 DNS_DECOMPRESS_DEFAULT, NULL)); 597 } else if (alg == DNS_KEYALG_PRIVATEOID) { 598 /* 599 * Check that we can extract the OID from the start of the 600 * key data. We have a length byte followed by the OID BER 601 * encoded. 602 */ 603 const unsigned char *in = NULL; 604 ASN1_OBJECT *obj = NULL; 605 606 isc_buffer_activeregion(source, &sr); 607 if (sr.length < 1 || (unsigned int)*sr.base + 1 > sr.length) { 608 RETERR(DNS_R_FORMERR); 609 } 610 in = sr.base + 1; 611 obj = d2i_ASN1_OBJECT(NULL, &in, *sr.base); 612 if (obj == NULL) { 613 ERR_clear_error(); 614 RETERR(DNS_R_FORMERR); 615 } 616 ASN1_OBJECT_free(obj); 617 if ((in - sr.base) != (*sr.base + 1)) { 618 RETERR(DNS_R_FORMERR); 619 } 620 } 621 return ISC_R_SUCCESS; 622 } 623 624 /* 625 * A relative URI template that has a "dns" variable. 626 */ 627 static bool 628 validate_dohpath(isc_region_t *region) { 629 const unsigned char *p; 630 const unsigned char *v = NULL; 631 const unsigned char *n = NULL; 632 unsigned char c; 633 bool dns = false; 634 bool wasop = false; 635 enum { 636 path, 637 variable, 638 percent1, 639 percent2, 640 variable_percent1, 641 variable_percent2, 642 prefix, 643 explode 644 } state = path; 645 646 if (region->length == 0 || *region->base != '/' || 647 !isc_utf8_valid(region->base, region->length)) 648 { 649 return false; 650 } 651 652 /* 653 * RFC 6570 URI Template check + "dns" variable. 654 */ 655 p = region->base; 656 while (p < region->base + region->length) { 657 switch (state) { 658 case path: 659 switch (*p++) { 660 case '{': /*}*/ 661 state = variable; 662 wasop = false; 663 v = p; 664 break; 665 case '%': 666 state = percent1; 667 break; 668 default: 669 break; 670 } 671 break; 672 case variable: 673 c = *p++; 674 switch (c) { 675 case '+': 676 case '#': 677 case '.': 678 case '/': 679 case ';': 680 case '?': 681 case '&': 682 /* Operators. */ 683 if (p != v + 1 || wasop) { 684 return false; 685 } 686 wasop = true; 687 v = p; 688 break; 689 case '=': 690 case '!': 691 case '@': 692 case '|': 693 /* Reserved operators. */ 694 return false; 695 case '*': 696 case ':': 697 case '}': 698 case ',': 699 /* Found the end of the variable name. */ 700 if (p == (v + 1)) { 701 return false; 702 } 703 /* 'p' has been incremented so 4 not 3 */ 704 if ((p - v) == 4 && memcmp(v, "dns", 3) == 0) { 705 dns = true; 706 } 707 switch (c) { 708 case ':': 709 state = prefix; 710 n = p; 711 break; 712 case /*{*/ '}': 713 state = path; 714 break; 715 case '*': 716 state = explode; 717 break; 718 case ',': 719 wasop = false; 720 v = p; 721 break; 722 } 723 break; 724 case '%': 725 /* Percent encoded variable name. */ 726 state = variable_percent1; 727 break; 728 default: 729 /* Valid variable name character? */ 730 if (c != '_' && !isalnum(c)) { 731 return false; 732 } 733 break; 734 } 735 break; 736 case explode: 737 switch (*p++) { 738 case ',': 739 state = variable; 740 wasop = false; 741 v = p; 742 break; 743 case /*}*/ '}': 744 state = path; 745 break; 746 default: 747 return false; 748 } 749 break; 750 /* Check % encoding */ 751 case percent1: 752 case percent2: 753 case variable_percent1: 754 case variable_percent2: 755 /* bad percent encoding? */ 756 if (!isxdigit(*p++)) { 757 return false; 758 } 759 if (state == percent1) { 760 state = percent2; 761 } else if (state == percent2) { 762 state = path; 763 } else if (state == variable_percent1) { 764 state = variable_percent2; 765 } else { 766 state = variable; 767 } 768 break; 769 case prefix: 770 c = *p++; 771 if (!isdigit(c)) { 772 /* valid number range [1..9999] */ 773 if ((p == n + 1) || (p - n) > 5 || *n == '0') { 774 return false; 775 } 776 switch (c) { 777 case ',': 778 state = variable; 779 wasop = false; 780 break; 781 case /*{*/ '}': 782 state = path; 783 break; 784 default: 785 return false; 786 } 787 } 788 break; 789 } 790 } 791 return state == path && dns; 792 } 793 794 #include "code.h" 795 796 #define META 0x0001 797 #define RESERVED 0x0002 798 799 /*** 800 *** Initialization 801 ***/ 802 803 void 804 dns_rdata_init(dns_rdata_t *rdata) { 805 REQUIRE(rdata != NULL); 806 807 rdata->data = NULL; 808 rdata->length = 0; 809 rdata->rdclass = 0; 810 rdata->type = 0; 811 rdata->flags = 0; 812 ISC_LINK_INIT(rdata, link); 813 /* ISC_LIST_INIT(rdata->list); */ 814 } 815 816 void 817 dns_rdata_reset(dns_rdata_t *rdata) { 818 REQUIRE(rdata != NULL); 819 820 REQUIRE(!ISC_LINK_LINKED(rdata, link)); 821 REQUIRE(DNS_RDATA_VALIDFLAGS(rdata)); 822 823 rdata->data = NULL; 824 rdata->length = 0; 825 rdata->rdclass = 0; 826 rdata->type = 0; 827 rdata->flags = 0; 828 } 829 830 /*** 831 *** 832 ***/ 833 834 void 835 dns_rdata_clone(const dns_rdata_t *src, dns_rdata_t *target) { 836 REQUIRE(src != NULL); 837 REQUIRE(target != NULL); 838 839 REQUIRE(DNS_RDATA_INITIALIZED(target)); 840 841 REQUIRE(DNS_RDATA_VALIDFLAGS(src)); 842 REQUIRE(DNS_RDATA_VALIDFLAGS(target)); 843 844 target->data = src->data; 845 target->length = src->length; 846 target->rdclass = src->rdclass; 847 target->type = src->type; 848 target->flags = src->flags; 849 } 850 851 /*** 852 *** Comparisons 853 ***/ 854 855 int 856 dns_rdata_compare(const dns_rdata_t *rdata1, const dns_rdata_t *rdata2) { 857 int result = 0; 858 bool use_default = false; 859 860 REQUIRE(rdata1 != NULL); 861 REQUIRE(rdata2 != NULL); 862 REQUIRE(rdata1->length == 0 || rdata1->data != NULL); 863 REQUIRE(rdata2->length == 0 || rdata2->data != NULL); 864 REQUIRE(DNS_RDATA_VALIDFLAGS(rdata1)); 865 REQUIRE(DNS_RDATA_VALIDFLAGS(rdata2)); 866 867 if (rdata1->rdclass != rdata2->rdclass) { 868 return rdata1->rdclass < rdata2->rdclass ? -1 : 1; 869 } 870 871 if (rdata1->type != rdata2->type) { 872 return rdata1->type < rdata2->type ? -1 : 1; 873 } 874 875 COMPARESWITCH 876 877 if (use_default) { 878 isc_region_t r1; 879 isc_region_t r2; 880 881 dns_rdata_toregion(rdata1, &r1); 882 dns_rdata_toregion(rdata2, &r2); 883 result = isc_region_compare(&r1, &r2); 884 } 885 return result; 886 } 887 888 int 889 dns_rdata_casecompare(const dns_rdata_t *rdata1, const dns_rdata_t *rdata2) { 890 int result = 0; 891 bool use_default = false; 892 893 REQUIRE(rdata1 != NULL); 894 REQUIRE(rdata2 != NULL); 895 REQUIRE(rdata1->length == 0 || rdata1->data != NULL); 896 REQUIRE(rdata2->length == 0 || rdata2->data != NULL); 897 REQUIRE(DNS_RDATA_VALIDFLAGS(rdata1)); 898 REQUIRE(DNS_RDATA_VALIDFLAGS(rdata2)); 899 900 if (rdata1->rdclass != rdata2->rdclass) { 901 return rdata1->rdclass < rdata2->rdclass ? -1 : 1; 902 } 903 904 if (rdata1->type != rdata2->type) { 905 return rdata1->type < rdata2->type ? -1 : 1; 906 } 907 908 CASECOMPARESWITCH 909 910 if (use_default) { 911 isc_region_t r1; 912 isc_region_t r2; 913 914 dns_rdata_toregion(rdata1, &r1); 915 dns_rdata_toregion(rdata2, &r2); 916 result = isc_region_compare(&r1, &r2); 917 } 918 return result; 919 } 920 921 /*** 922 *** Conversions 923 ***/ 924 925 void 926 dns_rdata_fromregion(dns_rdata_t *rdata, dns_rdataclass_t rdclass, 927 dns_rdatatype_t type, isc_region_t *r) { 928 REQUIRE(rdata != NULL); 929 REQUIRE(DNS_RDATA_INITIALIZED(rdata)); 930 REQUIRE(r != NULL); 931 932 REQUIRE(DNS_RDATA_VALIDFLAGS(rdata)); 933 934 rdata->data = r->base; 935 rdata->length = r->length; 936 rdata->rdclass = rdclass; 937 rdata->type = type; 938 rdata->flags = 0; 939 } 940 941 void 942 dns_rdata_toregion(const dns_rdata_t *rdata, isc_region_t *r) { 943 REQUIRE(rdata != NULL); 944 REQUIRE(r != NULL); 945 REQUIRE(DNS_RDATA_VALIDFLAGS(rdata)); 946 947 r->base = rdata->data; 948 r->length = rdata->length; 949 } 950 951 isc_result_t 952 dns_rdata_fromwire(dns_rdata_t *rdata, dns_rdataclass_t rdclass, 953 dns_rdatatype_t type, isc_buffer_t *source, 954 dns_decompress_t dctx, isc_buffer_t *target) { 955 isc_result_t result = ISC_R_NOTIMPLEMENTED; 956 isc_region_t region; 957 isc_buffer_t ss; 958 isc_buffer_t st; 959 bool use_default = false; 960 uint32_t activelength; 961 unsigned int length; 962 963 if (rdata != NULL) { 964 REQUIRE(DNS_RDATA_INITIALIZED(rdata)); 965 REQUIRE(DNS_RDATA_VALIDFLAGS(rdata)); 966 } 967 REQUIRE(source != NULL); 968 REQUIRE(target != NULL); 969 970 if (type == 0) { 971 return DNS_R_FORMERR; 972 } 973 974 ss = *source; 975 st = *target; 976 977 activelength = isc_buffer_activelength(source); 978 INSIST(activelength < 65536); 979 980 FROMWIRESWITCH 981 982 if (use_default) { 983 if (activelength > isc_buffer_availablelength(target)) { 984 result = ISC_R_NOSPACE; 985 } else { 986 isc_buffer_putmem(target, isc_buffer_current(source), 987 activelength); 988 isc_buffer_forward(source, activelength); 989 result = ISC_R_SUCCESS; 990 } 991 } 992 993 /* 994 * Reject any rdata that expands out to more than DNS_RDATA_MAXLENGTH 995 * as we cannot transmit it. 996 */ 997 length = isc_buffer_usedlength(target) - isc_buffer_usedlength(&st); 998 if (result == ISC_R_SUCCESS && length > DNS_RDATA_MAXLENGTH) { 999 result = DNS_R_FORMERR; 1000 } 1001 1002 /* 1003 * We should have consumed all of our buffer. 1004 */ 1005 if (result == ISC_R_SUCCESS && !buffer_empty(source)) { 1006 result = DNS_R_EXTRADATA; 1007 } 1008 1009 if (rdata != NULL && result == ISC_R_SUCCESS) { 1010 region.base = isc_buffer_used(&st); 1011 region.length = length; 1012 dns_rdata_fromregion(rdata, rdclass, type, ®ion); 1013 } 1014 1015 if (result != ISC_R_SUCCESS) { 1016 *source = ss; 1017 *target = st; 1018 } 1019 return result; 1020 } 1021 1022 isc_result_t 1023 dns_rdata_towire(dns_rdata_t *rdata, dns_compress_t *cctx, 1024 isc_buffer_t *target) { 1025 isc_result_t result = ISC_R_NOTIMPLEMENTED; 1026 bool use_default = false; 1027 isc_region_t tr; 1028 isc_buffer_t st; 1029 1030 REQUIRE(rdata != NULL); 1031 REQUIRE(DNS_RDATA_VALIDFLAGS(rdata)); 1032 1033 /* 1034 * Some DynDNS meta-RRs have empty rdata. 1035 */ 1036 if ((rdata->flags & DNS_RDATA_UPDATE) != 0) { 1037 INSIST(rdata->length == 0); 1038 return ISC_R_SUCCESS; 1039 } 1040 1041 st = *target; 1042 1043 TOWIRESWITCH 1044 1045 if (use_default) { 1046 isc_buffer_availableregion(target, &tr); 1047 if (tr.length < rdata->length) { 1048 return ISC_R_NOSPACE; 1049 } 1050 memmove(tr.base, rdata->data, rdata->length); 1051 isc_buffer_add(target, rdata->length); 1052 return ISC_R_SUCCESS; 1053 } 1054 if (result != ISC_R_SUCCESS) { 1055 *target = st; 1056 dns_compress_rollback(cctx, target->used); 1057 } 1058 return result; 1059 } 1060 1061 /* 1062 * If the binary data in 'src' is valid uncompressed wire format 1063 * rdata of class 'rdclass' and type 'type', return ISC_R_SUCCESS 1064 * and copy the validated rdata to 'dest'. Otherwise return an error. 1065 */ 1066 static isc_result_t 1067 rdata_validate(isc_buffer_t *src, isc_buffer_t *dest, dns_rdataclass_t rdclass, 1068 dns_rdatatype_t type) { 1069 isc_result_t result; 1070 1071 isc_buffer_setactive(src, isc_buffer_usedlength(src)); 1072 result = dns_rdata_fromwire(NULL, rdclass, type, src, 1073 DNS_DECOMPRESS_NEVER, dest); 1074 1075 return result; 1076 } 1077 1078 static isc_result_t 1079 unknown_fromtext(dns_rdataclass_t rdclass, dns_rdatatype_t type, 1080 isc_lex_t *lexer, isc_mem_t *mctx, isc_buffer_t *target) { 1081 isc_result_t result; 1082 isc_buffer_t *buf = NULL; 1083 isc_token_t token; 1084 1085 if (type == 0 || dns_rdatatype_ismeta(type)) { 1086 return DNS_R_METATYPE; 1087 } 1088 1089 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number, 1090 false)); 1091 if (token.value.as_ulong > 65535U) { 1092 return ISC_R_RANGE; 1093 } 1094 isc_buffer_allocate(mctx, &buf, token.value.as_ulong); 1095 1096 if (token.value.as_ulong != 0U) { 1097 result = isc_hex_tobuffer(lexer, buf, 1098 (unsigned int)token.value.as_ulong); 1099 if (result != ISC_R_SUCCESS) { 1100 goto failure; 1101 } 1102 if (isc_buffer_usedlength(buf) != token.value.as_ulong) { 1103 result = ISC_R_UNEXPECTEDEND; 1104 goto failure; 1105 } 1106 } 1107 1108 if (dns_rdatatype_isknown(type)) { 1109 result = rdata_validate(buf, target, rdclass, type); 1110 } else { 1111 isc_region_t r; 1112 isc_buffer_usedregion(buf, &r); 1113 result = isc_buffer_copyregion(target, &r); 1114 } 1115 if (result != ISC_R_SUCCESS) { 1116 goto failure; 1117 } 1118 1119 isc_buffer_free(&buf); 1120 return ISC_R_SUCCESS; 1121 1122 failure: 1123 isc_buffer_free(&buf); 1124 return result; 1125 } 1126 1127 isc_result_t 1128 dns_rdata_fromtext(dns_rdata_t *rdata, dns_rdataclass_t rdclass, 1129 dns_rdatatype_t type, isc_lex_t *lexer, 1130 const dns_name_t *origin, unsigned int options, 1131 isc_mem_t *mctx, isc_buffer_t *target, 1132 dns_rdatacallbacks_t *callbacks) { 1133 isc_result_t result = ISC_R_NOTIMPLEMENTED; 1134 isc_region_t region; 1135 isc_buffer_t st; 1136 isc_token_t token; 1137 unsigned int lexoptions = ISC_LEXOPT_EOL | ISC_LEXOPT_EOF | 1138 ISC_LEXOPT_DNSMULTILINE | ISC_LEXOPT_ESCAPE; 1139 char *name; 1140 unsigned long line; 1141 void (*callback)(dns_rdatacallbacks_t *, const char *, ...); 1142 isc_result_t tresult; 1143 unsigned int length; 1144 bool unknown; 1145 1146 REQUIRE(origin == NULL || dns_name_isabsolute(origin)); 1147 if (rdata != NULL) { 1148 REQUIRE(DNS_RDATA_INITIALIZED(rdata)); 1149 REQUIRE(DNS_RDATA_VALIDFLAGS(rdata)); 1150 } 1151 if (callbacks != NULL) { 1152 REQUIRE(callbacks->warn != NULL); 1153 REQUIRE(callbacks->error != NULL); 1154 } 1155 1156 st = *target; 1157 1158 if (callbacks != NULL) { 1159 callback = callbacks->error; 1160 } else { 1161 callback = default_fromtext_callback; 1162 } 1163 1164 result = isc_lex_getmastertoken(lexer, &token, isc_tokentype_qstring, 1165 true); 1166 if (result != ISC_R_SUCCESS) { 1167 name = isc_lex_getsourcename(lexer); 1168 line = isc_lex_getsourceline(lexer); 1169 fromtext_error(callback, callbacks, name, line, NULL, result); 1170 return result; 1171 } 1172 1173 unknown = false; 1174 if (token.type == isc_tokentype_string && 1175 strcmp(DNS_AS_STR(token), "\\#") == 0) 1176 { 1177 /* 1178 * If this is a TXT record '\#' could be a escaped '#'. 1179 * Look to see if the next token is a number and if so 1180 * treat it as a unknown record format. 1181 */ 1182 if (type == dns_rdatatype_txt) { 1183 result = isc_lex_getmastertoken( 1184 lexer, &token, isc_tokentype_number, false); 1185 if (result == ISC_R_SUCCESS) { 1186 isc_lex_ungettoken(lexer, &token); 1187 } 1188 } 1189 1190 if (result == ISC_R_SUCCESS) { 1191 unknown = true; 1192 result = unknown_fromtext(rdclass, type, lexer, mctx, 1193 target); 1194 } else { 1195 options |= DNS_RDATA_UNKNOWNESCAPE; 1196 } 1197 } else { 1198 isc_lex_ungettoken(lexer, &token); 1199 } 1200 1201 if (!unknown) { 1202 FROMTEXTSWITCH 1203 1204 /* 1205 * Consume to end of line / file. 1206 * If not at end of line initially set error code. 1207 * Call callback via fromtext_error once if there was an error. 1208 */ 1209 } 1210 do { 1211 name = isc_lex_getsourcename(lexer); 1212 line = isc_lex_getsourceline(lexer); 1213 tresult = isc_lex_gettoken(lexer, lexoptions, &token); 1214 if (tresult != ISC_R_SUCCESS) { 1215 if (result == ISC_R_SUCCESS) { 1216 result = tresult; 1217 } 1218 if (callback != NULL) { 1219 fromtext_error(callback, callbacks, name, line, 1220 NULL, result); 1221 } 1222 break; 1223 } else if (token.type != isc_tokentype_eol && 1224 token.type != isc_tokentype_eof) 1225 { 1226 if (result == ISC_R_SUCCESS) { 1227 result = DNS_R_EXTRATOKEN; 1228 } 1229 if (callback != NULL) { 1230 fromtext_error(callback, callbacks, name, line, 1231 &token, result); 1232 callback = NULL; 1233 } 1234 } else if (result != ISC_R_SUCCESS && callback != NULL) { 1235 fromtext_error(callback, callbacks, name, line, &token, 1236 result); 1237 break; 1238 } else { 1239 if (token.type == isc_tokentype_eof) { 1240 fromtext_warneof(lexer, callbacks); 1241 } 1242 break; 1243 } 1244 } while (1); 1245 1246 length = isc_buffer_usedlength(target) - isc_buffer_usedlength(&st); 1247 if (result == ISC_R_SUCCESS && length > DNS_RDATA_MAXLENGTH) { 1248 result = ISC_R_NOSPACE; 1249 } 1250 1251 if (rdata != NULL && result == ISC_R_SUCCESS) { 1252 region.base = isc_buffer_used(&st); 1253 region.length = length; 1254 dns_rdata_fromregion(rdata, rdclass, type, ®ion); 1255 } 1256 if (result != ISC_R_SUCCESS) { 1257 *target = st; 1258 } 1259 return result; 1260 } 1261 1262 static isc_result_t 1263 unknown_totext(dns_rdata_t *rdata, dns_rdata_textctx_t *tctx, 1264 isc_buffer_t *target) { 1265 isc_result_t result; 1266 char buf[sizeof("65535")]; 1267 isc_region_t sr; 1268 1269 strlcpy(buf, "\\# ", sizeof(buf)); 1270 result = str_totext(buf, target); 1271 if (result != ISC_R_SUCCESS) { 1272 return result; 1273 } 1274 1275 dns_rdata_toregion(rdata, &sr); 1276 INSIST(sr.length < 65536); 1277 snprintf(buf, sizeof(buf), "%u", sr.length); 1278 result = str_totext(buf, target); 1279 if (result != ISC_R_SUCCESS) { 1280 return result; 1281 } 1282 1283 if (sr.length != 0U) { 1284 if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) { 1285 result = str_totext(" ( ", target); 1286 } else { 1287 result = str_totext(" ", target); 1288 } 1289 1290 if (result != ISC_R_SUCCESS) { 1291 return result; 1292 } 1293 1294 if (tctx->width == 0) { /* No splitting */ 1295 result = isc_hex_totext(&sr, 0, "", target); 1296 } else { 1297 result = isc_hex_totext(&sr, tctx->width - 2, 1298 tctx->linebreak, target); 1299 } 1300 if (result == ISC_R_SUCCESS && 1301 (tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) 1302 { 1303 result = str_totext(" )", target); 1304 } 1305 } 1306 return result; 1307 } 1308 1309 static isc_result_t 1310 rdata_totext(dns_rdata_t *rdata, dns_rdata_textctx_t *tctx, 1311 isc_buffer_t *target) { 1312 isc_result_t result = ISC_R_NOTIMPLEMENTED; 1313 bool use_default = false; 1314 unsigned int cur; 1315 1316 REQUIRE(rdata != NULL); 1317 REQUIRE(tctx->origin == NULL || dns_name_isabsolute(tctx->origin)); 1318 1319 /* 1320 * Some DynDNS meta-RRs have empty rdata. 1321 */ 1322 if ((rdata->flags & DNS_RDATA_UPDATE) != 0) { 1323 INSIST(rdata->length == 0); 1324 return ISC_R_SUCCESS; 1325 } 1326 1327 if ((tctx->flags & DNS_STYLEFLAG_UNKNOWNFORMAT) != 0) { 1328 return unknown_totext(rdata, tctx, target); 1329 } 1330 1331 cur = isc_buffer_usedlength(target); 1332 1333 TOTEXTSWITCH 1334 1335 if (use_default || (result == ISC_R_NOTIMPLEMENTED)) { 1336 unsigned int u = isc_buffer_usedlength(target); 1337 1338 INSIST(u >= cur); 1339 isc_buffer_subtract(target, u - cur); 1340 result = unknown_totext(rdata, tctx, target); 1341 } 1342 1343 return result; 1344 } 1345 1346 isc_result_t 1347 dns_rdata_totext(dns_rdata_t *rdata, const dns_name_t *origin, 1348 isc_buffer_t *target) { 1349 dns_rdata_textctx_t tctx; 1350 1351 REQUIRE(DNS_RDATA_VALIDFLAGS(rdata)); 1352 1353 /* 1354 * Set up formatting options for single-line output. 1355 */ 1356 tctx.origin = origin; 1357 tctx.flags = 0; 1358 tctx.width = 60; 1359 tctx.linebreak = " "; 1360 return rdata_totext(rdata, &tctx, target); 1361 } 1362 1363 isc_result_t 1364 dns_rdata_tofmttext(dns_rdata_t *rdata, const dns_name_t *origin, 1365 dns_masterstyle_flags_t flags, unsigned int width, 1366 unsigned int split_width, const char *linebreak, 1367 isc_buffer_t *target) { 1368 dns_rdata_textctx_t tctx; 1369 1370 REQUIRE(DNS_RDATA_VALIDFLAGS(rdata)); 1371 1372 /* 1373 * Set up formatting options for formatted output. 1374 */ 1375 tctx.origin = origin; 1376 tctx.flags = flags; 1377 if (split_width == 0xffffffff) { 1378 tctx.width = width; 1379 } else { 1380 tctx.width = split_width; 1381 } 1382 1383 if ((flags & DNS_STYLEFLAG_MULTILINE) != 0) { 1384 tctx.linebreak = linebreak; 1385 } else { 1386 if (split_width == 0xffffffff) { 1387 tctx.width = 60; /* Used for hex word length only. */ 1388 } 1389 tctx.linebreak = " "; 1390 } 1391 return rdata_totext(rdata, &tctx, target); 1392 } 1393 1394 isc_result_t 1395 dns_rdata_fromstruct(dns_rdata_t *rdata, dns_rdataclass_t rdclass, 1396 dns_rdatatype_t type, void *source, isc_buffer_t *target) { 1397 isc_result_t result = ISC_R_NOTIMPLEMENTED; 1398 isc_buffer_t st; 1399 isc_region_t region; 1400 bool use_default = false; 1401 unsigned int length; 1402 1403 REQUIRE(source != NULL); 1404 if (rdata != NULL) { 1405 REQUIRE(DNS_RDATA_INITIALIZED(rdata)); 1406 REQUIRE(DNS_RDATA_VALIDFLAGS(rdata)); 1407 } 1408 1409 st = *target; 1410 1411 FROMSTRUCTSWITCH 1412 1413 if (use_default) { 1414 (void)NULL; 1415 } 1416 1417 length = isc_buffer_usedlength(target) - isc_buffer_usedlength(&st); 1418 if (result == ISC_R_SUCCESS && length > DNS_RDATA_MAXLENGTH) { 1419 result = ISC_R_NOSPACE; 1420 } 1421 1422 if (rdata != NULL && result == ISC_R_SUCCESS) { 1423 region.base = isc_buffer_used(&st); 1424 region.length = length; 1425 dns_rdata_fromregion(rdata, rdclass, type, ®ion); 1426 } 1427 if (result != ISC_R_SUCCESS) { 1428 *target = st; 1429 } 1430 return result; 1431 } 1432 1433 isc_result_t 1434 dns_rdata_tostruct(const dns_rdata_t *rdata, void *target, isc_mem_t *mctx) { 1435 isc_result_t result = ISC_R_NOTIMPLEMENTED; 1436 bool use_default = false; 1437 1438 REQUIRE(rdata != NULL); 1439 REQUIRE(DNS_RDATA_VALIDFLAGS(rdata)); 1440 REQUIRE((rdata->flags & DNS_RDATA_UPDATE) == 0); 1441 1442 TOSTRUCTSWITCH 1443 1444 if (use_default) { 1445 (void)NULL; 1446 } 1447 1448 return result; 1449 } 1450 1451 void 1452 dns_rdata_freestruct(void *source) { 1453 dns_rdatacommon_t *common = source; 1454 REQUIRE(common != NULL); 1455 1456 FREESTRUCTSWITCH 1457 } 1458 1459 isc_result_t 1460 dns_rdata_additionaldata(dns_rdata_t *rdata, const dns_name_t *owner, 1461 dns_additionaldatafunc_t add, void *arg) { 1462 isc_result_t result = ISC_R_NOTIMPLEMENTED; 1463 bool use_default = false; 1464 1465 /* 1466 * Call 'add' for each name and type from 'rdata' which is subject to 1467 * additional section processing. 1468 */ 1469 1470 REQUIRE(rdata != NULL); 1471 REQUIRE(add != NULL); 1472 REQUIRE(DNS_RDATA_VALIDFLAGS(rdata)); 1473 1474 ADDITIONALDATASWITCH 1475 1476 /* No additional processing for unknown types */ 1477 if (use_default) { 1478 result = ISC_R_SUCCESS; 1479 } 1480 1481 return result; 1482 } 1483 1484 isc_result_t 1485 dns_rdata_digest(dns_rdata_t *rdata, dns_digestfunc_t digest, void *arg) { 1486 isc_result_t result = ISC_R_NOTIMPLEMENTED; 1487 bool use_default = false; 1488 isc_region_t r; 1489 1490 /* 1491 * Send 'rdata' in DNSSEC canonical form to 'digest'. 1492 */ 1493 1494 REQUIRE(rdata != NULL); 1495 REQUIRE(digest != NULL); 1496 REQUIRE(DNS_RDATA_VALIDFLAGS(rdata)); 1497 1498 DIGESTSWITCH 1499 1500 if (use_default) { 1501 dns_rdata_toregion(rdata, &r); 1502 result = (digest)(arg, &r); 1503 } 1504 1505 return result; 1506 } 1507 1508 bool 1509 dns_rdata_checkowner(const dns_name_t *name, dns_rdataclass_t rdclass, 1510 dns_rdatatype_t type, bool wildcard) { 1511 bool result; 1512 1513 CHECKOWNERSWITCH 1514 return result; 1515 } 1516 1517 bool 1518 dns_rdata_checknames(dns_rdata_t *rdata, const dns_name_t *owner, 1519 dns_name_t *bad) { 1520 bool result; 1521 1522 CHECKNAMESSWITCH 1523 return result; 1524 } 1525 1526 unsigned int 1527 dns_rdatatype_attributes(dns_rdatatype_t type) { 1528 RDATATYPE_ATTRIBUTE_SW 1529 if (type >= (dns_rdatatype_t)128 && type <= (dns_rdatatype_t)255) { 1530 return DNS_RDATATYPEATTR_UNKNOWN | DNS_RDATATYPEATTR_META; 1531 } 1532 return DNS_RDATATYPEATTR_UNKNOWN; 1533 } 1534 1535 isc_result_t 1536 dns_rdatatype_fromtext(dns_rdatatype_t *typep, isc_textregion_t *source) { 1537 unsigned int hash; 1538 unsigned int n; 1539 unsigned char a, b; 1540 1541 n = source->length; 1542 1543 if (n == 0) { 1544 return DNS_R_UNKNOWN; 1545 } 1546 1547 a = isc_ascii_tolower(source->base[0]); 1548 b = isc_ascii_tolower(source->base[n - 1]); 1549 1550 hash = ((a + n) * b) % 256; 1551 1552 /* 1553 * This switch block is inlined via \#define, and will use "return" 1554 * to return a result to the caller if it is a valid (known) 1555 * rdatatype name. 1556 */ 1557 RDATATYPE_FROMTEXT_SW(hash, source->base, n, typep); 1558 1559 if (source->length > 4 && source->length < (4 + sizeof("65000")) && 1560 strncasecmp("type", source->base, 4) == 0) 1561 { 1562 char buf[sizeof("65000")]; 1563 char *endp; 1564 unsigned int val; 1565 1566 /* 1567 * source->base is not required to be NUL terminated. 1568 * Copy up to remaining bytes and NUL terminate. 1569 */ 1570 snprintf(buf, sizeof(buf), "%.*s", (int)(source->length - 4), 1571 source->base + 4); 1572 val = strtoul(buf, &endp, 10); 1573 if (*endp == '\0' && val <= 0xffff) { 1574 *typep = (dns_rdatatype_t)val; 1575 return ISC_R_SUCCESS; 1576 } 1577 } 1578 1579 return DNS_R_UNKNOWN; 1580 } 1581 1582 isc_result_t 1583 dns_rdatatype_totext(dns_rdatatype_t type, isc_buffer_t *target) { 1584 RDATATYPE_TOTEXT_SW 1585 1586 return dns_rdatatype_tounknowntext(type, target); 1587 } 1588 1589 isc_result_t 1590 dns_rdatatype_tounknowntext(dns_rdatatype_t type, isc_buffer_t *target) { 1591 char buf[sizeof("TYPE65535")]; 1592 1593 snprintf(buf, sizeof(buf), "TYPE%u", type); 1594 return str_totext(buf, target); 1595 } 1596 1597 void 1598 dns_rdatatype_format(dns_rdatatype_t rdtype, char *array, unsigned int size) { 1599 isc_result_t result; 1600 isc_buffer_t buf; 1601 1602 if (size == 0U) { 1603 return; 1604 } 1605 1606 isc_buffer_init(&buf, array, size); 1607 result = dns_rdatatype_totext(rdtype, &buf); 1608 /* 1609 * Null terminate. 1610 */ 1611 if (result == ISC_R_SUCCESS) { 1612 if (isc_buffer_availablelength(&buf) >= 1) { 1613 isc_buffer_putuint8(&buf, 0); 1614 } else { 1615 result = ISC_R_NOSPACE; 1616 } 1617 } 1618 if (result != ISC_R_SUCCESS) { 1619 strlcpy(array, "<unknown>", size); 1620 } 1621 } 1622 1623 /* 1624 * Private function. 1625 */ 1626 1627 static unsigned int 1628 name_length(const dns_name_t *name) { 1629 return name->length; 1630 } 1631 1632 static isc_result_t 1633 commatxt_totext(isc_region_t *source, bool quote, bool comma, 1634 isc_buffer_t *target) { 1635 unsigned int tl; 1636 unsigned int n; 1637 unsigned char *sp; 1638 char *tp; 1639 isc_region_t region; 1640 1641 isc_buffer_availableregion(target, ®ion); 1642 sp = source->base; 1643 tp = (char *)region.base; 1644 tl = region.length; 1645 1646 n = *sp++; 1647 1648 REQUIRE(n + 1 <= source->length); 1649 if (n == 0U) { 1650 REQUIRE(quote); 1651 } 1652 1653 if (quote) { 1654 if (tl < 1) { 1655 return ISC_R_NOSPACE; 1656 } 1657 *tp++ = '"'; 1658 tl--; 1659 } 1660 while (n--) { 1661 /* 1662 * \DDD space (0x20) if not quoting. 1663 */ 1664 if (*sp < (quote ? ' ' : '!') || *sp >= 0x7f) { 1665 if (tl < 4) { 1666 return ISC_R_NOSPACE; 1667 } 1668 *tp++ = '\\'; 1669 *tp++ = '0' + ((*sp / 100) % 10); 1670 *tp++ = '0' + ((*sp / 10) % 10); 1671 *tp++ = '0' + (*sp % 10); 1672 sp++; 1673 tl -= 4; 1674 continue; 1675 } 1676 /* 1677 * Escape double quote and backslash. If we are not 1678 * enclosing the string in double quotes, also escape 1679 * at sign (@) and semicolon (;) unless comma is set. 1680 * If comma is set, then only escape commas (,). 1681 */ 1682 if (*sp == '"' || *sp == '\\' || (comma && *sp == ',') || 1683 (!comma && !quote && (*sp == '@' || *sp == ';'))) 1684 { 1685 if (tl < 2) { 1686 return ISC_R_NOSPACE; 1687 } 1688 *tp++ = '\\'; 1689 tl--; 1690 /* 1691 * Perform comma escape processing. 1692 * ',' => '\\,' 1693 * '\' => '\\\\' 1694 */ 1695 if (comma && (*sp == ',' || *sp == '\\')) { 1696 if (tl < ((*sp == '\\') ? 3 : 2)) { 1697 return ISC_R_NOSPACE; 1698 } 1699 *tp++ = '\\'; 1700 tl--; 1701 if (*sp == '\\') { 1702 *tp++ = '\\'; 1703 tl--; 1704 } 1705 } 1706 } 1707 if (tl < 1) { 1708 return ISC_R_NOSPACE; 1709 } 1710 *tp++ = *sp++; 1711 tl--; 1712 } 1713 if (quote) { 1714 if (tl < 1) { 1715 return ISC_R_NOSPACE; 1716 } 1717 *tp++ = '"'; 1718 tl--; 1719 POST(tl); 1720 } 1721 isc_buffer_add(target, (unsigned int)(tp - (char *)region.base)); 1722 isc_region_consume(source, *source->base + 1); 1723 return ISC_R_SUCCESS; 1724 } 1725 1726 static isc_result_t 1727 txt_totext(isc_region_t *source, bool quote, isc_buffer_t *target) { 1728 return commatxt_totext(source, quote, false, target); 1729 } 1730 1731 static isc_result_t 1732 commatxt_fromtext(isc_textregion_t *source, bool comma, isc_buffer_t *target) { 1733 isc_region_t tregion; 1734 bool escape = false, comma_escape = false, seen_comma = false; 1735 unsigned int n, nrem; 1736 char *s; 1737 unsigned char *t; 1738 int d; 1739 int c; 1740 1741 isc_buffer_availableregion(target, &tregion); 1742 s = source->base; 1743 n = source->length; 1744 t = tregion.base; 1745 nrem = tregion.length; 1746 if (nrem < 1) { 1747 return ISC_R_NOSPACE; 1748 } 1749 /* 1750 * Length byte. 1751 */ 1752 nrem--; 1753 t++; 1754 /* 1755 * Maximum text string length. 1756 */ 1757 if (nrem > 255) { 1758 nrem = 255; 1759 } 1760 while (n-- != 0) { 1761 c = (*s++) & 0xff; 1762 if (escape && (d = decvalue((char)c)) != -1) { 1763 c = d; 1764 if (n == 0) { 1765 return DNS_R_SYNTAX; 1766 } 1767 n--; 1768 if ((d = decvalue(*s++)) != -1) { 1769 c = c * 10 + d; 1770 } else { 1771 return DNS_R_SYNTAX; 1772 } 1773 if (n == 0) { 1774 return DNS_R_SYNTAX; 1775 } 1776 n--; 1777 if ((d = decvalue(*s++)) != -1) { 1778 c = c * 10 + d; 1779 } else { 1780 return DNS_R_SYNTAX; 1781 } 1782 if (c > 255) { 1783 return DNS_R_SYNTAX; 1784 } 1785 } else if (!escape && c == '\\') { 1786 escape = true; 1787 continue; 1788 } 1789 escape = false; 1790 /* 1791 * Level 1 escape processing complete. 1792 * If comma is set perform comma escape processing. 1793 * 1794 * Level 1 Level 2 ALPN's 1795 * h1\,h2 => h1,h2 => h1 and h2 1796 * h1\\,h2 => h1\,h2 => h1,h2 1797 * h1\\h2 => h1\h2 => h1h2 1798 * h1\\\\h2 => h1\\h2 => h1\h2 1799 */ 1800 if (comma && !comma_escape && c == ',') { 1801 seen_comma = true; 1802 break; 1803 } 1804 if (comma && !comma_escape && c == '\\') { 1805 comma_escape = true; 1806 continue; 1807 } 1808 comma_escape = false; 1809 if (nrem == 0) { 1810 return (tregion.length <= 256U) ? ISC_R_NOSPACE 1811 : DNS_R_SYNTAX; 1812 } 1813 *t++ = c; 1814 nrem--; 1815 } 1816 1817 /* 1818 * Incomplete escape processing? 1819 */ 1820 if (escape || (comma && comma_escape)) { 1821 return DNS_R_SYNTAX; 1822 } 1823 1824 if (comma) { 1825 /* 1826 * Disallow empty ALPN at start (",h1" or "\,h1") or 1827 * in the middle ("h1,,h2" or "h1\,\,h2"). 1828 */ 1829 if ((t - tregion.base - 1) == 0) { 1830 return DNS_R_SYNTAX; 1831 } 1832 1833 /* 1834 * Consume this ALPN and possible ending comma. 1835 */ 1836 isc_textregion_consume(source, s - source->base); 1837 1838 /* 1839 * Disallow empty ALPN at end ("h1," or "h1\,"). 1840 */ 1841 if (seen_comma && source->length == 0) { 1842 return DNS_R_SYNTAX; 1843 } 1844 } 1845 1846 *tregion.base = (unsigned char)(t - tregion.base - 1); 1847 isc_buffer_add(target, *tregion.base + 1); 1848 return ISC_R_SUCCESS; 1849 } 1850 1851 static isc_result_t 1852 txt_fromtext(isc_textregion_t *source, isc_buffer_t *target) { 1853 return commatxt_fromtext(source, false, target); 1854 } 1855 1856 static isc_result_t 1857 txt_fromwire(isc_buffer_t *source, isc_buffer_t *target) { 1858 unsigned int n; 1859 isc_region_t sregion; 1860 isc_region_t tregion; 1861 1862 isc_buffer_activeregion(source, &sregion); 1863 if (sregion.length == 0) { 1864 return ISC_R_UNEXPECTEDEND; 1865 } 1866 n = *sregion.base + 1; 1867 if (n > sregion.length) { 1868 return ISC_R_UNEXPECTEDEND; 1869 } 1870 1871 isc_buffer_availableregion(target, &tregion); 1872 if (n > tregion.length) { 1873 return ISC_R_NOSPACE; 1874 } 1875 1876 if (tregion.base != sregion.base) { 1877 memmove(tregion.base, sregion.base, n); 1878 } 1879 isc_buffer_forward(source, n); 1880 isc_buffer_add(target, n); 1881 return ISC_R_SUCCESS; 1882 } 1883 1884 /* 1885 * Conversion of TXT-like rdata fields without length limits. 1886 */ 1887 static isc_result_t 1888 multitxt_totext(isc_region_t *source, isc_buffer_t *target) { 1889 unsigned int tl; 1890 unsigned int n0, n; 1891 unsigned char *sp; 1892 char *tp; 1893 isc_region_t region; 1894 1895 isc_buffer_availableregion(target, ®ion); 1896 sp = source->base; 1897 tp = (char *)region.base; 1898 tl = region.length; 1899 1900 if (tl < 1) { 1901 return ISC_R_NOSPACE; 1902 } 1903 *tp++ = '"'; 1904 tl--; 1905 do { 1906 n = source->length; 1907 n0 = source->length - 1; 1908 1909 while (n--) { 1910 if (*sp < ' ' || *sp >= 0x7f) { 1911 if (tl < 4) { 1912 return ISC_R_NOSPACE; 1913 } 1914 *tp++ = '\\'; 1915 *tp++ = '0' + ((*sp / 100) % 10); 1916 *tp++ = '0' + ((*sp / 10) % 10); 1917 *tp++ = '0' + (*sp % 10); 1918 sp++; 1919 tl -= 4; 1920 continue; 1921 } 1922 /* double quote, backslash */ 1923 if (*sp == '"' || *sp == '\\') { 1924 if (tl < 2) { 1925 return ISC_R_NOSPACE; 1926 } 1927 *tp++ = '\\'; 1928 tl--; 1929 } 1930 if (tl < 1) { 1931 return ISC_R_NOSPACE; 1932 } 1933 *tp++ = *sp++; 1934 tl--; 1935 } 1936 isc_region_consume(source, n0 + 1); 1937 } while (source->length != 0); 1938 if (tl < 1) { 1939 return ISC_R_NOSPACE; 1940 } 1941 *tp++ = '"'; 1942 tl--; 1943 POST(tl); 1944 isc_buffer_add(target, (unsigned int)(tp - (char *)region.base)); 1945 return ISC_R_SUCCESS; 1946 } 1947 1948 static isc_result_t 1949 multitxt_fromtext(isc_textregion_t *source, isc_buffer_t *target) { 1950 isc_region_t tregion; 1951 bool escape; 1952 unsigned int n, nrem; 1953 char *s; 1954 unsigned char *t0, *t; 1955 int d; 1956 int c; 1957 1958 s = source->base; 1959 n = source->length; 1960 escape = false; 1961 1962 do { 1963 isc_buffer_availableregion(target, &tregion); 1964 t0 = t = tregion.base; 1965 nrem = tregion.length; 1966 if (nrem < 1) { 1967 return ISC_R_NOSPACE; 1968 } 1969 1970 while (n != 0) { 1971 --n; 1972 c = (*s++) & 0xff; 1973 if (escape && (d = decvalue((char)c)) != -1) { 1974 c = d; 1975 if (n == 0) { 1976 return DNS_R_SYNTAX; 1977 } 1978 n--; 1979 if ((d = decvalue(*s++)) != -1) { 1980 c = c * 10 + d; 1981 } else { 1982 return DNS_R_SYNTAX; 1983 } 1984 if (n == 0) { 1985 return DNS_R_SYNTAX; 1986 } 1987 n--; 1988 if ((d = decvalue(*s++)) != -1) { 1989 c = c * 10 + d; 1990 } else { 1991 return DNS_R_SYNTAX; 1992 } 1993 if (c > 255) { 1994 return DNS_R_SYNTAX; 1995 } 1996 } else if (!escape && c == '\\') { 1997 escape = true; 1998 continue; 1999 } 2000 escape = false; 2001 *t++ = c; 2002 nrem--; 2003 if (nrem == 0) { 2004 break; 2005 } 2006 } 2007 if (escape) { 2008 return DNS_R_SYNTAX; 2009 } 2010 2011 isc_buffer_add(target, (unsigned int)(t - t0)); 2012 } while (n != 0); 2013 return ISC_R_SUCCESS; 2014 } 2015 2016 static bool 2017 name_prefix(dns_name_t *name, const dns_name_t *origin, dns_name_t *target) { 2018 int l1, l2; 2019 2020 if (origin == NULL) { 2021 goto return_false; 2022 } 2023 2024 if (dns_name_compare(origin, dns_rootname) == 0) { 2025 goto return_false; 2026 } 2027 2028 if (!dns_name_issubdomain(name, origin)) { 2029 goto return_false; 2030 } 2031 2032 l1 = dns_name_countlabels(name); 2033 l2 = dns_name_countlabels(origin); 2034 2035 if (l1 == l2) { 2036 goto return_false; 2037 } 2038 2039 /* Master files should be case preserving. */ 2040 dns_name_getlabelsequence(name, l1 - l2, l2, target); 2041 if (!dns_name_caseequal(origin, target)) { 2042 goto return_false; 2043 } 2044 2045 dns_name_getlabelsequence(name, 0, l1 - l2, target); 2046 return true; 2047 2048 return_false: 2049 *target = *name; 2050 return false; 2051 } 2052 2053 static isc_result_t 2054 str_totext(const char *source, isc_buffer_t *target) { 2055 unsigned int l; 2056 isc_region_t region; 2057 2058 isc_buffer_availableregion(target, ®ion); 2059 l = strlen(source); 2060 2061 if (l > region.length) { 2062 return ISC_R_NOSPACE; 2063 } 2064 2065 memmove(region.base, source, l); 2066 isc_buffer_add(target, l); 2067 return ISC_R_SUCCESS; 2068 } 2069 2070 static isc_result_t 2071 inet_totext(int af, uint32_t flags, isc_region_t *src, isc_buffer_t *target) { 2072 char tmpbuf[64]; 2073 2074 /* Note - inet_ntop doesn't do size checking on its input. */ 2075 if (inet_ntop(af, src->base, tmpbuf, sizeof(tmpbuf)) == NULL) { 2076 return ISC_R_NOSPACE; 2077 } 2078 if (strlen(tmpbuf) > isc_buffer_availablelength(target)) { 2079 return ISC_R_NOSPACE; 2080 } 2081 isc_buffer_putstr(target, tmpbuf); 2082 2083 /* 2084 * An IPv6 address ending in "::" breaks YAML 2085 * parsing, so append 0 in that case. 2086 */ 2087 if (af == AF_INET6 && (flags & DNS_STYLEFLAG_YAML) != 0) { 2088 isc_region_t r; 2089 isc_buffer_usedregion(target, &r); 2090 if (r.length > 0 && r.base[r.length - 1] == ':') { 2091 if (isc_buffer_availablelength(target) == 0) { 2092 return ISC_R_NOSPACE; 2093 } 2094 isc_buffer_putmem(target, (const unsigned char *)"0", 2095 1); 2096 } 2097 } 2098 2099 return ISC_R_SUCCESS; 2100 } 2101 2102 static bool 2103 buffer_empty(isc_buffer_t *source) { 2104 return (source->current == source->active) ? true : false; 2105 } 2106 2107 static void 2108 buffer_fromregion(isc_buffer_t *buffer, isc_region_t *region) { 2109 isc_buffer_init(buffer, region->base, region->length); 2110 isc_buffer_add(buffer, region->length); 2111 isc_buffer_setactive(buffer, region->length); 2112 } 2113 2114 static isc_result_t 2115 uint32_tobuffer(uint32_t value, isc_buffer_t *target) { 2116 isc_region_t region; 2117 2118 isc_buffer_availableregion(target, ®ion); 2119 if (region.length < 4) { 2120 return ISC_R_NOSPACE; 2121 } 2122 isc_buffer_putuint32(target, value); 2123 return ISC_R_SUCCESS; 2124 } 2125 2126 static isc_result_t 2127 uint16_tobuffer(uint32_t value, isc_buffer_t *target) { 2128 isc_region_t region; 2129 2130 if (value > 0xffff) { 2131 return ISC_R_RANGE; 2132 } 2133 isc_buffer_availableregion(target, ®ion); 2134 if (region.length < 2) { 2135 return ISC_R_NOSPACE; 2136 } 2137 isc_buffer_putuint16(target, (uint16_t)value); 2138 return ISC_R_SUCCESS; 2139 } 2140 2141 static isc_result_t 2142 uint8_tobuffer(uint32_t value, isc_buffer_t *target) { 2143 isc_region_t region; 2144 2145 if (value > 0xff) { 2146 return ISC_R_RANGE; 2147 } 2148 isc_buffer_availableregion(target, ®ion); 2149 if (region.length < 1) { 2150 return ISC_R_NOSPACE; 2151 } 2152 isc_buffer_putuint8(target, (uint8_t)value); 2153 return ISC_R_SUCCESS; 2154 } 2155 2156 static isc_result_t 2157 name_tobuffer(const dns_name_t *name, isc_buffer_t *target) { 2158 isc_region_t r; 2159 dns_name_toregion(name, &r); 2160 return isc_buffer_copyregion(target, &r); 2161 } 2162 2163 static uint32_t 2164 uint32_fromregion(isc_region_t *region) { 2165 uint32_t value; 2166 2167 REQUIRE(region->length >= 4); 2168 value = (uint32_t)region->base[0] << 24; 2169 value |= (uint32_t)region->base[1] << 16; 2170 value |= (uint32_t)region->base[2] << 8; 2171 value |= (uint32_t)region->base[3]; 2172 return value; 2173 } 2174 2175 static uint16_t 2176 uint16_consume_fromregion(isc_region_t *region) { 2177 uint16_t r = uint16_fromregion(region); 2178 2179 isc_region_consume(region, 2); 2180 return r; 2181 } 2182 2183 static uint16_t 2184 uint16_fromregion(isc_region_t *region) { 2185 REQUIRE(region->length >= 2); 2186 2187 return (region->base[0] << 8) | region->base[1]; 2188 } 2189 2190 static uint8_t 2191 uint8_fromregion(isc_region_t *region) { 2192 REQUIRE(region->length >= 1); 2193 2194 return region->base[0]; 2195 } 2196 2197 static uint8_t 2198 uint8_consume_fromregion(isc_region_t *region) { 2199 uint8_t r = uint8_fromregion(region); 2200 2201 isc_region_consume(region, 1); 2202 return r; 2203 } 2204 2205 static isc_result_t 2206 mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length) { 2207 isc_region_t tr; 2208 2209 if (length == 0U) { 2210 return ISC_R_SUCCESS; 2211 } 2212 2213 isc_buffer_availableregion(target, &tr); 2214 if (length > tr.length) { 2215 return ISC_R_NOSPACE; 2216 } 2217 if (tr.base != base) { 2218 memmove(tr.base, base, length); 2219 } 2220 isc_buffer_add(target, length); 2221 return ISC_R_SUCCESS; 2222 } 2223 2224 static int 2225 hexvalue(char value) { 2226 int hexval = isc_hex_char(value); 2227 if (hexval == 0) { 2228 return -1; 2229 } else { 2230 return value - hexval; 2231 } 2232 } 2233 2234 static int 2235 decvalue(char value) { 2236 if (isdigit((unsigned char)value)) { 2237 return value - '0'; 2238 } else { 2239 return -1; 2240 } 2241 } 2242 2243 static void 2244 default_fromtext_callback(dns_rdatacallbacks_t *callbacks, const char *fmt, 2245 ...) { 2246 va_list ap; 2247 2248 UNUSED(callbacks); 2249 2250 va_start(ap, fmt); 2251 vfprintf(stderr, fmt, ap); 2252 va_end(ap); 2253 fprintf(stderr, "\n"); 2254 } 2255 2256 static void 2257 fromtext_warneof(isc_lex_t *lexer, dns_rdatacallbacks_t *callbacks) { 2258 if (isc_lex_isfile(lexer) && callbacks != NULL) { 2259 const char *name = isc_lex_getsourcename(lexer); 2260 if (name == NULL) { 2261 name = "UNKNOWN"; 2262 } 2263 (*callbacks->warn)(callbacks, 2264 "%s:%lu: file does not end with newline", 2265 name, isc_lex_getsourceline(lexer)); 2266 } 2267 } 2268 2269 static void 2270 warn_badmx(isc_token_t *token, isc_lex_t *lexer, 2271 dns_rdatacallbacks_t *callbacks) { 2272 const char *file; 2273 unsigned long line; 2274 2275 if (lexer != NULL) { 2276 file = isc_lex_getsourcename(lexer); 2277 line = isc_lex_getsourceline(lexer); 2278 (*callbacks->warn)(callbacks, "%s:%u: warning: '%s': %s", file, 2279 line, DNS_AS_STR(*token), 2280 isc_result_totext(DNS_R_MXISADDRESS)); 2281 } 2282 } 2283 2284 static void 2285 warn_badname(const dns_name_t *name, isc_lex_t *lexer, 2286 dns_rdatacallbacks_t *callbacks) { 2287 const char *file; 2288 unsigned long line; 2289 char namebuf[DNS_NAME_FORMATSIZE]; 2290 2291 if (lexer != NULL) { 2292 file = isc_lex_getsourcename(lexer); 2293 line = isc_lex_getsourceline(lexer); 2294 dns_name_format(name, namebuf, sizeof(namebuf)); 2295 (*callbacks->warn)(callbacks, "%s:%u: warning: %s: %s", file, 2296 line, namebuf, 2297 isc_result_totext(DNS_R_BADNAME)); 2298 } 2299 } 2300 2301 static void 2302 fromtext_error(void (*callback)(dns_rdatacallbacks_t *, const char *, ...), 2303 dns_rdatacallbacks_t *callbacks, const char *name, 2304 unsigned long line, isc_token_t *token, isc_result_t result) { 2305 if (name == NULL) { 2306 name = "UNKNOWN"; 2307 } 2308 2309 if (token != NULL) { 2310 switch (token->type) { 2311 case isc_tokentype_eol: 2312 (*callback)(callbacks, "%s: %s:%lu: near eol: %s", 2313 "dns_rdata_fromtext", name, line, 2314 isc_result_totext(result)); 2315 break; 2316 case isc_tokentype_eof: 2317 (*callback)(callbacks, "%s: %s:%lu: near eof: %s", 2318 "dns_rdata_fromtext", name, line, 2319 isc_result_totext(result)); 2320 break; 2321 case isc_tokentype_number: 2322 (*callback)(callbacks, "%s: %s:%lu: near %lu: %s", 2323 "dns_rdata_fromtext", name, line, 2324 token->value.as_ulong, 2325 isc_result_totext(result)); 2326 break; 2327 case isc_tokentype_string: 2328 case isc_tokentype_qstring: 2329 (*callback)(callbacks, "%s: %s:%lu: near '%s': %s", 2330 "dns_rdata_fromtext", name, line, 2331 DNS_AS_STR(*token), 2332 isc_result_totext(result)); 2333 break; 2334 default: 2335 (*callback)(callbacks, "%s: %s:%lu: %s", 2336 "dns_rdata_fromtext", name, line, 2337 isc_result_totext(result)); 2338 break; 2339 } 2340 } else { 2341 (*callback)(callbacks, "dns_rdata_fromtext: %s:%lu: %s", name, 2342 line, isc_result_totext(result)); 2343 } 2344 } 2345 2346 dns_rdatatype_t 2347 dns_rdata_covers(dns_rdata_t *rdata) { 2348 if (rdata->type == dns_rdatatype_rrsig) { 2349 return covers_rrsig(rdata); 2350 } 2351 return covers_sig(rdata); 2352 } 2353 2354 bool 2355 dns_rdatatype_ismeta(dns_rdatatype_t type) { 2356 if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_META) != 0) { 2357 return true; 2358 } 2359 return false; 2360 } 2361 2362 bool 2363 dns_rdatatype_issingleton(dns_rdatatype_t type) { 2364 if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_SINGLETON) != 0) 2365 { 2366 return true; 2367 } 2368 return false; 2369 } 2370 2371 bool 2372 dns_rdatatype_notquestion(dns_rdatatype_t type) { 2373 if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_NOTQUESTION) != 2374 0) 2375 { 2376 return true; 2377 } 2378 return false; 2379 } 2380 2381 bool 2382 dns_rdatatype_questiononly(dns_rdatatype_t type) { 2383 if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_QUESTIONONLY) != 2384 0) 2385 { 2386 return true; 2387 } 2388 return false; 2389 } 2390 2391 bool 2392 dns_rdatatype_atcname(dns_rdatatype_t type) { 2393 if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_ATCNAME) != 0) { 2394 return true; 2395 } 2396 return false; 2397 } 2398 2399 bool 2400 dns_rdatatype_atparent(dns_rdatatype_t type) { 2401 if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_ATPARENT) != 0) 2402 { 2403 return true; 2404 } 2405 return false; 2406 } 2407 2408 bool 2409 dns_rdatatype_followadditional(dns_rdatatype_t type) { 2410 if ((dns_rdatatype_attributes(type) & 2411 DNS_RDATATYPEATTR_FOLLOWADDITIONAL) != 0) 2412 { 2413 return true; 2414 } 2415 return false; 2416 } 2417 2418 bool 2419 dns_rdataclass_ismeta(dns_rdataclass_t rdclass) { 2420 if (rdclass == dns_rdataclass_reserved0 || 2421 rdclass == dns_rdataclass_none || rdclass == dns_rdataclass_any) 2422 { 2423 return true; 2424 } 2425 2426 return false; /* Assume it is not a meta class. */ 2427 } 2428 2429 bool 2430 dns_rdatatype_isdnssec(dns_rdatatype_t type) { 2431 if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_DNSSEC) != 0) { 2432 return true; 2433 } 2434 return false; 2435 } 2436 2437 bool 2438 dns_rdatatype_iskeymaterial(dns_rdatatype_t type) { 2439 return type == dns_rdatatype_dnskey || type == dns_rdatatype_cdnskey || 2440 type == dns_rdatatype_cds; 2441 } 2442 2443 bool 2444 dns_rdatatype_iszonecutauth(dns_rdatatype_t type) { 2445 if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_ZONECUTAUTH) != 2446 0) 2447 { 2448 return true; 2449 } 2450 return false; 2451 } 2452 2453 bool 2454 dns_rdatatype_isknown(dns_rdatatype_t type) { 2455 if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_UNKNOWN) == 0) { 2456 return true; 2457 } 2458 return false; 2459 } 2460 2461 void 2462 dns_rdata_exists(dns_rdata_t *rdata, dns_rdatatype_t type) { 2463 REQUIRE(rdata != NULL); 2464 REQUIRE(DNS_RDATA_INITIALIZED(rdata)); 2465 2466 rdata->data = NULL; 2467 rdata->length = 0; 2468 rdata->flags = DNS_RDATA_UPDATE; 2469 rdata->type = type; 2470 rdata->rdclass = dns_rdataclass_any; 2471 } 2472 2473 void 2474 dns_rdata_notexist(dns_rdata_t *rdata, dns_rdatatype_t type) { 2475 REQUIRE(rdata != NULL); 2476 REQUIRE(DNS_RDATA_INITIALIZED(rdata)); 2477 2478 rdata->data = NULL; 2479 rdata->length = 0; 2480 rdata->flags = DNS_RDATA_UPDATE; 2481 rdata->type = type; 2482 rdata->rdclass = dns_rdataclass_none; 2483 } 2484 2485 void 2486 dns_rdata_deleterrset(dns_rdata_t *rdata, dns_rdatatype_t type) { 2487 REQUIRE(rdata != NULL); 2488 REQUIRE(DNS_RDATA_INITIALIZED(rdata)); 2489 2490 rdata->data = NULL; 2491 rdata->length = 0; 2492 rdata->flags = DNS_RDATA_UPDATE; 2493 rdata->type = type; 2494 rdata->rdclass = dns_rdataclass_any; 2495 } 2496 2497 void 2498 dns_rdata_makedelete(dns_rdata_t *rdata) { 2499 REQUIRE(rdata != NULL); 2500 2501 rdata->rdclass = dns_rdataclass_none; 2502 } 2503 2504 const char * 2505 dns_rdata_updateop(dns_rdata_t *rdata, dns_section_t section) { 2506 REQUIRE(rdata != NULL); 2507 REQUIRE(DNS_RDATA_INITIALIZED(rdata)); 2508 2509 switch (section) { 2510 case DNS_SECTION_PREREQUISITE: 2511 switch (rdata->rdclass) { 2512 case dns_rdataclass_none: 2513 switch (rdata->type) { 2514 case dns_rdatatype_any: 2515 return "domain doesn't exist"; 2516 default: 2517 return "rrset doesn't exist"; 2518 } 2519 case dns_rdataclass_any: 2520 switch (rdata->type) { 2521 case dns_rdatatype_any: 2522 return "domain exists"; 2523 default: 2524 return "rrset exists (value independent)"; 2525 } 2526 default: 2527 return "rrset exists (value dependent)"; 2528 } 2529 case DNS_SECTION_UPDATE: 2530 switch (rdata->rdclass) { 2531 case dns_rdataclass_none: 2532 return "delete"; 2533 case dns_rdataclass_any: 2534 switch (rdata->type) { 2535 case dns_rdatatype_any: 2536 return "delete all rrsets"; 2537 default: 2538 return "delete rrset"; 2539 } 2540 default: 2541 return "add"; 2542 } 2543 } 2544 return "invalid"; 2545 } 2546 2547 static bool 2548 svcb_ishttp(const char *s, size_t len) { 2549 /* 2550 * HTTP entries from: 2551 * 2552 * https://www.iana.org/assignments/tls-extensiontype-values/\ 2553 * tls-extensiontype-values.xhtml#alpn-protocol-ids 2554 */ 2555 struct { 2556 size_t len; 2557 const char *value; 2558 } http[] = { { 8, "http/0.9" }, { 8, "http/1.0" }, { 8, "http/1.1" }, 2559 { 2, "h2" }, { 3, "h2c" }, { 2, "h3" } }; 2560 2561 for (size_t i = 0; i < ARRAY_SIZE(http); i++) { 2562 if (len == http[i].len && memcmp(s, http[i].value, len) == 0) { 2563 return true; 2564 } 2565 } 2566 return false; 2567 } 2568 2569 static bool 2570 svcb_hashttp(isc_textregion_t *alpn) { 2571 while (alpn->length > 0) { 2572 char c, *s; 2573 unsigned char len = *alpn->base; 2574 2575 isc_textregion_consume(alpn, 1); 2576 2577 /* 2578 * This has to detect "http/1.1", "h2" and "h3", etc. 2579 * in a comma list. 2580 */ 2581 s = alpn->base; 2582 while (len-- > 0) { 2583 c = *alpn->base; 2584 isc_textregion_consume(alpn, 1); 2585 if (c == ',') { 2586 if (svcb_ishttp(s, (alpn->base - s) - 1)) { 2587 return true; 2588 } 2589 s = alpn->base; 2590 } 2591 } 2592 if (svcb_ishttp(s, alpn->base - s)) { 2593 return true; 2594 } 2595 } 2596 return false; 2597 } 2598 2599 isc_result_t 2600 dns_rdata_checksvcb(const dns_name_t *owner, const dns_rdata_t *rdata) { 2601 dns_rdata_in_svcb_t svcb; 2602 isc_result_t result; 2603 2604 REQUIRE(owner != NULL); 2605 REQUIRE(rdata != NULL); 2606 REQUIRE(rdata->type == dns_rdatatype_svcb); 2607 REQUIRE(DNS_RDATA_VALIDFLAGS(rdata)); 2608 2609 result = dns_rdata_tostruct(rdata, &svcb, NULL); 2610 RUNTIME_CHECK(result == ISC_R_SUCCESS); 2611 2612 /* 2613 * Check that Alias Mode records don't have SvcParamKeys. 2614 */ 2615 if (svcb.priority == 0 && svcb.svclen != 0) { 2616 return DNS_R_HAVEPARMKEYS; 2617 } 2618 2619 if (dns_name_isdnssvcb(owner)) { 2620 isc_region_t r = { .base = svcb.svc, .length = svcb.svclen }; 2621 isc_textregion_t alpn; 2622 uint16_t key = 0, len = 0; 2623 2624 /* Check for ALPN (key1) */ 2625 while (r.length > 0) { 2626 key = uint16_fromregion(&r); 2627 isc_region_consume(&r, 2); 2628 len = uint16_fromregion(&r); 2629 isc_region_consume(&r, 2); 2630 if (key >= SVCB_ALPN_KEY) { 2631 break; 2632 } 2633 isc_region_consume(&r, len); 2634 } 2635 if (key != SVCB_ALPN_KEY) { 2636 return DNS_R_NOALPN; 2637 } 2638 alpn = (isc_textregion_t){ .base = (char *)r.base, 2639 .length = len }; 2640 isc_region_consume(&r, len); 2641 if (svcb_hashttp(&alpn)) { 2642 /* Check for DOHPATH (key7) */ 2643 while (r.length > 0) { 2644 key = uint16_fromregion(&r); 2645 isc_region_consume(&r, 2); 2646 len = uint16_fromregion(&r); 2647 isc_region_consume(&r, 2); 2648 if (key >= SVCB_DOHPATH_KEY) { 2649 break; 2650 } 2651 isc_region_consume(&r, len); 2652 } 2653 if (key != SVCB_DOHPATH_KEY) { 2654 return DNS_R_NODOHPATH; 2655 } 2656 } 2657 } 2658 return ISC_R_SUCCESS; 2659 } 2660