• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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