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