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