• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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