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