Coverage Report

Created: 2026-06-13 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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