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/string_util.h"
8 #include "base/sys_byteorder.h"
9 #include "net/base/address_list.h"
10 #include "net/base/big_endian.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 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 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 DnsResponse::DnsResponse()
131 : io_buffer_(new IOBufferWithSize(dns_protocol::kMaxUDPSize
+ 1)) {
134 DnsResponse::DnsResponse(size_t length
)
135 : io_buffer_(new IOBufferWithSize(length
)) {
138 DnsResponse::DnsResponse(const void* data
,
140 size_t answer_offset
)
141 : io_buffer_(new IOBufferWithSize(length
)),
142 parser_(io_buffer_
->data(), length
, answer_offset
) {
144 memcpy(io_buffer_
->data(), data
, length
);
147 DnsResponse::~DnsResponse() {
150 bool DnsResponse::InitParse(int nbytes
, const DnsQuery
& query
) {
151 // Response includes query, it should be at least that size.
152 if (nbytes
< query
.io_buffer()->size() || nbytes
>= io_buffer_
->size())
155 // Match the query id.
156 if (base::NetToHost16(header()->id
) != query
.id())
159 // Match question count.
160 if (base::NetToHost16(header()->qdcount
) != 1)
163 // Match the question section.
164 const size_t hdr_size
= sizeof(dns_protocol::Header
);
165 const base::StringPiece question
= query
.question();
166 if (question
!= base::StringPiece(io_buffer_
->data() + hdr_size
,
171 // Construct the parser.
172 parser_
= DnsRecordParser(io_buffer_
->data(),
174 hdr_size
+ question
.size());
178 bool DnsResponse::IsValid() const {
179 return parser_
.IsValid();
182 uint16
DnsResponse::flags() const {
183 DCHECK(parser_
.IsValid());
184 return base::NetToHost16(header()->flags
) & ~(dns_protocol::kRcodeMask
);
187 uint8
DnsResponse::rcode() const {
188 DCHECK(parser_
.IsValid());
189 return base::NetToHost16(header()->flags
) & dns_protocol::kRcodeMask
;
192 unsigned DnsResponse::answer_count() const {
193 DCHECK(parser_
.IsValid());
194 return base::NetToHost16(header()->ancount
);
197 base::StringPiece
DnsResponse::qname() const {
198 DCHECK(parser_
.IsValid());
199 // The response is HEADER QNAME QTYPE QCLASS ANSWER.
200 // |parser_| is positioned at the beginning of ANSWER, so the end of QNAME is
201 // two uint16s before it.
202 const size_t hdr_size
= sizeof(dns_protocol::Header
);
203 const size_t qname_size
= parser_
.GetOffset() - 2 * sizeof(uint16
) - hdr_size
;
204 return base::StringPiece(io_buffer_
->data() + hdr_size
, qname_size
);
207 uint16
DnsResponse::qtype() const {
208 DCHECK(parser_
.IsValid());
209 // QTYPE starts where QNAME ends.
210 const size_t type_offset
= parser_
.GetOffset() - 2 * sizeof(uint16
);
212 ReadBigEndian
<uint16
>(io_buffer_
->data() + type_offset
, &type
);
216 std::string
DnsResponse::GetDottedName() const {
217 return DNSDomainToString(qname());
220 DnsRecordParser
DnsResponse::Parser() const {
221 DCHECK(parser_
.IsValid());
222 // Return a copy of the parser.
226 const dns_protocol::Header
* DnsResponse::header() const {
227 return reinterpret_cast<const dns_protocol::Header
*>(io_buffer_
->data());
230 DnsResponse::Result
DnsResponse::ParseToAddressList(
231 AddressList
* addr_list
,
232 base::TimeDelta
* ttl
) const {
234 // DnsTransaction already verified that |response| matches the issued query.
235 // We still need to determine if there is a valid chain of CNAMEs from the
236 // query name to the RR owner name.
237 // We err on the side of caution with the assumption that if we are too picky,
238 // we can always fall back to the system getaddrinfo.
240 // Expected owner of record. No trailing dot.
241 std::string expected_name
= GetDottedName();
243 uint16 expected_type
= qtype();
244 DCHECK(expected_type
== dns_protocol::kTypeA
||
245 expected_type
== dns_protocol::kTypeAAAA
);
247 size_t expected_size
= (expected_type
== dns_protocol::kTypeAAAA
)
248 ? kIPv6AddressSize
: kIPv4AddressSize
;
250 uint32 ttl_sec
= kuint32max
;
251 IPAddressList ip_addresses
;
252 DnsRecordParser parser
= Parser();
253 DnsResourceRecord record
;
254 unsigned ancount
= answer_count();
255 for (unsigned i
= 0; i
< ancount
; ++i
) {
256 if (!parser
.ReadRecord(&record
))
257 return DNS_MALFORMED_RESPONSE
;
259 if (record
.type
== dns_protocol::kTypeCNAME
) {
260 // Following the CNAME chain, only if no addresses seen.
261 if (!ip_addresses
.empty())
262 return DNS_CNAME_AFTER_ADDRESS
;
264 if (base::strcasecmp(record
.name
.c_str(), expected_name
.c_str()) != 0)
265 return DNS_NAME_MISMATCH
;
267 if (record
.rdata
.size() !=
268 parser
.ReadName(record
.rdata
.begin(), &expected_name
))
269 return DNS_MALFORMED_CNAME
;
271 ttl_sec
= std::min(ttl_sec
, record
.ttl
);
272 } else if (record
.type
== expected_type
) {
273 if (record
.rdata
.size() != expected_size
)
274 return DNS_SIZE_MISMATCH
;
276 if (base::strcasecmp(record
.name
.c_str(), expected_name
.c_str()) != 0)
277 return DNS_NAME_MISMATCH
;
279 ttl_sec
= std::min(ttl_sec
, record
.ttl
);
280 ip_addresses
.push_back(IPAddressNumber(record
.rdata
.begin(),
281 record
.rdata
.end()));
285 // TODO(szym): Extract TTL for NODATA results. http://crbug.com/115051
287 // getcanonname in eglibc returns the first owner name of an A or AAAA RR.
288 // If the response passed all the checks so far, then |expected_name| is it.
289 *addr_list
= AddressList::CreateFromIPAddressList(ip_addresses
,
291 *ttl
= base::TimeDelta::FromSeconds(ttl_sec
);