1 /* 2 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14 * PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 /* $Id: message.c,v 1.22 2024/12/27 09:04:48 florian Exp $ */ 18 19 /*! \file */ 20 21 /*** 22 *** Imports 23 ***/ 24 25 #include <sys/socket.h> 26 #include <arpa/inet.h> 27 28 #include <ctype.h> 29 #include <stdlib.h> 30 #include <string.h> 31 32 #include <isc/buffer.h> 33 #include <isc/util.h> 34 35 #include <dns/log.h> 36 #include <dns/masterdump.h> 37 #include <dns/message.h> 38 #include <dns/rdata.h> 39 #include <dns/rdatalist.h> 40 #include <dns/rdataset.h> 41 #include <dns/result.h> 42 #include <dns/tsig.h> 43 #include <dns/ttl.h> 44 45 #define DNS_MESSAGE_OPCODE_MASK 0x7800U 46 #define DNS_MESSAGE_OPCODE_SHIFT 11 47 #define DNS_MESSAGE_RCODE_MASK 0x000fU 48 #define DNS_MESSAGE_FLAG_MASK 0x8ff0U 49 #define DNS_MESSAGE_EDNSRCODE_MASK 0xff000000U 50 51 #define VALID_NAMED_SECTION(s) (((s) > DNS_SECTION_ANY) \ 52 && ((s) < DNS_SECTION_MAX)) 53 #define VALID_SECTION(s) (((s) >= DNS_SECTION_ANY) \ 54 && ((s) < DNS_SECTION_MAX)) 55 #define ADD_STRING(b, s) {if (strlen(s) >= \ 56 isc_buffer_availablelength(b)) \ 57 return(ISC_R_NOSPACE); else \ 58 isc_buffer_putstr(b, s);} 59 #define VALID_PSEUDOSECTION(s) (((s) >= DNS_PSEUDOSECTION_ANY) \ 60 && ((s) < DNS_PSEUDOSECTION_MAX)) 61 62 /*% 63 * This is the size of each individual scratchpad buffer, and the numbers 64 * of various block allocations used within the server. 65 * XXXMLG These should come from a config setting. 66 */ 67 #define SCRATCHPAD_SIZE 512 68 #define OFFSET_COUNT 4 69 #define RDATA_COUNT 8 70 #define RDATALIST_COUNT 8 71 72 /*% 73 * Text representation of the different items, for message_totext 74 * functions. 75 */ 76 static const char *sectiontext[] = { 77 "QUESTION", 78 "ANSWER", 79 "AUTHORITY", 80 "ADDITIONAL" 81 }; 82 83 static const char *updsectiontext[] = { 84 "ZONE", 85 "PREREQUISITE", 86 "UPDATE", 87 "ADDITIONAL" 88 }; 89 90 /*% 91 * "helper" type, which consists of a block of some type, and is linkable. 92 * For it to work, sizeof(dns_msgblock_t) must be a multiple of the pointer 93 * size, or the allocated elements will not be aligned correctly. 94 */ 95 struct dns_msgblock { 96 unsigned int count; 97 unsigned int remaining; 98 ISC_LINK(dns_msgblock_t) link; 99 }; /* dynamically sized */ 100 101 static inline dns_msgblock_t * 102 msgblock_allocate(unsigned int, unsigned int); 103 104 #define msgblock_get(block, type) \ 105 ((type *)msgblock_internalget(block, sizeof(type))) 106 107 static inline void * 108 msgblock_internalget(dns_msgblock_t *, unsigned int); 109 110 static inline void 111 msgblock_reset(dns_msgblock_t *); 112 113 /* 114 * Allocate a new dns_msgblock_t, and return a pointer to it. If no memory 115 * is free, return NULL. 116 */ 117 static inline dns_msgblock_t * 118 msgblock_allocate(unsigned int sizeof_type, 119 unsigned int count) 120 { 121 dns_msgblock_t *block; 122 unsigned int length; 123 124 length = sizeof(dns_msgblock_t) + (sizeof_type * count); 125 126 block = malloc(length); 127 if (block == NULL) 128 return (NULL); 129 130 block->count = count; 131 block->remaining = count; 132 133 ISC_LINK_INIT(block, link); 134 135 return (block); 136 } 137 138 /* 139 * Return an element from the msgblock. If no more are available, return 140 * NULL. 141 */ 142 static inline void * 143 msgblock_internalget(dns_msgblock_t *block, unsigned int sizeof_type) { 144 void *ptr; 145 146 if (block == NULL || block->remaining == 0) 147 return (NULL); 148 149 block->remaining--; 150 151 ptr = (((unsigned char *)block) 152 + sizeof(dns_msgblock_t) 153 + (sizeof_type * block->remaining)); 154 155 return (ptr); 156 } 157 158 static inline void 159 msgblock_reset(dns_msgblock_t *block) { 160 block->remaining = block->count; 161 } 162 163 /* 164 * Allocate a new dynamic buffer, and attach it to this message as the 165 * "current" buffer. (which is always the last on the list, for our 166 * uses) 167 */ 168 static inline isc_result_t 169 newbuffer(dns_message_t *msg, unsigned int size) { 170 isc_result_t result; 171 isc_buffer_t *dynbuf; 172 173 dynbuf = NULL; 174 result = isc_buffer_allocate(&dynbuf, size); 175 if (result != ISC_R_SUCCESS) 176 return (ISC_R_NOMEMORY); 177 178 ISC_LIST_APPEND(msg->scratchpad, dynbuf, link); 179 return (ISC_R_SUCCESS); 180 } 181 182 static inline isc_buffer_t * 183 currentbuffer(dns_message_t *msg) { 184 isc_buffer_t *dynbuf; 185 186 dynbuf = ISC_LIST_TAIL(msg->scratchpad); 187 INSIST(dynbuf != NULL); 188 189 return (dynbuf); 190 } 191 192 static inline void 193 releaserdata(dns_message_t *msg, dns_rdata_t *rdata) { 194 ISC_LIST_PREPEND(msg->freerdata, rdata, link); 195 } 196 197 static inline dns_rdata_t * 198 newrdata(dns_message_t *msg) { 199 dns_msgblock_t *msgblock; 200 dns_rdata_t *rdata; 201 202 rdata = ISC_LIST_HEAD(msg->freerdata); 203 if (rdata != NULL) { 204 ISC_LIST_UNLINK(msg->freerdata, rdata, link); 205 return (rdata); 206 } 207 208 msgblock = ISC_LIST_TAIL(msg->rdatas); 209 rdata = msgblock_get(msgblock, dns_rdata_t); 210 if (rdata == NULL) { 211 msgblock = msgblock_allocate(sizeof(dns_rdata_t), RDATA_COUNT); 212 if (msgblock == NULL) 213 return (NULL); 214 215 ISC_LIST_APPEND(msg->rdatas, msgblock, link); 216 217 rdata = msgblock_get(msgblock, dns_rdata_t); 218 } 219 220 dns_rdata_init(rdata); 221 return (rdata); 222 } 223 224 static inline void 225 releaserdatalist(dns_message_t *msg, dns_rdatalist_t *rdatalist) { 226 ISC_LIST_PREPEND(msg->freerdatalist, rdatalist, link); 227 } 228 229 static inline dns_rdatalist_t * 230 newrdatalist(dns_message_t *msg) { 231 dns_msgblock_t *msgblock; 232 dns_rdatalist_t *rdatalist; 233 234 rdatalist = ISC_LIST_HEAD(msg->freerdatalist); 235 if (rdatalist != NULL) { 236 ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link); 237 goto out; 238 } 239 240 msgblock = ISC_LIST_TAIL(msg->rdatalists); 241 rdatalist = msgblock_get(msgblock, dns_rdatalist_t); 242 if (rdatalist == NULL) { 243 msgblock = msgblock_allocate(sizeof(dns_rdatalist_t), 244 RDATALIST_COUNT); 245 if (msgblock == NULL) 246 return (NULL); 247 248 ISC_LIST_APPEND(msg->rdatalists, msgblock, link); 249 250 rdatalist = msgblock_get(msgblock, dns_rdatalist_t); 251 } 252 out: 253 if (rdatalist != NULL) 254 dns_rdatalist_init(rdatalist); 255 256 return (rdatalist); 257 } 258 259 static inline dns_offsets_t * 260 newoffsets(dns_message_t *msg) { 261 dns_msgblock_t *msgblock; 262 dns_offsets_t *offsets; 263 264 msgblock = ISC_LIST_TAIL(msg->offsets); 265 offsets = msgblock_get(msgblock, dns_offsets_t); 266 if (offsets == NULL) { 267 msgblock = msgblock_allocate(sizeof(dns_offsets_t), 268 OFFSET_COUNT); 269 if (msgblock == NULL) 270 return (NULL); 271 272 ISC_LIST_APPEND(msg->offsets, msgblock, link); 273 274 offsets = msgblock_get(msgblock, dns_offsets_t); 275 } 276 277 return (offsets); 278 } 279 280 static inline void 281 msginitheader(dns_message_t *m) { 282 m->id = 0; 283 m->flags = 0; 284 m->rcode = 0; 285 m->opcode = 0; 286 m->rdclass = 0; 287 } 288 289 static inline void 290 msginitprivate(dns_message_t *m) { 291 unsigned int i; 292 293 for (i = 0; i < DNS_SECTION_MAX; i++) { 294 m->cursors[i] = NULL; 295 m->counts[i] = 0; 296 } 297 m->opt = NULL; 298 m->sig0 = NULL; 299 m->sig0name = NULL; 300 m->tsig = NULL; 301 m->tsigname = NULL; 302 m->state = DNS_SECTION_ANY; /* indicate nothing parsed or rendered */ 303 m->opt_reserved = 0; 304 m->sig_reserved = 0; 305 m->reserved = 0; 306 m->buffer = NULL; 307 } 308 309 static inline void 310 msginittsig(dns_message_t *m) { 311 m->tsigstatus = dns_rcode_noerror; 312 m->querytsigstatus = dns_rcode_noerror; 313 m->tsigkey = NULL; 314 m->tsigctx = NULL; 315 m->sigstart = -1; 316 m->sig0status = dns_rcode_noerror; 317 m->timeadjust = 0; 318 } 319 320 /* 321 * Init elements to default state. Used both when allocating a new element 322 * and when resetting one. 323 */ 324 static inline void 325 msginit(dns_message_t *m) { 326 msginitheader(m); 327 msginitprivate(m); 328 msginittsig(m); 329 m->header_ok = 0; 330 m->question_ok = 0; 331 m->tcp_continuation = 0; 332 m->verified_sig = 0; 333 m->verify_attempted = 0; 334 m->query.base = NULL; 335 m->query.length = 0; 336 m->free_query = 0; 337 m->saved.base = NULL; 338 m->saved.length = 0; 339 m->free_saved = 0; 340 m->sitok = 0; 341 m->sitbad = 0; 342 m->tkey = 0; 343 m->rdclass_set = 0; 344 m->querytsig = NULL; 345 } 346 347 static inline void 348 msgresetnames(dns_message_t *msg, unsigned int first_section) { 349 unsigned int i; 350 dns_name_t *name, *next_name; 351 dns_rdataset_t *rds, *next_rds; 352 353 /* 354 * Clean up name lists by calling the rdataset disassociate function. 355 */ 356 for (i = first_section; i < DNS_SECTION_MAX; i++) { 357 name = ISC_LIST_HEAD(msg->sections[i]); 358 while (name != NULL) { 359 next_name = ISC_LIST_NEXT(name, link); 360 ISC_LIST_UNLINK(msg->sections[i], name, link); 361 362 rds = ISC_LIST_HEAD(name->list); 363 while (rds != NULL) { 364 next_rds = ISC_LIST_NEXT(rds, link); 365 ISC_LIST_UNLINK(name->list, rds, link); 366 367 INSIST(dns_rdataset_isassociated(rds)); 368 dns_rdataset_disassociate(rds); 369 free(rds); 370 rds = next_rds; 371 } 372 if (dns_name_dynamic(name)) 373 dns_name_free(name); 374 free(name); 375 name = next_name; 376 } 377 } 378 } 379 380 static void 381 msgresetopt(dns_message_t *msg) 382 { 383 if (msg->opt != NULL) { 384 if (msg->opt_reserved > 0) { 385 dns_message_renderrelease(msg, msg->opt_reserved); 386 msg->opt_reserved = 0; 387 } 388 INSIST(dns_rdataset_isassociated(msg->opt)); 389 dns_rdataset_disassociate(msg->opt); 390 free(msg->opt); 391 msg->opt = NULL; 392 msg->sitok = 0; 393 msg->sitbad = 0; 394 } 395 } 396 397 static void 398 msgresetsigs(dns_message_t *msg, int replying) { 399 if (msg->sig_reserved > 0) { 400 dns_message_renderrelease(msg, msg->sig_reserved); 401 msg->sig_reserved = 0; 402 } 403 if (msg->tsig != NULL) { 404 INSIST(dns_rdataset_isassociated(msg->tsig)); 405 if (replying) { 406 INSIST(msg->querytsig == NULL); 407 msg->querytsig = msg->tsig; 408 } else { 409 dns_rdataset_disassociate(msg->tsig); 410 free(msg->tsig); 411 if (msg->querytsig != NULL) { 412 dns_rdataset_disassociate(msg->querytsig); 413 free(msg->querytsig); 414 } 415 } 416 if (dns_name_dynamic(msg->tsigname)) 417 dns_name_free(msg->tsigname); 418 free(msg->tsigname); 419 msg->tsig = NULL; 420 msg->tsigname = NULL; 421 } else if (msg->querytsig != NULL && !replying) { 422 dns_rdataset_disassociate(msg->querytsig); 423 free(msg->querytsig); 424 msg->querytsig = NULL; 425 } 426 if (msg->sig0 != NULL) { 427 INSIST(dns_rdataset_isassociated(msg->sig0)); 428 dns_rdataset_disassociate(msg->sig0); 429 free(msg->sig0); 430 if (msg->sig0name != NULL) { 431 if (dns_name_dynamic(msg->sig0name)) 432 dns_name_free(msg->sig0name); 433 free(msg->sig0name); 434 } 435 msg->sig0 = NULL; 436 msg->sig0name = NULL; 437 } 438 } 439 440 /* 441 * Free all but one (or everything) for this message. This is used by 442 * both dns_message_reset() and dns_message_destroy(). 443 */ 444 static void 445 msgreset(dns_message_t *msg, int everything) { 446 dns_msgblock_t *msgblock, *next_msgblock; 447 isc_buffer_t *dynbuf, *next_dynbuf; 448 dns_rdata_t *rdata; 449 dns_rdatalist_t *rdatalist; 450 451 msgresetnames(msg, 0); 452 msgresetopt(msg); 453 msgresetsigs(msg, 0); 454 455 /* 456 * Clean up linked lists. 457 */ 458 459 /* 460 * Run through the free lists, and just unlink anything found there. 461 * The memory isn't lost since these are part of message blocks we 462 * have allocated. 463 */ 464 rdata = ISC_LIST_HEAD(msg->freerdata); 465 while (rdata != NULL) { 466 ISC_LIST_UNLINK(msg->freerdata, rdata, link); 467 rdata = ISC_LIST_HEAD(msg->freerdata); 468 } 469 rdatalist = ISC_LIST_HEAD(msg->freerdatalist); 470 while (rdatalist != NULL) { 471 ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link); 472 rdatalist = ISC_LIST_HEAD(msg->freerdatalist); 473 } 474 475 dynbuf = ISC_LIST_HEAD(msg->scratchpad); 476 INSIST(dynbuf != NULL); 477 if (!everything) { 478 isc_buffer_clear(dynbuf); 479 dynbuf = ISC_LIST_NEXT(dynbuf, link); 480 } 481 while (dynbuf != NULL) { 482 next_dynbuf = ISC_LIST_NEXT(dynbuf, link); 483 ISC_LIST_UNLINK(msg->scratchpad, dynbuf, link); 484 isc_buffer_free(&dynbuf); 485 dynbuf = next_dynbuf; 486 } 487 488 msgblock = ISC_LIST_HEAD(msg->rdatas); 489 if (!everything && msgblock != NULL) { 490 msgblock_reset(msgblock); 491 msgblock = ISC_LIST_NEXT(msgblock, link); 492 } 493 while (msgblock != NULL) { 494 next_msgblock = ISC_LIST_NEXT(msgblock, link); 495 ISC_LIST_UNLINK(msg->rdatas, msgblock, link); 496 free(msgblock); 497 msgblock = next_msgblock; 498 } 499 500 /* 501 * rdatalists could be empty. 502 */ 503 504 msgblock = ISC_LIST_HEAD(msg->rdatalists); 505 if (!everything && msgblock != NULL) { 506 msgblock_reset(msgblock); 507 msgblock = ISC_LIST_NEXT(msgblock, link); 508 } 509 while (msgblock != NULL) { 510 next_msgblock = ISC_LIST_NEXT(msgblock, link); 511 ISC_LIST_UNLINK(msg->rdatalists, msgblock, link); 512 free(msgblock); 513 msgblock = next_msgblock; 514 } 515 516 msgblock = ISC_LIST_HEAD(msg->offsets); 517 if (!everything && msgblock != NULL) { 518 msgblock_reset(msgblock); 519 msgblock = ISC_LIST_NEXT(msgblock, link); 520 } 521 while (msgblock != NULL) { 522 next_msgblock = ISC_LIST_NEXT(msgblock, link); 523 ISC_LIST_UNLINK(msg->offsets, msgblock, link); 524 free(msgblock); 525 msgblock = next_msgblock; 526 } 527 528 if (msg->tsigkey != NULL) { 529 dns_tsigkey_detach(&msg->tsigkey); 530 msg->tsigkey = NULL; 531 } 532 533 if (msg->tsigctx != NULL) 534 dst_context_destroy(&msg->tsigctx); 535 536 if (msg->query.base != NULL) { 537 if (msg->free_query != 0) 538 free(msg->query.base); 539 msg->query.base = NULL; 540 msg->query.length = 0; 541 } 542 543 if (msg->saved.base != NULL) { 544 if (msg->free_saved != 0) 545 free(msg->saved.base); 546 msg->saved.base = NULL; 547 msg->saved.length = 0; 548 } 549 550 /* 551 * cleanup the buffer cleanup list 552 */ 553 dynbuf = ISC_LIST_HEAD(msg->cleanup); 554 while (dynbuf != NULL) { 555 next_dynbuf = ISC_LIST_NEXT(dynbuf, link); 556 ISC_LIST_UNLINK(msg->cleanup, dynbuf, link); 557 isc_buffer_free(&dynbuf); 558 dynbuf = next_dynbuf; 559 } 560 561 /* 562 * Set other bits to normal default values. 563 */ 564 if (!everything) 565 msginit(msg); 566 } 567 568 static unsigned int 569 spacefortsig(dns_tsigkey_t *key, int otherlen) { 570 isc_region_t r1, r2; 571 unsigned int x; 572 isc_result_t result; 573 574 /* 575 * The space required for an TSIG record is: 576 * 577 * n1 bytes for the name 578 * 2 bytes for the type 579 * 2 bytes for the class 580 * 4 bytes for the ttl 581 * 2 bytes for the rdlength 582 * n2 bytes for the algorithm name 583 * 6 bytes for the time signed 584 * 2 bytes for the fudge 585 * 2 bytes for the MAC size 586 * x bytes for the MAC 587 * 2 bytes for the original id 588 * 2 bytes for the error 589 * 2 bytes for the other data length 590 * y bytes for the other data (at most) 591 * --------------------------------- 592 * 26 + n1 + n2 + x + y bytes 593 */ 594 595 dns_name_toregion(&key->name, &r1); 596 dns_name_toregion(key->algorithm, &r2); 597 if (key->key == NULL) 598 x = 0; 599 else { 600 result = dst_key_sigsize(key->key, &x); 601 if (result != ISC_R_SUCCESS) 602 x = 0; 603 } 604 return (26 + r1.length + r2.length + x + otherlen); 605 } 606 607 isc_result_t 608 dns_message_create(unsigned int intent, dns_message_t **msgp) 609 { 610 dns_message_t *m; 611 isc_result_t result; 612 isc_buffer_t *dynbuf; 613 unsigned int i; 614 615 REQUIRE(msgp != NULL); 616 REQUIRE(*msgp == NULL); 617 REQUIRE(intent == DNS_MESSAGE_INTENTPARSE 618 || intent == DNS_MESSAGE_INTENTRENDER); 619 620 m = malloc(sizeof(dns_message_t)); 621 if (m == NULL) 622 return (ISC_R_NOMEMORY); 623 624 /* 625 * No allocations until further notice. Just initialize all lists 626 * and other members that are freed in the cleanup phase here. 627 */ 628 629 m->from_to_wire = intent; 630 msginit(m); 631 632 for (i = 0; i < DNS_SECTION_MAX; i++) 633 ISC_LIST_INIT(m->sections[i]); 634 635 ISC_LIST_INIT(m->scratchpad); 636 ISC_LIST_INIT(m->cleanup); 637 ISC_LIST_INIT(m->rdatas); 638 ISC_LIST_INIT(m->rdatalists); 639 ISC_LIST_INIT(m->offsets); 640 ISC_LIST_INIT(m->freerdata); 641 ISC_LIST_INIT(m->freerdatalist); 642 643 /* 644 * Ok, it is safe to allocate (and then "goto cleanup" if failure) 645 */ 646 647 dynbuf = NULL; 648 result = isc_buffer_allocate(&dynbuf, SCRATCHPAD_SIZE); 649 if (result != ISC_R_SUCCESS) 650 goto cleanup; 651 ISC_LIST_APPEND(m->scratchpad, dynbuf, link); 652 653 m->cctx = NULL; 654 655 *msgp = m; 656 return (ISC_R_SUCCESS); 657 658 /* 659 * Cleanup for error returns. 660 */ 661 cleanup: 662 dynbuf = ISC_LIST_HEAD(m->scratchpad); 663 if (dynbuf != NULL) { 664 ISC_LIST_UNLINK(m->scratchpad, dynbuf, link); 665 isc_buffer_free(&dynbuf); 666 } 667 free(m); 668 669 return (ISC_R_NOMEMORY); 670 } 671 672 void 673 dns_message_destroy(dns_message_t **msgp) { 674 dns_message_t *msg; 675 676 REQUIRE(msgp != NULL); 677 678 msg = *msgp; 679 *msgp = NULL; 680 681 msgreset(msg, 1); 682 free(msg); 683 } 684 685 static isc_result_t 686 findname(dns_name_t **foundname, dns_name_t *target, 687 dns_namelist_t *section) 688 { 689 dns_name_t *curr; 690 691 for (curr = ISC_LIST_TAIL(*section); 692 curr != NULL; 693 curr = ISC_LIST_PREV(curr, link)) { 694 if (dns_name_equal(curr, target)) { 695 if (foundname != NULL) 696 *foundname = curr; 697 return (ISC_R_SUCCESS); 698 } 699 } 700 701 return (ISC_R_NOTFOUND); 702 } 703 704 isc_result_t 705 dns_message_find(dns_name_t *name, dns_rdataclass_t rdclass, 706 dns_rdatatype_t type, dns_rdatatype_t covers, 707 dns_rdataset_t **rdataset) 708 { 709 dns_rdataset_t *curr; 710 711 REQUIRE(name != NULL); 712 REQUIRE(rdataset == NULL || *rdataset == NULL); 713 714 for (curr = ISC_LIST_TAIL(name->list); 715 curr != NULL; 716 curr = ISC_LIST_PREV(curr, link)) { 717 if (curr->rdclass == rdclass && 718 curr->type == type && curr->covers == covers) { 719 if (rdataset != NULL) 720 *rdataset = curr; 721 return (ISC_R_SUCCESS); 722 } 723 } 724 725 return (ISC_R_NOTFOUND); 726 } 727 728 isc_result_t 729 dns_message_findtype(dns_name_t *name, dns_rdatatype_t type, 730 dns_rdatatype_t covers, dns_rdataset_t **rdataset) 731 { 732 dns_rdataset_t *curr; 733 734 REQUIRE(name != NULL); 735 REQUIRE(rdataset == NULL || *rdataset == NULL); 736 737 for (curr = ISC_LIST_TAIL(name->list); 738 curr != NULL; 739 curr = ISC_LIST_PREV(curr, link)) { 740 if (curr->type == type && curr->covers == covers) { 741 if (rdataset != NULL) 742 *rdataset = curr; 743 return (ISC_R_SUCCESS); 744 } 745 } 746 747 return (ISC_R_NOTFOUND); 748 } 749 750 /* 751 * Read a name from buffer "source". 752 */ 753 static isc_result_t 754 getname(dns_name_t *name, isc_buffer_t *source, dns_message_t *msg, 755 dns_decompress_t *dctx) 756 { 757 isc_buffer_t *scratch; 758 isc_result_t result; 759 unsigned int tries; 760 761 scratch = currentbuffer(msg); 762 763 /* 764 * First try: use current buffer. 765 * Second try: allocate a new buffer and use that. 766 */ 767 tries = 0; 768 while (tries < 2) { 769 result = dns_name_fromwire(name, source, dctx, 0, 770 scratch); 771 772 if (result == ISC_R_NOSPACE) { 773 tries++; 774 775 result = newbuffer(msg, SCRATCHPAD_SIZE); 776 if (result != ISC_R_SUCCESS) 777 return (result); 778 779 scratch = currentbuffer(msg); 780 dns_name_reset(name); 781 } else { 782 return (result); 783 } 784 } 785 786 INSIST(0); /* Cannot get here... */ 787 return (ISC_R_UNEXPECTED); 788 } 789 790 static isc_result_t 791 getrdata(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, 792 dns_rdataclass_t rdclass, dns_rdatatype_t rdtype, 793 unsigned int rdatalen, dns_rdata_t *rdata) 794 { 795 isc_buffer_t *scratch; 796 isc_result_t result; 797 unsigned int tries; 798 unsigned int trysize; 799 800 scratch = currentbuffer(msg); 801 802 isc_buffer_setactive(source, rdatalen); 803 804 /* 805 * First try: use current buffer. 806 * Second try: allocate a new buffer of size 807 * max(SCRATCHPAD_SIZE, 2 * compressed_rdatalen) 808 * (the data will fit if it was not more than 50% compressed) 809 * Subsequent tries: double buffer size on each try. 810 */ 811 tries = 0; 812 trysize = 0; 813 /* XXX possibly change this to a while (tries < 2) loop */ 814 for (;;) { 815 result = dns_rdata_fromwire(rdata, rdclass, rdtype, 816 source, dctx, 0, 817 scratch); 818 819 if (result == ISC_R_NOSPACE) { 820 if (tries == 0) { 821 trysize = 2 * rdatalen; 822 if (trysize < SCRATCHPAD_SIZE) 823 trysize = SCRATCHPAD_SIZE; 824 } else { 825 INSIST(trysize != 0); 826 if (trysize >= 65535) 827 return (ISC_R_NOSPACE); 828 /* XXX DNS_R_RRTOOLONG? */ 829 trysize *= 2; 830 } 831 tries++; 832 result = newbuffer(msg, trysize); 833 if (result != ISC_R_SUCCESS) 834 return (result); 835 836 scratch = currentbuffer(msg); 837 } else { 838 return (result); 839 } 840 } 841 } 842 843 #define DO_FORMERR \ 844 do { \ 845 if (best_effort) \ 846 seen_problem = 1; \ 847 else { \ 848 result = DNS_R_FORMERR; \ 849 goto cleanup; \ 850 } \ 851 } while (0) 852 853 static isc_result_t 854 getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, 855 unsigned int options) 856 { 857 isc_region_t r; 858 unsigned int count; 859 dns_name_t *name; 860 dns_name_t *name2; 861 dns_offsets_t *offsets; 862 dns_rdataset_t *rdataset; 863 dns_rdatalist_t *rdatalist; 864 isc_result_t result; 865 dns_rdatatype_t rdtype; 866 dns_rdataclass_t rdclass; 867 dns_namelist_t *section; 868 int free_name; 869 int best_effort; 870 int seen_problem; 871 872 section = &msg->sections[DNS_SECTION_QUESTION]; 873 874 best_effort = options & DNS_MESSAGEPARSE_BESTEFFORT; 875 seen_problem = 0; 876 877 name = NULL; 878 rdataset = NULL; 879 rdatalist = NULL; 880 881 for (count = 0; count < msg->counts[DNS_SECTION_QUESTION]; count++) { 882 name = malloc(sizeof(dns_name_t)); 883 if (name == NULL) 884 return (ISC_R_NOMEMORY); 885 free_name = 1; 886 887 offsets = newoffsets(msg); 888 if (offsets == NULL) { 889 result = ISC_R_NOMEMORY; 890 goto cleanup; 891 } 892 dns_name_init(name, *offsets); 893 894 /* 895 * Parse the name out of this packet. 896 */ 897 isc_buffer_remainingregion(source, &r); 898 isc_buffer_setactive(source, r.length); 899 result = getname(name, source, msg, dctx); 900 if (result != ISC_R_SUCCESS) 901 goto cleanup; 902 903 /* 904 * Run through the section, looking to see if this name 905 * is already there. If it is found, put back the allocated 906 * name since we no longer need it, and set our name pointer 907 * to point to the name we found. 908 */ 909 result = findname(&name2, name, section); 910 911 /* 912 * If it is the first name in the section, accept it. 913 * 914 * If it is not, but is not the same as the name already 915 * in the question section, append to the section. Note that 916 * here in the question section this is illegal, so return 917 * FORMERR. In the future, check the opcode to see if 918 * this should be legal or not. In either case we no longer 919 * need this name pointer. 920 */ 921 if (result != ISC_R_SUCCESS) { 922 if (!ISC_LIST_EMPTY(*section)) 923 DO_FORMERR; 924 ISC_LIST_APPEND(*section, name, link); 925 free_name = 0; 926 } else { 927 free(name); 928 name = name2; 929 name2 = NULL; 930 free_name = 0; 931 } 932 933 /* 934 * Get type and class. 935 */ 936 isc_buffer_remainingregion(source, &r); 937 if (r.length < 4) { 938 result = ISC_R_UNEXPECTEDEND; 939 goto cleanup; 940 } 941 rdtype = isc_buffer_getuint16(source); 942 rdclass = isc_buffer_getuint16(source); 943 944 /* 945 * If this class is different than the one we already read, 946 * this is an error. 947 */ 948 if (msg->rdclass_set == 0) { 949 msg->rdclass = rdclass; 950 msg->rdclass_set = 1; 951 } else if (msg->rdclass != rdclass) 952 DO_FORMERR; 953 954 /* 955 * Is this a TKEY query? 956 */ 957 if (rdtype == dns_rdatatype_tkey) 958 msg->tkey = 1; 959 960 /* 961 * Can't ask the same question twice. 962 */ 963 result = dns_message_find(name, rdclass, rdtype, 0, NULL); 964 if (result == ISC_R_SUCCESS) 965 DO_FORMERR; 966 967 /* 968 * Allocate a new rdatalist. 969 */ 970 rdatalist = newrdatalist(msg); 971 if (rdatalist == NULL) { 972 result = ISC_R_NOMEMORY; 973 goto cleanup; 974 } 975 rdataset = malloc(sizeof(dns_rdataset_t)); 976 if (rdataset == NULL) { 977 result = ISC_R_NOMEMORY; 978 goto cleanup; 979 } 980 981 /* 982 * Convert rdatalist to rdataset, and attach the latter to 983 * the name. 984 */ 985 rdatalist->type = rdtype; 986 rdatalist->covers = 0; 987 rdatalist->rdclass = rdclass; 988 rdatalist->ttl = 0; 989 ISC_LIST_INIT(rdatalist->rdata); 990 991 dns_rdataset_init(rdataset); 992 result = dns_rdatalist_tordataset(rdatalist, rdataset); 993 if (result != ISC_R_SUCCESS) 994 goto cleanup; 995 996 rdataset->attributes |= DNS_RDATASETATTR_QUESTION; 997 998 ISC_LIST_APPEND(name->list, rdataset, link); 999 rdataset = NULL; 1000 } 1001 1002 if (seen_problem) 1003 return (DNS_R_RECOVERABLE); 1004 return (ISC_R_SUCCESS); 1005 1006 cleanup: 1007 if (rdataset != NULL) { 1008 INSIST(!dns_rdataset_isassociated(rdataset)); 1009 free(rdataset); 1010 } 1011 if (free_name) 1012 free(name); 1013 1014 return (result); 1015 } 1016 1017 static int 1018 update(dns_section_t section, dns_rdataclass_t rdclass) { 1019 if (section == DNS_SECTION_PREREQUISITE) 1020 return (rdclass == dns_rdataclass_any || 1021 rdclass == dns_rdataclass_none); 1022 if (section == DNS_SECTION_UPDATE) 1023 return (rdclass == dns_rdataclass_any); 1024 return (0); 1025 } 1026 1027 static isc_result_t 1028 getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, 1029 dns_section_t sectionid, unsigned int options) 1030 { 1031 isc_region_t r; 1032 unsigned int count, rdatalen; 1033 dns_name_t *name = NULL; 1034 dns_offsets_t *offsets; 1035 dns_rdataset_t *rdataset; 1036 dns_rdatalist_t *rdatalist; 1037 isc_result_t result; 1038 dns_rdatatype_t rdtype, covers; 1039 dns_rdataclass_t rdclass; 1040 dns_rdata_t *rdata; 1041 dns_ttl_t ttl; 1042 dns_namelist_t *section; 1043 int free_name = 0, free_rdataset = 0; 1044 int best_effort, seen_problem; 1045 int issigzero; 1046 1047 best_effort = options & DNS_MESSAGEPARSE_BESTEFFORT; 1048 seen_problem = 0; 1049 1050 section = &msg->sections[sectionid]; 1051 1052 for (count = 0; count < msg->counts[sectionid]; count++) { 1053 int recstart = source->current; 1054 free_rdataset = 0; 1055 1056 name = malloc(sizeof(dns_name_t)); 1057 if (name == NULL) 1058 return (ISC_R_NOMEMORY); 1059 free_name = 1; 1060 1061 offsets = newoffsets(msg); 1062 if (offsets == NULL) { 1063 result = ISC_R_NOMEMORY; 1064 goto cleanup; 1065 } 1066 dns_name_init(name, *offsets); 1067 1068 /* 1069 * Parse the name out of this packet. 1070 */ 1071 isc_buffer_remainingregion(source, &r); 1072 isc_buffer_setactive(source, r.length); 1073 result = getname(name, source, msg, dctx); 1074 if (result != ISC_R_SUCCESS) 1075 goto cleanup; 1076 1077 /* 1078 * Get type, class, ttl, and rdatalen. Verify that at least 1079 * rdatalen bytes remain. (Some of this is deferred to 1080 * later.) 1081 */ 1082 isc_buffer_remainingregion(source, &r); 1083 if (r.length < 2 + 2 + 4 + 2) { 1084 result = ISC_R_UNEXPECTEDEND; 1085 goto cleanup; 1086 } 1087 rdtype = isc_buffer_getuint16(source); 1088 rdclass = isc_buffer_getuint16(source); 1089 1090 /* 1091 * If there was no question section, we may not yet have 1092 * established a class. Do so now. 1093 */ 1094 if (msg->rdclass_set == 0 && 1095 rdtype != dns_rdatatype_opt && /* class is UDP SIZE */ 1096 rdtype != dns_rdatatype_tsig && /* class is ANY */ 1097 rdtype != dns_rdatatype_tkey) { /* class is undefined */ 1098 msg->rdclass = rdclass; 1099 msg->rdclass_set = 1; 1100 } 1101 1102 /* 1103 * If this class is different than the one in the question 1104 * section, bail. 1105 */ 1106 if (msg->opcode != dns_opcode_update 1107 && rdtype != dns_rdatatype_tsig 1108 && rdtype != dns_rdatatype_opt 1109 && rdtype != dns_rdatatype_key /* in a TKEY query */ 1110 && rdtype != dns_rdatatype_sig /* SIG(0) */ 1111 && rdtype != dns_rdatatype_tkey /* Win2000 TKEY */ 1112 && msg->rdclass != dns_rdataclass_any 1113 && msg->rdclass != rdclass) 1114 DO_FORMERR; 1115 1116 /* 1117 * If this is not a TKEY query/response then the KEY 1118 * record's class needs to match. 1119 */ 1120 if (msg->opcode != dns_opcode_update && !msg->tkey && 1121 rdtype == dns_rdatatype_key && 1122 msg->rdclass != dns_rdataclass_any && 1123 msg->rdclass != rdclass) 1124 DO_FORMERR; 1125 1126 /* 1127 * Special type handling for TSIG, OPT, and TKEY. 1128 */ 1129 if (rdtype == dns_rdatatype_tsig) { 1130 /* 1131 * If it is a tsig, verify that it is in the 1132 * additional data section. 1133 */ 1134 if (sectionid != DNS_SECTION_ADDITIONAL || 1135 rdclass != dns_rdataclass_any || 1136 count != msg->counts[sectionid] - 1) 1137 DO_FORMERR; 1138 msg->sigstart = recstart; 1139 } else if (rdtype == dns_rdatatype_opt) { 1140 /* 1141 * The name of an OPT record must be ".", it 1142 * must be in the additional data section, and 1143 * it must be the first OPT we've seen. 1144 */ 1145 if (!dns_name_equal(dns_rootname, name) || 1146 sectionid != DNS_SECTION_ADDITIONAL || 1147 msg->opt != NULL) 1148 DO_FORMERR; 1149 } else if (rdtype == dns_rdatatype_tkey) { 1150 /* 1151 * A TKEY must be in the additional section if this 1152 * is a query, and the answer section if this is a 1153 * response. Unless it's a Win2000 client. 1154 * 1155 * Its class is ignored. 1156 */ 1157 dns_section_t tkeysection; 1158 1159 if ((msg->flags & DNS_MESSAGEFLAG_QR) == 0) 1160 tkeysection = DNS_SECTION_ADDITIONAL; 1161 else 1162 tkeysection = DNS_SECTION_ANSWER; 1163 if (sectionid != tkeysection && 1164 sectionid != DNS_SECTION_ANSWER) 1165 DO_FORMERR; 1166 } 1167 1168 /* 1169 * ... now get ttl and rdatalen, and check buffer. 1170 */ 1171 ttl = isc_buffer_getuint32(source); 1172 rdatalen = isc_buffer_getuint16(source); 1173 r.length -= (2 + 2 + 4 + 2); 1174 if (r.length < rdatalen) { 1175 result = ISC_R_UNEXPECTEDEND; 1176 goto cleanup; 1177 } 1178 1179 /* 1180 * Read the rdata from the wire format. Interpret the 1181 * rdata according to its actual class, even if it had a 1182 * DynDNS meta-class in the packet (unless this is a TSIG). 1183 * Then put the meta-class back into the finished rdata. 1184 */ 1185 rdata = newrdata(msg); 1186 if (rdata == NULL) { 1187 result = ISC_R_NOMEMORY; 1188 goto cleanup; 1189 } 1190 if (msg->opcode == dns_opcode_update && 1191 update(sectionid, rdclass)) { 1192 if (rdatalen != 0) { 1193 result = DNS_R_FORMERR; 1194 goto cleanup; 1195 } 1196 /* 1197 * When the rdata is empty, the data pointer is 1198 * never dereferenced, but it must still be non-NULL. 1199 * Casting 1 rather than "" avoids warnings about 1200 * discarding the const attribute of a string, 1201 * for compilers that would warn about such things. 1202 */ 1203 rdata->data = (unsigned char *)1; 1204 rdata->length = 0; 1205 rdata->rdclass = rdclass; 1206 rdata->type = rdtype; 1207 rdata->flags = DNS_RDATA_UPDATE; 1208 result = ISC_R_SUCCESS; 1209 } else if (rdclass == dns_rdataclass_none && 1210 msg->opcode == dns_opcode_update && 1211 sectionid == DNS_SECTION_UPDATE) { 1212 result = getrdata(source, msg, dctx, msg->rdclass, 1213 rdtype, rdatalen, rdata); 1214 } else 1215 result = getrdata(source, msg, dctx, rdclass, 1216 rdtype, rdatalen, rdata); 1217 if (result != ISC_R_SUCCESS) 1218 goto cleanup; 1219 rdata->rdclass = rdclass; 1220 issigzero = 0; 1221 if (rdtype == dns_rdatatype_rrsig && 1222 rdata->flags == 0) { 1223 covers = dns_rdata_covers(rdata); 1224 if (covers == 0) 1225 DO_FORMERR; 1226 } else if (rdtype == dns_rdatatype_sig /* SIG(0) */ && 1227 rdata->flags == 0) { 1228 covers = dns_rdata_covers(rdata); 1229 if (covers == 0) { 1230 if (sectionid != DNS_SECTION_ADDITIONAL || 1231 count != msg->counts[sectionid] - 1) 1232 DO_FORMERR; 1233 msg->sigstart = recstart; 1234 issigzero = 1; 1235 } else { 1236 if (msg->rdclass != dns_rdataclass_any && 1237 msg->rdclass != rdclass) 1238 DO_FORMERR; 1239 } 1240 } else 1241 covers = 0; 1242 1243 /* 1244 * Check the ownername of NSEC3 records 1245 */ 1246 if (rdtype == dns_rdatatype_nsec3 && 1247 !dns_rdata_checkowner_nsec3(name, msg->rdclass, rdtype, 1248 0)) { 1249 result = DNS_R_BADOWNERNAME; 1250 goto cleanup; 1251 } 1252 1253 if (rdtype != dns_rdatatype_opt && 1254 rdtype != dns_rdatatype_tsig && !issigzero) { 1255 ISC_LIST_APPEND(*section, name, link); 1256 free_name = 0; 1257 } 1258 1259 rdataset = malloc(sizeof(dns_rdataset_t)); 1260 if (rdataset == NULL) { 1261 result = ISC_R_NOMEMORY; 1262 goto cleanup; 1263 } 1264 free_rdataset = 1; 1265 1266 rdatalist = newrdatalist(msg); 1267 if (rdatalist == NULL) { 1268 result = ISC_R_NOMEMORY; 1269 goto cleanup; 1270 } 1271 1272 rdatalist->type = rdtype; 1273 rdatalist->covers = covers; 1274 rdatalist->rdclass = rdclass; 1275 rdatalist->ttl = ttl; 1276 ISC_LIST_INIT(rdatalist->rdata); 1277 1278 dns_rdataset_init(rdataset); 1279 RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, 1280 rdataset) 1281 == ISC_R_SUCCESS); 1282 1283 if (rdtype != dns_rdatatype_opt && 1284 rdtype != dns_rdatatype_tsig && 1285 !issigzero) 1286 { 1287 ISC_LIST_APPEND(name->list, rdataset, link); 1288 free_rdataset = 0; 1289 } 1290 1291 /* 1292 * Minimize TTLs. 1293 * 1294 * Section 5.2 of RFC2181 says we should drop 1295 * nonauthoritative rrsets where the TTLs differ, but we 1296 * currently treat them the as if they were authoritative and 1297 * minimize them. 1298 */ 1299 if (ttl < rdataset->ttl) 1300 rdataset->ttl = ttl; 1301 1302 /* Append this rdata to the rdataset. */ 1303 dns_rdatalist_fromrdataset(rdataset, &rdatalist); 1304 ISC_LIST_APPEND(rdatalist->rdata, rdata, link); 1305 1306 /* 1307 * If this is an OPT, SIG(0) or TSIG record, remember it. 1308 * Also, set the extended rcode for TSIG. 1309 * 1310 * Note msg->opt, msg->sig0 and msg->tsig will only be 1311 * already set if best-effort parsing is enabled otherwise 1312 * there will only be at most one of each. 1313 */ 1314 if (rdtype == dns_rdatatype_opt && msg->opt == NULL) { 1315 dns_rcode_t ercode; 1316 1317 msg->opt = rdataset; 1318 rdataset = NULL; 1319 free_rdataset = 0; 1320 ercode = (dns_rcode_t) 1321 ((msg->opt->ttl & DNS_MESSAGE_EDNSRCODE_MASK) 1322 >> 20); 1323 msg->rcode |= ercode; 1324 free(name); 1325 free_name = 0; 1326 } else if (issigzero && msg->sig0 == NULL) { 1327 msg->sig0 = rdataset; 1328 msg->sig0name = name; 1329 rdataset = NULL; 1330 free_rdataset = 0; 1331 free_name = 0; 1332 } else if (rdtype == dns_rdatatype_tsig && msg->tsig == NULL) { 1333 msg->tsig = rdataset; 1334 msg->tsigname = name; 1335 /* Windows doesn't like TSIG names to be compressed. */ 1336 msg->tsigname->attributes |= DNS_NAMEATTR_NOCOMPRESS; 1337 rdataset = NULL; 1338 free_rdataset = 0; 1339 free_name = 0; 1340 } 1341 1342 if (seen_problem) { 1343 if (free_name) 1344 free(name); 1345 if (free_rdataset) 1346 free(rdataset); 1347 free_name = free_rdataset = 0; 1348 } 1349 INSIST(!free_name); 1350 INSIST(!free_rdataset); 1351 } 1352 1353 if (seen_problem) 1354 return (DNS_R_RECOVERABLE); 1355 return (ISC_R_SUCCESS); 1356 1357 cleanup: 1358 if (free_name) 1359 free(name); 1360 if (free_rdataset) 1361 free(rdataset); 1362 1363 return (result); 1364 } 1365 1366 isc_result_t 1367 dns_message_parse(dns_message_t *msg, isc_buffer_t *source, 1368 unsigned int options) 1369 { 1370 isc_region_t r; 1371 dns_decompress_t dctx; 1372 isc_result_t ret; 1373 uint16_t tmpflags; 1374 isc_buffer_t origsource; 1375 int seen_problem; 1376 int ignore_tc; 1377 1378 REQUIRE(source != NULL); 1379 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE); 1380 1381 seen_problem = 0; 1382 ignore_tc = options & DNS_MESSAGEPARSE_IGNORETRUNCATION; 1383 1384 origsource = *source; 1385 1386 msg->header_ok = 0; 1387 msg->question_ok = 0; 1388 1389 isc_buffer_remainingregion(source, &r); 1390 if (r.length < DNS_MESSAGE_HEADERLEN) 1391 return (ISC_R_UNEXPECTEDEND); 1392 1393 msg->id = isc_buffer_getuint16(source); 1394 tmpflags = isc_buffer_getuint16(source); 1395 msg->opcode = ((tmpflags & DNS_MESSAGE_OPCODE_MASK) 1396 >> DNS_MESSAGE_OPCODE_SHIFT); 1397 msg->rcode = (dns_rcode_t)(tmpflags & DNS_MESSAGE_RCODE_MASK); 1398 msg->flags = (tmpflags & DNS_MESSAGE_FLAG_MASK); 1399 msg->counts[DNS_SECTION_QUESTION] = isc_buffer_getuint16(source); 1400 msg->counts[DNS_SECTION_ANSWER] = isc_buffer_getuint16(source); 1401 msg->counts[DNS_SECTION_AUTHORITY] = isc_buffer_getuint16(source); 1402 msg->counts[DNS_SECTION_ADDITIONAL] = isc_buffer_getuint16(source); 1403 1404 msg->header_ok = 1; 1405 msg->state = DNS_SECTION_QUESTION; 1406 1407 /* 1408 * -1 means no EDNS. 1409 */ 1410 dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_ANY); 1411 1412 dns_decompress_setmethods(&dctx, DNS_COMPRESS_GLOBAL14); 1413 1414 ret = getquestions(source, msg, &dctx, options); 1415 if (ret == ISC_R_UNEXPECTEDEND && ignore_tc) 1416 goto truncated; 1417 if (ret == DNS_R_RECOVERABLE) { 1418 seen_problem = 1; 1419 ret = ISC_R_SUCCESS; 1420 } 1421 if (ret != ISC_R_SUCCESS) 1422 return (ret); 1423 msg->question_ok = 1; 1424 1425 ret = getsection(source, msg, &dctx, DNS_SECTION_ANSWER, options); 1426 if (ret == ISC_R_UNEXPECTEDEND && ignore_tc) 1427 goto truncated; 1428 if (ret == DNS_R_RECOVERABLE) { 1429 seen_problem = 1; 1430 ret = ISC_R_SUCCESS; 1431 } 1432 if (ret != ISC_R_SUCCESS) 1433 return (ret); 1434 1435 ret = getsection(source, msg, &dctx, DNS_SECTION_AUTHORITY, options); 1436 if (ret == ISC_R_UNEXPECTEDEND && ignore_tc) 1437 goto truncated; 1438 if (ret == DNS_R_RECOVERABLE) { 1439 seen_problem = 1; 1440 ret = ISC_R_SUCCESS; 1441 } 1442 if (ret != ISC_R_SUCCESS) 1443 return (ret); 1444 1445 ret = getsection(source, msg, &dctx, DNS_SECTION_ADDITIONAL, options); 1446 if (ret == ISC_R_UNEXPECTEDEND && ignore_tc) 1447 goto truncated; 1448 if (ret == DNS_R_RECOVERABLE) { 1449 seen_problem = 1; 1450 ret = ISC_R_SUCCESS; 1451 } 1452 if (ret != ISC_R_SUCCESS) 1453 return (ret); 1454 1455 isc_buffer_remainingregion(source, &r); 1456 if (r.length != 0) { 1457 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL, 1458 DNS_LOGMODULE_MESSAGE, ISC_LOG_DEBUG(3), 1459 "message has %u byte(s) of trailing garbage", 1460 r.length); 1461 } 1462 1463 truncated: 1464 isc_buffer_usedregion(&origsource, &msg->saved); 1465 1466 if (ret == ISC_R_UNEXPECTEDEND && ignore_tc) 1467 return (DNS_R_RECOVERABLE); 1468 if (seen_problem) 1469 return (DNS_R_RECOVERABLE); 1470 return (ISC_R_SUCCESS); 1471 } 1472 1473 isc_result_t 1474 dns_message_renderbegin(dns_message_t *msg, dns_compress_t *cctx, 1475 isc_buffer_t *buffer) 1476 { 1477 isc_region_t r; 1478 1479 REQUIRE(buffer != NULL); 1480 REQUIRE(msg->buffer == NULL); 1481 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER); 1482 1483 msg->cctx = cctx; 1484 1485 /* 1486 * Erase the contents of this buffer. 1487 */ 1488 isc_buffer_clear(buffer); 1489 1490 /* 1491 * Make certain there is enough for at least the header in this 1492 * buffer. 1493 */ 1494 isc_buffer_availableregion(buffer, &r); 1495 if (r.length < DNS_MESSAGE_HEADERLEN) 1496 return (ISC_R_NOSPACE); 1497 1498 if (r.length - DNS_MESSAGE_HEADERLEN < msg->reserved) 1499 return (ISC_R_NOSPACE); 1500 1501 /* 1502 * Reserve enough space for the header in this buffer. 1503 */ 1504 isc_buffer_add(buffer, DNS_MESSAGE_HEADERLEN); 1505 1506 msg->buffer = buffer; 1507 1508 return (ISC_R_SUCCESS); 1509 } 1510 1511 void 1512 dns_message_renderrelease(dns_message_t *msg, unsigned int space) { 1513 REQUIRE(space <= msg->reserved); 1514 1515 msg->reserved -= space; 1516 } 1517 1518 isc_result_t 1519 dns_message_renderreserve(dns_message_t *msg, unsigned int space) { 1520 isc_region_t r; 1521 1522 if (msg->buffer != NULL) { 1523 isc_buffer_availableregion(msg->buffer, &r); 1524 if (r.length < (space + msg->reserved)) 1525 return (ISC_R_NOSPACE); 1526 } 1527 1528 msg->reserved += space; 1529 1530 return (ISC_R_SUCCESS); 1531 } 1532 1533 static inline int 1534 wrong_priority(dns_rdataset_t *rds, int pass) { 1535 int pass_needed; 1536 1537 /* 1538 * If we are not rendering class IN, this ordering is bogus. 1539 */ 1540 if (rds->rdclass != dns_rdataclass_in) 1541 return (0); 1542 1543 switch (rds->type) { 1544 case dns_rdatatype_a: 1545 case dns_rdatatype_aaaa: 1546 pass_needed = 3; 1547 break; 1548 case dns_rdatatype_rrsig: 1549 case dns_rdatatype_dnskey: 1550 pass_needed = 2; 1551 break; 1552 default: 1553 pass_needed = 1; 1554 } 1555 1556 if (pass_needed >= pass) 1557 return (0); 1558 1559 return (1); 1560 } 1561 1562 static isc_result_t 1563 renderset(dns_rdataset_t *rdataset, dns_name_t *owner_name, 1564 dns_compress_t *cctx, isc_buffer_t *target, 1565 unsigned int reserved, unsigned int *countp) 1566 { 1567 isc_result_t result; 1568 1569 /* 1570 * Shrink the space in the buffer by the reserved amount. 1571 */ 1572 if (target->length - target->used < reserved) 1573 return (ISC_R_NOSPACE); 1574 1575 target->length -= reserved; 1576 result = dns_rdataset_towire(rdataset, owner_name, 1577 cctx, target, countp); 1578 target->length += reserved; 1579 1580 return (result); 1581 } 1582 1583 static void 1584 maybe_clear_ad(dns_message_t *msg, dns_section_t sectionid) { 1585 if (msg->counts[sectionid] == 0 && 1586 (sectionid == DNS_SECTION_ANSWER || 1587 (sectionid == DNS_SECTION_AUTHORITY && 1588 msg->counts[DNS_SECTION_ANSWER] == 0))) 1589 msg->flags &= ~DNS_MESSAGEFLAG_AD; 1590 } 1591 1592 isc_result_t 1593 dns_message_rendersection(dns_message_t *msg, dns_section_t sectionid) 1594 { 1595 dns_namelist_t *section; 1596 dns_name_t *name, *next_name; 1597 dns_rdataset_t *rdataset, *next_rdataset; 1598 unsigned int count, total; 1599 isc_result_t result; 1600 isc_buffer_t st; /* for rollbacks */ 1601 int pass; 1602 1603 REQUIRE(msg->buffer != NULL); 1604 REQUIRE(VALID_NAMED_SECTION(sectionid)); 1605 1606 section = &msg->sections[sectionid]; 1607 1608 if (sectionid == DNS_SECTION_ADDITIONAL) 1609 pass = 3; 1610 else 1611 pass = 1; 1612 1613 /* 1614 * Shrink the space in the buffer by the reserved amount. 1615 */ 1616 if (msg->buffer->length - msg->buffer->used < msg->reserved) 1617 return (ISC_R_NOSPACE); 1618 msg->buffer->length -= msg->reserved; 1619 1620 total = 0; 1621 1622 do { 1623 name = ISC_LIST_HEAD(*section); 1624 if (name == NULL) { 1625 msg->buffer->length += msg->reserved; 1626 msg->counts[sectionid] += total; 1627 return (ISC_R_SUCCESS); 1628 } 1629 1630 while (name != NULL) { 1631 next_name = ISC_LIST_NEXT(name, link); 1632 1633 rdataset = ISC_LIST_HEAD(name->list); 1634 while (rdataset != NULL) { 1635 next_rdataset = ISC_LIST_NEXT(rdataset, link); 1636 1637 if ((rdataset->attributes & 1638 DNS_RDATASETATTR_RENDERED) != 0) 1639 goto next; 1640 1641 if ((sectionid == DNS_SECTION_ADDITIONAL) 1642 && wrong_priority(rdataset, pass)) 1643 goto next; 1644 1645 st = *(msg->buffer); 1646 1647 count = 0; 1648 result = dns_rdataset_towiresorted( 1649 rdataset, 1650 name, 1651 msg->cctx, 1652 msg->buffer, 1653 &count); 1654 1655 total += count; 1656 1657 /* 1658 * If out of space, record stats on what we 1659 * rendered so far, and return that status. 1660 * 1661 */ 1662 if (result != ISC_R_SUCCESS) { 1663 INSIST(st.used < 65536); 1664 dns_compress_rollback(msg->cctx, 1665 (uint16_t)st.used); 1666 *(msg->buffer) = st; /* rollback */ 1667 msg->buffer->length += msg->reserved; 1668 msg->counts[sectionid] += total; 1669 maybe_clear_ad(msg, sectionid); 1670 return (result); 1671 } 1672 1673 /* 1674 * If we have rendered non-validated data, 1675 * ensure that the AD bit is not set. 1676 */ 1677 if ((sectionid == DNS_SECTION_ANSWER || 1678 sectionid == DNS_SECTION_AUTHORITY)) 1679 msg->flags &= ~DNS_MESSAGEFLAG_AD; 1680 1681 rdataset->attributes |= 1682 DNS_RDATASETATTR_RENDERED; 1683 1684 next: 1685 rdataset = next_rdataset; 1686 } 1687 1688 name = next_name; 1689 } 1690 } while (--pass != 0); 1691 1692 msg->buffer->length += msg->reserved; 1693 msg->counts[sectionid] += total; 1694 1695 return (ISC_R_SUCCESS); 1696 } 1697 1698 void 1699 dns_message_renderheader(dns_message_t *msg, isc_buffer_t *target) { 1700 uint16_t tmp; 1701 isc_region_t r; 1702 1703 REQUIRE(target != NULL); 1704 1705 isc_buffer_availableregion(target, &r); 1706 REQUIRE(r.length >= DNS_MESSAGE_HEADERLEN); 1707 1708 isc_buffer_putuint16(target, msg->id); 1709 1710 tmp = ((msg->opcode << DNS_MESSAGE_OPCODE_SHIFT) 1711 & DNS_MESSAGE_OPCODE_MASK); 1712 tmp |= (msg->rcode & DNS_MESSAGE_RCODE_MASK); 1713 tmp |= (msg->flags & DNS_MESSAGE_FLAG_MASK); 1714 1715 INSIST(msg->counts[DNS_SECTION_QUESTION] < 65536 && 1716 msg->counts[DNS_SECTION_ANSWER] < 65536 && 1717 msg->counts[DNS_SECTION_AUTHORITY] < 65536 && 1718 msg->counts[DNS_SECTION_ADDITIONAL] < 65536); 1719 1720 isc_buffer_putuint16(target, tmp); 1721 isc_buffer_putuint16(target, 1722 (uint16_t)msg->counts[DNS_SECTION_QUESTION]); 1723 isc_buffer_putuint16(target, 1724 (uint16_t)msg->counts[DNS_SECTION_ANSWER]); 1725 isc_buffer_putuint16(target, 1726 (uint16_t)msg->counts[DNS_SECTION_AUTHORITY]); 1727 isc_buffer_putuint16(target, 1728 (uint16_t)msg->counts[DNS_SECTION_ADDITIONAL]); 1729 } 1730 1731 isc_result_t 1732 dns_message_renderend(dns_message_t *msg) { 1733 isc_buffer_t tmpbuf; 1734 isc_region_t r; 1735 int result; 1736 unsigned int count; 1737 1738 REQUIRE(msg->buffer != NULL); 1739 1740 if ((msg->rcode & ~DNS_MESSAGE_RCODE_MASK) != 0 && msg->opt == NULL) { 1741 /* 1742 * We have an extended rcode but are not using EDNS. 1743 */ 1744 return (DNS_R_FORMERR); 1745 } 1746 1747 /* 1748 * If we're adding a OPT, TSIG or SIG(0) to a truncated message, 1749 * clear all rdatasets from the message except for the question 1750 * before adding the OPT, TSIG or SIG(0). If the question doesn't 1751 * fit, don't include it. 1752 */ 1753 if ((msg->tsigkey != NULL || msg->opt) && 1754 (msg->flags & DNS_MESSAGEFLAG_TC) != 0) 1755 { 1756 isc_buffer_t *buf; 1757 1758 msgresetnames(msg, DNS_SECTION_ANSWER); 1759 buf = msg->buffer; 1760 dns_message_renderreset(msg); 1761 msg->buffer = buf; 1762 isc_buffer_clear(msg->buffer); 1763 isc_buffer_add(msg->buffer, DNS_MESSAGE_HEADERLEN); 1764 dns_compress_rollback(msg->cctx, 0); 1765 result = dns_message_rendersection(msg, DNS_SECTION_QUESTION); 1766 if (result != ISC_R_SUCCESS && result != ISC_R_NOSPACE) 1767 return (result); 1768 } 1769 1770 /* 1771 * If we've got an OPT record, render it. 1772 */ 1773 if (msg->opt != NULL) { 1774 dns_message_renderrelease(msg, msg->opt_reserved); 1775 msg->opt_reserved = 0; 1776 /* 1777 * Set the extended rcode. 1778 */ 1779 msg->opt->ttl &= ~DNS_MESSAGE_EDNSRCODE_MASK; 1780 msg->opt->ttl |= ((msg->rcode << 20) & 1781 DNS_MESSAGE_EDNSRCODE_MASK); 1782 /* 1783 * Render. 1784 */ 1785 count = 0; 1786 result = renderset(msg->opt, dns_rootname, msg->cctx, 1787 msg->buffer, msg->reserved, &count); 1788 msg->counts[DNS_SECTION_ADDITIONAL] += count; 1789 if (result != ISC_R_SUCCESS) 1790 return (result); 1791 } 1792 1793 /* 1794 * If we're adding a TSIG record, generate and render it. 1795 */ 1796 if (msg->tsigkey != NULL) { 1797 dns_message_renderrelease(msg, msg->sig_reserved); 1798 msg->sig_reserved = 0; 1799 result = dns_tsig_sign(msg); 1800 if (result != ISC_R_SUCCESS) 1801 return (result); 1802 count = 0; 1803 result = renderset(msg->tsig, msg->tsigname, msg->cctx, 1804 msg->buffer, msg->reserved, &count); 1805 msg->counts[DNS_SECTION_ADDITIONAL] += count; 1806 if (result != ISC_R_SUCCESS) 1807 return (result); 1808 } 1809 1810 isc_buffer_usedregion(msg->buffer, &r); 1811 isc_buffer_init(&tmpbuf, r.base, r.length); 1812 1813 dns_message_renderheader(msg, &tmpbuf); 1814 1815 msg->buffer = NULL; /* forget about this buffer only on success XXX */ 1816 1817 return (ISC_R_SUCCESS); 1818 } 1819 1820 void 1821 dns_message_renderreset(dns_message_t *msg) { 1822 unsigned int i; 1823 dns_name_t *name; 1824 dns_rdataset_t *rds; 1825 1826 /* 1827 * Reset the message so that it may be rendered again. 1828 */ 1829 1830 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER); 1831 1832 msg->buffer = NULL; 1833 1834 for (i = 0; i < DNS_SECTION_MAX; i++) { 1835 msg->cursors[i] = NULL; 1836 msg->counts[i] = 0; 1837 for (name = ISC_LIST_HEAD(msg->sections[i]); 1838 name != NULL; 1839 name = ISC_LIST_NEXT(name, link)) { 1840 for (rds = ISC_LIST_HEAD(name->list); 1841 rds != NULL; 1842 rds = ISC_LIST_NEXT(rds, link)) { 1843 rds->attributes &= ~DNS_RDATASETATTR_RENDERED; 1844 } 1845 } 1846 } 1847 if (msg->tsigname != NULL) 1848 dns_message_puttempname(msg, &msg->tsigname); 1849 if (msg->tsig != NULL) { 1850 dns_rdataset_disassociate(msg->tsig); 1851 dns_message_puttemprdataset(msg, &msg->tsig); 1852 } 1853 if (msg->sig0 != NULL) { 1854 dns_rdataset_disassociate(msg->sig0); 1855 dns_message_puttemprdataset(msg, &msg->sig0); 1856 } 1857 } 1858 1859 isc_result_t 1860 dns_message_firstname(dns_message_t *msg, dns_section_t section) { 1861 REQUIRE(VALID_NAMED_SECTION(section)); 1862 1863 msg->cursors[section] = ISC_LIST_HEAD(msg->sections[section]); 1864 1865 if (msg->cursors[section] == NULL) 1866 return (ISC_R_NOMORE); 1867 1868 return (ISC_R_SUCCESS); 1869 } 1870 1871 isc_result_t 1872 dns_message_nextname(dns_message_t *msg, dns_section_t section) { 1873 REQUIRE(VALID_NAMED_SECTION(section)); 1874 REQUIRE(msg->cursors[section] != NULL); 1875 1876 msg->cursors[section] = ISC_LIST_NEXT(msg->cursors[section], link); 1877 1878 if (msg->cursors[section] == NULL) 1879 return (ISC_R_NOMORE); 1880 1881 return (ISC_R_SUCCESS); 1882 } 1883 1884 void 1885 dns_message_currentname(dns_message_t *msg, dns_section_t section, 1886 dns_name_t **name) 1887 { 1888 REQUIRE(VALID_NAMED_SECTION(section)); 1889 REQUIRE(name != NULL && *name == NULL); 1890 REQUIRE(msg->cursors[section] != NULL); 1891 1892 *name = msg->cursors[section]; 1893 } 1894 1895 isc_result_t 1896 dns_message_findname(dns_message_t *msg, dns_section_t section, 1897 dns_name_t *target, dns_rdatatype_t type, 1898 dns_rdatatype_t covers, dns_name_t **name, 1899 dns_rdataset_t **rdataset) 1900 { 1901 dns_name_t *foundname; 1902 isc_result_t result; 1903 1904 /* 1905 * XXX These requirements are probably too intensive, especially 1906 * where things can be NULL, but as they are they ensure that if 1907 * something is NON-NULL, indicating that the caller expects it 1908 * to be filled in, that we can in fact fill it in. 1909 */ 1910 REQUIRE(msg != NULL); 1911 REQUIRE(VALID_SECTION(section)); 1912 REQUIRE(target != NULL); 1913 REQUIRE(name == NULL || *name == NULL); 1914 1915 if (type == dns_rdatatype_any) { 1916 REQUIRE(rdataset == NULL); 1917 } else { 1918 REQUIRE(rdataset == NULL || *rdataset == NULL); 1919 } 1920 1921 result = findname(&foundname, target, 1922 &msg->sections[section]); 1923 1924 if (result == ISC_R_NOTFOUND) 1925 return (DNS_R_NXDOMAIN); 1926 else if (result != ISC_R_SUCCESS) 1927 return (result); 1928 1929 if (name != NULL) 1930 *name = foundname; 1931 1932 /* 1933 * And now look for the type. 1934 */ 1935 if (type == dns_rdatatype_any) 1936 return (ISC_R_SUCCESS); 1937 1938 result = dns_message_findtype(foundname, type, covers, rdataset); 1939 if (result == ISC_R_NOTFOUND) 1940 return (DNS_R_NXRRSET); 1941 1942 return (result); 1943 } 1944 1945 void 1946 dns_message_addname(dns_message_t *msg, dns_name_t *name, 1947 dns_section_t section) 1948 { 1949 REQUIRE(msg != NULL); 1950 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER); 1951 REQUIRE(name != NULL); 1952 REQUIRE(VALID_NAMED_SECTION(section)); 1953 1954 ISC_LIST_APPEND(msg->sections[section], name, link); 1955 } 1956 1957 isc_result_t 1958 dns_message_gettempname(dns_message_t *msg, dns_name_t **item) { 1959 REQUIRE(item != NULL && *item == NULL); 1960 1961 UNUSED(msg); 1962 1963 *item = malloc(sizeof(dns_name_t)); 1964 if (*item == NULL) 1965 return (ISC_R_NOMEMORY); 1966 dns_name_init(*item, NULL); 1967 1968 return (ISC_R_SUCCESS); 1969 } 1970 1971 isc_result_t 1972 dns_message_gettemprdata(dns_message_t *msg, dns_rdata_t **item) { 1973 REQUIRE(item != NULL && *item == NULL); 1974 1975 *item = newrdata(msg); 1976 if (*item == NULL) 1977 return (ISC_R_NOMEMORY); 1978 1979 return (ISC_R_SUCCESS); 1980 } 1981 1982 isc_result_t 1983 dns_message_gettemprdataset(dns_message_t *msg, dns_rdataset_t **item) { 1984 REQUIRE(item != NULL && *item == NULL); 1985 1986 UNUSED(msg); 1987 1988 *item = malloc(sizeof(dns_rdataset_t)); 1989 if (*item == NULL) 1990 return (ISC_R_NOMEMORY); 1991 1992 dns_rdataset_init(*item); 1993 1994 return (ISC_R_SUCCESS); 1995 } 1996 1997 isc_result_t 1998 dns_message_gettemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) { 1999 REQUIRE(item != NULL && *item == NULL); 2000 2001 *item = newrdatalist(msg); 2002 if (*item == NULL) 2003 return (ISC_R_NOMEMORY); 2004 2005 return (ISC_R_SUCCESS); 2006 } 2007 2008 void 2009 dns_message_puttempname(dns_message_t *msg, dns_name_t **item) { 2010 REQUIRE(item != NULL && *item != NULL); 2011 2012 UNUSED(msg); 2013 2014 if (dns_name_dynamic(*item)) 2015 dns_name_free(*item); 2016 free(*item); 2017 *item = NULL; 2018 } 2019 2020 void 2021 dns_message_puttemprdata(dns_message_t *msg, dns_rdata_t **item) { 2022 REQUIRE(item != NULL && *item != NULL); 2023 2024 releaserdata(msg, *item); 2025 *item = NULL; 2026 } 2027 2028 void 2029 dns_message_puttemprdataset(dns_message_t *msg, dns_rdataset_t **item) { 2030 REQUIRE(item != NULL && *item != NULL); 2031 REQUIRE(!dns_rdataset_isassociated(*item)); 2032 2033 UNUSED(msg); 2034 2035 free(*item); 2036 *item = NULL; 2037 } 2038 2039 void 2040 dns_message_puttemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) { 2041 REQUIRE(item != NULL && *item != NULL); 2042 2043 releaserdatalist(msg, *item); 2044 *item = NULL; 2045 } 2046 2047 isc_result_t 2048 dns_message_peekheader(isc_buffer_t *source, dns_messageid_t *idp, 2049 unsigned int *flagsp) 2050 { 2051 isc_region_t r; 2052 isc_buffer_t buffer; 2053 dns_messageid_t id; 2054 unsigned int flags; 2055 2056 REQUIRE(source != NULL); 2057 2058 buffer = *source; 2059 2060 isc_buffer_remainingregion(&buffer, &r); 2061 if (r.length < DNS_MESSAGE_HEADERLEN) 2062 return (ISC_R_UNEXPECTEDEND); 2063 2064 id = isc_buffer_getuint16(&buffer); 2065 flags = isc_buffer_getuint16(&buffer); 2066 flags &= DNS_MESSAGE_FLAG_MASK; 2067 2068 if (flagsp != NULL) 2069 *flagsp = flags; 2070 if (idp != NULL) 2071 *idp = id; 2072 2073 return (ISC_R_SUCCESS); 2074 } 2075 2076 dns_rdataset_t * 2077 dns_message_getopt(dns_message_t *msg) { 2078 2079 /* 2080 * Get the OPT record for 'msg'. 2081 */ 2082 return (msg->opt); 2083 } 2084 2085 isc_result_t 2086 dns_message_setopt(dns_message_t *msg, dns_rdataset_t *opt) { 2087 isc_result_t result; 2088 dns_rdata_t rdata = DNS_RDATA_INIT; 2089 2090 /* 2091 * Set the OPT record for 'msg'. 2092 */ 2093 2094 /* 2095 * The space required for an OPT record is: 2096 * 2097 * 1 byte for the name 2098 * 2 bytes for the type 2099 * 2 bytes for the class 2100 * 4 bytes for the ttl 2101 * 2 bytes for the rdata length 2102 * --------------------------------- 2103 * 11 bytes 2104 * 2105 * plus the length of the rdata. 2106 */ 2107 2108 REQUIRE(opt->type == dns_rdatatype_opt); 2109 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER); 2110 REQUIRE(msg->state == DNS_SECTION_ANY); 2111 2112 msgresetopt(msg); 2113 2114 result = dns_rdataset_first(opt); 2115 if (result != ISC_R_SUCCESS) 2116 goto cleanup; 2117 dns_rdataset_current(opt, &rdata); 2118 msg->opt_reserved = 11 + rdata.length; 2119 result = dns_message_renderreserve(msg, msg->opt_reserved); 2120 if (result != ISC_R_SUCCESS) { 2121 msg->opt_reserved = 0; 2122 goto cleanup; 2123 } 2124 2125 msg->opt = opt; 2126 2127 return (ISC_R_SUCCESS); 2128 2129 cleanup: 2130 dns_rdataset_disassociate(opt); 2131 dns_message_puttemprdataset(msg, &opt); 2132 return (result); 2133 } 2134 2135 dns_rdataset_t * 2136 dns_message_gettsig(dns_message_t *msg, dns_name_t **owner) { 2137 2138 /* 2139 * Get the TSIG record and owner for 'msg'. 2140 */ 2141 2142 REQUIRE(owner == NULL || *owner == NULL); 2143 2144 if (owner != NULL) 2145 *owner = msg->tsigname; 2146 return (msg->tsig); 2147 } 2148 2149 isc_result_t 2150 dns_message_settsigkey(dns_message_t *msg, dns_tsigkey_t *key) { 2151 isc_result_t result; 2152 2153 /* 2154 * Set the TSIG key for 'msg' 2155 */ 2156 2157 REQUIRE(msg->state == DNS_SECTION_ANY); 2158 2159 if (key == NULL && msg->tsigkey != NULL) { 2160 if (msg->sig_reserved != 0) { 2161 dns_message_renderrelease(msg, msg->sig_reserved); 2162 msg->sig_reserved = 0; 2163 } 2164 dns_tsigkey_detach(&msg->tsigkey); 2165 } 2166 if (key != NULL) { 2167 REQUIRE(msg->tsigkey == NULL); 2168 dns_tsigkey_attach(key, &msg->tsigkey); 2169 if (msg->from_to_wire == DNS_MESSAGE_INTENTRENDER) { 2170 msg->sig_reserved = spacefortsig(msg->tsigkey, 0); 2171 result = dns_message_renderreserve(msg, 2172 msg->sig_reserved); 2173 if (result != ISC_R_SUCCESS) { 2174 dns_tsigkey_detach(&msg->tsigkey); 2175 msg->sig_reserved = 0; 2176 return (result); 2177 } 2178 } 2179 } 2180 return (ISC_R_SUCCESS); 2181 } 2182 2183 dns_tsigkey_t * 2184 dns_message_gettsigkey(dns_message_t *msg) { 2185 2186 /* 2187 * Get the TSIG key for 'msg' 2188 */ 2189 return (msg->tsigkey); 2190 } 2191 2192 isc_result_t 2193 dns_message_setquerytsig(dns_message_t *msg, isc_buffer_t *querytsig) { 2194 dns_rdata_t *rdata = NULL; 2195 dns_rdatalist_t *list = NULL; 2196 dns_rdataset_t *set = NULL; 2197 isc_buffer_t *buf = NULL; 2198 isc_region_t r; 2199 isc_result_t result; 2200 2201 REQUIRE(msg->querytsig == NULL); 2202 2203 if (querytsig == NULL) 2204 return (ISC_R_SUCCESS); 2205 2206 result = dns_message_gettemprdata(msg, &rdata); 2207 if (result != ISC_R_SUCCESS) 2208 goto cleanup; 2209 2210 result = dns_message_gettemprdatalist(msg, &list); 2211 if (result != ISC_R_SUCCESS) 2212 goto cleanup; 2213 result = dns_message_gettemprdataset(msg, &set); 2214 if (result != ISC_R_SUCCESS) 2215 goto cleanup; 2216 2217 isc_buffer_usedregion(querytsig, &r); 2218 result = isc_buffer_allocate(&buf, r.length); 2219 if (result != ISC_R_SUCCESS) 2220 goto cleanup; 2221 isc_buffer_putmem(buf, r.base, r.length); 2222 isc_buffer_usedregion(buf, &r); 2223 dns_rdata_init(rdata); 2224 dns_rdata_fromregion(rdata, dns_rdataclass_any, dns_rdatatype_tsig, &r); 2225 dns_message_takebuffer(msg, &buf); 2226 ISC_LIST_APPEND(list->rdata, rdata, link); 2227 result = dns_rdatalist_tordataset(list, set); 2228 if (result != ISC_R_SUCCESS) 2229 goto cleanup; 2230 2231 msg->querytsig = set; 2232 2233 return (result); 2234 2235 cleanup: 2236 if (rdata != NULL) 2237 dns_message_puttemprdata(msg, &rdata); 2238 if (list != NULL) 2239 dns_message_puttemprdatalist(msg, &list); 2240 if (set != NULL) 2241 dns_message_puttemprdataset(msg, &set); 2242 return (ISC_R_NOMEMORY); 2243 } 2244 2245 isc_result_t 2246 dns_message_getquerytsig(dns_message_t *msg, isc_buffer_t **querytsig) { 2247 isc_result_t result; 2248 dns_rdata_t rdata = DNS_RDATA_INIT; 2249 isc_region_t r; 2250 2251 REQUIRE(querytsig != NULL && *querytsig == NULL); 2252 2253 if (msg->tsig == NULL) 2254 return (ISC_R_SUCCESS); 2255 2256 result = dns_rdataset_first(msg->tsig); 2257 if (result != ISC_R_SUCCESS) 2258 return (result); 2259 dns_rdataset_current(msg->tsig, &rdata); 2260 dns_rdata_toregion(&rdata, &r); 2261 2262 result = isc_buffer_allocate(querytsig, r.length); 2263 if (result != ISC_R_SUCCESS) 2264 return (result); 2265 isc_buffer_putmem(*querytsig, r.base, r.length); 2266 return (ISC_R_SUCCESS); 2267 } 2268 2269 dns_rdataset_t * 2270 dns_message_getsig0(dns_message_t *msg, dns_name_t **owner) { 2271 2272 /* 2273 * Get the SIG(0) record for 'msg'. 2274 */ 2275 2276 REQUIRE(owner == NULL || *owner == NULL); 2277 2278 if (msg->sig0 != NULL && owner != NULL) { 2279 /* If dns_message_getsig0 is called on a rendered message 2280 * after the SIG(0) has been applied, we need to return the 2281 * root name, not NULL. 2282 */ 2283 if (msg->sig0name == NULL) 2284 *owner = dns_rootname; 2285 else 2286 *owner = msg->sig0name; 2287 } 2288 return (msg->sig0); 2289 } 2290 2291 void 2292 dns_message_takebuffer(dns_message_t *msg, isc_buffer_t **buffer) { 2293 REQUIRE(buffer != NULL); 2294 2295 ISC_LIST_APPEND(msg->cleanup, *buffer, link); 2296 *buffer = NULL; 2297 } 2298 2299 isc_result_t 2300 dns_message_sectiontotext(dns_message_t *msg, dns_section_t section, 2301 const dns_master_style_t *style, 2302 dns_messagetextflag_t flags, 2303 isc_buffer_t *target) { 2304 dns_name_t *name, empty_name; 2305 dns_rdataset_t *rdataset; 2306 isc_result_t result; 2307 int seensoa = 0; 2308 2309 REQUIRE(target != NULL); 2310 REQUIRE(VALID_SECTION(section)); 2311 2312 if (ISC_LIST_EMPTY(msg->sections[section])) 2313 return (ISC_R_SUCCESS); 2314 2315 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) { 2316 ADD_STRING(target, ";; "); 2317 if (msg->opcode != dns_opcode_update) { 2318 ADD_STRING(target, sectiontext[section]); 2319 } else { 2320 ADD_STRING(target, updsectiontext[section]); 2321 } 2322 ADD_STRING(target, " SECTION:\n"); 2323 } 2324 2325 dns_name_init(&empty_name, NULL); 2326 result = dns_message_firstname(msg, section); 2327 if (result != ISC_R_SUCCESS) { 2328 return (result); 2329 } 2330 do { 2331 name = NULL; 2332 dns_message_currentname(msg, section, &name); 2333 for (rdataset = ISC_LIST_HEAD(name->list); 2334 rdataset != NULL; 2335 rdataset = ISC_LIST_NEXT(rdataset, link)) { 2336 if (section == DNS_SECTION_ANSWER && 2337 rdataset->type == dns_rdatatype_soa) { 2338 if ((flags & DNS_MESSAGETEXTFLAG_OMITSOA) != 0) 2339 continue; 2340 if (seensoa && 2341 (flags & DNS_MESSAGETEXTFLAG_ONESOA) != 0) 2342 continue; 2343 seensoa = 1; 2344 } 2345 if (section == DNS_SECTION_QUESTION) { 2346 ADD_STRING(target, ";"); 2347 result = dns_master_questiontotext(name, 2348 rdataset, 2349 style, 2350 target); 2351 } else { 2352 result = dns_master_rdatasettotext(name, 2353 rdataset, 2354 style, 2355 target); 2356 } 2357 if (result != ISC_R_SUCCESS) 2358 return (result); 2359 } 2360 result = dns_message_nextname(msg, section); 2361 } while (result == ISC_R_SUCCESS); 2362 if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 && 2363 (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) 2364 ADD_STRING(target, "\n"); 2365 if (result == ISC_R_NOMORE) 2366 result = ISC_R_SUCCESS; 2367 return (result); 2368 } 2369 2370 static isc_result_t 2371 render_ecs(isc_buffer_t *ecsbuf, isc_buffer_t *target) { 2372 int i; 2373 char addr[16], addr_text[64]; 2374 uint16_t family; 2375 uint8_t addrlen, addrbytes, scopelen; 2376 2377 /* 2378 * Note: This routine needs to handle malformed ECS options. 2379 */ 2380 2381 if (isc_buffer_remaininglength(ecsbuf) < 4) 2382 return (DNS_R_OPTERR); 2383 family = isc_buffer_getuint16(ecsbuf); 2384 addrlen = isc_buffer_getuint8(ecsbuf); 2385 scopelen = isc_buffer_getuint8(ecsbuf); 2386 2387 addrbytes = (addrlen + 7) / 8; 2388 if (isc_buffer_remaininglength(ecsbuf) < addrbytes) 2389 return (DNS_R_OPTERR); 2390 2391 if (addrbytes > sizeof(addr)) 2392 return (DNS_R_OPTERR); 2393 2394 memset(addr, 0, sizeof(addr)); 2395 for (i = 0; i < addrbytes; i ++) 2396 addr[i] = isc_buffer_getuint8(ecsbuf); 2397 2398 switch (family) { 2399 case 0: 2400 if (addrlen != 0U || scopelen != 0U) 2401 return (DNS_R_OPTERR); 2402 strlcpy(addr_text, "0", sizeof(addr_text)); 2403 break; 2404 case 1: 2405 if (addrlen > 32 || scopelen > 32) 2406 return (DNS_R_OPTERR); 2407 inet_ntop(AF_INET, addr, addr_text, sizeof(addr_text)); 2408 break; 2409 case 2: 2410 if (addrlen > 128 || scopelen > 128) 2411 return (DNS_R_OPTERR); 2412 inet_ntop(AF_INET6, addr, addr_text, sizeof(addr_text)); 2413 break; 2414 default: 2415 return (DNS_R_OPTERR); 2416 } 2417 2418 ADD_STRING(target, ": "); 2419 ADD_STRING(target, addr_text); 2420 snprintf(addr_text, sizeof(addr_text), "/%d/%d", addrlen, scopelen); 2421 ADD_STRING(target, addr_text); 2422 return (ISC_R_SUCCESS); 2423 } 2424 2425 static const char * 2426 ede_info_code2str(uint16_t info_code) 2427 { 2428 if (info_code > 49151) 2429 return "Private Use"; 2430 2431 switch (info_code) { 2432 case 0: 2433 return "Other Error"; 2434 case 1: 2435 return "Unsupported DNSKEY Algorithm"; 2436 case 2: 2437 return "Unsupported DS Digest Type"; 2438 case 3: 2439 return "Stale Answer"; 2440 case 4: 2441 return "Forged Answer"; 2442 case 5: 2443 return "DNSSEC Indeterminate"; 2444 case 6: 2445 return "DNSSEC Bogus"; 2446 case 7: 2447 return "Signature Expired"; 2448 case 8: 2449 return "Signature Not Yet Valid"; 2450 case 9: 2451 return "DNSKEY Missing"; 2452 case 10: 2453 return "RRSIGs Missing"; 2454 case 11: 2455 return "No Zone Key Bit Set"; 2456 case 12: 2457 return "NSEC Missing"; 2458 case 13: 2459 return "Cached Error"; 2460 case 14: 2461 return "Not Ready"; 2462 case 15: 2463 return "Blocked"; 2464 case 16: 2465 return "Censored"; 2466 case 17: 2467 return "Filtered"; 2468 case 18: 2469 return "Prohibited"; 2470 case 19: 2471 return "Stale NXDomain Answer"; 2472 case 20: 2473 return "Not Authoritative"; 2474 case 21: 2475 return "Not Supported"; 2476 case 22: 2477 return "No Reachable Authority"; 2478 case 23: 2479 return "Network Error"; 2480 case 24: 2481 return "Invalid Data"; 2482 default: 2483 return "Unassigned"; 2484 } 2485 } 2486 2487 static const char * 2488 zoneversion_zone(const char *zone, int labelcount) 2489 { 2490 size_t pos; 2491 2492 if (zone == NULL || labelcount == 0) 2493 return "."; 2494 2495 pos = strlen(zone); 2496 if (pos == 0) 2497 return "."; 2498 2499 pos--; /* go to last char in string */ 2500 if (zone[pos] == '.') 2501 pos--; /* the labelcount does not count the empty root label */ 2502 2503 for (; pos > 0; pos--) { 2504 if (zone[pos] == '.') { 2505 labelcount--; 2506 2507 if (labelcount == 0) { 2508 pos++; 2509 break; 2510 } 2511 } 2512 } 2513 2514 return (zone + pos); 2515 } 2516 2517 isc_result_t 2518 dns_message_pseudosectiontotext(dns_message_t *msg, 2519 dns_pseudosection_t section, 2520 const dns_master_style_t *style, 2521 dns_messagetextflag_t flags, 2522 const char *textname, 2523 isc_buffer_t *target) 2524 { 2525 dns_rdataset_t *ps = NULL; 2526 dns_name_t *name = NULL; 2527 isc_result_t result; 2528 char buf[sizeof("1234567890")]; 2529 uint32_t mbz; 2530 dns_rdata_t rdata; 2531 isc_buffer_t optbuf; 2532 uint16_t optcode, optlen; 2533 unsigned char *optdata; 2534 2535 REQUIRE(target != NULL); 2536 REQUIRE(VALID_PSEUDOSECTION(section)); 2537 2538 switch (section) { 2539 case DNS_PSEUDOSECTION_OPT: 2540 ps = dns_message_getopt(msg); 2541 if (ps == NULL) 2542 return (ISC_R_SUCCESS); 2543 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) 2544 ADD_STRING(target, ";; OPT PSEUDOSECTION:\n"); 2545 ADD_STRING(target, "; EDNS: version: "); 2546 snprintf(buf, sizeof(buf), "%u", 2547 (unsigned int)((ps->ttl & 0x00ff0000) >> 16)); 2548 ADD_STRING(target, buf); 2549 ADD_STRING(target, ", flags:"); 2550 if ((ps->ttl & DNS_MESSAGEEXTFLAG_DO) != 0) 2551 ADD_STRING(target, " do"); 2552 mbz = ps->ttl & 0xffff; 2553 mbz &= ~DNS_MESSAGEEXTFLAG_DO; /* Known Flags. */ 2554 if (mbz != 0) { 2555 ADD_STRING(target, "; MBZ: "); 2556 snprintf(buf, sizeof(buf), "0x%.4x", mbz); 2557 ADD_STRING(target, buf); 2558 ADD_STRING(target, ", udp: "); 2559 } else 2560 ADD_STRING(target, "; udp: "); 2561 snprintf(buf, sizeof(buf), "%u\n", (unsigned int)ps->rdclass); 2562 ADD_STRING(target, buf); 2563 2564 result = dns_rdataset_first(ps); 2565 if (result != ISC_R_SUCCESS) 2566 return (ISC_R_SUCCESS); 2567 2568 /* 2569 * Print EDNS info, if any. 2570 * 2571 * WARNING: The option contents may be malformed as 2572 * dig +ednsopt=value:<content> does not validity 2573 * checking. 2574 */ 2575 dns_rdata_init(&rdata); 2576 dns_rdataset_current(ps, &rdata); 2577 2578 isc_buffer_init(&optbuf, rdata.data, rdata.length); 2579 isc_buffer_add(&optbuf, rdata.length); 2580 while (isc_buffer_remaininglength(&optbuf) != 0) { 2581 INSIST(isc_buffer_remaininglength(&optbuf) >= 4U); 2582 optcode = isc_buffer_getuint16(&optbuf); 2583 optlen = isc_buffer_getuint16(&optbuf); 2584 INSIST(isc_buffer_remaininglength(&optbuf) >= optlen); 2585 2586 if (optcode == DNS_OPT_NSID) { 2587 ADD_STRING(target, "; NSID"); 2588 } else if (optcode == DNS_OPT_COOKIE) { 2589 ADD_STRING(target, "; COOKIE"); 2590 } else if (optcode == DNS_OPT_CLIENT_SUBNET) { 2591 isc_buffer_t ecsbuf; 2592 2593 ADD_STRING(target, "; CLIENT-SUBNET"); 2594 isc_buffer_init(&ecsbuf, 2595 isc_buffer_current(&optbuf), 2596 optlen); 2597 isc_buffer_add(&ecsbuf, optlen); 2598 result = render_ecs(&ecsbuf, target); 2599 if (result == ISC_R_NOSPACE) 2600 return (result); 2601 if (result == ISC_R_SUCCESS) { 2602 isc_buffer_forward(&optbuf, optlen); 2603 ADD_STRING(target, "\n"); 2604 continue; 2605 } 2606 } else if (optcode == DNS_OPT_EXPIRE) { 2607 if (optlen == 4) { 2608 uint32_t secs; 2609 secs = isc_buffer_getuint32(&optbuf); 2610 ADD_STRING(target, "; EXPIRE: "); 2611 snprintf(buf, sizeof(buf), "%u", secs); 2612 ADD_STRING(target, buf); 2613 ADD_STRING(target, " ("); 2614 result = dns_ttl_totext(secs, 2615 1, 2616 target); 2617 if (result != ISC_R_SUCCESS) 2618 return (result); 2619 ADD_STRING(target, ")\n"); 2620 continue; 2621 } 2622 ADD_STRING(target, "; EXPIRE"); 2623 } else if (optcode == DNS_OPT_PAD) { 2624 ADD_STRING(target, "; PAD"); 2625 } else if (optcode == DNS_OPT_KEY_TAG) { 2626 ADD_STRING(target, "; KEY-TAG"); 2627 if (optlen > 0U && (optlen % 2U) == 0U) { 2628 const char *sep = ": "; 2629 uint16_t id; 2630 while (optlen > 0U) { 2631 id = isc_buffer_getuint16(&optbuf); 2632 snprintf(buf, sizeof(buf), "%s%u", 2633 sep, id); 2634 ADD_STRING(target, buf); 2635 sep = ", "; 2636 optlen -= 2; 2637 } 2638 ADD_STRING(target, "\n"); 2639 continue; 2640 } 2641 } else if (optcode == DNS_OPT_EDE) { 2642 uint16_t info_code; 2643 ADD_STRING(target, "; EDE"); 2644 if (optlen >= 2) { 2645 info_code = 2646 isc_buffer_getuint16(&optbuf); 2647 optlen -= 2; 2648 snprintf(buf, sizeof(buf), ": %u (", 2649 info_code); 2650 ADD_STRING(target, buf); 2651 ADD_STRING(target, 2652 ede_info_code2str(info_code)); 2653 ADD_STRING(target, ")"); 2654 } 2655 } else if (optcode == DNS_OPT_ZONEVERSION) { 2656 int i; 2657 2658 ADD_STRING(target, "; ZONEVERSION: "); 2659 optdata = isc_buffer_current(&optbuf); 2660 for (i = 0; i < optlen; i++) { 2661 snprintf(buf, sizeof(buf), "%02x ", 2662 optdata[i]); 2663 ADD_STRING(target, buf); 2664 } 2665 2666 if (optlen >= 2) { 2667 uint8_t labelcount, type; 2668 const char *zone; 2669 2670 labelcount = 2671 isc_buffer_getuint8(&optbuf); 2672 optlen -= 1; 2673 type = isc_buffer_getuint8(&optbuf); 2674 optlen -= 1; 2675 zone = zoneversion_zone(textname, 2676 labelcount); 2677 2678 if (type == 0 && optlen == 4) { 2679 uint32_t serial; 2680 2681 serial = isc_buffer_getuint32( 2682 &optbuf); 2683 optlen -= 4; 2684 ADD_STRING(target, 2685 "(\"SOA-SERIAL: "); 2686 snprintf(buf, sizeof(buf), "%u", 2687 serial); 2688 ADD_STRING(target, buf); 2689 ADD_STRING(target, " ("); 2690 ADD_STRING(target, zone); 2691 ADD_STRING(target, ")"); 2692 ADD_STRING(target, "\")"); 2693 } 2694 } 2695 } else { 2696 ADD_STRING(target, "; OPT="); 2697 snprintf(buf, sizeof(buf), "%u", optcode); 2698 ADD_STRING(target, buf); 2699 } 2700 2701 if (optlen != 0) { 2702 int i; 2703 ADD_STRING(target, ": "); 2704 2705 optdata = isc_buffer_current(&optbuf); 2706 for (i = 0; i < optlen; i++) { 2707 const char *sep; 2708 switch (optcode) { 2709 case DNS_OPT_COOKIE: 2710 sep = ""; 2711 break; 2712 default: 2713 sep = " "; 2714 break; 2715 } 2716 snprintf(buf, sizeof(buf), "%02x%s", 2717 optdata[i], sep); 2718 ADD_STRING(target, buf); 2719 } 2720 2721 isc_buffer_forward(&optbuf, optlen); 2722 2723 if (optcode == DNS_OPT_COOKIE) { 2724 if (msg->sitok) 2725 ADD_STRING(target, " (good)"); 2726 if (msg->sitbad) 2727 ADD_STRING(target, " (bad)"); 2728 ADD_STRING(target, "\n"); 2729 continue; 2730 } 2731 2732 if (optcode == DNS_OPT_CLIENT_SUBNET) { 2733 ADD_STRING(target, "\n"); 2734 continue; 2735 } 2736 2737 /* 2738 * For non-SIT options, add a printable 2739 * version 2740 */ 2741 ADD_STRING(target, "(\""); 2742 if (isc_buffer_availablelength(target) < optlen) 2743 return (ISC_R_NOSPACE); 2744 for (i = 0; i < optlen; i++) { 2745 if (isprint(optdata[i])) 2746 isc_buffer_putmem(target, 2747 &optdata[i], 2748 1); 2749 else 2750 isc_buffer_putstr(target, "."); 2751 } 2752 ADD_STRING(target, "\")"); 2753 } 2754 ADD_STRING(target, "\n"); 2755 } 2756 return (ISC_R_SUCCESS); 2757 case DNS_PSEUDOSECTION_TSIG: 2758 ps = dns_message_gettsig(msg, &name); 2759 if (ps == NULL) 2760 return (ISC_R_SUCCESS); 2761 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) 2762 ADD_STRING(target, ";; TSIG PSEUDOSECTION:\n"); 2763 result = dns_master_rdatasettotext(name, ps, style, target); 2764 if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 && 2765 (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) 2766 ADD_STRING(target, "\n"); 2767 return (result); 2768 case DNS_PSEUDOSECTION_SIG0: 2769 ps = dns_message_getsig0(msg, &name); 2770 if (ps == NULL) 2771 return (ISC_R_SUCCESS); 2772 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) 2773 ADD_STRING(target, ";; SIG0 PSEUDOSECTION:\n"); 2774 result = dns_master_rdatasettotext(name, ps, style, target); 2775 if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 && 2776 (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) 2777 ADD_STRING(target, "\n"); 2778 return (result); 2779 } 2780 return (ISC_R_UNEXPECTED); 2781 } 2782 2783 isc_result_t 2784 dns_message_buildopt(dns_message_t *message, dns_rdataset_t **rdatasetp, 2785 unsigned int version, uint16_t udpsize, 2786 unsigned int flags, dns_ednsopt_t *ednsopts, size_t count) 2787 { 2788 dns_rdataset_t *rdataset = NULL; 2789 dns_rdatalist_t *rdatalist = NULL; 2790 dns_rdata_t *rdata = NULL; 2791 isc_result_t result; 2792 unsigned int len = 0, i; 2793 2794 REQUIRE(rdatasetp != NULL && *rdatasetp == NULL); 2795 2796 result = dns_message_gettemprdatalist(message, &rdatalist); 2797 if (result != ISC_R_SUCCESS) 2798 return (result); 2799 result = dns_message_gettemprdata(message, &rdata); 2800 if (result != ISC_R_SUCCESS) 2801 goto cleanup; 2802 result = dns_message_gettemprdataset(message, &rdataset); 2803 if (result != ISC_R_SUCCESS) 2804 goto cleanup; 2805 2806 rdatalist->type = dns_rdatatype_opt; 2807 2808 /* 2809 * Set Maximum UDP buffer size. 2810 */ 2811 rdatalist->rdclass = udpsize; 2812 2813 /* 2814 * Set EXTENDED-RCODE and Z to 0. 2815 */ 2816 rdatalist->ttl = (version << 16); 2817 rdatalist->ttl |= (flags & 0xffff); 2818 2819 /* 2820 * Set EDNS options if applicable 2821 */ 2822 if (count != 0U) { 2823 isc_buffer_t *buf = NULL; 2824 for (i = 0; i < count; i++) 2825 len += ednsopts[i].length + 4; 2826 2827 if (len > 0xffffU) { 2828 result = ISC_R_NOSPACE; 2829 goto cleanup; 2830 } 2831 2832 result = isc_buffer_allocate(&buf, len); 2833 if (result != ISC_R_SUCCESS) 2834 goto cleanup; 2835 2836 for (i = 0; i < count; i++) { 2837 isc_buffer_putuint16(buf, ednsopts[i].code); 2838 isc_buffer_putuint16(buf, ednsopts[i].length); 2839 if (ednsopts[i].length != 0) { 2840 isc_buffer_putmem(buf, ednsopts[i].value, 2841 ednsopts[i].length); 2842 } 2843 } 2844 rdata->data = isc_buffer_base(buf); 2845 rdata->length = len; 2846 dns_message_takebuffer(message, &buf); 2847 } else { 2848 rdata->data = NULL; 2849 rdata->length = 0; 2850 } 2851 2852 rdata->rdclass = rdatalist->rdclass; 2853 rdata->type = rdatalist->type; 2854 rdata->flags = 0; 2855 2856 ISC_LIST_APPEND(rdatalist->rdata, rdata, link); 2857 result = dns_rdatalist_tordataset(rdatalist, rdataset); 2858 RUNTIME_CHECK(result == ISC_R_SUCCESS); 2859 2860 *rdatasetp = rdataset; 2861 return (ISC_R_SUCCESS); 2862 2863 cleanup: 2864 if (rdata != NULL) 2865 dns_message_puttemprdata(message, &rdata); 2866 if (rdataset != NULL) 2867 dns_message_puttemprdataset(message, &rdataset); 2868 if (rdatalist != NULL) 2869 dns_message_puttemprdatalist(message, &rdatalist); 2870 return (result); 2871 } 2872