Coverage Report

Created: 2026-03-11 06:25

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