xref: /aosp_15_r20/external/cronet/net/dns/dns_response_fuzzer.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2018 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "net/dns/dns_response.h"
6 
7 #include <fuzzer/FuzzedDataProvider.h>
8 #include <stddef.h>
9 #include <stdint.h>
10 
11 #include <optional>
12 
13 #include "base/check.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/string_piece.h"
16 #include "net/base/io_buffer.h"
17 #include "net/dns/dns_names_util.h"
18 #include "net/dns/dns_query.h"
19 #include "net/dns/dns_util.h"
20 #include "net/dns/public/dns_protocol.h"
21 
22 namespace {
23 
ValidateParsedResponse(net::DnsResponse & response,const net::IOBufferWithSize & packet,std::optional<net::DnsQuery> query=std::nullopt)24 void ValidateParsedResponse(net::DnsResponse& response,
25                             const net::IOBufferWithSize& packet,
26                             std::optional<net::DnsQuery> query = std::nullopt) {
27   CHECK_EQ(response.io_buffer(), &packet);
28   CHECK_EQ(static_cast<int>(response.io_buffer_size()), packet.size());
29 
30   response.id();
31   if (response.IsValid()) {
32     CHECK(response.id().has_value());
33     response.flags();
34     response.rcode();
35 
36     CHECK_EQ(response.dotted_qnames().size(), response.question_count());
37     CHECK_EQ(response.qtypes().size(), response.question_count());
38     if (response.question_count() == 1) {
39       response.GetSingleDottedName();
40       response.GetSingleQType();
41     }
42 
43     response.answer_count();
44     response.authority_count();
45     response.additional_answer_count();
46 
47     bool success = false;
48     size_t last_offset = 0;
49     net::DnsRecordParser parser = response.Parser();
50     do {
51       net::DnsResourceRecord record;
52       success = parser.ReadRecord(&record);
53 
54       CHECK(!success || parser.GetOffset() > last_offset);
55       last_offset = parser.GetOffset();
56     } while (success);
57 
58     // Attempt to parse a couple more.
59     for (int i = 0; i < 10; ++i) {
60       net::DnsResourceRecord record;
61       CHECK(!parser.ReadRecord(&record));
62     }
63 
64     if (query) {
65       CHECK_EQ(response.question_count(), 1u);
66       CHECK_EQ(response.id().value(), query->id());
67       std::optional<std::string> dotted_qname =
68           net::dns_names_util::NetworkToDottedName(query->qname(),
69                                                    /*require_complete=*/true);
70       CHECK(dotted_qname.has_value());
71       CHECK_EQ(response.GetSingleDottedName(), dotted_qname.value());
72       CHECK_EQ(response.GetSingleQType(), query->qtype());
73     }
74   }
75 }
76 
77 }  // namespace
78 
79 // Entry point for LibFuzzer.
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)80 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
81   FuzzedDataProvider data_provider(data, size);
82   std::string response_string = data_provider.ConsumeRandomLengthString();
83 
84   auto response_packet =
85       base::MakeRefCounted<net::IOBufferWithSize>(response_string.size());
86   memcpy(response_packet->data(), response_string.data(),
87          response_string.size());
88 
89   net::DnsResponse received_response(response_packet, response_string.size());
90   received_response.InitParseWithoutQuery(response_string.size());
91   ValidateParsedResponse(received_response, *response_packet.get());
92 
93   size_t query_size = data_provider.remaining_bytes();
94   auto query_packet = base::MakeRefCounted<net::IOBufferWithSize>(query_size);
95   data_provider.ConsumeData(query_packet->data(), query_size);
96   net::DnsQuery query(query_packet);
97 
98   if (!query.Parse(query_size))
99     return 0;
100 
101   net::DnsResponse received_response_with_query(response_packet,
102                                                 response_string.size());
103   received_response_with_query.InitParse(response_string.size(), query);
104   ValidateParsedResponse(received_response_with_query, *response_packet.get(),
105                          query);
106 
107   net::DnsResponse response(query.id(), true /* is_authoritative */,
108                             {} /* answers */, {} /* authority_records */,
109                             {} /* additional records */, query);
110   std::string out =
111       base::HexEncode(response.io_buffer()->data(), response.io_buffer_size());
112 
113   return 0;
114 }
115