1// Copyright (c) 2013 The Chromium Authors. All rights reserved.
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 "base/big_endian.h"
8#include "net/base/dns_util.h"
9#include "net/dns/dns_protocol.h"
10#include "net/dns/dns_response.h"
11
12namespace net {
13
14static const size_t kSrvRecordMinimumSize = 6;
15
16RecordRdata::RecordRdata() {
17}
18
19SrvRecordRdata::SrvRecordRdata() : priority_(0), weight_(0), port_(0) {
20}
21
22SrvRecordRdata::~SrvRecordRdata() {}
23
24// static
25scoped_ptr<SrvRecordRdata> SrvRecordRdata::Create(
26    const base::StringPiece& data,
27    const DnsRecordParser& parser) {
28  if (data.size() < kSrvRecordMinimumSize) return scoped_ptr<SrvRecordRdata>();
29
30  scoped_ptr<SrvRecordRdata> rdata(new SrvRecordRdata);
31
32  base::BigEndianReader reader(data.data(), data.size());
33  // 2 bytes for priority, 2 bytes for weight, 2 bytes for port.
34  reader.ReadU16(&rdata->priority_);
35  reader.ReadU16(&rdata->weight_);
36  reader.ReadU16(&rdata->port_);
37
38  if (!parser.ReadName(data.substr(kSrvRecordMinimumSize).begin(),
39                       &rdata->target_))
40    return scoped_ptr<SrvRecordRdata>();
41
42  return rdata.Pass();
43}
44
45uint16 SrvRecordRdata::Type() const {
46  return SrvRecordRdata::kType;
47}
48
49bool SrvRecordRdata::IsEqual(const RecordRdata* other) const {
50  if (other->Type() != Type()) return false;
51  const SrvRecordRdata* srv_other = static_cast<const SrvRecordRdata*>(other);
52  return weight_ == srv_other->weight_ &&
53      port_ == srv_other->port_ &&
54      priority_ == srv_other->priority_ &&
55      target_ == srv_other->target_;
56}
57
58ARecordRdata::ARecordRdata() {
59}
60
61ARecordRdata::~ARecordRdata() {
62}
63
64// static
65scoped_ptr<ARecordRdata> ARecordRdata::Create(
66    const base::StringPiece& data,
67    const DnsRecordParser& parser) {
68  if (data.size() != kIPv4AddressSize)
69    return scoped_ptr<ARecordRdata>();
70
71  scoped_ptr<ARecordRdata> rdata(new ARecordRdata);
72
73  rdata->address_.resize(kIPv4AddressSize);
74  for (unsigned i = 0; i < kIPv4AddressSize; ++i) {
75    rdata->address_[i] = data[i];
76  }
77
78  return rdata.Pass();
79}
80
81uint16 ARecordRdata::Type() const {
82  return ARecordRdata::kType;
83}
84
85bool ARecordRdata::IsEqual(const RecordRdata* other) const {
86  if (other->Type() != Type()) return false;
87  const ARecordRdata* a_other = static_cast<const ARecordRdata*>(other);
88  return address_ == a_other->address_;
89}
90
91AAAARecordRdata::AAAARecordRdata() {
92}
93
94AAAARecordRdata::~AAAARecordRdata() {
95}
96
97// static
98scoped_ptr<AAAARecordRdata> AAAARecordRdata::Create(
99    const base::StringPiece& data,
100    const DnsRecordParser& parser) {
101  if (data.size() != kIPv6AddressSize)
102    return scoped_ptr<AAAARecordRdata>();
103
104  scoped_ptr<AAAARecordRdata> rdata(new AAAARecordRdata);
105
106  rdata->address_.resize(kIPv6AddressSize);
107  for (unsigned i = 0; i < kIPv6AddressSize; ++i) {
108    rdata->address_[i] = data[i];
109  }
110
111  return rdata.Pass();
112}
113
114uint16 AAAARecordRdata::Type() const {
115  return AAAARecordRdata::kType;
116}
117
118bool AAAARecordRdata::IsEqual(const RecordRdata* other) const {
119  if (other->Type() != Type()) return false;
120  const AAAARecordRdata* a_other = static_cast<const AAAARecordRdata*>(other);
121  return address_ == a_other->address_;
122}
123
124CnameRecordRdata::CnameRecordRdata() {
125}
126
127CnameRecordRdata::~CnameRecordRdata() {
128}
129
130// static
131scoped_ptr<CnameRecordRdata> CnameRecordRdata::Create(
132    const base::StringPiece& data,
133    const DnsRecordParser& parser) {
134  scoped_ptr<CnameRecordRdata> rdata(new CnameRecordRdata);
135
136  if (!parser.ReadName(data.begin(), &rdata->cname_))
137    return scoped_ptr<CnameRecordRdata>();
138
139  return rdata.Pass();
140}
141
142uint16 CnameRecordRdata::Type() const {
143  return CnameRecordRdata::kType;
144}
145
146bool CnameRecordRdata::IsEqual(const RecordRdata* other) const {
147  if (other->Type() != Type()) return false;
148  const CnameRecordRdata* cname_other =
149      static_cast<const CnameRecordRdata*>(other);
150  return cname_ == cname_other->cname_;
151}
152
153PtrRecordRdata::PtrRecordRdata() {
154}
155
156PtrRecordRdata::~PtrRecordRdata() {
157}
158
159// static
160scoped_ptr<PtrRecordRdata> PtrRecordRdata::Create(
161    const base::StringPiece& data,
162    const DnsRecordParser& parser) {
163  scoped_ptr<PtrRecordRdata> rdata(new PtrRecordRdata);
164
165  if (!parser.ReadName(data.begin(), &rdata->ptrdomain_))
166    return scoped_ptr<PtrRecordRdata>();
167
168  return rdata.Pass();
169}
170
171uint16 PtrRecordRdata::Type() const {
172  return PtrRecordRdata::kType;
173}
174
175bool PtrRecordRdata::IsEqual(const RecordRdata* other) const {
176  if (other->Type() != Type()) return false;
177  const PtrRecordRdata* ptr_other = static_cast<const PtrRecordRdata*>(other);
178  return ptrdomain_ == ptr_other->ptrdomain_;
179}
180
181TxtRecordRdata::TxtRecordRdata() {
182}
183
184TxtRecordRdata::~TxtRecordRdata() {
185}
186
187// static
188scoped_ptr<TxtRecordRdata> TxtRecordRdata::Create(
189    const base::StringPiece& data,
190    const DnsRecordParser& parser) {
191  scoped_ptr<TxtRecordRdata> rdata(new TxtRecordRdata);
192
193  for (size_t i = 0; i < data.size(); ) {
194    uint8 length = data[i];
195
196    if (i + length >= data.size())
197      return scoped_ptr<TxtRecordRdata>();
198
199    rdata->texts_.push_back(data.substr(i + 1, length).as_string());
200
201    // Move to the next string.
202    i += length + 1;
203  }
204
205  return rdata.Pass();
206}
207
208uint16 TxtRecordRdata::Type() const {
209  return TxtRecordRdata::kType;
210}
211
212bool TxtRecordRdata::IsEqual(const RecordRdata* other) const {
213  if (other->Type() != Type()) return false;
214  const TxtRecordRdata* txt_other = static_cast<const TxtRecordRdata*>(other);
215  return texts_ == txt_other->texts_;
216}
217
218NsecRecordRdata::NsecRecordRdata() {
219}
220
221NsecRecordRdata::~NsecRecordRdata() {
222}
223
224// static
225scoped_ptr<NsecRecordRdata> NsecRecordRdata::Create(
226    const base::StringPiece& data,
227    const DnsRecordParser& parser) {
228  scoped_ptr<NsecRecordRdata> rdata(new NsecRecordRdata);
229
230  // Read the "next domain". This part for the NSEC record format is
231  // ignored for mDNS, since it has no semantic meaning.
232  unsigned next_domain_length = parser.ReadName(data.data(), NULL);
233
234  // If we did not succeed in getting the next domain or the data length
235  // is too short for reading the bitmap header, return.
236  if (next_domain_length == 0 || data.length() < next_domain_length + 2)
237    return scoped_ptr<NsecRecordRdata>();
238
239  struct BitmapHeader {
240    uint8 block_number;  // The block number should be zero.
241    uint8 length;  // Bitmap length in bytes. Between 1 and 32.
242  };
243
244  const BitmapHeader* header = reinterpret_cast<const BitmapHeader*>(
245      data.data() + next_domain_length);
246
247  // The block number must be zero in mDns-specific NSEC records. The bitmap
248  // length must be between 1 and 32.
249  if (header->block_number != 0 || header->length == 0 || header->length > 32)
250    return scoped_ptr<NsecRecordRdata>();
251
252  base::StringPiece bitmap_data = data.substr(next_domain_length + 2);
253
254  // Since we may only have one block, the data length must be exactly equal to
255  // the domain length plus bitmap size.
256  if (bitmap_data.length() != header->length)
257    return scoped_ptr<NsecRecordRdata>();
258
259  rdata->bitmap_.insert(rdata->bitmap_.begin(),
260                        bitmap_data.begin(),
261                        bitmap_data.end());
262
263  return rdata.Pass();
264}
265
266uint16 NsecRecordRdata::Type() const {
267  return NsecRecordRdata::kType;
268}
269
270bool NsecRecordRdata::IsEqual(const RecordRdata* other) const {
271  if (other->Type() != Type())
272    return false;
273  const NsecRecordRdata* nsec_other =
274      static_cast<const NsecRecordRdata*>(other);
275  return bitmap_ == nsec_other->bitmap_;
276}
277
278bool NsecRecordRdata::GetBit(unsigned i) const {
279  unsigned byte_num = i/8;
280  if (bitmap_.size() < byte_num + 1)
281    return false;
282
283  unsigned bit_num = 7 - i % 8;
284  return (bitmap_[byte_num] & (1 << bit_num)) != 0;
285}
286
287}  // namespace net
288