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