• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 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 <algorithm>
8 #include <cstdint>
9 #include <limits>
10 #include <numeric>
11 #include <optional>
12 #include <string_view>
13 #include <utility>
14 #include <vector>
15 
16 #include "base/big_endian.h"
17 #include "base/containers/span.h"
18 #include "base/containers/span_reader.h"
19 #include "base/containers/span_writer.h"
20 #include "base/logging.h"
21 #include "base/numerics/safe_conversions.h"
22 #include "base/strings/string_util.h"
23 #include "base/sys_byteorder.h"
24 #include "base/types/optional_util.h"
25 #include "net/base/io_buffer.h"
26 #include "net/base/net_errors.h"
27 #include "net/dns/dns_names_util.h"
28 #include "net/dns/dns_query.h"
29 #include "net/dns/dns_response_result_extractor.h"
30 #include "net/dns/dns_util.h"
31 #include "net/dns/public/dns_protocol.h"
32 #include "net/dns/record_rdata.h"
33 
34 namespace net {
35 
36 namespace {
37 
38 const size_t kHeaderSize = sizeof(dns_protocol::Header);
39 
40 const uint8_t kRcodeMask = 0xf;
41 
42 }  // namespace
43 
44 DnsResourceRecord::DnsResourceRecord() = default;
45 
DnsResourceRecord(const DnsResourceRecord & other)46 DnsResourceRecord::DnsResourceRecord(const DnsResourceRecord& other)
47     : name(other.name),
48       type(other.type),
49       klass(other.klass),
50       ttl(other.ttl),
51       owned_rdata(other.owned_rdata) {
52   if (!owned_rdata.empty())
53     rdata = owned_rdata;
54   else
55     rdata = other.rdata;
56 }
57 
DnsResourceRecord(DnsResourceRecord && other)58 DnsResourceRecord::DnsResourceRecord(DnsResourceRecord&& other)
59     : name(std::move(other.name)),
60       type(other.type),
61       klass(other.klass),
62       ttl(other.ttl),
63       owned_rdata(std::move(other.owned_rdata)) {
64   if (!owned_rdata.empty())
65     rdata = owned_rdata;
66   else
67     rdata = other.rdata;
68 }
69 
70 DnsResourceRecord::~DnsResourceRecord() = default;
71 
operator =(const DnsResourceRecord & other)72 DnsResourceRecord& DnsResourceRecord::operator=(
73     const DnsResourceRecord& other) {
74   name = other.name;
75   type = other.type;
76   klass = other.klass;
77   ttl = other.ttl;
78   owned_rdata = other.owned_rdata;
79 
80   if (!owned_rdata.empty())
81     rdata = owned_rdata;
82   else
83     rdata = other.rdata;
84 
85   return *this;
86 }
87 
operator =(DnsResourceRecord && other)88 DnsResourceRecord& DnsResourceRecord::operator=(DnsResourceRecord&& other) {
89   name = std::move(other.name);
90   type = other.type;
91   klass = other.klass;
92   ttl = other.ttl;
93   owned_rdata = std::move(other.owned_rdata);
94 
95   if (!owned_rdata.empty())
96     rdata = owned_rdata;
97   else
98     rdata = other.rdata;
99 
100   return *this;
101 }
102 
SetOwnedRdata(std::string value)103 void DnsResourceRecord::SetOwnedRdata(std::string value) {
104   DCHECK(!value.empty());
105   owned_rdata = std::move(value);
106   rdata = owned_rdata;
107   DCHECK_EQ(owned_rdata.data(), rdata.data());
108 }
109 
CalculateRecordSize() const110 size_t DnsResourceRecord::CalculateRecordSize() const {
111   bool has_final_dot = name.back() == '.';
112   // Depending on if |name| in the dotted format has the final dot for the root
113   // domain or not, the corresponding wire data in the DNS domain name format is
114   // 1 byte (with dot) or 2 bytes larger in size. See RFC 1035, Section 3.1 and
115   // DNSDomainFromDot.
116   return name.size() + (has_final_dot ? 1 : 2) +
117          net::dns_protocol::kResourceRecordSizeInBytesWithoutNameAndRData +
118          (owned_rdata.empty() ? rdata.size() : owned_rdata.size());
119 }
120 
121 DnsRecordParser::DnsRecordParser() = default;
122 
123 DnsRecordParser::~DnsRecordParser() = default;
124 
125 DnsRecordParser::DnsRecordParser(const DnsRecordParser&) = default;
126 
127 DnsRecordParser::DnsRecordParser(DnsRecordParser&&) = default;
128 
129 DnsRecordParser& DnsRecordParser::operator=(const DnsRecordParser&) = default;
130 
131 DnsRecordParser& DnsRecordParser::operator=(DnsRecordParser&&) = default;
132 
DnsRecordParser(base::span<const uint8_t> packet,size_t offset,size_t num_records)133 DnsRecordParser::DnsRecordParser(base::span<const uint8_t> packet,
134                                  size_t offset,
135                                  size_t num_records)
136     : packet_(packet), num_records_(num_records), cur_(offset) {
137   CHECK_LE(offset, packet_.size());
138 }
139 
ReadName(const void * const vpos,std::string * out) const140 unsigned DnsRecordParser::ReadName(const void* const vpos,
141                                    std::string* out) const {
142   static const char kAbortMsg[] = "Abort parsing of noncompliant DNS record.";
143 
144   CHECK_LE(packet_.data(), vpos);
145   CHECK_LE(vpos, packet_.last(0u).data());
146   const size_t initial_offset =
147       // SAFETY: `vpos` points into the span, as verified by the CHECKs above,
148       // so subtracting the data pointer is well-defined and gives an offset
149       // into the span.
150       //
151       // TODO(danakj): Since we need an offset anyway, no unsafe pointer usage
152       // would be required, and fewer CHECKs, if this function took an offset
153       // instead of a pointer.
154       UNSAFE_BUFFERS(static_cast<const uint8_t*>(vpos) - packet_.data());
155 
156   if (initial_offset == packet_.size()) {
157     return 0;
158   }
159 
160   size_t offset = initial_offset;
161   // Count number of seen bytes to detect loops.
162   unsigned seen = 0u;
163   // Remember how many bytes were consumed before first jump.
164   unsigned consumed = 0u;
165   // The length of the encoded name (sum of label octets and label lengths).
166   // For context, RFC 1034 states that the total number of octets representing a
167   // domain name (the sum of all label octets and label lengths) is limited to
168   // 255. RFC 1035 introduces message compression as a way to reduce packet size
169   // on the wire, not to increase the maximum domain name length.
170   unsigned encoded_name_len = 0u;
171 
172   if (out) {
173     out->clear();
174     out->reserve(dns_protocol::kMaxCharNameLength);
175   }
176 
177   for (;;) {
178     // The first two bits of the length give the type of the length. It's
179     // either a direct length or a pointer to the remainder of the name.
180     switch (packet_[offset] & dns_protocol::kLabelMask) {
181       case dns_protocol::kLabelPointer: {
182         if (packet_.size() < sizeof(uint16_t) ||
183             offset > packet_.size() - sizeof(uint16_t)) {
184           VLOG(1) << kAbortMsg << " Truncated or missing label pointer.";
185           return 0;
186         }
187         if (consumed == 0u) {
188           consumed = offset - initial_offset + sizeof(uint16_t);
189           if (!out) {
190             return consumed;  // If name is not stored, that's all we need.
191           }
192         }
193         seen += sizeof(uint16_t);
194         // If seen the whole packet, then we must be in a loop.
195         if (seen > packet_.size()) {
196           VLOG(1) << kAbortMsg << " Detected loop in label pointers.";
197           return 0;
198         }
199         uint16_t new_offset =
200             base::U16FromBigEndian(packet_.subspan(offset).first<2u>());
201         offset = new_offset & dns_protocol::kOffsetMask;
202         if (offset >= packet_.size()) {
203           VLOG(1) << kAbortMsg << " Label pointer points outside packet.";
204           return 0;
205         }
206         break;
207       }
208       case dns_protocol::kLabelDirect: {
209         uint8_t label_len = packet_[offset];
210         ++offset;
211         // Note: root domain (".") is NOT included.
212         if (label_len == 0) {
213           if (consumed == 0) {
214             consumed = offset - initial_offset;
215           }  // else we set |consumed| before first jump
216           return consumed;
217         }
218         // Add one octet for the length and |label_len| for the number of
219         // following octets.
220         encoded_name_len += 1 + label_len;
221         if (encoded_name_len > dns_protocol::kMaxNameLength) {
222           VLOG(1) << kAbortMsg << " Name is too long.";
223           return 0;
224         }
225         if (label_len >= packet_.size() - offset) {
226           VLOG(1) << kAbortMsg << " Truncated or missing label.";
227           return 0;  // Truncated or missing label.
228         }
229         if (out) {
230           if (!out->empty())
231             out->append(".");
232           // TODO(danakj): Use append_range() in C++23.
233           auto range = packet_.subspan(offset, label_len);
234           out->append(range.begin(), range.end());
235           CHECK_LE(out->size(), dns_protocol::kMaxCharNameLength);
236         }
237         offset += label_len;
238         seen += 1 + label_len;
239         break;
240       }
241       default:
242         // unhandled label type
243         VLOG(1) << kAbortMsg << " Unhandled label type.";
244         return 0;
245     }
246   }
247 }
248 
ReadRecord(DnsResourceRecord * out)249 bool DnsRecordParser::ReadRecord(DnsResourceRecord* out) {
250   CHECK(!packet_.empty());
251 
252   // Disallow parsing any more than the claimed number of records.
253   if (num_records_parsed_ >= num_records_)
254     return false;
255 
256   size_t consumed = ReadName(packet_.subspan(cur_).data(), &out->name);
257   if (!consumed) {
258     return false;
259   }
260   auto reader = base::SpanReader(packet_.subspan(cur_ + consumed));
261   uint16_t rdlen;
262   if (reader.ReadU16BigEndian(out->type) &&
263       reader.ReadU16BigEndian(out->klass) &&
264       reader.ReadU32BigEndian(out->ttl) &&  //
265       reader.ReadU16BigEndian(rdlen) &&
266       base::OptionalUnwrapTo(reader.Read(rdlen), out->rdata, [](auto span) {
267         return base::as_string_view(span);
268       })) {
269     cur_ += consumed + 2u + 2u + 4u + 2u + rdlen;
270     ++num_records_parsed_;
271     return true;
272   }
273   return false;
274 }
275 
ReadQuestion(std::string & out_dotted_qname,uint16_t & out_qtype)276 bool DnsRecordParser::ReadQuestion(std::string& out_dotted_qname,
277                                    uint16_t& out_qtype) {
278   size_t consumed = ReadName(packet_.subspan(cur_).data(), &out_dotted_qname);
279   if (!consumed)
280     return false;
281 
282   if (consumed + 2 * sizeof(uint16_t) > packet_.size() - cur_) {
283     return false;
284   }
285 
286   out_qtype = base::U16FromBigEndian(
287       packet_.subspan(cur_ + consumed).first<sizeof(uint16_t)>());
288 
289   cur_ += consumed + 2 * sizeof(uint16_t);  // QTYPE + QCLASS
290 
291   return true;
292 }
293 
DnsResponse(uint16_t id,bool is_authoritative,const std::vector<DnsResourceRecord> & answers,const std::vector<DnsResourceRecord> & authority_records,const std::vector<DnsResourceRecord> & additional_records,const std::optional<DnsQuery> & query,uint8_t rcode,bool validate_records,bool validate_names_as_internet_hostnames)294 DnsResponse::DnsResponse(
295     uint16_t id,
296     bool is_authoritative,
297     const std::vector<DnsResourceRecord>& answers,
298     const std::vector<DnsResourceRecord>& authority_records,
299     const std::vector<DnsResourceRecord>& additional_records,
300     const std::optional<DnsQuery>& query,
301     uint8_t rcode,
302     bool validate_records,
303     bool validate_names_as_internet_hostnames) {
304   bool has_query = query.has_value();
305   dns_protocol::Header header;
306   header.id = id;
307   bool success = true;
308   if (has_query) {
309     success &= (id == query.value().id());
310     DCHECK(success);
311     // DnsQuery only supports a single question.
312     header.qdcount = 1;
313   }
314   header.flags |= dns_protocol::kFlagResponse;
315   if (is_authoritative)
316     header.flags |= dns_protocol::kFlagAA;
317   DCHECK_EQ(0, rcode & ~kRcodeMask);
318   header.flags |= rcode;
319 
320   header.ancount = answers.size();
321   header.nscount = authority_records.size();
322   header.arcount = additional_records.size();
323 
324   // Response starts with the header and the question section (if any).
325   size_t response_size = has_query
326                              ? sizeof(header) + query.value().question_size()
327                              : sizeof(header);
328   // Add the size of all answers and additional records.
329   auto do_accumulation = [](size_t cur_size, const DnsResourceRecord& record) {
330     return cur_size + record.CalculateRecordSize();
331   };
332   response_size = std::accumulate(answers.begin(), answers.end(), response_size,
333                                   do_accumulation);
334   response_size =
335       std::accumulate(authority_records.begin(), authority_records.end(),
336                       response_size, do_accumulation);
337   response_size =
338       std::accumulate(additional_records.begin(), additional_records.end(),
339                       response_size, do_accumulation);
340 
341   auto io_buffer = base::MakeRefCounted<IOBufferWithSize>(response_size);
342   auto writer = base::SpanWriter(io_buffer->span());
343   success &= WriteHeader(&writer, header);
344   DCHECK(success);
345   if (has_query) {
346     success &= WriteQuestion(&writer, query.value());
347     DCHECK(success);
348   }
349   // Start the Answer section.
350   for (const auto& answer : answers) {
351     success &= WriteAnswer(&writer, answer, query, validate_records,
352                            validate_names_as_internet_hostnames);
353     DCHECK(success);
354   }
355   // Start the Authority section.
356   for (const auto& record : authority_records) {
357     success &= WriteRecord(&writer, record, validate_records,
358                            validate_names_as_internet_hostnames);
359     DCHECK(success);
360   }
361   // Start the Additional section.
362   for (const auto& record : additional_records) {
363     success &= WriteRecord(&writer, record, validate_records,
364                            validate_names_as_internet_hostnames);
365     DCHECK(success);
366   }
367   if (!success) {
368     return;
369   }
370   io_buffer_ = io_buffer;
371   io_buffer_size_ = response_size;
372   // Ensure we don't have any remaining uninitialized bytes in the buffer.
373   DCHECK_EQ(writer.remaining(), 0u);
374   std::ranges::fill(writer.remaining_span(), uint8_t{0});
375   if (has_query)
376     InitParse(io_buffer_size_, query.value());
377   else
378     InitParseWithoutQuery(io_buffer_size_);
379 }
380 
DnsResponse()381 DnsResponse::DnsResponse()
382     : io_buffer_(base::MakeRefCounted<IOBufferWithSize>(
383           dns_protocol::kMaxUDPSize + 1)),
384       io_buffer_size_(dns_protocol::kMaxUDPSize + 1) {}
385 
DnsResponse(scoped_refptr<IOBuffer> buffer,size_t size)386 DnsResponse::DnsResponse(scoped_refptr<IOBuffer> buffer, size_t size)
387     : io_buffer_(std::move(buffer)), io_buffer_size_(size) {}
388 
DnsResponse(size_t length)389 DnsResponse::DnsResponse(size_t length)
390     : io_buffer_(base::MakeRefCounted<IOBufferWithSize>(length)),
391       io_buffer_size_(length) {}
392 
DnsResponse(base::span<const uint8_t> data,size_t answer_offset)393 DnsResponse::DnsResponse(base::span<const uint8_t> data, size_t answer_offset)
394     : io_buffer_(base::MakeRefCounted<IOBufferWithSize>(data.size())),
395       io_buffer_size_(data.size()),
396       parser_(io_buffer_->span(),
397               answer_offset,
398               std::numeric_limits<size_t>::max()) {
399   io_buffer_->span().copy_from(data);
400 }
401 
402 // static
CreateEmptyNoDataResponse(uint16_t id,bool is_authoritative,base::span<const uint8_t> qname,uint16_t qtype)403 DnsResponse DnsResponse::CreateEmptyNoDataResponse(
404     uint16_t id,
405     bool is_authoritative,
406     base::span<const uint8_t> qname,
407     uint16_t qtype) {
408   return DnsResponse(id, is_authoritative,
409                      /*answers=*/{},
410                      /*authority_records=*/{},
411                      /*additional_records=*/{}, DnsQuery(id, qname, qtype));
412 }
413 
414 DnsResponse::DnsResponse(DnsResponse&& other) = default;
415 DnsResponse& DnsResponse::operator=(DnsResponse&& other) = default;
416 
417 DnsResponse::~DnsResponse() = default;
418 
InitParse(size_t nbytes,const DnsQuery & query)419 bool DnsResponse::InitParse(size_t nbytes, const DnsQuery& query) {
420   const std::string_view question = query.question();
421 
422   // Response includes question, it should be at least that size.
423   if (nbytes < kHeaderSize + question.size() || nbytes > io_buffer_size_) {
424     return false;
425   }
426 
427   // At this point, it has been validated that the response is at least large
428   // enough to read the ID field.
429   id_available_ = true;
430 
431   // Match the query id.
432   DCHECK(id());
433   if (id().value() != query.id())
434     return false;
435 
436   // Not a response?
437   if ((base::NetToHost16(header()->flags) & dns_protocol::kFlagResponse) == 0)
438     return false;
439 
440   // Match question count.
441   if (base::NetToHost16(header()->qdcount) != 1)
442     return false;
443 
444   base::span<const uint8_t> subspan =
445       io_buffer_->span().subspan(kHeaderSize, question.size());
446   // Match the question section.
447   if (question != base::as_string_view(subspan)) {
448     return false;
449   }
450 
451   std::optional<std::string> dotted_qname =
452       dns_names_util::NetworkToDottedName(query.qname());
453   if (!dotted_qname.has_value())
454     return false;
455   dotted_qnames_.push_back(std::move(dotted_qname).value());
456   qtypes_.push_back(query.qtype());
457 
458   size_t num_records = base::NetToHost16(header()->ancount) +
459                        base::NetToHost16(header()->nscount) +
460                        base::NetToHost16(header()->arcount);
461 
462   // Construct the parser. Only allow parsing up to `num_records` records. If
463   // more records are present in the buffer, it's just garbage extra data after
464   // the formal end of the response and should be ignored.
465   parser_ = DnsRecordParser(io_buffer_->span().first(nbytes),
466                             kHeaderSize + question.size(), num_records);
467   return true;
468 }
469 
InitParseWithoutQuery(size_t nbytes)470 bool DnsResponse::InitParseWithoutQuery(size_t nbytes) {
471   if (nbytes < kHeaderSize || nbytes > io_buffer_size_) {
472     return false;
473   }
474   id_available_ = true;
475 
476   // Not a response?
477   if ((base::NetToHost16(header()->flags) & dns_protocol::kFlagResponse) == 0)
478     return false;
479 
480   size_t num_records = base::NetToHost16(header()->ancount) +
481                        base::NetToHost16(header()->nscount) +
482                        base::NetToHost16(header()->arcount);
483   // Only allow parsing up to `num_records` records. If more records are present
484   // in the buffer, it's just garbage extra data after the formal end of the
485   // response and should be ignored.
486   parser_ = DnsRecordParser(io_buffer_->span().first(nbytes), kHeaderSize,
487                             num_records);
488 
489   unsigned qdcount = base::NetToHost16(header()->qdcount);
490   for (unsigned i = 0; i < qdcount; ++i) {
491     std::string dotted_qname;
492     uint16_t qtype;
493     if (!parser_.ReadQuestion(dotted_qname, qtype)) {
494       parser_ = DnsRecordParser();  // Make parser invalid again.
495       return false;
496     }
497     dotted_qnames_.push_back(std::move(dotted_qname));
498     qtypes_.push_back(qtype);
499   }
500 
501   return true;
502 }
503 
id() const504 std::optional<uint16_t> DnsResponse::id() const {
505   if (!id_available_)
506     return std::nullopt;
507 
508   return base::NetToHost16(header()->id);
509 }
510 
IsValid() const511 bool DnsResponse::IsValid() const {
512   return parser_.IsValid();
513 }
514 
flags() const515 uint16_t DnsResponse::flags() const {
516   DCHECK(parser_.IsValid());
517   return base::NetToHost16(header()->flags) & ~(kRcodeMask);
518 }
519 
rcode() const520 uint8_t DnsResponse::rcode() const {
521   DCHECK(parser_.IsValid());
522   return base::NetToHost16(header()->flags) & kRcodeMask;
523 }
524 
question_count() const525 unsigned DnsResponse::question_count() const {
526   DCHECK(parser_.IsValid());
527   return base::NetToHost16(header()->qdcount);
528 }
529 
answer_count() const530 unsigned DnsResponse::answer_count() const {
531   DCHECK(parser_.IsValid());
532   return base::NetToHost16(header()->ancount);
533 }
534 
authority_count() const535 unsigned DnsResponse::authority_count() const {
536   DCHECK(parser_.IsValid());
537   return base::NetToHost16(header()->nscount);
538 }
539 
additional_answer_count() const540 unsigned DnsResponse::additional_answer_count() const {
541   DCHECK(parser_.IsValid());
542   return base::NetToHost16(header()->arcount);
543 }
544 
GetSingleQType() const545 uint16_t DnsResponse::GetSingleQType() const {
546   DCHECK_EQ(qtypes().size(), 1u);
547   return qtypes().front();
548 }
549 
GetSingleDottedName() const550 std::string_view DnsResponse::GetSingleDottedName() const {
551   DCHECK_EQ(dotted_qnames().size(), 1u);
552   return dotted_qnames().front();
553 }
554 
Parser() const555 DnsRecordParser DnsResponse::Parser() const {
556   DCHECK(parser_.IsValid());
557   // Return a copy of the parser.
558   return parser_;
559 }
560 
header() const561 const dns_protocol::Header* DnsResponse::header() const {
562   return reinterpret_cast<const dns_protocol::Header*>(io_buffer_->data());
563 }
564 
WriteHeader(base::SpanWriter<uint8_t> * writer,const dns_protocol::Header & header)565 bool DnsResponse::WriteHeader(base::SpanWriter<uint8_t>* writer,
566                               const dns_protocol::Header& header) {
567   return writer->WriteU16BigEndian(header.id) &&
568          writer->WriteU16BigEndian(header.flags) &&
569          writer->WriteU16BigEndian(header.qdcount) &&
570          writer->WriteU16BigEndian(header.ancount) &&
571          writer->WriteU16BigEndian(header.nscount) &&
572          writer->WriteU16BigEndian(header.arcount);
573 }
574 
WriteQuestion(base::SpanWriter<uint8_t> * writer,const DnsQuery & query)575 bool DnsResponse::WriteQuestion(base::SpanWriter<uint8_t>* writer,
576                                 const DnsQuery& query) {
577   return writer->Write(base::as_byte_span(query.question()));
578 }
579 
WriteRecord(base::SpanWriter<uint8_t> * writer,const DnsResourceRecord & record,bool validate_record,bool validate_name_as_internet_hostname)580 bool DnsResponse::WriteRecord(base::SpanWriter<uint8_t>* writer,
581                               const DnsResourceRecord& record,
582                               bool validate_record,
583                               bool validate_name_as_internet_hostname) {
584   if (record.rdata != std::string_view(record.owned_rdata)) {
585     VLOG(1) << "record.rdata should point to record.owned_rdata.";
586     return false;
587   }
588 
589   if (validate_record &&
590       !RecordRdata::HasValidSize(record.owned_rdata, record.type)) {
591     VLOG(1) << "Invalid RDATA size for a record.";
592     return false;
593   }
594 
595   std::optional<std::vector<uint8_t>> domain_name =
596       dns_names_util::DottedNameToNetwork(record.name,
597                                           validate_name_as_internet_hostname);
598   if (!domain_name.has_value()) {
599     VLOG(1) << "Invalid dotted name (as "
600             << (validate_name_as_internet_hostname ? "Internet hostname)."
601                                                    : "DNS name).");
602     return false;
603   }
604 
605   return writer->Write(domain_name.value()) &&
606          writer->WriteU16BigEndian(record.type) &&
607          writer->WriteU16BigEndian(record.klass) &&
608          writer->WriteU32BigEndian(record.ttl) &&
609          writer->WriteU16BigEndian(record.owned_rdata.size()) &&
610          // Use the owned RDATA in the record to construct the response.
611          writer->Write(base::as_byte_span(record.owned_rdata));
612 }
613 
WriteAnswer(base::SpanWriter<uint8_t> * writer,const DnsResourceRecord & answer,const std::optional<DnsQuery> & query,bool validate_record,bool validate_name_as_internet_hostname)614 bool DnsResponse::WriteAnswer(base::SpanWriter<uint8_t>* writer,
615                               const DnsResourceRecord& answer,
616                               const std::optional<DnsQuery>& query,
617                               bool validate_record,
618                               bool validate_name_as_internet_hostname) {
619   // Generally assumed to be a mistake if we write answers that don't match the
620   // query type, except CNAME answers which can always be added.
621   if (validate_record && query.has_value() &&
622       answer.type != query.value().qtype() &&
623       answer.type != dns_protocol::kTypeCNAME) {
624     VLOG(1) << "Mismatched answer resource record type and qtype.";
625     return false;
626   }
627   return WriteRecord(writer, answer, validate_record,
628                      validate_name_as_internet_hostname);
629 }
630 
631 }  // namespace net
632