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
ares_buf_create(void)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
ares_buf_create_const(const unsigned char * data,size_t data_len)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
ares_buf_destroy(ares_buf_t * buf)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
ares_buf_is_const(const ares_buf_t * buf)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
ares_buf_reclaim(ares_buf_t * buf)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
ares_buf_ensure_space(ares_buf_t * buf,size_t needed_size)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
ares_buf_set_length(ares_buf_t * buf,size_t len)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
ares_buf_append(ares_buf_t * buf,const unsigned char * data,size_t data_len)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
ares_buf_append_byte(ares_buf_t * buf,unsigned char b)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
ares_buf_append_be16(ares_buf_t * buf,unsigned short u16)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
ares_buf_append_be32(ares_buf_t * buf,unsigned int u32)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
ares_buf_append_start(ares_buf_t * buf,size_t * len)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
ares_buf_append_finish(ares_buf_t * buf,size_t len)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
ares_buf_finish_bin(ares_buf_t * buf,size_t * len)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
ares_buf_finish_str(ares_buf_t * buf,size_t * len)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
ares_buf_tag(ares_buf_t * buf)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
ares_buf_tag_rollback(ares_buf_t * buf)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
ares_buf_tag_clear(ares_buf_t * buf)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
ares_buf_tag_fetch(const ares_buf_t * buf,size_t * len)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
ares_buf_tag_length(const ares_buf_t * buf)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
ares_buf_tag_fetch_bytes(const ares_buf_t * buf,unsigned char * bytes,size_t * len)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
ares_buf_tag_fetch_constbuf(const ares_buf_t * buf,ares_buf_t ** newbuf)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
ares_buf_tag_fetch_string(const ares_buf_t * buf,char * str,size_t len)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
ares_buf_tag_fetch_strdup(const ares_buf_t * buf,char ** str)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
ares_buf_fetch(const ares_buf_t * buf,size_t * len)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
ares_buf_consume(ares_buf_t * buf,size_t len)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
ares_buf_fetch_be16(ares_buf_t * buf,unsigned short * u16)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
ares_buf_fetch_be32(ares_buf_t * buf,unsigned int * u32)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
ares_buf_fetch_bytes(ares_buf_t * buf,unsigned char * bytes,size_t len)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
ares_buf_fetch_bytes_dup(ares_buf_t * buf,size_t len,ares_bool_t null_term,unsigned char ** bytes)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
ares_buf_fetch_str_dup(ares_buf_t * buf,size_t len,char ** str)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
ares_buf_fetch_bytes_into_buf(ares_buf_t * buf,ares_buf_t * dest,size_t len)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
ares_is_whitespace(unsigned char c,ares_bool_t include_linefeed)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
ares_buf_consume_whitespace(ares_buf_t * buf,ares_bool_t include_linefeed)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
ares_buf_consume_nonwhitespace(ares_buf_t * buf)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
ares_buf_consume_line(ares_buf_t * buf,ares_bool_t include_linefeed)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
ares_buf_consume_until_charset(ares_buf_t * buf,const unsigned char * charset,size_t len,ares_bool_t require_charset)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
ares_buf_consume_until_seq(ares_buf_t * buf,const unsigned char * seq,size_t len,ares_bool_t require_seq)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
ares_buf_consume_charset(ares_buf_t * buf,const unsigned char * charset,size_t len)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
ares_buf_destroy_cb(void * arg)836 static void ares_buf_destroy_cb(void *arg)
837 {
838 ares_buf_t **buf = arg;
839 ares_buf_destroy(*buf);
840 }
841
ares_buf_split_isduplicate(ares_array_t * arr,const unsigned char * val,size_t len,ares_buf_split_t flags)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
ares_buf_split(ares_buf_t * buf,const unsigned char * delims,size_t delims_len,ares_buf_split_t flags,size_t max_sections,ares_array_t ** arr)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
ares_free_split_array(void * arg)980 static void ares_free_split_array(void *arg)
981 {
982 void **ptr = arg;
983 ares_free(*ptr);
984 }
985
ares_buf_split_str_array(ares_buf_t * buf,const unsigned char * delims,size_t delims_len,ares_buf_split_t flags,size_t max_sections,ares_array_t ** arr)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
ares_buf_split_str(ares_buf_t * buf,const unsigned char * delims,size_t delims_len,ares_buf_split_t flags,size_t max_sections,char *** strs,size_t * nstrs)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
ares_buf_begins_with(const ares_buf_t * buf,const unsigned char * data,size_t data_len)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
ares_buf_len(const ares_buf_t * buf)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
ares_buf_peek(const ares_buf_t * buf,size_t * len)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
ares_buf_replace(ares_buf_t * buf,const unsigned char * srch,size_t srch_size,const unsigned char * rplc,size_t rplc_size)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
ares_buf_peek_byte(const ares_buf_t * buf,unsigned char * b)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
ares_buf_get_position(const ares_buf_t * buf)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
ares_buf_set_position(ares_buf_t * buf,size_t idx)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
ares_buf_parse_dns_binstr_int(ares_buf_t * buf,size_t remaining_len,unsigned char ** bin,size_t * bin_len,ares_bool_t validate_printable)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
ares_buf_parse_dns_binstr(ares_buf_t * buf,size_t remaining_len,unsigned char ** bin,size_t * bin_len)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
ares_buf_parse_dns_str(ares_buf_t * buf,size_t remaining_len,char ** str)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
ares_buf_append_num_dec(ares_buf_t * buf,size_t num,size_t len)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
ares_buf_append_num_hex(ares_buf_t * buf,size_t num,size_t len)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
ares_buf_append_str(ares_buf_t * buf,const char * str)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
ares_buf_hexdump_line(ares_buf_t * buf,size_t idx,const unsigned char * data,size_t len)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
ares_buf_hexdump(ares_buf_t * buf,const unsigned char * data,size_t len)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
ares_buf_load_file(const char * filename,ares_buf_t * buf)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 }
1499