/src/c-ares/src/lib/ares_parse_txt_reply.c
Line | Count | Source (jump to first uncovered line) |
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 | | |
27 | | #include "ares_setup.h" |
28 | | #include "ares.h" |
29 | | #include "ares_data.h" |
30 | | #include "ares_private.h" |
31 | | |
32 | | static int ares__parse_txt_reply(const unsigned char *abuf, size_t alen, |
33 | | ares_bool_t ex, void **txt_out) |
34 | 2.40k | { |
35 | 2.40k | ares_status_t status; |
36 | 2.40k | struct ares_txt_ext *txt_head = NULL; |
37 | 2.40k | struct ares_txt_ext *txt_last = NULL; |
38 | 2.40k | struct ares_txt_ext *txt_curr; |
39 | 2.40k | ares_dns_record_t *dnsrec = NULL; |
40 | 2.40k | size_t i; |
41 | | |
42 | 2.40k | *txt_out = NULL; |
43 | | |
44 | 2.40k | status = ares_dns_parse(abuf, alen, 0, &dnsrec); |
45 | 2.40k | if (status != ARES_SUCCESS) { |
46 | 1.70k | goto done; |
47 | 1.70k | } |
48 | | |
49 | 700 | if (ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ANSWER) == 0) { |
50 | 6 | status = ARES_ENODATA; |
51 | 6 | goto done; |
52 | 6 | } |
53 | | |
54 | 82.3k | for (i = 0; i < ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ANSWER); i++) { |
55 | 81.6k | const ares_dns_rr_t *rr = |
56 | 81.6k | ares_dns_record_rr_get(dnsrec, ARES_SECTION_ANSWER, i); |
57 | 81.6k | const unsigned char *ptr; |
58 | 81.6k | size_t ptr_len; |
59 | | |
60 | 81.6k | if (rr == NULL) { |
61 | | /* Shouldn't be possible */ |
62 | 0 | status = ARES_EBADRESP; |
63 | 0 | goto done; |
64 | 0 | } |
65 | | |
66 | | /* XXX: Why Chaos? */ |
67 | 81.6k | if ((ares_dns_rr_get_class(rr) != ARES_CLASS_IN && |
68 | 81.6k | ares_dns_rr_get_class(rr) != ARES_CLASS_CHAOS) || |
69 | 81.6k | ares_dns_rr_get_type(rr) != ARES_REC_TYPE_TXT) { |
70 | 81.3k | continue; |
71 | 81.3k | } |
72 | | |
73 | | /* Allocate storage for this TXT answer appending it to the list */ |
74 | 322 | txt_curr = |
75 | 322 | ares_malloc_data(ex ? ARES_DATATYPE_TXT_EXT : ARES_DATATYPE_TXT_REPLY); |
76 | 322 | if (txt_curr == NULL) { |
77 | 0 | status = ARES_ENOMEM; |
78 | 0 | goto done; |
79 | 0 | } |
80 | | |
81 | | /* Link in the record */ |
82 | 322 | if (txt_last) { |
83 | 292 | txt_last->next = txt_curr; |
84 | 292 | } else { |
85 | 30 | txt_head = txt_curr; |
86 | 30 | } |
87 | 322 | txt_last = txt_curr; |
88 | | |
89 | | /* These days, records are joined, always tag as start */ |
90 | 322 | if (ex) { |
91 | 0 | txt_curr->record_start = 1; |
92 | 0 | } |
93 | | |
94 | 322 | ptr = ares_dns_rr_get_bin(rr, ARES_RR_TXT_DATA, &ptr_len); |
95 | | |
96 | 322 | txt_curr->txt = ares_malloc(ptr_len + 1); |
97 | 322 | if (txt_curr->txt == NULL) { |
98 | 0 | status = ARES_ENOMEM; |
99 | 0 | goto done; |
100 | 0 | } |
101 | 322 | memcpy(txt_curr->txt, ptr, ptr_len); |
102 | 322 | txt_curr->txt[ptr_len] = 0; |
103 | 322 | txt_curr->length = ptr_len; |
104 | 322 | } |
105 | | |
106 | 2.40k | done: |
107 | | /* clean up on error */ |
108 | 2.40k | if (status != ARES_SUCCESS) { |
109 | 1.71k | if (txt_head) { |
110 | 0 | ares_free_data(txt_head); |
111 | 0 | } |
112 | 1.71k | } else { |
113 | | /* everything looks fine, return the data */ |
114 | 694 | *txt_out = txt_head; |
115 | 694 | } |
116 | 2.40k | ares_dns_record_destroy(dnsrec); |
117 | 2.40k | return (int)status; |
118 | 694 | } |
119 | | |
120 | | int ares_parse_txt_reply(const unsigned char *abuf, int alen, |
121 | | struct ares_txt_reply **txt_out) |
122 | 2.40k | { |
123 | 2.40k | if (alen < 0) { |
124 | 0 | return ARES_EBADRESP; |
125 | 0 | } |
126 | 2.40k | return ares__parse_txt_reply(abuf, (size_t)alen, ARES_FALSE, |
127 | 2.40k | (void **)txt_out); |
128 | 2.40k | } |
129 | | |
130 | | int ares_parse_txt_reply_ext(const unsigned char *abuf, int alen, |
131 | | struct ares_txt_ext **txt_out) |
132 | 0 | { |
133 | 0 | if (alen < 0) { |
134 | 0 | return ARES_EBADRESP; |
135 | 0 | } |
136 | 0 | return ares__parse_txt_reply(abuf, (size_t)alen, ARES_TRUE, (void **)txt_out); |
137 | 0 | } |