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_setup.h" 27#include "ares.h" 28#include "ares_private.h" 29#include "ares__buf.h" 30#include <limits.h> 31#ifdef HAVE_STDINT_H 32# include <stdint.h> 33#endif 34 35struct ares__buf { 36 const unsigned char *data; /*!< pointer to start of data buffer */ 37 size_t data_len; /*!< total size of data in buffer */ 38 39 unsigned char *alloc_buf; /*!< Pointer to allocated data buffer, 40 * not used for const buffers */ 41 size_t alloc_buf_len; /*!< Size of allocated data buffer */ 42 43 size_t offset; /*!< Current working offset in buffer */ 44 size_t tag_offset; /*!< Tagged offset in buffer. Uses 45 * SIZE_MAX if not set. */ 46}; 47 48ares_bool_t ares__isprint(int ch) 49{ 50 if (ch >= 0x20 && ch <= 0x7E) { 51 return ARES_TRUE; 52 } 53 return ARES_FALSE; 54} 55 56/* Character set allowed by hostnames. This is to include the normal 57 * domain name character set plus: 58 * - underscores which are used in SRV records. 59 * - Forward slashes such as are used for classless in-addr.arpa 60 * delegation (CNAMEs) 61 * - Asterisks may be used for wildcard domains in CNAMEs as seen in the 62 * real world. 63 * While RFC 2181 section 11 does state not to do validation, 64 * that applies to servers, not clients. Vulnerabilities have been 65 * reported when this validation is not performed. Security is more 66 * important than edge-case compatibility (which is probably invalid 67 * anyhow). */ 68ares_bool_t ares__is_hostnamech(int ch) 69{ 70 /* [A-Za-z0-9-*._/] 71 * Don't use isalnum() as it is locale-specific 72 */ 73 if (ch >= 'A' && ch <= 'Z') { 74 return ARES_TRUE; 75 } 76 if (ch >= 'a' && ch <= 'z') { 77 return ARES_TRUE; 78 } 79 if (ch >= '0' && ch <= '9') { 80 return ARES_TRUE; 81 } 82 if (ch == '-' || ch == '.' || ch == '_' || ch == '/' || ch == '*') { 83 return ARES_TRUE; 84 } 85 86 return ARES_FALSE; 87} 88 89ares__buf_t *ares__buf_create(void) 90{ 91 ares__buf_t *buf = ares_malloc_zero(sizeof(*buf)); 92 if (buf == NULL) { 93 return NULL; 94 } 95 96 buf->tag_offset = SIZE_MAX; 97 return buf; 98} 99 100ares__buf_t *ares__buf_create_const(const unsigned char *data, size_t data_len) 101{ 102 ares__buf_t *buf; 103 104 if (data == NULL || data_len == 0) { 105 return NULL; 106 } 107 108 buf = ares__buf_create(); 109 if (buf == NULL) { 110 return NULL; 111 } 112 113 buf->data = data; 114 buf->data_len = data_len; 115 116 return buf; 117} 118 119void ares__buf_destroy(ares__buf_t *buf) 120{ 121 if (buf == NULL) { 122 return; 123 } 124 ares_free(buf->alloc_buf); 125 ares_free(buf); 126} 127 128static ares_bool_t ares__buf_is_const(const ares__buf_t *buf) 129{ 130 if (buf == NULL) { 131 return ARES_FALSE; 132 } 133 134 if (buf->data != NULL && buf->alloc_buf == NULL) { 135 return ARES_TRUE; 136 } 137 138 return ARES_FALSE; 139} 140 141void ares__buf_reclaim(ares__buf_t *buf) 142{ 143 size_t prefix_size; 144 size_t data_size; 145 146 if (buf == NULL) { 147 return; 148 } 149 150 if (ares__buf_is_const(buf)) { 151 return; 152 } 153 154 /* Silence coverity. All lengths are zero so would bail out later but 155 * coverity doesn't know this */ 156 if (buf->alloc_buf == NULL) { 157 return; 158 } 159 160 if (buf->tag_offset != SIZE_MAX && buf->tag_offset < buf->offset) { 161 prefix_size = buf->tag_offset; 162 } else { 163 prefix_size = buf->offset; 164 } 165 166 if (prefix_size == 0) { 167 return; 168 } 169 170 data_size = buf->data_len - prefix_size; 171 172 memmove(buf->alloc_buf, buf->alloc_buf + prefix_size, data_size); 173 buf->data = buf->alloc_buf; 174 buf->data_len = data_size; 175 buf->offset -= prefix_size; 176 if (buf->tag_offset != SIZE_MAX) { 177 buf->tag_offset -= prefix_size; 178 } 179 180 return; 181} 182 183static ares_status_t ares__buf_ensure_space(ares__buf_t *buf, 184 size_t needed_size) 185{ 186 size_t remaining_size; 187 size_t alloc_size; 188 unsigned char *ptr; 189 190 if (buf == NULL) { 191 return ARES_EFORMERR; 192 } 193 194 if (ares__buf_is_const(buf)) { 195 return ARES_EFORMERR; 196 } 197 198 /* When calling ares__buf_finish_str() we end up adding a null terminator, 199 * so we want to ensure the size is always sufficient for this as we don't 200 * want an ARES_ENOMEM at that point */ 201 needed_size++; 202 203 /* No need to do an expensive move operation, we have enough to just append */ 204 remaining_size = buf->alloc_buf_len - buf->data_len; 205 if (remaining_size >= needed_size) { 206 return ARES_SUCCESS; 207 } 208 209 /* See if just moving consumed data frees up enough space */ 210 ares__buf_reclaim(buf); 211 212 remaining_size = buf->alloc_buf_len - buf->data_len; 213 if (remaining_size >= needed_size) { 214 return ARES_SUCCESS; 215 } 216 217 alloc_size = buf->alloc_buf_len; 218 219 /* Not yet started */ 220 if (alloc_size == 0) { 221 alloc_size = 16; /* Always shifts 1, so ends up being 32 minimum */ 222 } 223 224 /* Increase allocation by powers of 2 */ 225 do { 226 alloc_size <<= 1; 227 remaining_size = alloc_size - buf->data_len; 228 } while (remaining_size < needed_size); 229 230 ptr = ares_realloc(buf->alloc_buf, alloc_size); 231 if (ptr == NULL) { 232 return ARES_ENOMEM; 233 } 234 235 buf->alloc_buf = ptr; 236 buf->alloc_buf_len = alloc_size; 237 buf->data = ptr; 238 239 return ARES_SUCCESS; 240} 241 242ares_status_t ares__buf_set_length(ares__buf_t *buf, size_t len) 243{ 244 if (buf == NULL || ares__buf_is_const(buf)) { 245 return ARES_EFORMERR; 246 } 247 248 if (len >= buf->alloc_buf_len - buf->offset) { 249 return ARES_EFORMERR; 250 } 251 252 buf->data_len = len; 253 return ARES_SUCCESS; 254} 255 256ares_status_t ares__buf_append(ares__buf_t *buf, const unsigned char *data, 257 size_t data_len) 258{ 259 ares_status_t status; 260 261 if (data == NULL || data_len == 0) { 262 return ARES_EFORMERR; 263 } 264 265 status = ares__buf_ensure_space(buf, data_len); 266 if (status != ARES_SUCCESS) { 267 return status; 268 } 269 270 memcpy(buf->alloc_buf + buf->data_len, data, data_len); 271 buf->data_len += data_len; 272 return ARES_SUCCESS; 273} 274 275ares_status_t ares__buf_append_byte(ares__buf_t *buf, unsigned char byte) 276{ 277 return ares__buf_append(buf, &byte, 1); 278} 279 280ares_status_t ares__buf_append_be16(ares__buf_t *buf, unsigned short u16) 281{ 282 ares_status_t status; 283 284 status = ares__buf_append_byte(buf, (unsigned char)((u16 >> 8) & 0xff)); 285 if (status != ARES_SUCCESS) { 286 return status; 287 } 288 289 status = ares__buf_append_byte(buf, (unsigned char)(u16 & 0xff)); 290 if (status != ARES_SUCCESS) { 291 return status; 292 } 293 294 return ARES_SUCCESS; 295} 296 297ares_status_t ares__buf_append_be32(ares__buf_t *buf, unsigned int u32) 298{ 299 ares_status_t status; 300 301 status = ares__buf_append_byte(buf, ((unsigned char)(u32 >> 24) & 0xff)); 302 if (status != ARES_SUCCESS) { 303 return status; 304 } 305 306 status = ares__buf_append_byte(buf, ((unsigned char)(u32 >> 16) & 0xff)); 307 if (status != ARES_SUCCESS) { 308 return status; 309 } 310 311 status = ares__buf_append_byte(buf, ((unsigned char)(u32 >> 8) & 0xff)); 312 if (status != ARES_SUCCESS) { 313 return status; 314 } 315 316 status = ares__buf_append_byte(buf, ((unsigned char)u32 & 0xff)); 317 if (status != ARES_SUCCESS) { 318 return status; 319 } 320 321 return ARES_SUCCESS; 322} 323 324unsigned char *ares__buf_append_start(ares__buf_t *buf, size_t *len) 325{ 326 ares_status_t status; 327 328 if (len == NULL || *len == 0) { 329 return NULL; 330 } 331 332 status = ares__buf_ensure_space(buf, *len); 333 if (status != ARES_SUCCESS) { 334 return NULL; 335 } 336 337 /* -1 for possible null terminator for ares__buf_finish_str() */ 338 *len = buf->alloc_buf_len - buf->data_len - 1; 339 return buf->alloc_buf + buf->data_len; 340} 341 342void ares__buf_append_finish(ares__buf_t *buf, size_t len) 343{ 344 if (buf == NULL) { 345 return; 346 } 347 348 buf->data_len += len; 349} 350 351unsigned char *ares__buf_finish_bin(ares__buf_t *buf, size_t *len) 352{ 353 unsigned char *ptr = NULL; 354 if (buf == NULL || len == NULL || ares__buf_is_const(buf)) { 355 return NULL; 356 } 357 358 ares__buf_reclaim(buf); 359 360 /* We don't want to return NULL except on failure, may be zero-length */ 361 if (buf->alloc_buf == NULL && 362 ares__buf_ensure_space(buf, 1) != ARES_SUCCESS) { 363 return NULL; 364 } 365 ptr = buf->alloc_buf; 366 *len = buf->data_len; 367 ares_free(buf); 368 return ptr; 369} 370 371char *ares__buf_finish_str(ares__buf_t *buf, size_t *len) 372{ 373 char *ptr; 374 size_t mylen; 375 376 ptr = (char *)ares__buf_finish_bin(buf, &mylen); 377 if (ptr == NULL) { 378 return NULL; 379 } 380 381 if (len != NULL) { 382 *len = mylen; 383 } 384 385 /* NOTE: ensured via ares__buf_ensure_space() that there is always at least 386 * 1 extra byte available for this specific use-case */ 387 ptr[mylen] = 0; 388 389 return ptr; 390} 391 392void ares__buf_tag(ares__buf_t *buf) 393{ 394 if (buf == NULL) { 395 return; 396 } 397 398 buf->tag_offset = buf->offset; 399} 400 401ares_status_t ares__buf_tag_rollback(ares__buf_t *buf) 402{ 403 if (buf == NULL || buf->tag_offset == SIZE_MAX) { 404 return ARES_EFORMERR; 405 } 406 407 buf->offset = buf->tag_offset; 408 buf->tag_offset = SIZE_MAX; 409 return ARES_SUCCESS; 410} 411 412ares_status_t ares__buf_tag_clear(ares__buf_t *buf) 413{ 414 if (buf == NULL || buf->tag_offset == SIZE_MAX) { 415 return ARES_EFORMERR; 416 } 417 418 buf->tag_offset = SIZE_MAX; 419 return ARES_SUCCESS; 420} 421 422const unsigned char *ares__buf_tag_fetch(const ares__buf_t *buf, size_t *len) 423{ 424 if (buf == NULL || buf->tag_offset == SIZE_MAX || len == NULL) { 425 return NULL; 426 } 427 428 *len = buf->offset - buf->tag_offset; 429 return buf->data + buf->tag_offset; 430} 431 432size_t ares__buf_tag_length(const ares__buf_t *buf) 433{ 434 if (buf == NULL || buf->tag_offset == SIZE_MAX) { 435 return 0; 436 } 437 return buf->offset - buf->tag_offset; 438} 439 440ares_status_t ares__buf_tag_fetch_bytes(const ares__buf_t *buf, 441 unsigned char *bytes, size_t *len) 442{ 443 size_t ptr_len = 0; 444 const unsigned char *ptr = ares__buf_tag_fetch(buf, &ptr_len); 445 446 if (ptr == NULL || bytes == NULL || len == NULL) { 447 return ARES_EFORMERR; 448 } 449 450 if (*len < ptr_len) { 451 return ARES_EFORMERR; 452 } 453 454 *len = ptr_len; 455 456 if (ptr_len > 0) { 457 memcpy(bytes, ptr, ptr_len); 458 } 459 return ARES_SUCCESS; 460} 461 462ares_status_t ares__buf_tag_fetch_string(const ares__buf_t *buf, char *str, 463 size_t len) 464{ 465 size_t out_len; 466 ares_status_t status; 467 size_t i; 468 469 if (str == NULL || len == 0) { 470 return ARES_EFORMERR; 471 } 472 473 /* Space for NULL terminator */ 474 out_len = len - 1; 475 476 status = ares__buf_tag_fetch_bytes(buf, (unsigned char *)str, &out_len); 477 if (status != ARES_SUCCESS) { 478 return status; 479 } 480 481 /* NULL terminate */ 482 str[out_len] = 0; 483 484 /* Validate string is printable */ 485 for (i = 0; i < out_len; i++) { 486 if (!ares__isprint(str[i])) { 487 return ARES_EBADSTR; 488 } 489 } 490 491 return ARES_SUCCESS; 492} 493 494static const unsigned char *ares__buf_fetch(const ares__buf_t *buf, size_t *len) 495{ 496 if (len != NULL) { 497 *len = 0; 498 } 499 500 if (buf == NULL || len == NULL || buf->data == NULL) { 501 return NULL; 502 } 503 504 *len = buf->data_len - buf->offset; 505 if (*len == 0) { 506 return NULL; 507 } 508 509 return buf->data + buf->offset; 510} 511 512ares_status_t ares__buf_consume(ares__buf_t *buf, size_t len) 513{ 514 size_t remaining_len = ares__buf_len(buf); 515 516 if (remaining_len < len) { 517 return ARES_EBADRESP; 518 } 519 520 buf->offset += len; 521 return ARES_SUCCESS; 522} 523 524ares_status_t ares__buf_fetch_be16(ares__buf_t *buf, unsigned short *u16) 525{ 526 size_t remaining_len; 527 const unsigned char *ptr = ares__buf_fetch(buf, &remaining_len); 528 unsigned int u32; 529 530 if (buf == NULL || u16 == NULL || remaining_len < sizeof(*u16)) { 531 return ARES_EBADRESP; 532 } 533 534 /* Do math in an unsigned int in order to prevent warnings due to automatic 535 * conversion by the compiler from short to int during shifts */ 536 u32 = ((unsigned int)(ptr[0]) << 8 | (unsigned int)ptr[1]); 537 *u16 = (unsigned short)(u32 & 0xFFFF); 538 539 return ares__buf_consume(buf, sizeof(*u16)); 540} 541 542ares_status_t ares__buf_fetch_be32(ares__buf_t *buf, unsigned int *u32) 543{ 544 size_t remaining_len; 545 const unsigned char *ptr = ares__buf_fetch(buf, &remaining_len); 546 547 if (buf == NULL || u32 == NULL || remaining_len < sizeof(*u32)) { 548 return ARES_EBADRESP; 549 } 550 551 *u32 = ((unsigned int)(ptr[0]) << 24 | (unsigned int)(ptr[1]) << 16 | 552 (unsigned int)(ptr[2]) << 8 | (unsigned int)(ptr[3])); 553 554 return ares__buf_consume(buf, sizeof(*u32)); 555} 556 557ares_status_t ares__buf_fetch_bytes(ares__buf_t *buf, unsigned char *bytes, 558 size_t len) 559{ 560 size_t remaining_len; 561 const unsigned char *ptr = ares__buf_fetch(buf, &remaining_len); 562 563 if (buf == NULL || bytes == NULL || len == 0 || remaining_len < len) { 564 return ARES_EBADRESP; 565 } 566 567 memcpy(bytes, ptr, len); 568 return ares__buf_consume(buf, len); 569} 570 571ares_status_t ares__buf_fetch_bytes_dup(ares__buf_t *buf, size_t len, 572 ares_bool_t null_term, 573 unsigned char **bytes) 574{ 575 size_t remaining_len; 576 const unsigned char *ptr = ares__buf_fetch(buf, &remaining_len); 577 578 if (buf == NULL || bytes == NULL || len == 0 || remaining_len < len) { 579 return ARES_EBADRESP; 580 } 581 582 *bytes = ares_malloc(null_term ? len + 1 : len); 583 if (*bytes == NULL) { 584 return ARES_ENOMEM; 585 } 586 587 memcpy(*bytes, ptr, len); 588 if (null_term) { 589 (*bytes)[len] = 0; 590 } 591 return ares__buf_consume(buf, len); 592} 593 594ares_status_t ares__buf_fetch_str_dup(ares__buf_t *buf, size_t len, char **str) 595{ 596 size_t remaining_len; 597 const unsigned char *ptr = ares__buf_fetch(buf, &remaining_len); 598 599 if (buf == NULL || str == NULL || len == 0 || remaining_len < len) { 600 return ARES_EBADRESP; 601 } 602 603 *str = ares_malloc(len + 1); 604 if (*str == NULL) { 605 return ARES_ENOMEM; 606 } 607 608 memcpy(*str, ptr, len); 609 (*str)[len] = 0; 610 611 return ares__buf_consume(buf, len); 612} 613 614ares_status_t ares__buf_fetch_bytes_into_buf(ares__buf_t *buf, 615 ares__buf_t *dest, size_t len) 616{ 617 size_t remaining_len; 618 const unsigned char *ptr = ares__buf_fetch(buf, &remaining_len); 619 ares_status_t status; 620 621 if (buf == NULL || dest == NULL || len == 0 || remaining_len < len) { 622 return ARES_EBADRESP; 623 } 624 625 status = ares__buf_append(dest, ptr, len); 626 if (status != ARES_SUCCESS) { 627 return status; 628 } 629 630 return ares__buf_consume(buf, len); 631} 632 633size_t ares__buf_consume_whitespace(ares__buf_t *buf, 634 ares_bool_t include_linefeed) 635{ 636 size_t remaining_len = 0; 637 const unsigned char *ptr = ares__buf_fetch(buf, &remaining_len); 638 size_t i; 639 640 if (ptr == NULL) { 641 return 0; 642 } 643 644 for (i = 0; i < remaining_len; i++) { 645 switch (ptr[i]) { 646 case '\r': 647 case '\t': 648 case ' ': 649 case '\v': 650 case '\f': 651 break; 652 case '\n': 653 if (!include_linefeed) { 654 goto done; 655 } 656 break; 657 default: 658 goto done; 659 } 660 } 661 662done: 663 if (i > 0) { 664 ares__buf_consume(buf, i); 665 } 666 return i; 667} 668 669size_t ares__buf_consume_nonwhitespace(ares__buf_t *buf) 670{ 671 size_t remaining_len = 0; 672 const unsigned char *ptr = ares__buf_fetch(buf, &remaining_len); 673 size_t i; 674 675 if (ptr == NULL) { 676 return 0; 677 } 678 679 for (i = 0; i < remaining_len; i++) { 680 switch (ptr[i]) { 681 case '\r': 682 case '\t': 683 case ' ': 684 case '\v': 685 case '\f': 686 case '\n': 687 goto done; 688 default: 689 break; 690 } 691 } 692 693done: 694 if (i > 0) { 695 ares__buf_consume(buf, i); 696 } 697 return i; 698} 699 700size_t ares__buf_consume_line(ares__buf_t *buf, ares_bool_t include_linefeed) 701{ 702 size_t remaining_len = 0; 703 const unsigned char *ptr = ares__buf_fetch(buf, &remaining_len); 704 size_t i; 705 706 if (ptr == NULL) { 707 return 0; 708 } 709 710 for (i = 0; i < remaining_len; i++) { 711 if (ptr[i] == '\n') { 712 goto done; 713 } 714 } 715 716done: 717 if (include_linefeed && i < remaining_len && ptr[i] == '\n') { 718 i++; 719 } 720 721 if (i > 0) { 722 ares__buf_consume(buf, i); 723 } 724 return i; 725} 726 727size_t ares__buf_consume_until_charset(ares__buf_t *buf, 728 const unsigned char *charset, size_t len, 729 ares_bool_t require_charset) 730{ 731 size_t remaining_len = 0; 732 const unsigned char *ptr = ares__buf_fetch(buf, &remaining_len); 733 size_t i; 734 ares_bool_t found = ARES_FALSE; 735 736 if (ptr == NULL || charset == NULL || len == 0) { 737 return 0; 738 } 739 740 for (i = 0; i < remaining_len; i++) { 741 size_t j; 742 for (j = 0; j < len; j++) { 743 if (ptr[i] == charset[j]) { 744 found = ARES_TRUE; 745 goto done; 746 } 747 } 748 } 749 750done: 751 if (require_charset && !found) { 752 return 0; 753 } 754 755 if (i > 0) { 756 ares__buf_consume(buf, i); 757 } 758 return i; 759} 760 761size_t ares__buf_consume_charset(ares__buf_t *buf, const unsigned char *charset, 762 size_t len) 763{ 764 size_t remaining_len = 0; 765 const unsigned char *ptr = ares__buf_fetch(buf, &remaining_len); 766 size_t i; 767 768 if (ptr == NULL || charset == NULL || len == 0) { 769 return 0; 770 } 771 772 for (i = 0; i < remaining_len; i++) { 773 size_t j; 774 for (j = 0; j < len; j++) { 775 if (ptr[i] == charset[j]) { 776 break; 777 } 778 } 779 /* Not found */ 780 if (j == len) { 781 break; 782 } 783 } 784 785 if (i > 0) { 786 ares__buf_consume(buf, i); 787 } 788 return i; 789} 790 791static void ares__buf_destroy_cb(void *arg) 792{ 793 ares__buf_destroy(arg); 794} 795 796static ares_bool_t ares__buf_split_isduplicate(ares__llist_t *list, 797 const unsigned char *val, 798 size_t len, 799 ares__buf_split_t flags) 800{ 801 ares__llist_node_t *node; 802 803 for (node = ares__llist_node_first(list); node != NULL; 804 node = ares__llist_node_next(node)) { 805 const ares__buf_t *buf = ares__llist_node_val(node); 806 size_t plen = 0; 807 const unsigned char *ptr = ares__buf_peek(buf, &plen); 808 809 /* Can't be duplicate if lengths mismatch */ 810 if (plen != len) { 811 continue; 812 } 813 814 if (flags & ARES_BUF_SPLIT_CASE_INSENSITIVE) { 815 if (ares__memeq_ci(ptr, val, len)) { 816 return ARES_TRUE; 817 } 818 } else { 819 if (memcmp(ptr, val, len) == 0) { 820 return ARES_TRUE; 821 } 822 } 823 } 824 return ARES_FALSE; 825} 826 827ares_status_t ares__buf_split(ares__buf_t *buf, const unsigned char *delims, 828 size_t delims_len, ares__buf_split_t flags, 829 ares__llist_t **list) 830{ 831 ares_status_t status = ARES_SUCCESS; 832 ares_bool_t first = ARES_TRUE; 833 834 if (buf == NULL || delims == NULL || delims_len == 0 || list == NULL) { 835 return ARES_EFORMERR; 836 } 837 838 *list = ares__llist_create(ares__buf_destroy_cb); 839 if (*list == NULL) { 840 status = ARES_ENOMEM; 841 goto done; 842 } 843 844 while (ares__buf_len(buf)) { 845 size_t len; 846 847 ares__buf_tag(buf); 848 849 len = ares__buf_consume_until_charset(buf, delims, delims_len, ARES_FALSE); 850 851 /* Don't treat a delimiter as part of the length */ 852 if (!first && len && flags & ARES_BUF_SPLIT_DONT_CONSUME_DELIMS) { 853 len--; 854 } 855 856 if (len != 0 || flags & ARES_BUF_SPLIT_ALLOW_BLANK) { 857 const unsigned char *ptr = ares__buf_tag_fetch(buf, &len); 858 ares__buf_t *data; 859 860 if (!(flags & ARES_BUF_SPLIT_NO_DUPLICATES) || 861 !ares__buf_split_isduplicate(*list, ptr, len, flags)) { 862 /* Since we don't allow const buffers of 0 length, and user wants 863 * 0-length buffers, swap what we do here */ 864 if (len) { 865 data = ares__buf_create_const(ptr, len); 866 } else { 867 data = ares__buf_create(); 868 } 869 870 if (data == NULL) { 871 status = ARES_ENOMEM; 872 goto done; 873 } 874 875 if (ares__llist_insert_last(*list, data) == NULL) { 876 ares__buf_destroy(data); 877 status = ARES_ENOMEM; 878 goto done; 879 } 880 } 881 } 882 883 if (!(flags & ARES_BUF_SPLIT_DONT_CONSUME_DELIMS) && 884 ares__buf_len(buf) != 0) { 885 /* Consume delimiter */ 886 ares__buf_consume(buf, 1); 887 } 888 889 first = ARES_FALSE; 890 } 891 892done: 893 if (status != ARES_SUCCESS) { 894 ares__llist_destroy(*list); 895 *list = NULL; 896 } 897 898 return status; 899} 900 901ares_bool_t ares__buf_begins_with(const ares__buf_t *buf, 902 const unsigned char *data, size_t data_len) 903{ 904 size_t remaining_len = 0; 905 const unsigned char *ptr = ares__buf_fetch(buf, &remaining_len); 906 907 if (ptr == NULL || data == NULL || data_len == 0) { 908 return ARES_FALSE; 909 } 910 911 if (data_len > remaining_len) { 912 return ARES_FALSE; 913 } 914 915 if (memcmp(ptr, data, data_len) != 0) { 916 return ARES_FALSE; 917 } 918 919 return ARES_TRUE; 920} 921 922size_t ares__buf_len(const ares__buf_t *buf) 923{ 924 if (buf == NULL) { 925 return 0; 926 } 927 928 return buf->data_len - buf->offset; 929} 930 931const unsigned char *ares__buf_peek(const ares__buf_t *buf, size_t *len) 932{ 933 return ares__buf_fetch(buf, len); 934} 935 936size_t ares__buf_get_position(const ares__buf_t *buf) 937{ 938 if (buf == NULL) { 939 return 0; 940 } 941 return buf->offset; 942} 943 944ares_status_t ares__buf_set_position(ares__buf_t *buf, size_t idx) 945{ 946 if (buf == NULL) { 947 return ARES_EFORMERR; 948 } 949 950 if (idx > buf->data_len) { 951 return ARES_EFORMERR; 952 } 953 954 buf->offset = idx; 955 return ARES_SUCCESS; 956} 957 958ares_status_t ares__buf_parse_dns_binstr(ares__buf_t *buf, size_t remaining_len, 959 unsigned char **bin, size_t *bin_len, 960 ares_bool_t allow_multiple) 961{ 962 unsigned char len; 963 ares_status_t status; 964 ares__buf_t *binbuf = NULL; 965 size_t orig_len = ares__buf_len(buf); 966 967 if (buf == NULL) { 968 return ARES_EFORMERR; 969 } 970 971 if (remaining_len == 0) { 972 return ARES_EBADRESP; 973 } 974 975 binbuf = ares__buf_create(); 976 if (binbuf == NULL) { 977 return ARES_ENOMEM; 978 } 979 980 while (orig_len - ares__buf_len(buf) < remaining_len) { 981 status = ares__buf_fetch_bytes(buf, &len, 1); 982 if (status != ARES_SUCCESS) { 983 break; 984 } 985 986 if (len) { 987 /* XXX: Maybe we should scan to make sure it is printable? */ 988 if (bin != NULL) { 989 status = ares__buf_fetch_bytes_into_buf(buf, binbuf, len); 990 } else { 991 status = ares__buf_consume(buf, len); 992 } 993 if (status != ARES_SUCCESS) { 994 break; 995 } 996 } 997 998 if (!allow_multiple) { 999 break; 1000 } 1001 } 1002 1003 1004 if (status != ARES_SUCCESS) { 1005 ares__buf_destroy(binbuf); 1006 } else { 1007 if (bin != NULL) { 1008 size_t mylen = 0; 1009 /* NOTE: we use ares__buf_finish_str() here as we guarantee NULL 1010 * Termination even though we are technically returning binary data. 1011 */ 1012 *bin = (unsigned char *)ares__buf_finish_str(binbuf, &mylen); 1013 *bin_len = mylen; 1014 } 1015 } 1016 1017 return status; 1018} 1019 1020ares_status_t ares__buf_parse_dns_str(ares__buf_t *buf, size_t remaining_len, 1021 char **str, ares_bool_t allow_multiple) 1022{ 1023 size_t len; 1024 return ares__buf_parse_dns_binstr(buf, remaining_len, (unsigned char **)str, 1025 &len, allow_multiple); 1026} 1027 1028ares_status_t ares__buf_append_num_dec(ares__buf_t *buf, size_t num, size_t len) 1029{ 1030 size_t i; 1031 size_t mod; 1032 1033 if (len == 0) { 1034 len = ares__count_digits(num); 1035 } 1036 1037 mod = ares__pow(10, len); 1038 1039 for (i = len; i > 0; i--) { 1040 size_t digit = (num % mod); 1041 ares_status_t status; 1042 1043 mod /= 10; 1044 1045 /* Silence coverity. Shouldn't be possible since we calculate it above */ 1046 if (mod == 0) { 1047 return ARES_EFORMERR; 1048 } 1049 1050 digit /= mod; 1051 status = ares__buf_append_byte(buf, '0' + (unsigned char)(digit & 0xFF)); 1052 if (status != ARES_SUCCESS) { 1053 return status; 1054 } 1055 } 1056 return ARES_SUCCESS; 1057} 1058 1059ares_status_t ares__buf_append_num_hex(ares__buf_t *buf, size_t num, size_t len) 1060{ 1061 size_t i; 1062 static const unsigned char hexbytes[] = "0123456789ABCDEF"; 1063 1064 if (len == 0) { 1065 len = ares__count_hexdigits(num); 1066 } 1067 1068 for (i = len; i > 0; i--) { 1069 ares_status_t status; 1070 status = ares__buf_append_byte(buf, hexbytes[(num >> ((i - 1) * 4)) & 0xF]); 1071 if (status != ARES_SUCCESS) { 1072 return status; 1073 } 1074 } 1075 return ARES_SUCCESS; 1076} 1077 1078ares_status_t ares__buf_append_str(ares__buf_t *buf, const char *str) 1079{ 1080 return ares__buf_append(buf, (const unsigned char *)str, ares_strlen(str)); 1081} 1082 1083static ares_status_t ares__buf_hexdump_line(ares__buf_t *buf, size_t idx, 1084 const unsigned char *data, 1085 size_t len) 1086{ 1087 size_t i; 1088 ares_status_t status; 1089 1090 /* Address */ 1091 status = ares__buf_append_num_hex(buf, idx, 6); 1092 if (status != ARES_SUCCESS) { 1093 return status; 1094 } 1095 1096 /* | */ 1097 status = ares__buf_append_str(buf, " | "); 1098 if (status != ARES_SUCCESS) { 1099 return status; 1100 } 1101 1102 for (i = 0; i < 16; i++) { 1103 if (i >= len) { 1104 status = ares__buf_append_str(buf, " "); 1105 } else { 1106 status = ares__buf_append_num_hex(buf, data[i], 2); 1107 } 1108 if (status != ARES_SUCCESS) { 1109 return status; 1110 } 1111 1112 status = ares__buf_append_byte(buf, ' '); 1113 if (status != ARES_SUCCESS) { 1114 return status; 1115 } 1116 } 1117 1118 /* | */ 1119 status = ares__buf_append_str(buf, " | "); 1120 if (status != ARES_SUCCESS) { 1121 return status; 1122 } 1123 1124 for (i = 0; i < 16; i++) { 1125 if (i >= len) { 1126 break; 1127 } 1128 status = ares__buf_append_byte(buf, ares__isprint(data[i]) ? data[i] : '.'); 1129 if (status != ARES_SUCCESS) { 1130 return status; 1131 } 1132 } 1133 1134 return ares__buf_append_byte(buf, '\n'); 1135} 1136 1137ares_status_t ares__buf_hexdump(ares__buf_t *buf, const unsigned char *data, 1138 size_t len) 1139{ 1140 size_t i; 1141 1142 /* Each line is 16 bytes */ 1143 for (i = 0; i < len; i += 16) { 1144 ares_status_t status; 1145 status = ares__buf_hexdump_line(buf, i, data + i, len - i); 1146 if (status != ARES_SUCCESS) { 1147 return status; 1148 } 1149 } 1150 1151 return ARES_SUCCESS; 1152} 1153