/src/c-ares/test/ares-test-fuzz.c
Line | Count | Source |
1 | | /* MIT License |
2 | | * |
3 | | * Copyright (c) The c-ares project and its contributors |
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 <stddef.h> |
27 | | #include <stdio.h> |
28 | | #include "ares.h" |
29 | | #include "include/ares_buf.h" |
30 | | #include "include/ares_mem.h" |
31 | | |
32 | | int LLVMFuzzerTestOneInput(const unsigned char *data, unsigned long size); |
33 | | |
34 | | #ifdef USE_LEGACY_FUZZERS |
35 | | |
36 | | /* This implementation calls the legacy c-ares parsers, which historically |
37 | | * all used different logic and parsing. As of c-ares 1.21.0 these are |
38 | | * simply wrappers around a single parser, and simply convert the parsed |
39 | | * DNS response into the data structures the legacy parsers used which is a |
40 | | * small amount of code and not likely going to vary based on the input data. |
41 | | * |
42 | | * Instead, these days, it makes more sense to test the new parser directly |
43 | | * instead of calling it 10 or 11 times with the same input data to speed up |
44 | | * the number of iterations per second the fuzzer can perform. |
45 | | * |
46 | | * We are keeping this legacy fuzzer test for historic reasons or if someone |
47 | | * finds them of use. |
48 | | */ |
49 | | |
50 | | int LLVMFuzzerTestOneInput(const unsigned char *data, unsigned long size) |
51 | | { |
52 | | /* Feed the data into each of the ares_parse_*_reply functions. */ |
53 | | struct hostent *host = NULL; |
54 | | struct ares_addrttl info[5]; |
55 | | struct ares_addr6ttl info6[5]; |
56 | | unsigned char addrv4[4] = { 0x10, 0x20, 0x30, 0x40 }; |
57 | | struct ares_srv_reply *srv = NULL; |
58 | | struct ares_mx_reply *mx = NULL; |
59 | | struct ares_txt_reply *txt = NULL; |
60 | | struct ares_soa_reply *soa = NULL; |
61 | | struct ares_naptr_reply *naptr = NULL; |
62 | | struct ares_caa_reply *caa = NULL; |
63 | | struct ares_uri_reply *uri = NULL; |
64 | | int count = 5; |
65 | | ares_parse_a_reply(data, (int)size, &host, info, &count); |
66 | | if (host) { |
67 | | ares_free_hostent(host); |
68 | | } |
69 | | |
70 | | host = NULL; |
71 | | count = 5; |
72 | | ares_parse_aaaa_reply(data, (int)size, &host, info6, &count); |
73 | | if (host) { |
74 | | ares_free_hostent(host); |
75 | | } |
76 | | |
77 | | host = NULL; |
78 | | ares_parse_ptr_reply(data, (int)size, addrv4, sizeof(addrv4), AF_INET, &host); |
79 | | if (host) { |
80 | | ares_free_hostent(host); |
81 | | } |
82 | | |
83 | | host = NULL; |
84 | | ares_parse_ns_reply(data, (int)size, &host); |
85 | | if (host) { |
86 | | ares_free_hostent(host); |
87 | | } |
88 | | |
89 | | ares_parse_srv_reply(data, (int)size, &srv); |
90 | | if (srv) { |
91 | | ares_free_data(srv); |
92 | | } |
93 | | |
94 | | ares_parse_mx_reply(data, (int)size, &mx); |
95 | | if (mx) { |
96 | | ares_free_data(mx); |
97 | | } |
98 | | |
99 | | ares_parse_txt_reply(data, (int)size, &txt); |
100 | | if (txt) { |
101 | | ares_free_data(txt); |
102 | | } |
103 | | |
104 | | ares_parse_soa_reply(data, (int)size, &soa); |
105 | | if (soa) { |
106 | | ares_free_data(soa); |
107 | | } |
108 | | |
109 | | ares_parse_naptr_reply(data, (int)size, &naptr); |
110 | | if (naptr) { |
111 | | ares_free_data(naptr); |
112 | | } |
113 | | |
114 | | ares_parse_caa_reply(data, (int)size, &caa); |
115 | | if (caa) { |
116 | | ares_free_data(caa); |
117 | | } |
118 | | |
119 | | ares_parse_uri_reply(data, (int)size, &uri); |
120 | | if (uri) { |
121 | | ares_free_data(uri); |
122 | | } |
123 | | |
124 | | return 0; |
125 | | } |
126 | | |
127 | | #else |
128 | | |
129 | | int LLVMFuzzerTestOneInput(const unsigned char *data, unsigned long size) |
130 | 3.40k | { |
131 | 3.40k | ares_dns_record_t *dnsrec = NULL; |
132 | 3.40k | char *printdata = NULL; |
133 | 3.40k | ares_buf_t *printmsg = NULL; |
134 | 3.40k | size_t i; |
135 | 3.40k | unsigned char *datadup = NULL; |
136 | 3.40k | size_t datadup_len = 0; |
137 | | |
138 | | /* There is never a reason to have a size > 65535, it is immediately |
139 | | * rejected by the parser */ |
140 | 3.40k | if (size > 65535) { |
141 | 6 | return -1; |
142 | 6 | } |
143 | | |
144 | 3.39k | if (ares_dns_parse(data, size, 0, &dnsrec) != ARES_SUCCESS) { |
145 | 1.57k | goto done; |
146 | 1.57k | } |
147 | | |
148 | | /* Lets test the message fetchers */ |
149 | 1.82k | printmsg = ares_buf_create(); |
150 | 1.82k | if (printmsg == NULL) { |
151 | 0 | goto done; |
152 | 0 | } |
153 | | |
154 | 1.82k | ares_buf_append_str(printmsg, ";; ->>HEADER<<- opcode: "); |
155 | 1.82k | ares_buf_append_str( |
156 | 1.82k | printmsg, ares_dns_opcode_tostr(ares_dns_record_get_opcode(dnsrec))); |
157 | 1.82k | ares_buf_append_str(printmsg, ", status: "); |
158 | 1.82k | ares_buf_append_str(printmsg, |
159 | 1.82k | ares_dns_rcode_tostr(ares_dns_record_get_rcode(dnsrec))); |
160 | 1.82k | ares_buf_append_str(printmsg, ", id: "); |
161 | 1.82k | ares_buf_append_num_dec(printmsg, (size_t)ares_dns_record_get_id(dnsrec), 0); |
162 | 1.82k | ares_buf_append_str(printmsg, "\n;; flags: "); |
163 | 1.82k | ares_buf_append_num_hex(printmsg, (size_t)ares_dns_record_get_flags(dnsrec), |
164 | 1.82k | 0); |
165 | 1.82k | ares_buf_append_str(printmsg, "; QUERY: "); |
166 | 1.82k | ares_buf_append_num_dec(printmsg, ares_dns_record_query_cnt(dnsrec), 0); |
167 | 1.82k | ares_buf_append_str(printmsg, ", ANSWER: "); |
168 | 1.82k | ares_buf_append_num_dec( |
169 | 1.82k | printmsg, ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ANSWER), 0); |
170 | 1.82k | ares_buf_append_str(printmsg, ", AUTHORITY: "); |
171 | 1.82k | ares_buf_append_num_dec( |
172 | 1.82k | printmsg, ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_AUTHORITY), 0); |
173 | 1.82k | ares_buf_append_str(printmsg, ", ADDITIONAL: "); |
174 | 1.82k | ares_buf_append_num_dec( |
175 | 1.82k | printmsg, ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ADDITIONAL), 0); |
176 | 1.82k | ares_buf_append_str(printmsg, "\n\n"); |
177 | 1.82k | ares_buf_append_str(printmsg, ";; QUESTION SECTION:\n"); |
178 | 3.64k | for (i = 0; i < ares_dns_record_query_cnt(dnsrec); i++) { |
179 | 1.82k | const char *name; |
180 | 1.82k | ares_dns_rec_type_t qtype; |
181 | 1.82k | ares_dns_class_t qclass; |
182 | | |
183 | 1.82k | if (ares_dns_record_query_get(dnsrec, i, &name, &qtype, &qclass) != |
184 | 1.82k | ARES_SUCCESS) { |
185 | 0 | goto done; |
186 | 0 | } |
187 | | |
188 | 1.82k | ares_buf_append_str(printmsg, ";"); |
189 | 1.82k | ares_buf_append_str(printmsg, name); |
190 | 1.82k | ares_buf_append_str(printmsg, ".\t\t\t"); |
191 | 1.82k | ares_buf_append_str(printmsg, ares_dns_class_tostr(qclass)); |
192 | 1.82k | ares_buf_append_str(printmsg, "\t"); |
193 | 1.82k | ares_buf_append_str(printmsg, ares_dns_rec_type_tostr(qtype)); |
194 | 1.82k | ares_buf_append_str(printmsg, "\n"); |
195 | 1.82k | } |
196 | 1.82k | ares_buf_append_str(printmsg, "\n"); |
197 | 7.28k | for (i = ARES_SECTION_ANSWER; i < ARES_SECTION_ADDITIONAL + 1; i++) { |
198 | 5.46k | size_t j; |
199 | | |
200 | 5.46k | ares_buf_append_str(printmsg, ";; "); |
201 | 5.46k | ares_buf_append_str(printmsg, |
202 | 5.46k | ares_dns_section_tostr((ares_dns_section_t)i)); |
203 | 5.46k | ares_buf_append_str(printmsg, " SECTION:\n"); |
204 | 61.4k | for (j = 0; j < ares_dns_record_rr_cnt(dnsrec, (ares_dns_section_t)i); |
205 | 55.9k | j++) { |
206 | 55.9k | size_t keys_cnt = 0; |
207 | 55.9k | const ares_dns_rr_key_t *keys = NULL; |
208 | 55.9k | ares_dns_rr_t *rr = NULL; |
209 | 55.9k | size_t k; |
210 | | |
211 | 55.9k | rr = ares_dns_record_rr_get(dnsrec, (ares_dns_section_t)i, j); |
212 | 55.9k | ares_buf_append_str(printmsg, ares_dns_rr_get_name(rr)); |
213 | 55.9k | ares_buf_append_str(printmsg, ".\t\t\t"); |
214 | 55.9k | ares_buf_append_str(printmsg, |
215 | 55.9k | ares_dns_class_tostr(ares_dns_rr_get_class(rr))); |
216 | 55.9k | ares_buf_append_str(printmsg, "\t"); |
217 | 55.9k | ares_buf_append_str(printmsg, |
218 | 55.9k | ares_dns_rec_type_tostr(ares_dns_rr_get_type(rr))); |
219 | 55.9k | ares_buf_append_str(printmsg, "\t"); |
220 | 55.9k | ares_buf_append_num_dec(printmsg, ares_dns_rr_get_ttl(rr), 0); |
221 | 55.9k | ares_buf_append_str(printmsg, "\t"); |
222 | | |
223 | 55.9k | keys = ares_dns_rr_get_keys(ares_dns_rr_get_type(rr), &keys_cnt); |
224 | 181k | for (k = 0; k < keys_cnt; k++) { |
225 | 125k | char buf[256] = ""; |
226 | | |
227 | 125k | ares_buf_append_str(printmsg, ares_dns_rr_key_tostr(keys[k])); |
228 | 125k | ares_buf_append_str(printmsg, "="); |
229 | 125k | switch (ares_dns_rr_key_datatype(keys[k])) { |
230 | 450 | case ARES_DATATYPE_INADDR: |
231 | 450 | ares_inet_ntop(AF_INET, ares_dns_rr_get_addr(rr, keys[k]), buf, |
232 | 450 | sizeof(buf)); |
233 | 450 | ares_buf_append_str(printmsg, buf); |
234 | 450 | break; |
235 | 6.07k | case ARES_DATATYPE_INADDR6: |
236 | 6.07k | ares_inet_ntop(AF_INET6, ares_dns_rr_get_addr6(rr, keys[k]), buf, |
237 | 6.07k | sizeof(buf)); |
238 | 6.07k | ares_buf_append_str(printmsg, buf); |
239 | 6.07k | break; |
240 | 6.89k | case ARES_DATATYPE_U8: |
241 | 6.89k | ares_buf_append_num_dec(printmsg, ares_dns_rr_get_u8(rr, keys[k]), |
242 | 6.89k | 0); |
243 | 6.89k | break; |
244 | 48.6k | case ARES_DATATYPE_U16: |
245 | 48.6k | ares_buf_append_num_dec(printmsg, ares_dns_rr_get_u16(rr, keys[k]), |
246 | 48.6k | 0); |
247 | 48.6k | break; |
248 | 7.13k | case ARES_DATATYPE_U32: |
249 | 7.13k | ares_buf_append_num_dec(printmsg, ares_dns_rr_get_u32(rr, keys[k]), |
250 | 7.13k | 0); |
251 | 7.13k | break; |
252 | 12.0k | case ARES_DATATYPE_NAME: |
253 | 16.3k | case ARES_DATATYPE_STR: |
254 | 16.3k | ares_buf_append_byte(printmsg, '"'); |
255 | 16.3k | ares_buf_append_str(printmsg, ares_dns_rr_get_str(rr, keys[k])); |
256 | 16.3k | ares_buf_append_byte(printmsg, '"'); |
257 | 16.3k | break; |
258 | 34.1k | case ARES_DATATYPE_BIN: |
259 | | /* TODO */ |
260 | 34.1k | break; |
261 | 542 | case ARES_DATATYPE_BINP: |
262 | 542 | { |
263 | 542 | size_t templen; |
264 | 542 | ares_buf_append_byte(printmsg, '"'); |
265 | 542 | ares_buf_append_str(printmsg, (const char *)ares_dns_rr_get_bin( |
266 | 542 | rr, keys[k], &templen)); |
267 | 542 | ares_buf_append_byte(printmsg, '"'); |
268 | 542 | } |
269 | 542 | break; |
270 | 1.17k | case ARES_DATATYPE_ABINP: |
271 | 1.17k | { |
272 | 1.17k | size_t a; |
273 | 138k | for (a = 0; a < ares_dns_rr_get_abin_cnt(rr, keys[k]); a++) { |
274 | 137k | size_t templen; |
275 | | |
276 | 137k | if (a != 0) { |
277 | 135k | ares_buf_append_byte(printmsg, ' '); |
278 | 135k | } |
279 | 137k | ares_buf_append_byte(printmsg, '"'); |
280 | 137k | ares_buf_append_str( |
281 | 137k | printmsg, |
282 | 137k | (const char *)ares_dns_rr_get_abin(rr, keys[k], a, &templen)); |
283 | 137k | ares_buf_append_byte(printmsg, '"'); |
284 | 137k | } |
285 | 1.17k | } |
286 | 1.17k | break; |
287 | 4.31k | case ARES_DATATYPE_OPT: |
288 | | /* TODO */ |
289 | 4.31k | break; |
290 | 125k | } |
291 | 125k | ares_buf_append_str(printmsg, " "); |
292 | 125k | } |
293 | 55.9k | ares_buf_append_str(printmsg, "\n"); |
294 | 55.9k | } |
295 | 5.46k | } |
296 | 1.82k | ares_buf_append_str(printmsg, ";; SIZE: "); |
297 | 1.82k | ares_buf_append_num_dec(printmsg, size, 0); |
298 | 1.82k | ares_buf_append_str(printmsg, "\n\n"); |
299 | | |
300 | 1.82k | printdata = ares_buf_finish_str(printmsg, NULL); |
301 | 1.82k | printmsg = NULL; |
302 | | |
303 | | /* Write it back out as a dns message to test writer */ |
304 | 1.82k | if (ares_dns_write(dnsrec, &datadup, &datadup_len) != ARES_SUCCESS) { |
305 | 773 | goto done; |
306 | 773 | } |
307 | | |
308 | 3.39k | done: |
309 | 3.39k | ares_dns_record_destroy(dnsrec); |
310 | 3.39k | ares_buf_destroy(printmsg); |
311 | 3.39k | ares_free(printdata); |
312 | 3.39k | ares_free(datadup); |
313 | 3.39k | return 0; |
314 | 1.82k | } |
315 | | |
316 | | #endif |