/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 | } |