15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/dns/dns_response.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/big_endian.h"
85e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/string_util.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/sys_byteorder.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/address_list.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/dns_util.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/io_buffer.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_errors.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/dns/dns_protocol.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/dns/dns_query.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net {
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DnsResourceRecord::DnsResourceRecord() {
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DnsResourceRecord::~DnsResourceRecord() {
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DnsRecordParser::DnsRecordParser() : packet_(NULL), length_(0), cur_(0) {
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DnsRecordParser::DnsRecordParser(const void* packet,
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 size_t length,
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 size_t offset)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : packet_(reinterpret_cast<const char*>(packet)),
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      length_(length),
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cur_(packet_ + offset) {
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_LE(offset, length);
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)unsigned DnsRecordParser::ReadName(const void* const vpos,
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   std::string* out) const {
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char* const pos = reinterpret_cast<const char*>(vpos);
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(packet_);
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_LE(packet_, pos);
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_LE(pos, packet_ + length_);
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char* p = pos;
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char* end = packet_ + length_;
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Count number of seen bytes to detect loops.
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned seen = 0;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Remember how many bytes were consumed before first jump.
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned consumed = 0;
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pos >= end)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (out) {
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    out->clear();
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    out->reserve(dns_protocol::kMaxNameLength);
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (;;) {
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The first two bits of the length give the type of the length. It's
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // either a direct length or a pointer to the remainder of the name.
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (*p & dns_protocol::kLabelMask) {
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case dns_protocol::kLabelPointer: {
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (p + sizeof(uint16) > end)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return 0;
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (consumed == 0) {
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          consumed = p - pos + sizeof(uint16);
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (!out)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return consumed;  // If name is not stored, that's all we need.
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        seen += sizeof(uint16);
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // If seen the whole packet, then we must be in a loop.
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (seen > length_)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return 0;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        uint16 offset;
76a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        base::ReadBigEndian<uint16>(p, &offset);
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        offset &= dns_protocol::kOffsetMask;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        p = packet_ + offset;
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (p >= end)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return 0;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case dns_protocol::kLabelDirect: {
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        uint8 label_len = *p;
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ++p;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Note: root domain (".") is NOT included.
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (label_len == 0) {
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (consumed == 0) {
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            consumed = p - pos;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          }  // else we set |consumed| before first jump
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return consumed;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (p + label_len >= end)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return 0;  // Truncated or missing label.
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (out) {
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (!out->empty())
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            out->append(".");
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          out->append(p, label_len);
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        p += label_len;
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        seen += 1 + label_len;
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      default:
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // unhandled label type
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return 0;
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DnsRecordParser::ReadRecord(DnsResourceRecord* out) {
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(packet_);
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t consumed = ReadName(cur_, &out->name);
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!consumed)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
116a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::BigEndianReader reader(cur_ + consumed,
117a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                               packet_ + length_ - (cur_ + consumed));
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint16 rdlen;
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (reader.ReadU16(&out->type) &&
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reader.ReadU16(&out->klass) &&
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reader.ReadU32(&out->ttl) &&
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reader.ReadU16(&rdlen) &&
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reader.ReadPiece(&out->rdata, rdlen)) {
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cur_ = reader.ptr();
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool DnsRecordParser::SkipQuestion() {
131c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  size_t consumed = ReadName(cur_, NULL);
132c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!consumed)
133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return false;
134c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
135c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const char* next = cur_ + consumed + 2 * sizeof(uint16);  // QTYPE + QCLASS
136c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (next > packet_ + length_)
137c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return false;
138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
139c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  cur_ = next;
140c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
141c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return true;
142c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
143c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DnsResponse::DnsResponse()
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : io_buffer_(new IOBufferWithSize(dns_protocol::kMaxUDPSize + 1)) {
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)DnsResponse::DnsResponse(size_t length)
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : io_buffer_(new IOBufferWithSize(length)) {
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DnsResponse::DnsResponse(const void* data,
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         size_t length,
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         size_t answer_offset)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : io_buffer_(new IOBufferWithSize(length)),
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      parser_(io_buffer_->data(), length, answer_offset) {
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(data);
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memcpy(io_buffer_->data(), data, length);
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DnsResponse::~DnsResponse() {
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DnsResponse::InitParse(int nbytes, const DnsQuery& query) {
16590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK_GE(nbytes, 0);
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Response includes query, it should be at least that size.
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (nbytes < query.io_buffer()->size() || nbytes >= io_buffer_->size())
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Match the query id.
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (base::NetToHost16(header()->id) != query.id())
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Match question count.
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (base::NetToHost16(header()->qdcount) != 1)
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Match the question section.
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const size_t hdr_size = sizeof(dns_protocol::Header);
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const base::StringPiece question = query.question();
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (question != base::StringPiece(io_buffer_->data() + hdr_size,
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    question.size())) {
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Construct the parser.
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parser_ = DnsRecordParser(io_buffer_->data(),
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            nbytes,
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            hdr_size + question.size());
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
193c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool DnsResponse::InitParseWithoutQuery(int nbytes) {
19490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK_GE(nbytes, 0);
195c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
196c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  size_t hdr_size = sizeof(dns_protocol::Header);
19790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
19890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (nbytes < static_cast<int>(hdr_size) || nbytes >= io_buffer_->size())
19990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return false;
20090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
201c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  parser_ = DnsRecordParser(
202c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      io_buffer_->data(), nbytes, hdr_size);
203c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
204c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  unsigned qdcount = base::NetToHost16(header()->qdcount);
205c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for (unsigned i = 0; i < qdcount; ++i) {
206c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!parser_.SkipQuestion()) {
207c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      parser_ = DnsRecordParser();  // Make parser invalid again.
208c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return false;
209c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
210c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
211c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
212c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return true;
213c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
214c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DnsResponse::IsValid() const {
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return parser_.IsValid();
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)uint16 DnsResponse::flags() const {
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(parser_.IsValid());
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return base::NetToHost16(header()->flags) & ~(dns_protocol::kRcodeMask);
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)uint8 DnsResponse::rcode() const {
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(parser_.IsValid());
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return base::NetToHost16(header()->flags) & dns_protocol::kRcodeMask;
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)unsigned DnsResponse::answer_count() const {
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(parser_.IsValid());
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return base::NetToHost16(header()->ancount);
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2347d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)unsigned DnsResponse::additional_answer_count() const {
2357d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  DCHECK(parser_.IsValid());
2367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return base::NetToHost16(header()->arcount);
2377d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
2387d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)base::StringPiece DnsResponse::qname() const {
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(parser_.IsValid());
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The response is HEADER QNAME QTYPE QCLASS ANSWER.
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |parser_| is positioned at the beginning of ANSWER, so the end of QNAME is
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // two uint16s before it.
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const size_t hdr_size = sizeof(dns_protocol::Header);
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const size_t qname_size = parser_.GetOffset() - 2 * sizeof(uint16) - hdr_size;
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return base::StringPiece(io_buffer_->data() + hdr_size, qname_size);
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)uint16 DnsResponse::qtype() const {
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(parser_.IsValid());
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // QTYPE starts where QNAME ends.
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const size_t type_offset = parser_.GetOffset() - 2 * sizeof(uint16);
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint16 type;
254a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::ReadBigEndian<uint16>(io_buffer_->data() + type_offset, &type);
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return type;
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string DnsResponse::GetDottedName() const {
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return DNSDomainToString(qname());
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DnsRecordParser DnsResponse::Parser() const {
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(parser_.IsValid());
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Return a copy of the parser.
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return parser_;
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const dns_protocol::Header* DnsResponse::header() const {
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return reinterpret_cast<const dns_protocol::Header*>(io_buffer_->data());
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DnsResponse::Result DnsResponse::ParseToAddressList(
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AddressList* addr_list,
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::TimeDelta* ttl) const {
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(IsValid());
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // DnsTransaction already verified that |response| matches the issued query.
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We still need to determine if there is a valid chain of CNAMEs from the
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // query name to the RR owner name.
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We err on the side of caution with the assumption that if we are too picky,
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // we can always fall back to the system getaddrinfo.
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Expected owner of record. No trailing dot.
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string expected_name = GetDottedName();
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint16 expected_type = qtype();
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(expected_type == dns_protocol::kTypeA ||
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         expected_type == dns_protocol::kTypeAAAA);
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t expected_size = (expected_type == dns_protocol::kTypeAAAA)
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ? kIPv6AddressSize : kIPv4AddressSize;
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  uint32 ttl_sec = kuint32max;
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IPAddressList ip_addresses;
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DnsRecordParser parser = Parser();
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DnsResourceRecord record;
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned ancount = answer_count();
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (unsigned i = 0; i < ancount; ++i) {
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!parser.ReadRecord(&record))
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return DNS_MALFORMED_RESPONSE;
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (record.type == dns_protocol::kTypeCNAME) {
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Following the CNAME chain, only if no addresses seen.
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!ip_addresses.empty())
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return DNS_CNAME_AFTER_ADDRESS;
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (base::strcasecmp(record.name.c_str(), expected_name.c_str()) != 0)
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return DNS_NAME_MISMATCH;
3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (record.rdata.size() !=
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          parser.ReadName(record.rdata.begin(), &expected_name))
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return DNS_MALFORMED_CNAME;
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ttl_sec = std::min(ttl_sec, record.ttl);
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (record.type == expected_type) {
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (record.rdata.size() != expected_size)
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return DNS_SIZE_MISMATCH;
3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (base::strcasecmp(record.name.c_str(), expected_name.c_str()) != 0)
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return DNS_NAME_MISMATCH;
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ttl_sec = std::min(ttl_sec, record.ttl);
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ip_addresses.push_back(IPAddressNumber(record.rdata.begin(),
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             record.rdata.end()));
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(szym): Extract TTL for NODATA results. http://crbug.com/115051
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // getcanonname in eglibc returns the first owner name of an A or AAAA RR.
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the response passed all the checks so far, then |expected_name| is it.
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *addr_list = AddressList::CreateFromIPAddressList(ip_addresses,
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                    expected_name);
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  *ttl = base::TimeDelta::FromSeconds(ttl_sec);
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return DNS_PARSE_OK;
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace net
338