// Copyright (c) 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "net/dns/record_rdata.h" #include #include "base/big_endian.h" #include "net/dns/dns_protocol.h" #include "net/dns/dns_response.h" namespace net { static const size_t kSrvRecordMinimumSize = 6; RecordRdata::RecordRdata() { } SrvRecordRdata::SrvRecordRdata() : priority_(0), weight_(0), port_(0) { } SrvRecordRdata::~SrvRecordRdata() {} // static std::unique_ptr SrvRecordRdata::Create( const base::StringPiece& data, const DnsRecordParser& parser) { if (data.size() < kSrvRecordMinimumSize) return std::unique_ptr(); std::unique_ptr rdata(new SrvRecordRdata); base::BigEndianReader reader(data.data(), data.size()); // 2 bytes for priority, 2 bytes for weight, 2 bytes for port. reader.ReadU16(&rdata->priority_); reader.ReadU16(&rdata->weight_); reader.ReadU16(&rdata->port_); if (!parser.ReadName(data.substr(kSrvRecordMinimumSize).begin(), &rdata->target_)) return std::unique_ptr(); return rdata; } uint16_t SrvRecordRdata::Type() const { return SrvRecordRdata::kType; } bool SrvRecordRdata::IsEqual(const RecordRdata* other) const { if (other->Type() != Type()) return false; const SrvRecordRdata* srv_other = static_cast(other); return weight_ == srv_other->weight_ && port_ == srv_other->port_ && priority_ == srv_other->priority_ && target_ == srv_other->target_; } ARecordRdata::ARecordRdata() { } ARecordRdata::~ARecordRdata() { } // static std::unique_ptr ARecordRdata::Create( const base::StringPiece& data, const DnsRecordParser& parser) { if (data.size() != IPAddress::kIPv4AddressSize) return std::unique_ptr(); std::unique_ptr rdata(new ARecordRdata); rdata->address_ = IPAddress(reinterpret_cast(data.data()), data.length()); return rdata; } uint16_t ARecordRdata::Type() const { return ARecordRdata::kType; } bool ARecordRdata::IsEqual(const RecordRdata* other) const { if (other->Type() != Type()) return false; const ARecordRdata* a_other = static_cast(other); return address_ == a_other->address_; } AAAARecordRdata::AAAARecordRdata() { } AAAARecordRdata::~AAAARecordRdata() { } // static std::unique_ptr AAAARecordRdata::Create( const base::StringPiece& data, const DnsRecordParser& parser) { if (data.size() != IPAddress::kIPv6AddressSize) return std::unique_ptr(); std::unique_ptr rdata(new AAAARecordRdata); rdata->address_ = IPAddress(reinterpret_cast(data.data()), data.length()); return rdata; } uint16_t AAAARecordRdata::Type() const { return AAAARecordRdata::kType; } bool AAAARecordRdata::IsEqual(const RecordRdata* other) const { if (other->Type() != Type()) return false; const AAAARecordRdata* a_other = static_cast(other); return address_ == a_other->address_; } CnameRecordRdata::CnameRecordRdata() { } CnameRecordRdata::~CnameRecordRdata() { } // static std::unique_ptr CnameRecordRdata::Create( const base::StringPiece& data, const DnsRecordParser& parser) { std::unique_ptr rdata(new CnameRecordRdata); if (!parser.ReadName(data.begin(), &rdata->cname_)) return std::unique_ptr(); return rdata; } uint16_t CnameRecordRdata::Type() const { return CnameRecordRdata::kType; } bool CnameRecordRdata::IsEqual(const RecordRdata* other) const { if (other->Type() != Type()) return false; const CnameRecordRdata* cname_other = static_cast(other); return cname_ == cname_other->cname_; } PtrRecordRdata::PtrRecordRdata() { } PtrRecordRdata::~PtrRecordRdata() { } // static std::unique_ptr PtrRecordRdata::Create( const base::StringPiece& data, const DnsRecordParser& parser) { std::unique_ptr rdata(new PtrRecordRdata); if (!parser.ReadName(data.begin(), &rdata->ptrdomain_)) return std::unique_ptr(); return rdata; } uint16_t PtrRecordRdata::Type() const { return PtrRecordRdata::kType; } bool PtrRecordRdata::IsEqual(const RecordRdata* other) const { if (other->Type() != Type()) return false; const PtrRecordRdata* ptr_other = static_cast(other); return ptrdomain_ == ptr_other->ptrdomain_; } TxtRecordRdata::TxtRecordRdata() { } TxtRecordRdata::~TxtRecordRdata() { } // static std::unique_ptr TxtRecordRdata::Create( const base::StringPiece& data, const DnsRecordParser& parser) { std::unique_ptr rdata(new TxtRecordRdata); for (size_t i = 0; i < data.size(); ) { uint8_t length = data[i]; if (i + length >= data.size()) return std::unique_ptr(); rdata->texts_.push_back(data.substr(i + 1, length).as_string()); // Move to the next string. i += length + 1; } return rdata; } uint16_t TxtRecordRdata::Type() const { return TxtRecordRdata::kType; } bool TxtRecordRdata::IsEqual(const RecordRdata* other) const { if (other->Type() != Type()) return false; const TxtRecordRdata* txt_other = static_cast(other); return texts_ == txt_other->texts_; } NsecRecordRdata::NsecRecordRdata() { } NsecRecordRdata::~NsecRecordRdata() { } // static std::unique_ptr NsecRecordRdata::Create( const base::StringPiece& data, const DnsRecordParser& parser) { std::unique_ptr rdata(new NsecRecordRdata); // Read the "next domain". This part for the NSEC record format is // ignored for mDNS, since it has no semantic meaning. unsigned next_domain_length = parser.ReadName(data.data(), NULL); // If we did not succeed in getting the next domain or the data length // is too short for reading the bitmap header, return. if (next_domain_length == 0 || data.length() < next_domain_length + 2) return std::unique_ptr(); struct BitmapHeader { uint8_t block_number; // The block number should be zero. uint8_t length; // Bitmap length in bytes. Between 1 and 32. }; const BitmapHeader* header = reinterpret_cast( data.data() + next_domain_length); // The block number must be zero in mDns-specific NSEC records. The bitmap // length must be between 1 and 32. if (header->block_number != 0 || header->length == 0 || header->length > 32) return std::unique_ptr(); base::StringPiece bitmap_data = data.substr(next_domain_length + 2); // Since we may only have one block, the data length must be exactly equal to // the domain length plus bitmap size. if (bitmap_data.length() != header->length) return std::unique_ptr(); rdata->bitmap_.insert(rdata->bitmap_.begin(), bitmap_data.begin(), bitmap_data.end()); return rdata; } uint16_t NsecRecordRdata::Type() const { return NsecRecordRdata::kType; } bool NsecRecordRdata::IsEqual(const RecordRdata* other) const { if (other->Type() != Type()) return false; const NsecRecordRdata* nsec_other = static_cast(other); return bitmap_ == nsec_other->bitmap_; } bool NsecRecordRdata::GetBit(unsigned i) const { unsigned byte_num = i/8; if (bitmap_.size() < byte_num + 1) return false; unsigned bit_num = 7 - i % 8; return (bitmap_[byte_num] & (1 << bit_num)) != 0; } OptRecordRdata::OptRecordRdata() {} OptRecordRdata::~OptRecordRdata() {} // static std::unique_ptr OptRecordRdata::Create( const base::StringPiece& data, const DnsRecordParser& parser) { std::unique_ptr rdata(new OptRecordRdata); rdata->buf_.assign(data.begin(), data.end()); base::BigEndianReader reader(data.data(), data.size()); while (reader.remaining() > 0) { uint16_t opt_code, opt_data_size; base::StringPiece opt_data; if (!(reader.ReadU16(&opt_code) && reader.ReadU16(&opt_data_size) && reader.ReadPiece(&opt_data, opt_data_size))) { return std::unique_ptr(); } rdata->opts_.push_back(Opt(opt_code, opt_data)); } return rdata; } uint16_t OptRecordRdata::Type() const { return OptRecordRdata::kType; } bool OptRecordRdata::IsEqual(const RecordRdata* other) const { if (other->Type() != Type()) return false; const OptRecordRdata* opt_other = static_cast(other); return opt_other->opts_ == opts_; } void OptRecordRdata::AddOpt(const Opt& opt) { base::StringPiece opt_data = opt.data(); // Resize buffer to accommodate new OPT. const size_t orig_rdata_size = buf_.size(); buf_.resize(orig_rdata_size + Opt::kHeaderSize + opt_data.size()); // Start writing from the end of the existing rdata. base::BigEndianWriter writer(buf_.data() + orig_rdata_size, buf_.size()); bool success = writer.WriteU16(opt.code()) && writer.WriteU16(opt_data.size()) && writer.WriteBytes(opt_data.data(), opt_data.size()); DCHECK(success); opts_.push_back(opt); } OptRecordRdata::Opt::Opt(uint16_t code, base::StringPiece data) : code_(code) { data.CopyToString(&data_); } bool OptRecordRdata::Opt::operator==(const OptRecordRdata::Opt& other) const { return code_ == other.code_ && data_ == other.data_; } } // namespace net