• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "net/dns/record_rdata.h"
6 
7 #include <algorithm>
8 #include <numeric>
9 #include <utility>
10 
11 #include "base/big_endian.h"
12 #include "base/logging.h"
13 #include "base/memory/ptr_util.h"
14 #include "base/rand_util.h"
15 #include "base/strings/string_piece.h"
16 #include "net/base/ip_address.h"
17 #include "net/dns/dns_response.h"
18 #include "net/dns/public/dns_protocol.h"
19 
20 namespace net {
21 
22 static const size_t kSrvRecordMinimumSize = 6;
23 
24 // Minimal HTTPS rdata is 2 octets priority + 1 octet empty name.
25 static constexpr size_t kHttpsRdataMinimumSize = 3;
26 
HasValidSize(base::StringPiece data,uint16_t type)27 bool RecordRdata::HasValidSize(base::StringPiece data, uint16_t type) {
28   switch (type) {
29     case dns_protocol::kTypeSRV:
30       return data.size() >= kSrvRecordMinimumSize;
31     case dns_protocol::kTypeA:
32       return data.size() == IPAddress::kIPv4AddressSize;
33     case dns_protocol::kTypeAAAA:
34       return data.size() == IPAddress::kIPv6AddressSize;
35     case dns_protocol::kTypeHttps:
36       return data.size() >= kHttpsRdataMinimumSize;
37     case dns_protocol::kTypeCNAME:
38     case dns_protocol::kTypePTR:
39     case dns_protocol::kTypeTXT:
40     case dns_protocol::kTypeNSEC:
41     case dns_protocol::kTypeOPT:
42     case dns_protocol::kTypeSOA:
43       return true;
44     default:
45       VLOG(1) << "Unrecognized RDATA type.";
46       return true;
47   }
48 }
49 
50 SrvRecordRdata::SrvRecordRdata() = default;
51 
52 SrvRecordRdata::~SrvRecordRdata() = default;
53 
54 // static
Create(base::StringPiece data,const DnsRecordParser & parser)55 std::unique_ptr<SrvRecordRdata> SrvRecordRdata::Create(
56     base::StringPiece data,
57     const DnsRecordParser& parser) {
58   if (!HasValidSize(data, kType))
59     return nullptr;
60 
61   auto rdata = base::WrapUnique(new SrvRecordRdata());
62 
63   auto reader = base::BigEndianReader::FromStringPiece(data);
64   // 2 bytes for priority, 2 bytes for weight, 2 bytes for port.
65   reader.ReadU16(&rdata->priority_);
66   reader.ReadU16(&rdata->weight_);
67   reader.ReadU16(&rdata->port_);
68 
69   if (!parser.ReadName(data.substr(kSrvRecordMinimumSize).begin(),
70                        &rdata->target_))
71     return nullptr;
72 
73   return rdata;
74 }
75 
Type() const76 uint16_t SrvRecordRdata::Type() const {
77   return SrvRecordRdata::kType;
78 }
79 
IsEqual(const RecordRdata * other) const80 bool SrvRecordRdata::IsEqual(const RecordRdata* other) const {
81   if (other->Type() != Type()) return false;
82   const SrvRecordRdata* srv_other = static_cast<const SrvRecordRdata*>(other);
83   return weight_ == srv_other->weight_ &&
84       port_ == srv_other->port_ &&
85       priority_ == srv_other->priority_ &&
86       target_ == srv_other->target_;
87 }
88 
89 ARecordRdata::ARecordRdata() = default;
90 
91 ARecordRdata::~ARecordRdata() = default;
92 
93 // static
Create(base::StringPiece data,const DnsRecordParser & parser)94 std::unique_ptr<ARecordRdata> ARecordRdata::Create(
95     base::StringPiece data,
96     const DnsRecordParser& parser) {
97   if (!HasValidSize(data, kType))
98     return nullptr;
99 
100   auto rdata = base::WrapUnique(new ARecordRdata());
101   rdata->address_ =
102       IPAddress(reinterpret_cast<const uint8_t*>(data.data()), data.length());
103   return rdata;
104 }
105 
Type() const106 uint16_t ARecordRdata::Type() const {
107   return ARecordRdata::kType;
108 }
109 
IsEqual(const RecordRdata * other) const110 bool ARecordRdata::IsEqual(const RecordRdata* other) const {
111   if (other->Type() != Type()) return false;
112   const ARecordRdata* a_other = static_cast<const ARecordRdata*>(other);
113   return address_ == a_other->address_;
114 }
115 
116 AAAARecordRdata::AAAARecordRdata() = default;
117 
118 AAAARecordRdata::~AAAARecordRdata() = default;
119 
120 // static
Create(base::StringPiece data,const DnsRecordParser & parser)121 std::unique_ptr<AAAARecordRdata> AAAARecordRdata::Create(
122     base::StringPiece data,
123     const DnsRecordParser& parser) {
124   if (!HasValidSize(data, kType))
125     return nullptr;
126 
127   auto rdata = base::WrapUnique(new AAAARecordRdata());
128   rdata->address_ =
129       IPAddress(reinterpret_cast<const uint8_t*>(data.data()), data.length());
130   return rdata;
131 }
132 
Type() const133 uint16_t AAAARecordRdata::Type() const {
134   return AAAARecordRdata::kType;
135 }
136 
IsEqual(const RecordRdata * other) const137 bool AAAARecordRdata::IsEqual(const RecordRdata* other) const {
138   if (other->Type() != Type()) return false;
139   const AAAARecordRdata* a_other = static_cast<const AAAARecordRdata*>(other);
140   return address_ == a_other->address_;
141 }
142 
143 CnameRecordRdata::CnameRecordRdata() = default;
144 
145 CnameRecordRdata::~CnameRecordRdata() = default;
146 
147 // static
Create(base::StringPiece data,const DnsRecordParser & parser)148 std::unique_ptr<CnameRecordRdata> CnameRecordRdata::Create(
149     base::StringPiece data,
150     const DnsRecordParser& parser) {
151   auto rdata = base::WrapUnique(new CnameRecordRdata());
152 
153   if (!parser.ReadName(data.begin(), &rdata->cname_))
154     return nullptr;
155 
156   return rdata;
157 }
158 
Type() const159 uint16_t CnameRecordRdata::Type() const {
160   return CnameRecordRdata::kType;
161 }
162 
IsEqual(const RecordRdata * other) const163 bool CnameRecordRdata::IsEqual(const RecordRdata* other) const {
164   if (other->Type() != Type()) return false;
165   const CnameRecordRdata* cname_other =
166       static_cast<const CnameRecordRdata*>(other);
167   return cname_ == cname_other->cname_;
168 }
169 
170 PtrRecordRdata::PtrRecordRdata() = default;
171 
172 PtrRecordRdata::~PtrRecordRdata() = default;
173 
174 // static
Create(base::StringPiece data,const DnsRecordParser & parser)175 std::unique_ptr<PtrRecordRdata> PtrRecordRdata::Create(
176     base::StringPiece data,
177     const DnsRecordParser& parser) {
178   auto rdata = base::WrapUnique(new PtrRecordRdata());
179 
180   if (!parser.ReadName(data.begin(), &rdata->ptrdomain_))
181     return nullptr;
182 
183   return rdata;
184 }
185 
Type() const186 uint16_t PtrRecordRdata::Type() const {
187   return PtrRecordRdata::kType;
188 }
189 
IsEqual(const RecordRdata * other) const190 bool PtrRecordRdata::IsEqual(const RecordRdata* other) const {
191   if (other->Type() != Type()) return false;
192   const PtrRecordRdata* ptr_other = static_cast<const PtrRecordRdata*>(other);
193   return ptrdomain_ == ptr_other->ptrdomain_;
194 }
195 
196 TxtRecordRdata::TxtRecordRdata() = default;
197 
198 TxtRecordRdata::~TxtRecordRdata() = default;
199 
200 // static
Create(base::StringPiece data,const DnsRecordParser & parser)201 std::unique_ptr<TxtRecordRdata> TxtRecordRdata::Create(
202     base::StringPiece data,
203     const DnsRecordParser& parser) {
204   auto rdata = base::WrapUnique(new TxtRecordRdata());
205 
206   for (size_t i = 0; i < data.size(); ) {
207     uint8_t length = data[i];
208 
209     if (i + length >= data.size())
210       return nullptr;
211 
212     rdata->texts_.push_back(std::string(data.substr(i + 1, length)));
213 
214     // Move to the next string.
215     i += length + 1;
216   }
217 
218   return rdata;
219 }
220 
Type() const221 uint16_t TxtRecordRdata::Type() const {
222   return TxtRecordRdata::kType;
223 }
224 
IsEqual(const RecordRdata * other) const225 bool TxtRecordRdata::IsEqual(const RecordRdata* other) const {
226   if (other->Type() != Type()) return false;
227   const TxtRecordRdata* txt_other = static_cast<const TxtRecordRdata*>(other);
228   return texts_ == txt_other->texts_;
229 }
230 
231 NsecRecordRdata::NsecRecordRdata() = default;
232 
233 NsecRecordRdata::~NsecRecordRdata() = default;
234 
235 // static
Create(base::StringPiece data,const DnsRecordParser & parser)236 std::unique_ptr<NsecRecordRdata> NsecRecordRdata::Create(
237     base::StringPiece data,
238     const DnsRecordParser& parser) {
239   auto rdata = base::WrapUnique(new NsecRecordRdata());
240 
241   // Read the "next domain". This part for the NSEC record format is
242   // ignored for mDNS, since it has no semantic meaning.
243   unsigned next_domain_length = parser.ReadName(data.data(), nullptr);
244 
245   // If we did not succeed in getting the next domain or the data length
246   // is too short for reading the bitmap header, return.
247   if (next_domain_length == 0 || data.length() < next_domain_length + 2)
248     return nullptr;
249 
250   struct BitmapHeader {
251     uint8_t block_number;  // The block number should be zero.
252     uint8_t length;        // Bitmap length in bytes. Between 1 and 32.
253   };
254 
255   const BitmapHeader* header = reinterpret_cast<const BitmapHeader*>(
256       data.data() + next_domain_length);
257 
258   // The block number must be zero in mDns-specific NSEC records. The bitmap
259   // length must be between 1 and 32.
260   if (header->block_number != 0 || header->length == 0 || header->length > 32)
261     return nullptr;
262 
263   base::StringPiece bitmap_data = data.substr(next_domain_length + 2);
264 
265   // Since we may only have one block, the data length must be exactly equal to
266   // the domain length plus bitmap size.
267   if (bitmap_data.length() != header->length)
268     return nullptr;
269 
270   rdata->bitmap_.insert(rdata->bitmap_.begin(),
271                         bitmap_data.begin(),
272                         bitmap_data.end());
273 
274   return rdata;
275 }
276 
Type() const277 uint16_t NsecRecordRdata::Type() const {
278   return NsecRecordRdata::kType;
279 }
280 
IsEqual(const RecordRdata * other) const281 bool NsecRecordRdata::IsEqual(const RecordRdata* other) const {
282   if (other->Type() != Type())
283     return false;
284   const NsecRecordRdata* nsec_other =
285       static_cast<const NsecRecordRdata*>(other);
286   return bitmap_ == nsec_other->bitmap_;
287 }
288 
GetBit(unsigned i) const289 bool NsecRecordRdata::GetBit(unsigned i) const {
290   unsigned byte_num = i/8;
291   if (bitmap_.size() < byte_num + 1)
292     return false;
293 
294   unsigned bit_num = 7 - i % 8;
295   return (bitmap_[byte_num] & (1 << bit_num)) != 0;
296 }
297 
298 }  // namespace net
299