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