ares_buf.c (36767B)
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 "ares_buf.h" 28 #include <limits.h> 29 #ifdef HAVE_STDINT_H 30 # include <stdint.h> 31 #endif 32 33 struct ares_buf { 34 const unsigned char *data; /*!< pointer to start of data buffer */ 35 size_t data_len; /*!< total size of data in buffer */ 36 37 unsigned char *alloc_buf; /*!< Pointer to allocated data buffer, 38 * not used for const buffers */ 39 size_t alloc_buf_len; /*!< Size of allocated data buffer */ 40 41 size_t offset; /*!< Current working offset in buffer */ 42 size_t tag_offset; /*!< Tagged offset in buffer. Uses 43 * SIZE_MAX if not set. */ 44 }; 45 46 ares_buf_t *ares_buf_create(void) 47 { 48 ares_buf_t *buf = ares_malloc_zero(sizeof(*buf)); 49 if (buf == NULL) { 50 return NULL; 51 } 52 53 buf->tag_offset = SIZE_MAX; 54 return buf; 55 } 56 57 ares_buf_t *ares_buf_create_const(const unsigned char *data, size_t data_len) 58 { 59 ares_buf_t *buf; 60 61 if (data == NULL || data_len == 0) { 62 return NULL; 63 } 64 65 buf = ares_buf_create(); 66 if (buf == NULL) { 67 return NULL; 68 } 69 70 buf->data = data; 71 buf->data_len = data_len; 72 73 return buf; 74 } 75 76 void ares_buf_destroy(ares_buf_t *buf) 77 { 78 if (buf == NULL) { 79 return; 80 } 81 ares_free(buf->alloc_buf); 82 ares_free(buf); 83 } 84 85 static ares_bool_t ares_buf_is_const(const ares_buf_t *buf) 86 { 87 if (buf == NULL) { 88 return ARES_FALSE; /* LCOV_EXCL_LINE: DefensiveCoding */ 89 } 90 91 if (buf->data != NULL && buf->alloc_buf == NULL) { 92 return ARES_TRUE; 93 } 94 95 return ARES_FALSE; 96 } 97 98 void ares_buf_reclaim(ares_buf_t *buf) 99 { 100 size_t prefix_size; 101 size_t data_size; 102 103 if (buf == NULL) { 104 return; 105 } 106 107 if (ares_buf_is_const(buf)) { 108 return; /* LCOV_EXCL_LINE: DefensiveCoding */ 109 } 110 111 /* Silence coverity. All lengths are zero so would bail out later but 112 * coverity doesn't know this */ 113 if (buf->alloc_buf == NULL) { 114 return; 115 } 116 117 if (buf->tag_offset != SIZE_MAX && buf->tag_offset < buf->offset) { 118 prefix_size = buf->tag_offset; 119 } else { 120 prefix_size = buf->offset; 121 } 122 123 if (prefix_size == 0) { 124 return; 125 } 126 127 data_size = buf->data_len - prefix_size; 128 129 memmove(buf->alloc_buf, buf->alloc_buf + prefix_size, data_size); 130 buf->data = buf->alloc_buf; 131 buf->data_len = data_size; 132 buf->offset -= prefix_size; 133 if (buf->tag_offset != SIZE_MAX) { 134 buf->tag_offset -= prefix_size; 135 } 136 } 137 138 static ares_status_t ares_buf_ensure_space(ares_buf_t *buf, size_t needed_size) 139 { 140 size_t remaining_size; 141 size_t alloc_size; 142 unsigned char *ptr; 143 144 if (buf == NULL) { 145 return ARES_EFORMERR; 146 } 147 148 if (ares_buf_is_const(buf)) { 149 return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */ 150 } 151 152 /* When calling ares_buf_finish_str() we end up adding a null terminator, 153 * so we want to ensure the size is always sufficient for this as we don't 154 * want an ARES_ENOMEM at that point */ 155 needed_size++; 156 157 /* No need to do an expensive move operation, we have enough to just append */ 158 remaining_size = buf->alloc_buf_len - buf->data_len; 159 if (remaining_size >= needed_size) { 160 return ARES_SUCCESS; 161 } 162 163 /* See if just moving consumed data frees up enough space */ 164 ares_buf_reclaim(buf); 165 166 remaining_size = buf->alloc_buf_len - buf->data_len; 167 if (remaining_size >= needed_size) { 168 return ARES_SUCCESS; 169 } 170 171 alloc_size = buf->alloc_buf_len; 172 173 /* Not yet started */ 174 if (alloc_size == 0) { 175 alloc_size = 16; /* Always shifts 1, so ends up being 32 minimum */ 176 } 177 178 /* Increase allocation by powers of 2 */ 179 do { 180 alloc_size <<= 1; 181 remaining_size = alloc_size - buf->data_len; 182 } while (remaining_size < needed_size); 183 184 ptr = ares_realloc(buf->alloc_buf, alloc_size); 185 if (ptr == NULL) { 186 return ARES_ENOMEM; 187 } 188 189 buf->alloc_buf = ptr; 190 buf->alloc_buf_len = alloc_size; 191 buf->data = ptr; 192 193 return ARES_SUCCESS; 194 } 195 196 ares_status_t ares_buf_set_length(ares_buf_t *buf, size_t len) 197 { 198 if (buf == NULL || ares_buf_is_const(buf)) { 199 return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */ 200 } 201 202 if (len >= buf->alloc_buf_len - buf->offset) { 203 return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */ 204 } 205 206 buf->data_len = len + buf->offset; 207 return ARES_SUCCESS; 208 } 209 210 ares_status_t ares_buf_append(ares_buf_t *buf, const unsigned char *data, 211 size_t data_len) 212 { 213 ares_status_t status; 214 215 if (data == NULL && data_len != 0) { 216 return ARES_EFORMERR; 217 } 218 219 if (data_len == 0) { 220 return ARES_SUCCESS; 221 } 222 223 status = ares_buf_ensure_space(buf, data_len); 224 if (status != ARES_SUCCESS) { 225 return status; 226 } 227 228 memcpy(buf->alloc_buf + buf->data_len, data, data_len); 229 buf->data_len += data_len; 230 return ARES_SUCCESS; 231 } 232 233 ares_status_t ares_buf_append_byte(ares_buf_t *buf, unsigned char b) 234 { 235 return ares_buf_append(buf, &b, 1); 236 } 237 238 ares_status_t ares_buf_append_be16(ares_buf_t *buf, unsigned short u16) 239 { 240 ares_status_t status; 241 242 status = ares_buf_append_byte(buf, (unsigned char)((u16 >> 8) & 0xff)); 243 if (status != ARES_SUCCESS) { 244 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 245 } 246 247 status = ares_buf_append_byte(buf, (unsigned char)(u16 & 0xff)); 248 if (status != ARES_SUCCESS) { 249 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 250 } 251 252 return ARES_SUCCESS; 253 } 254 255 ares_status_t ares_buf_append_be32(ares_buf_t *buf, unsigned int u32) 256 { 257 ares_status_t status; 258 259 status = ares_buf_append_byte(buf, ((unsigned char)(u32 >> 24) & 0xff)); 260 if (status != ARES_SUCCESS) { 261 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 262 } 263 264 status = ares_buf_append_byte(buf, ((unsigned char)(u32 >> 16) & 0xff)); 265 if (status != ARES_SUCCESS) { 266 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 267 } 268 269 status = ares_buf_append_byte(buf, ((unsigned char)(u32 >> 8) & 0xff)); 270 if (status != ARES_SUCCESS) { 271 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 272 } 273 274 status = ares_buf_append_byte(buf, ((unsigned char)u32 & 0xff)); 275 if (status != ARES_SUCCESS) { 276 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 277 } 278 279 return ARES_SUCCESS; 280 } 281 282 unsigned char *ares_buf_append_start(ares_buf_t *buf, size_t *len) 283 { 284 ares_status_t status; 285 286 if (len == NULL || *len == 0) { 287 return NULL; 288 } 289 290 status = ares_buf_ensure_space(buf, *len); 291 if (status != ARES_SUCCESS) { 292 return NULL; 293 } 294 295 /* -1 for possible null terminator for ares_buf_finish_str() */ 296 *len = buf->alloc_buf_len - buf->data_len - 1; 297 return buf->alloc_buf + buf->data_len; 298 } 299 300 void ares_buf_append_finish(ares_buf_t *buf, size_t len) 301 { 302 if (buf == NULL) { 303 return; 304 } 305 306 buf->data_len += len; 307 } 308 309 unsigned char *ares_buf_finish_bin(ares_buf_t *buf, size_t *len) 310 { 311 unsigned char *ptr = NULL; 312 if (buf == NULL || len == NULL || ares_buf_is_const(buf)) { 313 return NULL; 314 } 315 316 ares_buf_reclaim(buf); 317 318 /* We don't want to return NULL except on failure, may be zero-length */ 319 if (buf->alloc_buf == NULL && ares_buf_ensure_space(buf, 1) != ARES_SUCCESS) { 320 return NULL; /* LCOV_EXCL_LINE: OutOfMemory */ 321 } 322 ptr = buf->alloc_buf; 323 *len = buf->data_len; 324 ares_free(buf); 325 return ptr; 326 } 327 328 char *ares_buf_finish_str(ares_buf_t *buf, size_t *len) 329 { 330 char *ptr; 331 size_t mylen; 332 333 ptr = (char *)ares_buf_finish_bin(buf, &mylen); 334 if (ptr == NULL) { 335 return NULL; 336 } 337 338 if (len != NULL) { 339 *len = mylen; 340 } 341 342 /* NOTE: ensured via ares_buf_ensure_space() that there is always at least 343 * 1 extra byte available for this specific use-case */ 344 ptr[mylen] = 0; 345 346 return ptr; 347 } 348 349 void ares_buf_tag(ares_buf_t *buf) 350 { 351 if (buf == NULL) { 352 return; 353 } 354 355 buf->tag_offset = buf->offset; 356 } 357 358 ares_status_t ares_buf_tag_rollback(ares_buf_t *buf) 359 { 360 if (buf == NULL || buf->tag_offset == SIZE_MAX) { 361 return ARES_EFORMERR; 362 } 363 364 buf->offset = buf->tag_offset; 365 buf->tag_offset = SIZE_MAX; 366 return ARES_SUCCESS; 367 } 368 369 ares_status_t ares_buf_tag_clear(ares_buf_t *buf) 370 { 371 if (buf == NULL || buf->tag_offset == SIZE_MAX) { 372 return ARES_EFORMERR; 373 } 374 375 buf->tag_offset = SIZE_MAX; 376 return ARES_SUCCESS; 377 } 378 379 const unsigned char *ares_buf_tag_fetch(const ares_buf_t *buf, size_t *len) 380 { 381 if (buf == NULL || buf->tag_offset == SIZE_MAX || len == NULL) { 382 return NULL; 383 } 384 385 *len = buf->offset - buf->tag_offset; 386 return buf->data + buf->tag_offset; 387 } 388 389 size_t ares_buf_tag_length(const ares_buf_t *buf) 390 { 391 if (buf == NULL || buf->tag_offset == SIZE_MAX) { 392 return 0; 393 } 394 return buf->offset - buf->tag_offset; 395 } 396 397 ares_status_t ares_buf_tag_fetch_bytes(const ares_buf_t *buf, 398 unsigned char *bytes, size_t *len) 399 { 400 size_t ptr_len = 0; 401 const unsigned char *ptr = ares_buf_tag_fetch(buf, &ptr_len); 402 403 if (ptr == NULL || bytes == NULL || len == NULL) { 404 return ARES_EFORMERR; 405 } 406 407 if (*len < ptr_len) { 408 return ARES_EFORMERR; 409 } 410 411 *len = ptr_len; 412 413 if (ptr_len > 0) { 414 memcpy(bytes, ptr, ptr_len); 415 } 416 return ARES_SUCCESS; 417 } 418 419 ares_status_t ares_buf_tag_fetch_constbuf(const ares_buf_t *buf, 420 ares_buf_t **newbuf) 421 { 422 size_t ptr_len = 0; 423 const unsigned char *ptr = ares_buf_tag_fetch(buf, &ptr_len); 424 425 if (ptr == NULL || newbuf == NULL) { 426 return ARES_EFORMERR; 427 } 428 429 *newbuf = ares_buf_create_const(ptr, ptr_len); 430 if (*newbuf == NULL) { 431 return ARES_ENOMEM; 432 } 433 return ARES_SUCCESS; 434 } 435 436 ares_status_t ares_buf_tag_fetch_string(const ares_buf_t *buf, char *str, 437 size_t len) 438 { 439 size_t out_len; 440 ares_status_t status; 441 size_t i; 442 443 if (str == NULL || len == 0) { 444 return ARES_EFORMERR; 445 } 446 447 /* Space for NULL terminator */ 448 out_len = len - 1; 449 450 status = ares_buf_tag_fetch_bytes(buf, (unsigned char *)str, &out_len); 451 if (status != ARES_SUCCESS) { 452 return status; 453 } 454 455 /* NULL terminate */ 456 str[out_len] = 0; 457 458 /* Validate string is printable */ 459 for (i = 0; i < out_len; i++) { 460 if (!ares_isprint(str[i])) { 461 return ARES_EBADSTR; 462 } 463 } 464 465 return ARES_SUCCESS; 466 } 467 468 ares_status_t ares_buf_tag_fetch_strdup(const ares_buf_t *buf, char **str) 469 { 470 size_t ptr_len = 0; 471 const unsigned char *ptr = ares_buf_tag_fetch(buf, &ptr_len); 472 473 if (ptr == NULL || str == NULL) { 474 return ARES_EFORMERR; 475 } 476 477 if (!ares_str_isprint((const char *)ptr, ptr_len)) { 478 return ARES_EBADSTR; 479 } 480 481 *str = ares_malloc(ptr_len + 1); 482 if (*str == NULL) { 483 return ARES_ENOMEM; 484 } 485 486 if (ptr_len > 0) { 487 memcpy(*str, ptr, ptr_len); 488 } 489 (*str)[ptr_len] = 0; 490 return ARES_SUCCESS; 491 } 492 493 static const unsigned char *ares_buf_fetch(const ares_buf_t *buf, size_t *len) 494 { 495 if (len != NULL) { 496 *len = 0; 497 } 498 499 if (buf == NULL || len == NULL || buf->data == NULL) { 500 return NULL; 501 } 502 503 *len = buf->data_len - buf->offset; 504 if (*len == 0) { 505 return NULL; 506 } 507 508 return buf->data + buf->offset; 509 } 510 511 ares_status_t ares_buf_consume(ares_buf_t *buf, size_t len) 512 { 513 size_t remaining_len = ares_buf_len(buf); 514 515 if (remaining_len < len) { 516 return ARES_EBADRESP; 517 } 518 519 buf->offset += len; 520 return ARES_SUCCESS; 521 } 522 523 ares_status_t ares_buf_fetch_be16(ares_buf_t *buf, unsigned short *u16) 524 { 525 size_t remaining_len; 526 const unsigned char *ptr = ares_buf_fetch(buf, &remaining_len); 527 unsigned int u32; 528 529 if (buf == NULL || u16 == NULL || remaining_len < sizeof(*u16)) { 530 return ARES_EBADRESP; 531 } 532 533 /* Do math in an unsigned int in order to prevent warnings due to automatic 534 * conversion by the compiler from short to int during shifts */ 535 u32 = ((unsigned int)(ptr[0]) << 8 | (unsigned int)ptr[1]); 536 *u16 = (unsigned short)(u32 & 0xFFFF); 537 538 return ares_buf_consume(buf, sizeof(*u16)); 539 } 540 541 ares_status_t ares_buf_fetch_be32(ares_buf_t *buf, unsigned int *u32) 542 { 543 size_t remaining_len; 544 const unsigned char *ptr = ares_buf_fetch(buf, &remaining_len); 545 546 if (buf == NULL || u32 == NULL || remaining_len < sizeof(*u32)) { 547 return ARES_EBADRESP; 548 } 549 550 *u32 = ((unsigned int)(ptr[0]) << 24 | (unsigned int)(ptr[1]) << 16 | 551 (unsigned int)(ptr[2]) << 8 | (unsigned int)(ptr[3])); 552 553 return ares_buf_consume(buf, sizeof(*u32)); 554 } 555 556 ares_status_t ares_buf_fetch_bytes(ares_buf_t *buf, unsigned char *bytes, 557 size_t len) 558 { 559 size_t remaining_len; 560 const unsigned char *ptr = ares_buf_fetch(buf, &remaining_len); 561 562 if (buf == NULL || bytes == NULL || len == 0 || remaining_len < len) { 563 return ARES_EBADRESP; 564 } 565 566 memcpy(bytes, ptr, len); 567 return ares_buf_consume(buf, len); 568 } 569 570 ares_status_t ares_buf_fetch_bytes_dup(ares_buf_t *buf, size_t len, 571 ares_bool_t null_term, 572 unsigned char **bytes) 573 { 574 size_t remaining_len; 575 const unsigned char *ptr = ares_buf_fetch(buf, &remaining_len); 576 577 if (buf == NULL || bytes == NULL || len == 0 || remaining_len < len) { 578 return ARES_EBADRESP; 579 } 580 581 *bytes = ares_malloc(null_term ? len + 1 : len); 582 if (*bytes == NULL) { 583 return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ 584 } 585 586 memcpy(*bytes, ptr, len); 587 if (null_term) { 588 (*bytes)[len] = 0; 589 } 590 return ares_buf_consume(buf, len); 591 } 592 593 ares_status_t ares_buf_fetch_str_dup(ares_buf_t *buf, size_t len, char **str) 594 { 595 size_t remaining_len; 596 size_t i; 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 /* Validate string is printable */ 604 for (i = 0; i < len; i++) { 605 if (!ares_isprint(ptr[i])) { 606 return ARES_EBADSTR; 607 } 608 } 609 610 *str = ares_malloc(len + 1); 611 if (*str == NULL) { 612 return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ 613 } 614 615 memcpy(*str, ptr, len); 616 (*str)[len] = 0; 617 618 return ares_buf_consume(buf, len); 619 } 620 621 ares_status_t ares_buf_fetch_bytes_into_buf(ares_buf_t *buf, ares_buf_t *dest, 622 size_t len) 623 { 624 size_t remaining_len; 625 const unsigned char *ptr = ares_buf_fetch(buf, &remaining_len); 626 ares_status_t status; 627 628 if (buf == NULL || dest == NULL || len == 0 || remaining_len < len) { 629 return ARES_EBADRESP; 630 } 631 632 status = ares_buf_append(dest, ptr, len); 633 if (status != ARES_SUCCESS) { 634 return status; 635 } 636 637 return ares_buf_consume(buf, len); 638 } 639 640 static ares_bool_t ares_is_whitespace(unsigned char c, 641 ares_bool_t include_linefeed) 642 { 643 switch (c) { 644 case '\r': 645 case '\t': 646 case ' ': 647 case '\v': 648 case '\f': 649 return ARES_TRUE; 650 case '\n': 651 return include_linefeed; 652 default: 653 break; 654 } 655 return ARES_FALSE; 656 } 657 658 size_t ares_buf_consume_whitespace(ares_buf_t *buf, 659 ares_bool_t include_linefeed) 660 { 661 size_t remaining_len = 0; 662 const unsigned char *ptr = ares_buf_fetch(buf, &remaining_len); 663 size_t i; 664 665 if (ptr == NULL) { 666 return 0; 667 } 668 669 for (i = 0; i < remaining_len; i++) { 670 if (!ares_is_whitespace(ptr[i], include_linefeed)) { 671 break; 672 } 673 } 674 675 if (i > 0) { 676 ares_buf_consume(buf, i); 677 } 678 return i; 679 } 680 681 size_t ares_buf_consume_nonwhitespace(ares_buf_t *buf) 682 { 683 size_t remaining_len = 0; 684 const unsigned char *ptr = ares_buf_fetch(buf, &remaining_len); 685 size_t i; 686 687 if (ptr == NULL) { 688 return 0; 689 } 690 691 for (i = 0; i < remaining_len; i++) { 692 if (ares_is_whitespace(ptr[i], ARES_TRUE)) { 693 break; 694 } 695 } 696 697 if (i > 0) { 698 ares_buf_consume(buf, i); 699 } 700 return i; 701 } 702 703 size_t ares_buf_consume_line(ares_buf_t *buf, ares_bool_t include_linefeed) 704 { 705 size_t remaining_len = 0; 706 const unsigned char *ptr = ares_buf_fetch(buf, &remaining_len); 707 size_t i; 708 709 if (ptr == NULL) { 710 return 0; 711 } 712 713 for (i = 0; i < remaining_len; i++) { 714 if (ptr[i] == '\n') { 715 goto done; 716 } 717 } 718 719 done: 720 if (include_linefeed && i < remaining_len && ptr[i] == '\n') { 721 i++; 722 } 723 724 if (i > 0) { 725 ares_buf_consume(buf, i); 726 } 727 return i; 728 } 729 730 size_t ares_buf_consume_until_charset(ares_buf_t *buf, 731 const unsigned char *charset, size_t len, 732 ares_bool_t require_charset) 733 { 734 size_t remaining_len = 0; 735 const unsigned char *ptr = ares_buf_fetch(buf, &remaining_len); 736 size_t pos; 737 ares_bool_t found = ARES_FALSE; 738 739 if (ptr == NULL || charset == NULL || len == 0) { 740 return 0; 741 } 742 743 /* Optimize for single character searches */ 744 if (len == 1) { 745 const unsigned char *p = memchr(ptr, charset[0], remaining_len); 746 if (p != NULL) { 747 found = ARES_TRUE; 748 pos = (size_t)(p - ptr); 749 } else { 750 pos = remaining_len; 751 } 752 goto done; 753 } 754 755 for (pos = 0; pos < remaining_len; pos++) { 756 size_t j; 757 for (j = 0; j < len; j++) { 758 if (ptr[pos] == charset[j]) { 759 found = ARES_TRUE; 760 goto done; 761 } 762 } 763 } 764 765 done: 766 if (require_charset && !found) { 767 return SIZE_MAX; 768 } 769 770 if (pos > 0) { 771 ares_buf_consume(buf, pos); 772 } 773 return pos; 774 } 775 776 size_t ares_buf_consume_until_seq(ares_buf_t *buf, const unsigned char *seq, 777 size_t len, ares_bool_t require_seq) 778 { 779 size_t remaining_len = 0; 780 const unsigned char *ptr = ares_buf_fetch(buf, &remaining_len); 781 const unsigned char *p; 782 size_t consume_len = 0; 783 784 if (ptr == NULL || seq == NULL || len == 0) { 785 return 0; 786 } 787 788 p = ares_memmem(ptr, remaining_len, seq, len); 789 if (require_seq && p == NULL) { 790 return SIZE_MAX; 791 } 792 793 if (p != NULL) { 794 consume_len = (size_t)(p - ptr); 795 } else { 796 consume_len = remaining_len; 797 } 798 799 if (consume_len > 0) { 800 ares_buf_consume(buf, consume_len); 801 } 802 803 return consume_len; 804 } 805 806 size_t ares_buf_consume_charset(ares_buf_t *buf, const unsigned char *charset, 807 size_t len) 808 { 809 size_t remaining_len = 0; 810 const unsigned char *ptr = ares_buf_fetch(buf, &remaining_len); 811 size_t i; 812 813 if (ptr == NULL || charset == NULL || len == 0) { 814 return 0; 815 } 816 817 for (i = 0; i < remaining_len; i++) { 818 size_t j; 819 for (j = 0; j < len; j++) { 820 if (ptr[i] == charset[j]) { 821 break; 822 } 823 } 824 /* Not found */ 825 if (j == len) { 826 break; 827 } 828 } 829 830 if (i > 0) { 831 ares_buf_consume(buf, i); 832 } 833 return i; 834 } 835 836 static void ares_buf_destroy_cb(void *arg) 837 { 838 ares_buf_t **buf = arg; 839 ares_buf_destroy(*buf); 840 } 841 842 static ares_bool_t ares_buf_split_isduplicate(ares_array_t *arr, 843 const unsigned char *val, 844 size_t len, 845 ares_buf_split_t flags) 846 { 847 size_t i; 848 size_t num = ares_array_len(arr); 849 850 for (i = 0; i < num; i++) { 851 ares_buf_t **bufptr = ares_array_at(arr, i); 852 const ares_buf_t *buf = *bufptr; 853 size_t plen = 0; 854 const unsigned char *ptr = ares_buf_peek(buf, &plen); 855 856 /* Can't be duplicate if lengths mismatch */ 857 if (plen != len) { 858 continue; 859 } 860 861 if (flags & ARES_BUF_SPLIT_CASE_INSENSITIVE) { 862 if (ares_memeq_ci(ptr, val, len)) { 863 return ARES_TRUE; 864 } 865 } else { 866 if (ares_memeq(ptr, val, len)) { 867 return ARES_TRUE; 868 } 869 } 870 } 871 872 return ARES_FALSE; 873 } 874 875 ares_status_t ares_buf_split(ares_buf_t *buf, const unsigned char *delims, 876 size_t delims_len, ares_buf_split_t flags, 877 size_t max_sections, ares_array_t **arr) 878 { 879 ares_status_t status = ARES_SUCCESS; 880 ares_bool_t first = ARES_TRUE; 881 882 if (buf == NULL || delims == NULL || delims_len == 0 || arr == NULL) { 883 return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */ 884 } 885 886 *arr = ares_array_create(sizeof(ares_buf_t *), ares_buf_destroy_cb); 887 if (*arr == NULL) { 888 status = ARES_ENOMEM; 889 goto done; 890 } 891 892 while (ares_buf_len(buf)) { 893 size_t len = 0; 894 const unsigned char *ptr; 895 896 if (first) { 897 /* No delimiter yet, just tag the start */ 898 ares_buf_tag(buf); 899 } else { 900 if (flags & ARES_BUF_SPLIT_KEEP_DELIMS) { 901 /* tag then eat delimiter so its first byte in buffer */ 902 ares_buf_tag(buf); 903 ares_buf_consume(buf, 1); 904 } else { 905 /* throw away delimiter */ 906 ares_buf_consume(buf, 1); 907 ares_buf_tag(buf); 908 } 909 } 910 911 if (max_sections && ares_array_len(*arr) >= max_sections - 1) { 912 ares_buf_consume(buf, ares_buf_len(buf)); 913 } else { 914 ares_buf_consume_until_charset(buf, delims, delims_len, ARES_FALSE); 915 } 916 917 ptr = ares_buf_tag_fetch(buf, &len); 918 919 /* Shouldn't be possible */ 920 if (ptr == NULL) { 921 status = ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */ 922 goto done; 923 } 924 925 if (flags & ARES_BUF_SPLIT_LTRIM) { 926 size_t i; 927 for (i = 0; i < len; i++) { 928 if (!ares_is_whitespace(ptr[i], ARES_TRUE)) { 929 break; 930 } 931 } 932 ptr += i; 933 len -= i; 934 } 935 936 if (flags & ARES_BUF_SPLIT_RTRIM) { 937 while (len > 0 && ares_is_whitespace(ptr[len - 1], ARES_TRUE)) { 938 len--; 939 } 940 } 941 942 if (len != 0 || flags & ARES_BUF_SPLIT_ALLOW_BLANK) { 943 ares_buf_t *data; 944 945 if (!(flags & ARES_BUF_SPLIT_NO_DUPLICATES) || 946 !ares_buf_split_isduplicate(*arr, ptr, len, flags)) { 947 /* Since we don't allow const buffers of 0 length, and user wants 948 * 0-length buffers, swap what we do here */ 949 if (len) { 950 data = ares_buf_create_const(ptr, len); 951 } else { 952 data = ares_buf_create(); 953 } 954 955 if (data == NULL) { 956 status = ARES_ENOMEM; 957 goto done; 958 } 959 960 status = ares_array_insertdata_last(*arr, &data); 961 if (status != ARES_SUCCESS) { 962 ares_buf_destroy(data); 963 goto done; 964 } 965 } 966 } 967 968 first = ARES_FALSE; 969 } 970 971 done: 972 if (status != ARES_SUCCESS) { 973 ares_array_destroy(*arr); 974 *arr = NULL; 975 } 976 977 return status; 978 } 979 980 static void ares_free_split_array(void *arg) 981 { 982 void **ptr = arg; 983 ares_free(*ptr); 984 } 985 986 ares_status_t ares_buf_split_str_array(ares_buf_t *buf, 987 const unsigned char *delims, 988 size_t delims_len, 989 ares_buf_split_t flags, 990 size_t max_sections, ares_array_t **arr) 991 { 992 ares_status_t status; 993 ares_array_t *split = NULL; 994 size_t i; 995 size_t len; 996 997 if (arr == NULL) { 998 return ARES_EFORMERR; 999 } 1000 1001 *arr = NULL; 1002 1003 status = ares_buf_split(buf, delims, delims_len, flags, max_sections, &split); 1004 if (status != ARES_SUCCESS) { 1005 goto done; 1006 } 1007 1008 *arr = ares_array_create(sizeof(char *), ares_free_split_array); 1009 if (*arr == NULL) { 1010 status = ARES_ENOMEM; 1011 goto done; 1012 } 1013 1014 len = ares_array_len(split); 1015 for (i = 0; i < len; i++) { 1016 ares_buf_t **bufptr = ares_array_at(split, i); 1017 ares_buf_t *lbuf = *bufptr; 1018 char *str = NULL; 1019 1020 status = ares_buf_fetch_str_dup(lbuf, ares_buf_len(lbuf), &str); 1021 if (status != ARES_SUCCESS) { 1022 goto done; 1023 } 1024 1025 status = ares_array_insertdata_last(*arr, &str); 1026 if (status != ARES_SUCCESS) { 1027 ares_free(str); 1028 goto done; 1029 } 1030 } 1031 1032 done: 1033 ares_array_destroy(split); 1034 if (status != ARES_SUCCESS) { 1035 ares_array_destroy(*arr); 1036 *arr = NULL; 1037 } 1038 return status; 1039 } 1040 1041 ares_status_t ares_buf_split_str(ares_buf_t *buf, const unsigned char *delims, 1042 size_t delims_len, ares_buf_split_t flags, 1043 size_t max_sections, char ***strs, 1044 size_t *nstrs) 1045 { 1046 ares_status_t status; 1047 ares_array_t *arr = NULL; 1048 1049 if (strs == NULL || nstrs == NULL) { 1050 return ARES_EFORMERR; 1051 } 1052 1053 *strs = NULL; 1054 *nstrs = 0; 1055 1056 status = ares_buf_split_str_array(buf, delims, delims_len, flags, 1057 max_sections, &arr); 1058 1059 if (status != ARES_SUCCESS) { 1060 goto done; 1061 } 1062 1063 done: 1064 if (status == ARES_SUCCESS) { 1065 *strs = ares_array_finish(arr, nstrs); 1066 } else { 1067 ares_array_destroy(arr); 1068 } 1069 return status; 1070 } 1071 1072 ares_bool_t ares_buf_begins_with(const ares_buf_t *buf, 1073 const unsigned char *data, size_t data_len) 1074 { 1075 size_t remaining_len = 0; 1076 const unsigned char *ptr = ares_buf_fetch(buf, &remaining_len); 1077 1078 if (ptr == NULL || data == NULL || data_len == 0) { 1079 return ARES_FALSE; 1080 } 1081 1082 if (data_len > remaining_len) { 1083 return ARES_FALSE; 1084 } 1085 1086 if (memcmp(ptr, data, data_len) != 0) { 1087 return ARES_FALSE; 1088 } 1089 1090 return ARES_TRUE; 1091 } 1092 1093 size_t ares_buf_len(const ares_buf_t *buf) 1094 { 1095 if (buf == NULL) { 1096 return 0; 1097 } 1098 1099 return buf->data_len - buf->offset; 1100 } 1101 1102 const unsigned char *ares_buf_peek(const ares_buf_t *buf, size_t *len) 1103 { 1104 return ares_buf_fetch(buf, len); 1105 } 1106 1107 ares_status_t ares_buf_replace(ares_buf_t *buf, const unsigned char *srch, 1108 size_t srch_size, const unsigned char *rplc, 1109 size_t rplc_size) 1110 { 1111 size_t processed_len = 0; 1112 ares_status_t status; 1113 1114 if (buf->alloc_buf == NULL || srch == NULL || srch_size == 0 || 1115 (rplc == NULL && rplc_size != 0)) { 1116 return ARES_EFORMERR; 1117 } 1118 1119 while (1) { 1120 unsigned char *ptr = buf->alloc_buf + buf->offset + processed_len; 1121 size_t remaining_len = buf->data_len - buf->offset - processed_len; 1122 size_t found_offset = 0; 1123 size_t move_data_len; 1124 1125 /* Find pattern */ 1126 ptr = ares_memmem(ptr, remaining_len, srch, srch_size); 1127 if (ptr == NULL) { 1128 break; 1129 } 1130 1131 /* Store the offset this was found because our actual pointer might be 1132 * switched out from under us by the call to ensure_space() if the 1133 * replacement pattern is larger than the search pattern */ 1134 found_offset = (size_t)(ptr - (size_t)(buf->alloc_buf + buf->offset)); 1135 if (rplc_size > srch_size) { 1136 status = ares_buf_ensure_space(buf, rplc_size - srch_size); 1137 if (status != ARES_SUCCESS) { 1138 return status; 1139 } 1140 } 1141 1142 /* Impossible, but silence clang */ 1143 if (buf->alloc_buf == NULL) { 1144 return ARES_ENOMEM; 1145 } 1146 1147 /* Recalculate actual pointer */ 1148 ptr = buf->alloc_buf + buf->offset + found_offset; 1149 1150 /* Move the data */ 1151 move_data_len = buf->data_len - buf->offset - found_offset - srch_size; 1152 memmove(ptr + rplc_size, 1153 ptr + srch_size, 1154 move_data_len); 1155 1156 /* Copy in the replacement data */ 1157 if (rplc != NULL && rplc_size > 0) { 1158 memcpy(ptr, rplc, rplc_size); 1159 } 1160 1161 if (rplc_size > srch_size) { 1162 buf->data_len += rplc_size - srch_size; 1163 } else { 1164 buf->data_len -= srch_size - rplc_size; 1165 } 1166 1167 processed_len = found_offset + rplc_size; 1168 } 1169 1170 return ARES_SUCCESS; 1171 } 1172 1173 ares_status_t ares_buf_peek_byte(const ares_buf_t *buf, unsigned char *b) 1174 { 1175 size_t remaining_len = 0; 1176 const unsigned char *ptr = ares_buf_fetch(buf, &remaining_len); 1177 1178 if (buf == NULL || b == NULL) { 1179 return ARES_EFORMERR; 1180 } 1181 1182 if (remaining_len == 0) { 1183 return ARES_EBADRESP; 1184 } 1185 *b = ptr[0]; 1186 return ARES_SUCCESS; 1187 } 1188 1189 size_t ares_buf_get_position(const ares_buf_t *buf) 1190 { 1191 if (buf == NULL) { 1192 return 0; 1193 } 1194 return buf->offset; 1195 } 1196 1197 ares_status_t ares_buf_set_position(ares_buf_t *buf, size_t idx) 1198 { 1199 if (buf == NULL) { 1200 return ARES_EFORMERR; 1201 } 1202 1203 if (idx > buf->data_len) { 1204 return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */ 1205 } 1206 1207 buf->offset = idx; 1208 return ARES_SUCCESS; 1209 } 1210 1211 static ares_status_t 1212 ares_buf_parse_dns_binstr_int(ares_buf_t *buf, size_t remaining_len, 1213 unsigned char **bin, size_t *bin_len, 1214 ares_bool_t validate_printable) 1215 { 1216 unsigned char len; 1217 ares_status_t status = ARES_EBADRESP; 1218 ares_buf_t *binbuf = NULL; 1219 1220 if (buf == NULL) { 1221 return ARES_EFORMERR; 1222 } 1223 1224 if (remaining_len == 0) { 1225 return ARES_EBADRESP; 1226 } 1227 1228 binbuf = ares_buf_create(); 1229 if (binbuf == NULL) { 1230 return ARES_ENOMEM; 1231 } 1232 1233 status = ares_buf_fetch_bytes(buf, &len, 1); 1234 if (status != ARES_SUCCESS) { 1235 goto done; /* LCOV_EXCL_LINE: DefensiveCoding */ 1236 } 1237 1238 remaining_len--; 1239 1240 if (len > remaining_len) { 1241 status = ARES_EBADRESP; 1242 goto done; 1243 } 1244 1245 if (len) { 1246 /* When used by the _str() parser, it really needs to be validated to 1247 * be a valid printable ascii string. Do that here */ 1248 if (validate_printable && ares_buf_len(buf) >= len) { 1249 size_t mylen; 1250 const char *data = (const char *)ares_buf_peek(buf, &mylen); 1251 if (!ares_str_isprint(data, len)) { 1252 status = ARES_EBADSTR; 1253 goto done; 1254 } 1255 } 1256 1257 if (bin != NULL) { 1258 status = ares_buf_fetch_bytes_into_buf(buf, binbuf, len); 1259 } else { 1260 status = ares_buf_consume(buf, len); 1261 } 1262 } 1263 1264 done: 1265 if (status != ARES_SUCCESS) { 1266 ares_buf_destroy(binbuf); 1267 } else { 1268 if (bin != NULL) { 1269 size_t mylen = 0; 1270 /* NOTE: we use ares_buf_finish_str() here as we guarantee NULL 1271 * Termination even though we are technically returning binary data. 1272 */ 1273 *bin = (unsigned char *)ares_buf_finish_str(binbuf, &mylen); 1274 *bin_len = mylen; 1275 } 1276 } 1277 1278 return status; 1279 } 1280 1281 ares_status_t ares_buf_parse_dns_binstr(ares_buf_t *buf, size_t remaining_len, 1282 unsigned char **bin, size_t *bin_len) 1283 { 1284 return ares_buf_parse_dns_binstr_int(buf, remaining_len, bin, bin_len, 1285 ARES_FALSE); 1286 } 1287 1288 ares_status_t ares_buf_parse_dns_str(ares_buf_t *buf, size_t remaining_len, 1289 char **str) 1290 { 1291 size_t len; 1292 1293 return ares_buf_parse_dns_binstr_int(buf, remaining_len, 1294 (unsigned char **)str, &len, ARES_TRUE); 1295 } 1296 1297 ares_status_t ares_buf_append_num_dec(ares_buf_t *buf, size_t num, size_t len) 1298 { 1299 size_t i; 1300 size_t mod; 1301 1302 if (len == 0) { 1303 len = ares_count_digits(num); 1304 } 1305 1306 mod = ares_pow(10, len); 1307 1308 for (i = len; i > 0; i--) { 1309 size_t digit = (num % mod); 1310 ares_status_t status; 1311 1312 mod /= 10; 1313 1314 /* Silence coverity. Shouldn't be possible since we calculate it above */ 1315 if (mod == 0) { 1316 return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */ 1317 } 1318 1319 digit /= mod; 1320 status = ares_buf_append_byte(buf, '0' + (unsigned char)(digit & 0xFF)); 1321 if (status != ARES_SUCCESS) { 1322 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 1323 } 1324 } 1325 return ARES_SUCCESS; 1326 } 1327 1328 ares_status_t ares_buf_append_num_hex(ares_buf_t *buf, size_t num, size_t len) 1329 { 1330 size_t i; 1331 static const unsigned char hexbytes[] = "0123456789ABCDEF"; 1332 1333 if (len == 0) { 1334 len = ares_count_hexdigits(num); 1335 } 1336 1337 for (i = len; i > 0; i--) { 1338 ares_status_t status; 1339 status = ares_buf_append_byte(buf, hexbytes[(num >> ((i - 1) * 4)) & 0xF]); 1340 if (status != ARES_SUCCESS) { 1341 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 1342 } 1343 } 1344 return ARES_SUCCESS; 1345 } 1346 1347 ares_status_t ares_buf_append_str(ares_buf_t *buf, const char *str) 1348 { 1349 return ares_buf_append(buf, (const unsigned char *)str, ares_strlen(str)); 1350 } 1351 1352 static ares_status_t ares_buf_hexdump_line(ares_buf_t *buf, size_t idx, 1353 const unsigned char *data, 1354 size_t len) 1355 { 1356 size_t i; 1357 ares_status_t status; 1358 1359 /* Address */ 1360 status = ares_buf_append_num_hex(buf, idx, 6); 1361 if (status != ARES_SUCCESS) { 1362 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 1363 } 1364 1365 /* | */ 1366 status = ares_buf_append_str(buf, " | "); 1367 if (status != ARES_SUCCESS) { 1368 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 1369 } 1370 1371 for (i = 0; i < 16; i++) { 1372 if (i >= len) { 1373 status = ares_buf_append_str(buf, " "); 1374 } else { 1375 status = ares_buf_append_num_hex(buf, data[i], 2); 1376 } 1377 if (status != ARES_SUCCESS) { 1378 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 1379 } 1380 1381 status = ares_buf_append_byte(buf, ' '); 1382 if (status != ARES_SUCCESS) { 1383 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 1384 } 1385 } 1386 1387 /* | */ 1388 status = ares_buf_append_str(buf, " | "); 1389 if (status != ARES_SUCCESS) { 1390 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 1391 } 1392 1393 for (i = 0; i < 16; i++) { 1394 if (i >= len) { 1395 break; 1396 } 1397 status = ares_buf_append_byte(buf, ares_isprint(data[i]) ? data[i] : '.'); 1398 if (status != ARES_SUCCESS) { 1399 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 1400 } 1401 } 1402 1403 return ares_buf_append_byte(buf, '\n'); 1404 } 1405 1406 ares_status_t ares_buf_hexdump(ares_buf_t *buf, const unsigned char *data, 1407 size_t len) 1408 { 1409 size_t i; 1410 1411 /* Each line is 16 bytes */ 1412 for (i = 0; i < len; i += 16) { 1413 ares_status_t status; 1414 status = ares_buf_hexdump_line(buf, i, data + i, len - i); 1415 if (status != ARES_SUCCESS) { 1416 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 1417 } 1418 } 1419 1420 return ARES_SUCCESS; 1421 } 1422 1423 ares_status_t ares_buf_load_file(const char *filename, ares_buf_t *buf) 1424 { 1425 FILE *fp = NULL; 1426 unsigned char *ptr = NULL; 1427 size_t len = 0; 1428 size_t ptr_len = 0; 1429 long ftell_len = 0; 1430 ares_status_t status; 1431 1432 if (filename == NULL || buf == NULL) { 1433 return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */ 1434 } 1435 1436 fp = fopen(filename, "rb"); 1437 if (fp == NULL) { 1438 int error = errno; 1439 switch (error) { 1440 case ENOENT: 1441 case ESRCH: 1442 status = ARES_ENOTFOUND; 1443 goto done; 1444 default: 1445 DEBUGF(fprintf(stderr, "fopen() failed with error: %d %s\n", error, 1446 strerror(error))); 1447 DEBUGF(fprintf(stderr, "Error opening file: %s\n", filename)); 1448 status = ARES_EFILE; 1449 goto done; 1450 } 1451 } 1452 1453 /* Get length portably, fstat() is POSIX, not C */ 1454 if (fseek(fp, 0, SEEK_END) != 0) { 1455 status = ARES_EFILE; /* LCOV_EXCL_LINE: DefensiveCoding */ 1456 goto done; /* LCOV_EXCL_LINE: DefensiveCoding */ 1457 } 1458 1459 ftell_len = ftell(fp); 1460 if (ftell_len < 0) { 1461 status = ARES_EFILE; /* LCOV_EXCL_LINE: DefensiveCoding */ 1462 goto done; /* LCOV_EXCL_LINE: DefensiveCoding */ 1463 } 1464 len = (size_t)ftell_len; 1465 1466 if (fseek(fp, 0, SEEK_SET) != 0) { 1467 status = ARES_EFILE; /* LCOV_EXCL_LINE: DefensiveCoding */ 1468 goto done; /* LCOV_EXCL_LINE: DefensiveCoding */ 1469 } 1470 1471 if (len == 0) { 1472 status = ARES_SUCCESS; /* LCOV_EXCL_LINE: DefensiveCoding */ 1473 goto done; /* LCOV_EXCL_LINE: DefensiveCoding */ 1474 } 1475 1476 /* Read entire data into buffer */ 1477 ptr_len = len; 1478 ptr = ares_buf_append_start(buf, &ptr_len); 1479 if (ptr == NULL) { 1480 status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ 1481 goto done; /* LCOV_EXCL_LINE: OutOfMemory */ 1482 } 1483 1484 ptr_len = fread(ptr, 1, len, fp); 1485 if (ptr_len != len) { 1486 status = ARES_EFILE; /* LCOV_EXCL_LINE: DefensiveCoding */ 1487 goto done; /* LCOV_EXCL_LINE: DefensiveCoding */ 1488 } 1489 1490 ares_buf_append_finish(buf, len); 1491 status = ARES_SUCCESS; 1492 1493 done: 1494 if (fp != NULL) { 1495 fclose(fp); 1496 } 1497 return status; 1498 }