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