ares-test-fuzz.c (10956B)
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 { 131 ares_dns_record_t *dnsrec = NULL; 132 char *printdata = NULL; 133 ares_buf_t *printmsg = NULL; 134 size_t i; 135 unsigned char *datadup = NULL; 136 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 if (size > 65535) { 141 return -1; 142 } 143 144 if (ares_dns_parse(data, size, 0, &dnsrec) != ARES_SUCCESS) { 145 goto done; 146 } 147 148 /* Lets test the message fetchers */ 149 printmsg = ares_buf_create(); 150 if (printmsg == NULL) { 151 goto done; 152 } 153 154 ares_buf_append_str(printmsg, ";; ->>HEADER<<- opcode: "); 155 ares_buf_append_str( 156 printmsg, ares_dns_opcode_tostr(ares_dns_record_get_opcode(dnsrec))); 157 ares_buf_append_str(printmsg, ", status: "); 158 ares_buf_append_str(printmsg, 159 ares_dns_rcode_tostr(ares_dns_record_get_rcode(dnsrec))); 160 ares_buf_append_str(printmsg, ", id: "); 161 ares_buf_append_num_dec(printmsg, (size_t)ares_dns_record_get_id(dnsrec), 0); 162 ares_buf_append_str(printmsg, "\n;; flags: "); 163 ares_buf_append_num_hex(printmsg, (size_t)ares_dns_record_get_flags(dnsrec), 164 0); 165 ares_buf_append_str(printmsg, "; QUERY: "); 166 ares_buf_append_num_dec(printmsg, ares_dns_record_query_cnt(dnsrec), 0); 167 ares_buf_append_str(printmsg, ", ANSWER: "); 168 ares_buf_append_num_dec( 169 printmsg, ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ANSWER), 0); 170 ares_buf_append_str(printmsg, ", AUTHORITY: "); 171 ares_buf_append_num_dec( 172 printmsg, ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_AUTHORITY), 0); 173 ares_buf_append_str(printmsg, ", ADDITIONAL: "); 174 ares_buf_append_num_dec( 175 printmsg, ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ADDITIONAL), 0); 176 ares_buf_append_str(printmsg, "\n\n"); 177 ares_buf_append_str(printmsg, ";; QUESTION SECTION:\n"); 178 for (i = 0; i < ares_dns_record_query_cnt(dnsrec); i++) { 179 const char *name; 180 ares_dns_rec_type_t qtype; 181 ares_dns_class_t qclass; 182 183 if (ares_dns_record_query_get(dnsrec, i, &name, &qtype, &qclass) != 184 ARES_SUCCESS) { 185 goto done; 186 } 187 188 ares_buf_append_str(printmsg, ";"); 189 ares_buf_append_str(printmsg, name); 190 ares_buf_append_str(printmsg, ".\t\t\t"); 191 ares_buf_append_str(printmsg, ares_dns_class_tostr(qclass)); 192 ares_buf_append_str(printmsg, "\t"); 193 ares_buf_append_str(printmsg, ares_dns_rec_type_tostr(qtype)); 194 ares_buf_append_str(printmsg, "\n"); 195 } 196 ares_buf_append_str(printmsg, "\n"); 197 for (i = ARES_SECTION_ANSWER; i < ARES_SECTION_ADDITIONAL + 1; i++) { 198 size_t j; 199 200 ares_buf_append_str(printmsg, ";; "); 201 ares_buf_append_str(printmsg, 202 ares_dns_section_tostr((ares_dns_section_t)i)); 203 ares_buf_append_str(printmsg, " SECTION:\n"); 204 for (j = 0; j < ares_dns_record_rr_cnt(dnsrec, (ares_dns_section_t)i); 205 j++) { 206 size_t keys_cnt = 0; 207 const ares_dns_rr_key_t *keys = NULL; 208 ares_dns_rr_t *rr = NULL; 209 size_t k; 210 211 rr = ares_dns_record_rr_get(dnsrec, (ares_dns_section_t)i, j); 212 ares_buf_append_str(printmsg, ares_dns_rr_get_name(rr)); 213 ares_buf_append_str(printmsg, ".\t\t\t"); 214 ares_buf_append_str(printmsg, 215 ares_dns_class_tostr(ares_dns_rr_get_class(rr))); 216 ares_buf_append_str(printmsg, "\t"); 217 ares_buf_append_str(printmsg, 218 ares_dns_rec_type_tostr(ares_dns_rr_get_type(rr))); 219 ares_buf_append_str(printmsg, "\t"); 220 ares_buf_append_num_dec(printmsg, ares_dns_rr_get_ttl(rr), 0); 221 ares_buf_append_str(printmsg, "\t"); 222 223 keys = ares_dns_rr_get_keys(ares_dns_rr_get_type(rr), &keys_cnt); 224 for (k = 0; k < keys_cnt; k++) { 225 char buf[256] = ""; 226 227 ares_buf_append_str(printmsg, ares_dns_rr_key_tostr(keys[k])); 228 ares_buf_append_str(printmsg, "="); 229 switch (ares_dns_rr_key_datatype(keys[k])) { 230 case ARES_DATATYPE_INADDR: 231 ares_inet_ntop(AF_INET, ares_dns_rr_get_addr(rr, keys[k]), buf, 232 sizeof(buf)); 233 ares_buf_append_str(printmsg, buf); 234 break; 235 case ARES_DATATYPE_INADDR6: 236 ares_inet_ntop(AF_INET6, ares_dns_rr_get_addr6(rr, keys[k]), buf, 237 sizeof(buf)); 238 ares_buf_append_str(printmsg, buf); 239 break; 240 case ARES_DATATYPE_U8: 241 ares_buf_append_num_dec(printmsg, ares_dns_rr_get_u8(rr, keys[k]), 242 0); 243 break; 244 case ARES_DATATYPE_U16: 245 ares_buf_append_num_dec(printmsg, ares_dns_rr_get_u16(rr, keys[k]), 246 0); 247 break; 248 case ARES_DATATYPE_U32: 249 ares_buf_append_num_dec(printmsg, ares_dns_rr_get_u32(rr, keys[k]), 250 0); 251 break; 252 case ARES_DATATYPE_NAME: 253 case ARES_DATATYPE_STR: 254 ares_buf_append_byte(printmsg, '"'); 255 ares_buf_append_str(printmsg, ares_dns_rr_get_str(rr, keys[k])); 256 ares_buf_append_byte(printmsg, '"'); 257 break; 258 case ARES_DATATYPE_BIN: 259 /* TODO */ 260 break; 261 case ARES_DATATYPE_BINP: 262 { 263 size_t templen; 264 ares_buf_append_byte(printmsg, '"'); 265 ares_buf_append_str(printmsg, (const char *)ares_dns_rr_get_bin( 266 rr, keys[k], &templen)); 267 ares_buf_append_byte(printmsg, '"'); 268 } 269 break; 270 case ARES_DATATYPE_ABINP: 271 { 272 size_t a; 273 for (a = 0; a < ares_dns_rr_get_abin_cnt(rr, keys[k]); a++) { 274 size_t templen; 275 276 if (a != 0) { 277 ares_buf_append_byte(printmsg, ' '); 278 } 279 ares_buf_append_byte(printmsg, '"'); 280 ares_buf_append_str( 281 printmsg, 282 (const char *)ares_dns_rr_get_abin(rr, keys[k], a, &templen)); 283 ares_buf_append_byte(printmsg, '"'); 284 } 285 } 286 break; 287 case ARES_DATATYPE_OPT: 288 /* TODO */ 289 break; 290 } 291 ares_buf_append_str(printmsg, " "); 292 } 293 ares_buf_append_str(printmsg, "\n"); 294 } 295 } 296 ares_buf_append_str(printmsg, ";; SIZE: "); 297 ares_buf_append_num_dec(printmsg, size, 0); 298 ares_buf_append_str(printmsg, "\n\n"); 299 300 printdata = ares_buf_finish_str(printmsg, NULL); 301 printmsg = NULL; 302 303 /* Write it back out as a dns message to test writer */ 304 if (ares_dns_write(dnsrec, &datadup, &datadup_len) != ARES_SUCCESS) { 305 goto done; 306 } 307 308 done: 309 ares_dns_record_destroy(dnsrec); 310 ares_buf_destroy(printmsg); 311 ares_free(printdata); 312 ares_free(datadup); 313 return 0; 314 } 315 316 #endif