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