ares_dns_write.c (35667B)
1 /* MIT License 2 * 3 * Copyright (c) 2023 Brad House 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a copy 6 * of this software and associated documentation files (the "Software"), to deal 7 * in the Software without restriction, including without limitation the rights 8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 * copies of the Software, and to permit persons to whom the Software is 10 * furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice (including the next 13 * paragraph) shall be included in all copies or substantial portions of the 14 * Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 * SOFTWARE. 23 * 24 * SPDX-License-Identifier: MIT 25 */ 26 #include "ares_private.h" 27 #include <limits.h> 28 #ifdef HAVE_STDINT_H 29 # include <stdint.h> 30 #endif 31 32 33 static ares_status_t ares_dns_write_header(const ares_dns_record_t *dnsrec, 34 ares_buf_t *buf) 35 { 36 unsigned short u16; 37 unsigned short opcode; 38 unsigned short rcode; 39 40 ares_status_t status; 41 42 /* ID */ 43 status = ares_buf_append_be16(buf, dnsrec->id); 44 if (status != ARES_SUCCESS) { 45 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 46 } 47 48 /* Flags */ 49 u16 = 0; 50 51 /* QR */ 52 if (dnsrec->flags & ARES_FLAG_QR) { 53 u16 |= 0x8000; 54 } 55 56 /* OPCODE */ 57 opcode = (unsigned short)(dnsrec->opcode & 0xF); 58 opcode <<= 11; 59 u16 |= opcode; 60 61 /* AA */ 62 if (dnsrec->flags & ARES_FLAG_AA) { 63 u16 |= 0x400; 64 } 65 66 /* TC */ 67 if (dnsrec->flags & ARES_FLAG_TC) { 68 u16 |= 0x200; 69 } 70 71 /* RD */ 72 if (dnsrec->flags & ARES_FLAG_RD) { 73 u16 |= 0x100; 74 } 75 76 /* RA */ 77 if (dnsrec->flags & ARES_FLAG_RA) { 78 u16 |= 0x80; 79 } 80 81 /* Z -- unused */ 82 83 /* AD */ 84 if (dnsrec->flags & ARES_FLAG_AD) { 85 u16 |= 0x20; 86 } 87 88 /* CD */ 89 if (dnsrec->flags & ARES_FLAG_CD) { 90 u16 |= 0x10; 91 } 92 93 /* RCODE */ 94 if (dnsrec->rcode > 15 && ares_dns_get_opt_rr_const(dnsrec) == NULL) { 95 /* Must have OPT RR in order to write extended error codes */ 96 rcode = ARES_RCODE_SERVFAIL; 97 } else { 98 rcode = (unsigned short)(dnsrec->rcode & 0xF); 99 } 100 u16 |= rcode; 101 102 status = ares_buf_append_be16(buf, u16); 103 if (status != ARES_SUCCESS) { 104 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 105 } 106 107 /* QDCOUNT */ 108 status = ares_buf_append_be16( 109 buf, (unsigned short)ares_dns_record_query_cnt(dnsrec)); 110 if (status != ARES_SUCCESS) { 111 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 112 } 113 114 /* ANCOUNT */ 115 status = ares_buf_append_be16( 116 buf, (unsigned short)ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ANSWER)); 117 if (status != ARES_SUCCESS) { 118 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 119 } 120 121 /* NSCOUNT */ 122 status = ares_buf_append_be16(buf, (unsigned short)ares_dns_record_rr_cnt( 123 dnsrec, ARES_SECTION_AUTHORITY)); 124 if (status != ARES_SUCCESS) { 125 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 126 } 127 128 /* ARCOUNT */ 129 status = ares_buf_append_be16(buf, (unsigned short)ares_dns_record_rr_cnt( 130 dnsrec, ARES_SECTION_ADDITIONAL)); 131 if (status != ARES_SUCCESS) { 132 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 133 } 134 135 return ARES_SUCCESS; 136 } 137 138 static ares_status_t ares_dns_write_questions(const ares_dns_record_t *dnsrec, 139 ares_llist_t **namelist, 140 ares_buf_t *buf) 141 { 142 size_t i; 143 144 for (i = 0; i < ares_dns_record_query_cnt(dnsrec); i++) { 145 ares_status_t status; 146 const char *name = NULL; 147 ares_dns_rec_type_t qtype; 148 ares_dns_class_t qclass; 149 150 status = ares_dns_record_query_get(dnsrec, i, &name, &qtype, &qclass); 151 if (status != ARES_SUCCESS) { 152 return status; 153 } 154 155 /* Name */ 156 status = ares_dns_name_write(buf, namelist, ARES_TRUE, name); 157 if (status != ARES_SUCCESS) { 158 return status; 159 } 160 161 /* Type */ 162 status = ares_buf_append_be16(buf, (unsigned short)qtype); 163 if (status != ARES_SUCCESS) { 164 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 165 } 166 167 /* Class */ 168 status = ares_buf_append_be16(buf, (unsigned short)qclass); 169 if (status != ARES_SUCCESS) { 170 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 171 } 172 } 173 174 return ARES_SUCCESS; 175 } 176 177 static ares_status_t ares_dns_write_rr_name(ares_buf_t *buf, 178 const ares_dns_rr_t *rr, 179 ares_llist_t **namelist, 180 ares_bool_t validate_hostname, 181 ares_dns_rr_key_t key) 182 { 183 const char *name; 184 185 name = ares_dns_rr_get_str(rr, key); 186 if (name == NULL) { 187 return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */ 188 } 189 190 return ares_dns_name_write(buf, namelist, validate_hostname, name); 191 } 192 193 static ares_status_t ares_dns_write_rr_str(ares_buf_t *buf, 194 const ares_dns_rr_t *rr, 195 ares_dns_rr_key_t key) 196 { 197 const char *str; 198 size_t len; 199 ares_status_t status; 200 201 str = ares_dns_rr_get_str(rr, key); 202 if (str == NULL) { 203 return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */ 204 } 205 206 len = ares_strlen(str); 207 if (len > 255) { 208 return ARES_EFORMERR; 209 } 210 211 /* Write 1 byte length */ 212 status = ares_buf_append_byte(buf, (unsigned char)(len & 0xFF)); 213 if (status != ARES_SUCCESS) { 214 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 215 } 216 217 if (len == 0) { 218 return ARES_SUCCESS; 219 } 220 221 /* Write string */ 222 return ares_buf_append(buf, (const unsigned char *)str, len); 223 } 224 225 static ares_status_t ares_dns_write_binstr(ares_buf_t *buf, 226 const unsigned char *bin, 227 size_t bin_len) 228 { 229 const unsigned char *ptr; 230 size_t ptr_len; 231 ares_status_t status; 232 233 /* split into possible multiple 255-byte or less length strings */ 234 ptr = bin; 235 ptr_len = bin_len; 236 do { 237 size_t len = ptr_len; 238 if (len > 255) { 239 len = 255; 240 } 241 242 /* Length */ 243 status = ares_buf_append_byte(buf, (unsigned char)(len & 0xFF)); 244 if (status != ARES_SUCCESS) { 245 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 246 } 247 248 /* String */ 249 if (len) { 250 status = ares_buf_append(buf, ptr, len); 251 if (status != ARES_SUCCESS) { 252 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 253 } 254 } 255 256 ptr += len; 257 ptr_len -= len; 258 } while (ptr_len > 0); 259 260 return ARES_SUCCESS; 261 } 262 263 static ares_status_t ares_dns_write_rr_abin(ares_buf_t *buf, 264 const ares_dns_rr_t *rr, 265 ares_dns_rr_key_t key) 266 { 267 ares_status_t status = ARES_EFORMERR; 268 size_t i; 269 size_t cnt = ares_dns_rr_get_abin_cnt(rr, key); 270 271 if (cnt == 0) { 272 return ARES_EFORMERR; 273 } 274 275 for (i = 0; i < cnt; i++) { 276 const unsigned char *bin; 277 size_t bin_len; 278 279 bin = ares_dns_rr_get_abin(rr, key, i, &bin_len); 280 281 status = ares_dns_write_binstr(buf, bin, bin_len); 282 if (status != ARES_SUCCESS) { 283 break; 284 } 285 } 286 287 return status; 288 } 289 290 static ares_status_t ares_dns_write_rr_be32(ares_buf_t *buf, 291 const ares_dns_rr_t *rr, 292 ares_dns_rr_key_t key) 293 { 294 if (ares_dns_rr_key_datatype(key) != ARES_DATATYPE_U32) { 295 return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */ 296 } 297 return ares_buf_append_be32(buf, ares_dns_rr_get_u32(rr, key)); 298 } 299 300 static ares_status_t ares_dns_write_rr_be16(ares_buf_t *buf, 301 const ares_dns_rr_t *rr, 302 ares_dns_rr_key_t key) 303 { 304 if (ares_dns_rr_key_datatype(key) != ARES_DATATYPE_U16) { 305 return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */ 306 } 307 return ares_buf_append_be16(buf, ares_dns_rr_get_u16(rr, key)); 308 } 309 310 static ares_status_t ares_dns_write_rr_u8(ares_buf_t *buf, 311 const ares_dns_rr_t *rr, 312 ares_dns_rr_key_t key) 313 { 314 if (ares_dns_rr_key_datatype(key) != ARES_DATATYPE_U8) { 315 return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */ 316 } 317 return ares_buf_append_byte(buf, ares_dns_rr_get_u8(rr, key)); 318 } 319 320 static ares_status_t ares_dns_write_rr_a(ares_buf_t *buf, 321 const ares_dns_rr_t *rr, 322 ares_llist_t **namelist) 323 { 324 const struct in_addr *addr; 325 (void)namelist; 326 327 addr = ares_dns_rr_get_addr(rr, ARES_RR_A_ADDR); 328 if (addr == NULL) { 329 return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */ 330 } 331 332 return ares_buf_append(buf, (const unsigned char *)addr, sizeof(*addr)); 333 } 334 335 static ares_status_t ares_dns_write_rr_ns(ares_buf_t *buf, 336 const ares_dns_rr_t *rr, 337 ares_llist_t **namelist) 338 { 339 return ares_dns_write_rr_name(buf, rr, namelist, ARES_FALSE, 340 ARES_RR_NS_NSDNAME); 341 } 342 343 static ares_status_t ares_dns_write_rr_cname(ares_buf_t *buf, 344 const ares_dns_rr_t *rr, 345 ares_llist_t **namelist) 346 { 347 return ares_dns_write_rr_name(buf, rr, namelist, ARES_FALSE, 348 ARES_RR_CNAME_CNAME); 349 } 350 351 static ares_status_t ares_dns_write_rr_soa(ares_buf_t *buf, 352 const ares_dns_rr_t *rr, 353 ares_llist_t **namelist) 354 { 355 ares_status_t status; 356 357 /* MNAME */ 358 status = 359 ares_dns_write_rr_name(buf, rr, namelist, ARES_FALSE, ARES_RR_SOA_MNAME); 360 if (status != ARES_SUCCESS) { 361 return status; 362 } 363 364 /* RNAME */ 365 status = 366 ares_dns_write_rr_name(buf, rr, namelist, ARES_FALSE, ARES_RR_SOA_RNAME); 367 if (status != ARES_SUCCESS) { 368 return status; 369 } 370 371 /* SERIAL */ 372 status = ares_dns_write_rr_be32(buf, rr, ARES_RR_SOA_SERIAL); 373 if (status != ARES_SUCCESS) { 374 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 375 } 376 377 /* REFRESH */ 378 status = ares_dns_write_rr_be32(buf, rr, ARES_RR_SOA_REFRESH); 379 if (status != ARES_SUCCESS) { 380 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 381 } 382 383 /* RETRY */ 384 status = ares_dns_write_rr_be32(buf, rr, ARES_RR_SOA_RETRY); 385 if (status != ARES_SUCCESS) { 386 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 387 } 388 389 /* EXPIRE */ 390 status = ares_dns_write_rr_be32(buf, rr, ARES_RR_SOA_EXPIRE); 391 if (status != ARES_SUCCESS) { 392 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 393 } 394 395 /* MINIMUM */ 396 return ares_dns_write_rr_be32(buf, rr, ARES_RR_SOA_MINIMUM); 397 } 398 399 static ares_status_t ares_dns_write_rr_ptr(ares_buf_t *buf, 400 const ares_dns_rr_t *rr, 401 ares_llist_t **namelist) 402 { 403 return ares_dns_write_rr_name(buf, rr, namelist, ARES_FALSE, 404 ARES_RR_PTR_DNAME); 405 } 406 407 static ares_status_t ares_dns_write_rr_hinfo(ares_buf_t *buf, 408 const ares_dns_rr_t *rr, 409 ares_llist_t **namelist) 410 { 411 ares_status_t status; 412 413 (void)namelist; 414 415 /* CPU */ 416 status = ares_dns_write_rr_str(buf, rr, ARES_RR_HINFO_CPU); 417 if (status != ARES_SUCCESS) { 418 return status; 419 } 420 421 /* OS */ 422 return ares_dns_write_rr_str(buf, rr, ARES_RR_HINFO_OS); 423 } 424 425 static ares_status_t ares_dns_write_rr_mx(ares_buf_t *buf, 426 const ares_dns_rr_t *rr, 427 ares_llist_t **namelist) 428 { 429 ares_status_t status; 430 431 /* PREFERENCE */ 432 status = ares_dns_write_rr_be16(buf, rr, ARES_RR_MX_PREFERENCE); 433 if (status != ARES_SUCCESS) { 434 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 435 } 436 437 /* EXCHANGE */ 438 return ares_dns_write_rr_name(buf, rr, namelist, ARES_FALSE, 439 ARES_RR_MX_EXCHANGE); 440 } 441 442 static ares_status_t ares_dns_write_rr_txt(ares_buf_t *buf, 443 const ares_dns_rr_t *rr, 444 ares_llist_t **namelist) 445 { 446 (void)namelist; 447 return ares_dns_write_rr_abin(buf, rr, ARES_RR_TXT_DATA); 448 } 449 450 static ares_status_t ares_dns_write_rr_sig(ares_buf_t *buf, 451 const ares_dns_rr_t *rr, 452 ares_llist_t **namelist) 453 { 454 ares_status_t status; 455 const unsigned char *data; 456 size_t len = 0; 457 458 (void)namelist; 459 460 /* TYPE COVERED */ 461 status = ares_dns_write_rr_be16(buf, rr, ARES_RR_SIG_TYPE_COVERED); 462 if (status != ARES_SUCCESS) { 463 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 464 } 465 466 /* ALGORITHM */ 467 status = ares_dns_write_rr_u8(buf, rr, ARES_RR_SIG_ALGORITHM); 468 if (status != ARES_SUCCESS) { 469 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 470 } 471 472 /* LABELS */ 473 status = ares_dns_write_rr_u8(buf, rr, ARES_RR_SIG_LABELS); 474 if (status != ARES_SUCCESS) { 475 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 476 } 477 478 /* ORIGINAL TTL */ 479 status = ares_dns_write_rr_be32(buf, rr, ARES_RR_SIG_ORIGINAL_TTL); 480 if (status != ARES_SUCCESS) { 481 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 482 } 483 484 /* EXPIRATION */ 485 status = ares_dns_write_rr_be32(buf, rr, ARES_RR_SIG_EXPIRATION); 486 if (status != ARES_SUCCESS) { 487 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 488 } 489 490 /* INCEPTION */ 491 status = ares_dns_write_rr_be32(buf, rr, ARES_RR_SIG_INCEPTION); 492 if (status != ARES_SUCCESS) { 493 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 494 } 495 496 /* KEY TAG */ 497 status = ares_dns_write_rr_be16(buf, rr, ARES_RR_SIG_KEY_TAG); 498 if (status != ARES_SUCCESS) { 499 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 500 } 501 502 /* SIGNERS NAME */ 503 status = ares_dns_write_rr_name(buf, rr, namelist, ARES_FALSE, 504 ARES_RR_SIG_SIGNERS_NAME); 505 if (status != ARES_SUCCESS) { 506 return status; 507 } 508 509 /* SIGNATURE -- binary, rest of buffer, required to be non-zero length */ 510 data = ares_dns_rr_get_bin(rr, ARES_RR_SIG_SIGNATURE, &len); 511 if (data == NULL || len == 0) { 512 return ARES_EFORMERR; 513 } 514 515 return ares_buf_append(buf, data, len); 516 } 517 518 static ares_status_t ares_dns_write_rr_aaaa(ares_buf_t *buf, 519 const ares_dns_rr_t *rr, 520 ares_llist_t **namelist) 521 { 522 const struct ares_in6_addr *addr; 523 (void)namelist; 524 525 addr = ares_dns_rr_get_addr6(rr, ARES_RR_AAAA_ADDR); 526 if (addr == NULL) { 527 return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */ 528 } 529 530 return ares_buf_append(buf, (const unsigned char *)addr, sizeof(*addr)); 531 } 532 533 static ares_status_t ares_dns_write_rr_srv(ares_buf_t *buf, 534 const ares_dns_rr_t *rr, 535 ares_llist_t **namelist) 536 { 537 ares_status_t status; 538 539 /* PRIORITY */ 540 status = ares_dns_write_rr_be16(buf, rr, ARES_RR_SRV_PRIORITY); 541 if (status != ARES_SUCCESS) { 542 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 543 } 544 545 /* WEIGHT */ 546 status = ares_dns_write_rr_be16(buf, rr, ARES_RR_SRV_WEIGHT); 547 if (status != ARES_SUCCESS) { 548 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 549 } 550 551 /* PORT */ 552 status = ares_dns_write_rr_be16(buf, rr, ARES_RR_SRV_PORT); 553 if (status != ARES_SUCCESS) { 554 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 555 } 556 557 /* TARGET */ 558 return ares_dns_write_rr_name(buf, rr, namelist, ARES_FALSE, 559 ARES_RR_SRV_TARGET); 560 } 561 562 static ares_status_t ares_dns_write_rr_naptr(ares_buf_t *buf, 563 const ares_dns_rr_t *rr, 564 ares_llist_t **namelist) 565 { 566 ares_status_t status; 567 568 /* ORDER */ 569 status = ares_dns_write_rr_be16(buf, rr, ARES_RR_NAPTR_ORDER); 570 if (status != ARES_SUCCESS) { 571 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 572 } 573 574 /* PREFERENCE */ 575 status = ares_dns_write_rr_be16(buf, rr, ARES_RR_NAPTR_PREFERENCE); 576 if (status != ARES_SUCCESS) { 577 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 578 } 579 580 /* FLAGS */ 581 status = ares_dns_write_rr_str(buf, rr, ARES_RR_NAPTR_FLAGS); 582 if (status != ARES_SUCCESS) { 583 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 584 } 585 586 /* SERVICES */ 587 status = ares_dns_write_rr_str(buf, rr, ARES_RR_NAPTR_SERVICES); 588 if (status != ARES_SUCCESS) { 589 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 590 } 591 592 /* REGEXP */ 593 status = ares_dns_write_rr_str(buf, rr, ARES_RR_NAPTR_REGEXP); 594 if (status != ARES_SUCCESS) { 595 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 596 } 597 598 /* REPLACEMENT */ 599 return ares_dns_write_rr_name(buf, rr, namelist, ARES_FALSE, 600 ARES_RR_NAPTR_REPLACEMENT); 601 } 602 603 static ares_status_t ares_dns_write_rr_opt(ares_buf_t *buf, 604 const ares_dns_rr_t *rr, 605 ares_llist_t **namelist) 606 { 607 size_t len = ares_buf_len(buf); 608 ares_status_t status; 609 unsigned int ttl = 0; 610 size_t i; 611 unsigned short rcode = (unsigned short)((rr->parent->rcode >> 4) & 0xFF); 612 613 (void)namelist; 614 615 /* Coverity reports on this even though its not possible when taken 616 * into context */ 617 if (len == 0) { 618 return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */ 619 } 620 621 /* We need to go back and overwrite the class and ttl that were emitted as 622 * the OPT record overloads them for its own use (yes, very strange!) */ 623 status = ares_buf_set_length(buf, len - 2 /* RDLENGTH */ 624 - 4 /* TTL */ 625 - 2 /* CLASS */); 626 if (status != ARES_SUCCESS) { 627 return status; 628 } 629 630 /* Class -> UDP Size */ 631 status = ares_dns_write_rr_be16(buf, rr, ARES_RR_OPT_UDP_SIZE); 632 if (status != ARES_SUCCESS) { 633 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 634 } 635 636 /* TTL -> rcode (u8) << 24 | version (u8) << 16 | flags (u16) */ 637 ttl |= (unsigned int)rcode << 24; 638 ttl |= (unsigned int)ares_dns_rr_get_u8(rr, ARES_RR_OPT_VERSION) << 16; 639 ttl |= (unsigned int)ares_dns_rr_get_u16(rr, ARES_RR_OPT_FLAGS); 640 641 status = ares_buf_append_be32(buf, ttl); 642 if (status != ARES_SUCCESS) { 643 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 644 } 645 646 /* Now go back to real end */ 647 status = ares_buf_set_length(buf, len); 648 if (status != ARES_SUCCESS) { 649 return status; 650 } 651 652 /* Append Options */ 653 for (i = 0; i < ares_dns_rr_get_opt_cnt(rr, ARES_RR_OPT_OPTIONS); i++) { 654 unsigned short opt; 655 size_t val_len; 656 const unsigned char *val; 657 658 opt = ares_dns_rr_get_opt(rr, ARES_RR_OPT_OPTIONS, i, &val, &val_len); 659 660 /* BE16 option */ 661 status = ares_buf_append_be16(buf, opt); 662 if (status != ARES_SUCCESS) { 663 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 664 } 665 666 /* BE16 length */ 667 status = ares_buf_append_be16(buf, (unsigned short)(val_len & 0xFFFF)); 668 if (status != ARES_SUCCESS) { 669 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 670 } 671 672 /* Value */ 673 if (val && val_len) { 674 status = ares_buf_append(buf, val, val_len); 675 if (status != ARES_SUCCESS) { 676 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 677 } 678 } 679 } 680 681 return ARES_SUCCESS; 682 } 683 684 static ares_status_t ares_dns_write_rr_tlsa(ares_buf_t *buf, 685 const ares_dns_rr_t *rr, 686 ares_llist_t **namelist) 687 { 688 ares_status_t status; 689 const unsigned char *data; 690 size_t len = 0; 691 692 (void)namelist; 693 694 /* CERT_USAGE */ 695 status = ares_dns_write_rr_u8(buf, rr, ARES_RR_TLSA_CERT_USAGE); 696 if (status != ARES_SUCCESS) { 697 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 698 } 699 700 /* SELECTOR */ 701 status = ares_dns_write_rr_u8(buf, rr, ARES_RR_TLSA_SELECTOR); 702 if (status != ARES_SUCCESS) { 703 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 704 } 705 706 /* MATCH */ 707 status = ares_dns_write_rr_u8(buf, rr, ARES_RR_TLSA_MATCH); 708 if (status != ARES_SUCCESS) { 709 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 710 } 711 712 /* DATA -- binary, rest of buffer, required to be non-zero length */ 713 data = ares_dns_rr_get_bin(rr, ARES_RR_TLSA_DATA, &len); 714 if (data == NULL || len == 0) { 715 return ARES_EFORMERR; 716 } 717 718 return ares_buf_append(buf, data, len); 719 } 720 721 static ares_status_t ares_dns_write_rr_svcb(ares_buf_t *buf, 722 const ares_dns_rr_t *rr, 723 ares_llist_t **namelist) 724 { 725 ares_status_t status; 726 size_t i; 727 728 /* PRIORITY */ 729 status = ares_dns_write_rr_be16(buf, rr, ARES_RR_SVCB_PRIORITY); 730 if (status != ARES_SUCCESS) { 731 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 732 } 733 734 /* TARGET */ 735 status = 736 ares_dns_write_rr_name(buf, rr, namelist, ARES_FALSE, ARES_RR_SVCB_TARGET); 737 if (status != ARES_SUCCESS) { 738 return status; 739 } 740 741 /* Append Params */ 742 for (i = 0; i < ares_dns_rr_get_opt_cnt(rr, ARES_RR_SVCB_PARAMS); i++) { 743 unsigned short opt; 744 size_t val_len; 745 const unsigned char *val; 746 747 opt = ares_dns_rr_get_opt(rr, ARES_RR_SVCB_PARAMS, i, &val, &val_len); 748 749 /* BE16 option */ 750 status = ares_buf_append_be16(buf, opt); 751 if (status != ARES_SUCCESS) { 752 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 753 } 754 755 /* BE16 length */ 756 status = ares_buf_append_be16(buf, (unsigned short)(val_len & 0xFFFF)); 757 if (status != ARES_SUCCESS) { 758 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 759 } 760 761 /* Value */ 762 if (val && val_len) { 763 status = ares_buf_append(buf, val, val_len); 764 if (status != ARES_SUCCESS) { 765 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 766 } 767 } 768 } 769 return ARES_SUCCESS; 770 } 771 772 static ares_status_t ares_dns_write_rr_https(ares_buf_t *buf, 773 const ares_dns_rr_t *rr, 774 ares_llist_t **namelist) 775 { 776 ares_status_t status; 777 size_t i; 778 779 /* PRIORITY */ 780 status = ares_dns_write_rr_be16(buf, rr, ARES_RR_HTTPS_PRIORITY); 781 if (status != ARES_SUCCESS) { 782 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 783 } 784 785 /* TARGET */ 786 status = 787 ares_dns_write_rr_name(buf, rr, namelist, ARES_FALSE, ARES_RR_HTTPS_TARGET); 788 if (status != ARES_SUCCESS) { 789 return status; 790 } 791 792 /* Append Params */ 793 for (i = 0; i < ares_dns_rr_get_opt_cnt(rr, ARES_RR_HTTPS_PARAMS); i++) { 794 unsigned short opt; 795 size_t val_len; 796 const unsigned char *val; 797 798 opt = ares_dns_rr_get_opt(rr, ARES_RR_HTTPS_PARAMS, i, &val, &val_len); 799 800 /* BE16 option */ 801 status = ares_buf_append_be16(buf, opt); 802 if (status != ARES_SUCCESS) { 803 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 804 } 805 806 /* BE16 length */ 807 status = ares_buf_append_be16(buf, (unsigned short)(val_len & 0xFFFF)); 808 if (status != ARES_SUCCESS) { 809 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 810 } 811 812 /* Value */ 813 if (val && val_len) { 814 status = ares_buf_append(buf, val, val_len); 815 if (status != ARES_SUCCESS) { 816 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 817 } 818 } 819 } 820 return ARES_SUCCESS; 821 } 822 823 static ares_status_t ares_dns_write_rr_uri(ares_buf_t *buf, 824 const ares_dns_rr_t *rr, 825 ares_llist_t **namelist) 826 { 827 ares_status_t status; 828 const char *target; 829 830 (void)namelist; 831 832 /* PRIORITY */ 833 status = ares_dns_write_rr_be16(buf, rr, ARES_RR_URI_PRIORITY); 834 if (status != ARES_SUCCESS) { 835 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 836 } 837 838 /* WEIGHT */ 839 status = ares_dns_write_rr_be16(buf, rr, ARES_RR_URI_WEIGHT); 840 if (status != ARES_SUCCESS) { 841 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 842 } 843 844 /* TARGET -- not in DNS string format, rest of buffer, required to be 845 * non-zero length */ 846 target = ares_dns_rr_get_str(rr, ARES_RR_URI_TARGET); 847 if (target == NULL || ares_strlen(target) == 0) { 848 return ARES_EFORMERR; 849 } 850 851 return ares_buf_append(buf, (const unsigned char *)target, 852 ares_strlen(target)); 853 } 854 855 static ares_status_t ares_dns_write_rr_caa(ares_buf_t *buf, 856 const ares_dns_rr_t *rr, 857 ares_llist_t **namelist) 858 { 859 const unsigned char *data = NULL; 860 size_t data_len = 0; 861 ares_status_t status; 862 863 (void)namelist; 864 865 /* CRITICAL */ 866 status = ares_dns_write_rr_u8(buf, rr, ARES_RR_CAA_CRITICAL); 867 if (status != ARES_SUCCESS) { 868 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 869 } 870 871 /* Tag */ 872 status = ares_dns_write_rr_str(buf, rr, ARES_RR_CAA_TAG); 873 if (status != ARES_SUCCESS) { 874 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 875 } 876 877 /* Value - binary! (remaining buffer */ 878 data = ares_dns_rr_get_bin(rr, ARES_RR_CAA_VALUE, &data_len); 879 if (data == NULL || data_len == 0) { 880 return ARES_EFORMERR; 881 } 882 883 return ares_buf_append(buf, data, data_len); 884 } 885 886 static ares_status_t ares_dns_write_rr_raw_rr(ares_buf_t *buf, 887 const ares_dns_rr_t *rr, 888 ares_llist_t **namelist) 889 { 890 size_t len = ares_buf_len(buf); 891 ares_status_t status; 892 const unsigned char *data = NULL; 893 size_t data_len = 0; 894 895 (void)namelist; 896 897 /* Coverity reports on this even though its not possible when taken 898 * into context */ 899 if (len == 0) { 900 return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */ 901 } 902 903 /* We need to go back and overwrite the type that was emitted by the parent 904 * function */ 905 status = ares_buf_set_length(buf, len - 2 /* RDLENGTH */ 906 - 4 /* TTL */ 907 - 2 /* CLASS */ 908 - 2 /* TYPE */); 909 if (status != ARES_SUCCESS) { 910 return status; 911 } 912 913 status = ares_dns_write_rr_be16(buf, rr, ARES_RR_RAW_RR_TYPE); 914 if (status != ARES_SUCCESS) { 915 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 916 } 917 918 /* Now go back to real end */ 919 status = ares_buf_set_length(buf, len); 920 if (status != ARES_SUCCESS) { 921 return status; 922 } 923 924 /* Output raw data */ 925 data = ares_dns_rr_get_bin(rr, ARES_RR_RAW_RR_DATA, &data_len); 926 if (data == NULL) { 927 return ARES_EFORMERR; 928 } 929 930 if (data_len == 0) { 931 return ARES_SUCCESS; 932 } 933 934 return ares_buf_append(buf, data, data_len); 935 } 936 937 static ares_status_t ares_dns_write_rr(const ares_dns_record_t *dnsrec, 938 ares_llist_t **namelist, 939 ares_dns_section_t section, 940 ares_buf_t *buf) 941 { 942 size_t i; 943 944 for (i = 0; i < ares_dns_record_rr_cnt(dnsrec, section); i++) { 945 const ares_dns_rr_t *rr; 946 ares_dns_rec_type_t type; 947 ares_bool_t allow_compress; 948 ares_llist_t **namelistptr = NULL; 949 size_t pos_len; 950 ares_status_t status; 951 size_t rdlength; 952 size_t end_length; 953 unsigned int ttl; 954 955 rr = ares_dns_record_rr_get_const(dnsrec, section, i); 956 if (rr == NULL) { 957 return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */ 958 } 959 960 type = ares_dns_rr_get_type(rr); 961 allow_compress = ares_dns_rec_allow_name_comp(type); 962 if (allow_compress) { 963 namelistptr = namelist; 964 } 965 966 /* Name */ 967 status = 968 ares_dns_name_write(buf, namelist, ARES_TRUE, ares_dns_rr_get_name(rr)); 969 if (status != ARES_SUCCESS) { 970 return status; 971 } 972 973 /* Type */ 974 status = ares_buf_append_be16(buf, (unsigned short)type); 975 if (status != ARES_SUCCESS) { 976 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 977 } 978 979 /* Class */ 980 status = 981 ares_buf_append_be16(buf, (unsigned short)ares_dns_rr_get_class(rr)); 982 if (status != ARES_SUCCESS) { 983 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 984 } 985 986 /* TTL */ 987 ttl = ares_dns_rr_get_ttl(rr); 988 if (rr->parent->ttl_decrement > ttl) { 989 ttl = 0; 990 } else { 991 ttl -= rr->parent->ttl_decrement; 992 } 993 status = ares_buf_append_be32(buf, ttl); 994 if (status != ARES_SUCCESS) { 995 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 996 } 997 998 /* Length */ 999 pos_len = ares_buf_len(buf); /* Save to write real length later */ 1000 status = ares_buf_append_be16(buf, 0); 1001 if (status != ARES_SUCCESS) { 1002 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 1003 } 1004 1005 /* Data */ 1006 switch (type) { 1007 case ARES_REC_TYPE_A: 1008 status = ares_dns_write_rr_a(buf, rr, namelistptr); 1009 break; 1010 case ARES_REC_TYPE_NS: 1011 status = ares_dns_write_rr_ns(buf, rr, namelistptr); 1012 break; 1013 case ARES_REC_TYPE_CNAME: 1014 status = ares_dns_write_rr_cname(buf, rr, namelistptr); 1015 break; 1016 case ARES_REC_TYPE_SOA: 1017 status = ares_dns_write_rr_soa(buf, rr, namelistptr); 1018 break; 1019 case ARES_REC_TYPE_PTR: 1020 status = ares_dns_write_rr_ptr(buf, rr, namelistptr); 1021 break; 1022 case ARES_REC_TYPE_HINFO: 1023 status = ares_dns_write_rr_hinfo(buf, rr, namelistptr); 1024 break; 1025 case ARES_REC_TYPE_MX: 1026 status = ares_dns_write_rr_mx(buf, rr, namelistptr); 1027 break; 1028 case ARES_REC_TYPE_TXT: 1029 status = ares_dns_write_rr_txt(buf, rr, namelistptr); 1030 break; 1031 case ARES_REC_TYPE_SIG: 1032 status = ares_dns_write_rr_sig(buf, rr, namelistptr); 1033 break; 1034 case ARES_REC_TYPE_AAAA: 1035 status = ares_dns_write_rr_aaaa(buf, rr, namelistptr); 1036 break; 1037 case ARES_REC_TYPE_SRV: 1038 status = ares_dns_write_rr_srv(buf, rr, namelistptr); 1039 break; 1040 case ARES_REC_TYPE_NAPTR: 1041 status = ares_dns_write_rr_naptr(buf, rr, namelistptr); 1042 break; 1043 case ARES_REC_TYPE_ANY: 1044 status = ARES_EFORMERR; 1045 break; 1046 case ARES_REC_TYPE_OPT: 1047 status = ares_dns_write_rr_opt(buf, rr, namelistptr); 1048 break; 1049 case ARES_REC_TYPE_TLSA: 1050 status = ares_dns_write_rr_tlsa(buf, rr, namelistptr); 1051 break; 1052 case ARES_REC_TYPE_SVCB: 1053 status = ares_dns_write_rr_svcb(buf, rr, namelistptr); 1054 break; 1055 case ARES_REC_TYPE_HTTPS: 1056 status = ares_dns_write_rr_https(buf, rr, namelistptr); 1057 break; 1058 case ARES_REC_TYPE_URI: 1059 status = ares_dns_write_rr_uri(buf, rr, namelistptr); 1060 break; 1061 case ARES_REC_TYPE_CAA: 1062 status = ares_dns_write_rr_caa(buf, rr, namelistptr); 1063 break; 1064 case ARES_REC_TYPE_RAW_RR: 1065 status = ares_dns_write_rr_raw_rr(buf, rr, namelistptr); 1066 break; 1067 } 1068 1069 if (status != ARES_SUCCESS) { 1070 return status; 1071 } 1072 1073 /* Back off write pointer, write real length, then go back to proper 1074 * position */ 1075 end_length = ares_buf_len(buf); 1076 rdlength = end_length - pos_len - 2; 1077 1078 status = ares_buf_set_length(buf, pos_len); 1079 if (status != ARES_SUCCESS) { 1080 return status; 1081 } 1082 1083 status = ares_buf_append_be16(buf, (unsigned short)(rdlength & 0xFFFF)); 1084 if (status != ARES_SUCCESS) { 1085 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 1086 } 1087 1088 status = ares_buf_set_length(buf, end_length); 1089 if (status != ARES_SUCCESS) { 1090 return status; 1091 } 1092 } 1093 1094 return ARES_SUCCESS; 1095 } 1096 1097 ares_status_t ares_dns_write_buf(const ares_dns_record_t *dnsrec, 1098 ares_buf_t *buf) 1099 { 1100 ares_llist_t *namelist = NULL; 1101 size_t orig_len; 1102 ares_status_t status; 1103 1104 if (dnsrec == NULL || buf == NULL) { 1105 return ARES_EFORMERR; 1106 } 1107 1108 orig_len = ares_buf_len(buf); 1109 1110 status = ares_dns_write_header(dnsrec, buf); 1111 if (status != ARES_SUCCESS) { 1112 goto done; 1113 } 1114 1115 status = ares_dns_write_questions(dnsrec, &namelist, buf); 1116 if (status != ARES_SUCCESS) { 1117 goto done; 1118 } 1119 1120 status = ares_dns_write_rr(dnsrec, &namelist, ARES_SECTION_ANSWER, buf); 1121 if (status != ARES_SUCCESS) { 1122 goto done; 1123 } 1124 1125 status = ares_dns_write_rr(dnsrec, &namelist, ARES_SECTION_AUTHORITY, buf); 1126 if (status != ARES_SUCCESS) { 1127 goto done; 1128 } 1129 1130 status = ares_dns_write_rr(dnsrec, &namelist, ARES_SECTION_ADDITIONAL, buf); 1131 if (status != ARES_SUCCESS) { 1132 goto done; 1133 } 1134 1135 done: 1136 ares_llist_destroy(namelist); 1137 if (status != ARES_SUCCESS) { 1138 ares_buf_set_length(buf, orig_len); 1139 } 1140 1141 return status; 1142 } 1143 1144 ares_status_t ares_dns_write_buf_tcp(const ares_dns_record_t *dnsrec, 1145 ares_buf_t *buf) 1146 { 1147 ares_status_t status; 1148 size_t orig_len; 1149 size_t msg_len; 1150 size_t len; 1151 1152 if (dnsrec == NULL || buf == NULL) { 1153 return ARES_EFORMERR; 1154 } 1155 1156 orig_len = ares_buf_len(buf); 1157 1158 /* Write placeholder for length */ 1159 status = ares_buf_append_be16(buf, 0); 1160 if (status != ARES_SUCCESS) { 1161 goto done; /* LCOV_EXCL_LINE: OutOfMemory */ 1162 } 1163 1164 /* Write message */ 1165 status = ares_dns_write_buf(dnsrec, buf); 1166 if (status != ARES_SUCCESS) { 1167 goto done; /* LCOV_EXCL_LINE: OutOfMemory */ 1168 } 1169 1170 len = ares_buf_len(buf); 1171 msg_len = len - orig_len - 2; 1172 if (msg_len > 65535) { 1173 status = ARES_EBADQUERY; 1174 goto done; 1175 } 1176 1177 /* Now we need to overwrite the length, so we jump back to the original 1178 * message length, overwrite the section and jump back */ 1179 ares_buf_set_length(buf, orig_len); 1180 status = ares_buf_append_be16(buf, (unsigned short)(msg_len & 0xFFFF)); 1181 if (status != ARES_SUCCESS) { 1182 goto done; /* LCOV_EXCL_LINE: UntestablePath */ 1183 } 1184 ares_buf_set_length(buf, len); 1185 1186 done: 1187 if (status != ARES_SUCCESS) { 1188 ares_buf_set_length(buf, orig_len); 1189 } 1190 return status; 1191 } 1192 1193 ares_status_t ares_dns_write(const ares_dns_record_t *dnsrec, 1194 unsigned char **buf, size_t *buf_len) 1195 { 1196 ares_buf_t *b = NULL; 1197 ares_status_t status; 1198 1199 if (buf == NULL || buf_len == NULL || dnsrec == NULL) { 1200 return ARES_EFORMERR; 1201 } 1202 1203 *buf = NULL; 1204 *buf_len = 0; 1205 1206 b = ares_buf_create(); 1207 if (b == NULL) { 1208 return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ 1209 } 1210 1211 status = ares_dns_write_buf(dnsrec, b); 1212 1213 if (status != ARES_SUCCESS) { 1214 ares_buf_destroy(b); 1215 return status; 1216 } 1217 1218 *buf = ares_buf_finish_bin(b, buf_len); 1219 return status; 1220 } 1221 1222 void ares_dns_record_ttl_decrement(ares_dns_record_t *dnsrec, 1223 unsigned int ttl_decrement) 1224 { 1225 if (dnsrec == NULL) { 1226 return; 1227 } 1228 dnsrec->ttl_decrement = ttl_decrement; 1229 }