1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/dns/dns_response.h"
7 #include "base/big_endian.h"
8 #include "base/strings/string_util.h"
9 #include "base/sys_byteorder.h"
10 #include "net/base/address_list.h"
11 #include "net/base/dns_util.h"
12 #include "net/base/io_buffer.h"
13 #include "net/base/net_errors.h"
14 #include "net/dns/dns_protocol.h"
15 #include "net/dns/dns_query.h"
19 DnsResourceRecord::DnsResourceRecord() {
22 DnsResourceRecord::~DnsResourceRecord() {
25 DnsRecordParser::DnsRecordParser() : packet_(NULL
), length_(0), cur_(0) {
28 DnsRecordParser::DnsRecordParser(const void* packet
,
31 : packet_(reinterpret_cast<const char*>(packet
)),
33 cur_(packet_
+ offset
) {
34 DCHECK_LE(offset
, length
);
37 unsigned DnsRecordParser::ReadName(const void* const vpos
,
38 std::string
* out
) const {
39 const char* const pos
= reinterpret_cast<const char*>(vpos
);
41 DCHECK_LE(packet_
, pos
);
42 DCHECK_LE(pos
, packet_
+ length_
);
45 const char* end
= packet_
+ length_
;
46 // Count number of seen bytes to detect loops.
48 // Remember how many bytes were consumed before first jump.
49 unsigned consumed
= 0;
56 out
->reserve(dns_protocol::kMaxNameLength
);
60 // The first two bits of the length give the type of the length. It's
61 // either a direct length or a pointer to the remainder of the name.
62 switch (*p
& dns_protocol::kLabelMask
) {
63 case dns_protocol::kLabelPointer
: {
64 if (p
+ sizeof(uint16
) > end
)
67 consumed
= p
- pos
+ sizeof(uint16
);
69 return consumed
; // If name is not stored, that's all we need.
71 seen
+= sizeof(uint16
);
72 // If seen the whole packet, then we must be in a loop.
76 base::ReadBigEndian
<uint16
>(p
, &offset
);
77 offset
&= dns_protocol::kOffsetMask
;
83 case dns_protocol::kLabelDirect
: {
86 // Note: root domain (".") is NOT included.
90 } // else we set |consumed| before first jump
93 if (p
+ label_len
>= end
)
94 return 0; // Truncated or missing label.
98 out
->append(p
, label_len
);
101 seen
+= 1 + label_len
;
105 // unhandled label type
111 bool DnsRecordParser::ReadRecord(DnsResourceRecord
* out
) {
113 size_t consumed
= ReadName(cur_
, &out
->name
);
116 base::BigEndianReader
reader(cur_
+ consumed
,
117 packet_
+ length_
- (cur_
+ consumed
));
119 if (reader
.ReadU16(&out
->type
) &&
120 reader
.ReadU16(&out
->klass
) &&
121 reader
.ReadU32(&out
->ttl
) &&
122 reader
.ReadU16(&rdlen
) &&
123 reader
.ReadPiece(&out
->rdata
, rdlen
)) {
130 bool DnsRecordParser::SkipQuestion() {
131 size_t consumed
= ReadName(cur_
, NULL
);
135 const char* next
= cur_
+ consumed
+ 2 * sizeof(uint16
); // QTYPE + QCLASS
136 if (next
> packet_
+ length_
)
144 DnsResponse::DnsResponse()
145 : io_buffer_(new IOBufferWithSize(dns_protocol::kMaxUDPSize
+ 1)) {
148 DnsResponse::DnsResponse(size_t length
)
149 : io_buffer_(new IOBufferWithSize(length
)) {
152 DnsResponse::DnsResponse(const void* data
,
154 size_t answer_offset
)
155 : io_buffer_(new IOBufferWithSize(length
)),
156 parser_(io_buffer_
->data(), length
, answer_offset
) {
158 memcpy(io_buffer_
->data(), data
, length
);
161 DnsResponse::~DnsResponse() {
164 bool DnsResponse::InitParse(int nbytes
, const DnsQuery
& query
) {
165 DCHECK_GE(nbytes
, 0);
166 // Response includes query, it should be at least that size.
167 if (nbytes
< query
.io_buffer()->size() || nbytes
>= io_buffer_
->size())
170 // Match the query id.
171 if (base::NetToHost16(header()->id
) != query
.id())
174 // Match question count.
175 if (base::NetToHost16(header()->qdcount
) != 1)
178 // Match the question section.
179 const size_t hdr_size
= sizeof(dns_protocol::Header
);
180 const base::StringPiece question
= query
.question();
181 if (question
!= base::StringPiece(io_buffer_
->data() + hdr_size
,
186 // Construct the parser.
187 parser_
= DnsRecordParser(io_buffer_
->data(),
189 hdr_size
+ question
.size());
193 bool DnsResponse::InitParseWithoutQuery(int nbytes
) {
194 DCHECK_GE(nbytes
, 0);
196 size_t hdr_size
= sizeof(dns_protocol::Header
);
198 if (nbytes
< static_cast<int>(hdr_size
) || nbytes
>= io_buffer_
->size())
201 parser_
= DnsRecordParser(
202 io_buffer_
->data(), nbytes
, hdr_size
);
204 unsigned qdcount
= base::NetToHost16(header()->qdcount
);
205 for (unsigned i
= 0; i
< qdcount
; ++i
) {
206 if (!parser_
.SkipQuestion()) {
207 parser_
= DnsRecordParser(); // Make parser invalid again.
215 bool DnsResponse::IsValid() const {
216 return parser_
.IsValid();
219 uint16
DnsResponse::flags() const {
220 DCHECK(parser_
.IsValid());
221 return base::NetToHost16(header()->flags
) & ~(dns_protocol::kRcodeMask
);
224 uint8
DnsResponse::rcode() const {
225 DCHECK(parser_
.IsValid());
226 return base::NetToHost16(header()->flags
) & dns_protocol::kRcodeMask
;
229 unsigned DnsResponse::answer_count() const {
230 DCHECK(parser_
.IsValid());
231 return base::NetToHost16(header()->ancount
);
234 unsigned DnsResponse::additional_answer_count() const {
235 DCHECK(parser_
.IsValid());
236 return base::NetToHost16(header()->arcount
);
239 base::StringPiece
DnsResponse::qname() const {
240 DCHECK(parser_
.IsValid());
241 // The response is HEADER QNAME QTYPE QCLASS ANSWER.
242 // |parser_| is positioned at the beginning of ANSWER, so the end of QNAME is
243 // two uint16s before it.
244 const size_t hdr_size
= sizeof(dns_protocol::Header
);
245 const size_t qname_size
= parser_
.GetOffset() - 2 * sizeof(uint16
) - hdr_size
;
246 return base::StringPiece(io_buffer_
->data() + hdr_size
, qname_size
);
249 uint16
DnsResponse::qtype() const {
250 DCHECK(parser_
.IsValid());
251 // QTYPE starts where QNAME ends.
252 const size_t type_offset
= parser_
.GetOffset() - 2 * sizeof(uint16
);
254 base::ReadBigEndian
<uint16
>(io_buffer_
->data() + type_offset
, &type
);
258 std::string
DnsResponse::GetDottedName() const {
259 return DNSDomainToString(qname());
262 DnsRecordParser
DnsResponse::Parser() const {
263 DCHECK(parser_
.IsValid());
264 // Return a copy of the parser.
268 const dns_protocol::Header
* DnsResponse::header() const {
269 return reinterpret_cast<const dns_protocol::Header
*>(io_buffer_
->data());
272 DnsResponse::Result
DnsResponse::ParseToAddressList(
273 AddressList
* addr_list
,
274 base::TimeDelta
* ttl
) const {
276 // DnsTransaction already verified that |response| matches the issued query.
277 // We still need to determine if there is a valid chain of CNAMEs from the
278 // query name to the RR owner name.
279 // We err on the side of caution with the assumption that if we are too picky,
280 // we can always fall back to the system getaddrinfo.
282 // Expected owner of record. No trailing dot.
283 std::string expected_name
= GetDottedName();
285 uint16 expected_type
= qtype();
286 DCHECK(expected_type
== dns_protocol::kTypeA
||
287 expected_type
== dns_protocol::kTypeAAAA
);
289 size_t expected_size
= (expected_type
== dns_protocol::kTypeAAAA
)
290 ? kIPv6AddressSize
: kIPv4AddressSize
;
292 uint32 ttl_sec
= kuint32max
;
293 IPAddressList ip_addresses
;
294 DnsRecordParser parser
= Parser();
295 DnsResourceRecord record
;
296 unsigned ancount
= answer_count();
297 for (unsigned i
= 0; i
< ancount
; ++i
) {
298 if (!parser
.ReadRecord(&record
))
299 return DNS_MALFORMED_RESPONSE
;
301 if (record
.type
== dns_protocol::kTypeCNAME
) {
302 // Following the CNAME chain, only if no addresses seen.
303 if (!ip_addresses
.empty())
304 return DNS_CNAME_AFTER_ADDRESS
;
306 if (!base::EqualsCaseInsensitiveASCII(record
.name
, expected_name
))
307 return DNS_NAME_MISMATCH
;
309 if (record
.rdata
.size() !=
310 parser
.ReadName(record
.rdata
.begin(), &expected_name
))
311 return DNS_MALFORMED_CNAME
;
313 ttl_sec
= std::min(ttl_sec
, record
.ttl
);
314 } else if (record
.type
== expected_type
) {
315 if (record
.rdata
.size() != expected_size
)
316 return DNS_SIZE_MISMATCH
;
318 if (!base::EqualsCaseInsensitiveASCII(record
.name
, expected_name
))
319 return DNS_NAME_MISMATCH
;
321 ttl_sec
= std::min(ttl_sec
, record
.ttl
);
322 ip_addresses
.push_back(IPAddressNumber(record
.rdata
.begin(),
323 record
.rdata
.end()));
327 // TODO(szym): Extract TTL for NODATA results. http://crbug.com/115051
329 // getcanonname in eglibc returns the first owner name of an A or AAAA RR.
330 // If the response passed all the checks so far, then |expected_name| is it.
331 *addr_list
= AddressList::CreateFromIPAddressList(ip_addresses
,
333 *ttl
= base::TimeDelta::FromSeconds(ttl_sec
);