xref: /aosp_15_r20/external/cronet/net/dns/record_rdata.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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 <string_view>
10 #include <utility>
11 
12 #include "base/containers/span.h"
13 #include "base/containers/span_reader.h"
14 #include "base/logging.h"
15 #include "base/memory/ptr_util.h"
16 #include "base/rand_util.h"
17 #include "net/base/ip_address.h"
18 #include "net/dns/dns_response.h"
19 #include "net/dns/public/dns_protocol.h"
20 
21 namespace net {
22 
23 static const size_t kSrvRecordMinimumSize = 6;
24 
25 // Minimal HTTPS rdata is 2 octets priority + 1 octet empty name.
26 static constexpr size_t kHttpsRdataMinimumSize = 3;
27 
HasValidSize(std::string_view data,uint16_t type)28 bool RecordRdata::HasValidSize(std::string_view data, uint16_t type) {
29   switch (type) {
30     case dns_protocol::kTypeSRV:
31       return data.size() >= kSrvRecordMinimumSize;
32     case dns_protocol::kTypeA:
33       return data.size() == IPAddress::kIPv4AddressSize;
34     case dns_protocol::kTypeAAAA:
35       return data.size() == IPAddress::kIPv6AddressSize;
36     case dns_protocol::kTypeHttps:
37       return data.size() >= kHttpsRdataMinimumSize;
38     case dns_protocol::kTypeCNAME:
39     case dns_protocol::kTypePTR:
40     case dns_protocol::kTypeTXT:
41     case dns_protocol::kTypeNSEC:
42     case dns_protocol::kTypeOPT:
43     case dns_protocol::kTypeSOA:
44       return true;
45     default:
46       VLOG(1) << "Unrecognized RDATA type.";
47       return true;
48   }
49 }
50 
51 SrvRecordRdata::SrvRecordRdata() = default;
52 
53 SrvRecordRdata::~SrvRecordRdata() = default;
54 
55 // static
Create(std::string_view data,const DnsRecordParser & parser)56 std::unique_ptr<SrvRecordRdata> SrvRecordRdata::Create(
57     std::string_view data,
58     const DnsRecordParser& parser) {
59   if (!HasValidSize(data, kType))
60     return nullptr;
61 
62   auto rdata = base::WrapUnique(new SrvRecordRdata());
63 
64   auto reader = base::SpanReader(base::as_byte_span(data));
65   // 2 bytes for priority, 2 bytes for weight, 2 bytes for port.
66   reader.ReadU16BigEndian(rdata->priority_);
67   reader.ReadU16BigEndian(rdata->weight_);
68   reader.ReadU16BigEndian(rdata->port_);
69 
70   if (!parser.ReadName(data.substr(kSrvRecordMinimumSize).data(),
71                        &rdata->target_)) {
72     return nullptr;
73   }
74 
75   return rdata;
76 }
77 
Type() const78 uint16_t SrvRecordRdata::Type() const {
79   return SrvRecordRdata::kType;
80 }
81 
IsEqual(const RecordRdata * other) const82 bool SrvRecordRdata::IsEqual(const RecordRdata* other) const {
83   if (other->Type() != Type()) return false;
84   const SrvRecordRdata* srv_other = static_cast<const SrvRecordRdata*>(other);
85   return weight_ == srv_other->weight_ &&
86       port_ == srv_other->port_ &&
87       priority_ == srv_other->priority_ &&
88       target_ == srv_other->target_;
89 }
90 
91 ARecordRdata::ARecordRdata() = default;
92 
93 ARecordRdata::~ARecordRdata() = default;
94 
95 // static
Create(std::string_view data,const DnsRecordParser & parser)96 std::unique_ptr<ARecordRdata> ARecordRdata::Create(
97     std::string_view data,
98     const DnsRecordParser& parser) {
99   if (!HasValidSize(data, kType))
100     return nullptr;
101 
102   auto rdata = base::WrapUnique(new ARecordRdata());
103   rdata->address_ = IPAddress(base::as_byte_span(data));
104   return rdata;
105 }
106 
Type() const107 uint16_t ARecordRdata::Type() const {
108   return ARecordRdata::kType;
109 }
110 
IsEqual(const RecordRdata * other) const111 bool ARecordRdata::IsEqual(const RecordRdata* other) const {
112   if (other->Type() != Type()) return false;
113   const ARecordRdata* a_other = static_cast<const ARecordRdata*>(other);
114   return address_ == a_other->address_;
115 }
116 
117 AAAARecordRdata::AAAARecordRdata() = default;
118 
119 AAAARecordRdata::~AAAARecordRdata() = default;
120 
121 // static
Create(std::string_view data,const DnsRecordParser & parser)122 std::unique_ptr<AAAARecordRdata> AAAARecordRdata::Create(
123     std::string_view data,
124     const DnsRecordParser& parser) {
125   if (!HasValidSize(data, kType))
126     return nullptr;
127 
128   auto rdata = base::WrapUnique(new AAAARecordRdata());
129   rdata->address_ = IPAddress(base::as_byte_span(data));
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(std::string_view data,const DnsRecordParser & parser)148 std::unique_ptr<CnameRecordRdata> CnameRecordRdata::Create(
149     std::string_view data,
150     const DnsRecordParser& parser) {
151   auto rdata = base::WrapUnique(new CnameRecordRdata());
152 
153   if (!parser.ReadName(data.data(), &rdata->cname_)) {
154     return nullptr;
155   }
156 
157   return rdata;
158 }
159 
Type() const160 uint16_t CnameRecordRdata::Type() const {
161   return CnameRecordRdata::kType;
162 }
163 
IsEqual(const RecordRdata * other) const164 bool CnameRecordRdata::IsEqual(const RecordRdata* other) const {
165   if (other->Type() != Type()) return false;
166   const CnameRecordRdata* cname_other =
167       static_cast<const CnameRecordRdata*>(other);
168   return cname_ == cname_other->cname_;
169 }
170 
171 PtrRecordRdata::PtrRecordRdata() = default;
172 
173 PtrRecordRdata::~PtrRecordRdata() = default;
174 
175 // static
Create(std::string_view data,const DnsRecordParser & parser)176 std::unique_ptr<PtrRecordRdata> PtrRecordRdata::Create(
177     std::string_view data,
178     const DnsRecordParser& parser) {
179   auto rdata = base::WrapUnique(new PtrRecordRdata());
180 
181   if (!parser.ReadName(data.data(), &rdata->ptrdomain_)) {
182     return nullptr;
183   }
184 
185   return rdata;
186 }
187 
Type() const188 uint16_t PtrRecordRdata::Type() const {
189   return PtrRecordRdata::kType;
190 }
191 
IsEqual(const RecordRdata * other) const192 bool PtrRecordRdata::IsEqual(const RecordRdata* other) const {
193   if (other->Type() != Type()) return false;
194   const PtrRecordRdata* ptr_other = static_cast<const PtrRecordRdata*>(other);
195   return ptrdomain_ == ptr_other->ptrdomain_;
196 }
197 
198 TxtRecordRdata::TxtRecordRdata() = default;
199 
200 TxtRecordRdata::~TxtRecordRdata() = default;
201 
202 // static
Create(std::string_view data,const DnsRecordParser & parser)203 std::unique_ptr<TxtRecordRdata> TxtRecordRdata::Create(
204     std::string_view data,
205     const DnsRecordParser& parser) {
206   auto rdata = base::WrapUnique(new TxtRecordRdata());
207 
208   for (size_t i = 0; i < data.size(); ) {
209     uint8_t length = data[i];
210 
211     if (i + length >= data.size())
212       return nullptr;
213 
214     rdata->texts_.push_back(std::string(data.substr(i + 1, length)));
215 
216     // Move to the next string.
217     i += length + 1;
218   }
219 
220   return rdata;
221 }
222 
Type() const223 uint16_t TxtRecordRdata::Type() const {
224   return TxtRecordRdata::kType;
225 }
226 
IsEqual(const RecordRdata * other) const227 bool TxtRecordRdata::IsEqual(const RecordRdata* other) const {
228   if (other->Type() != Type()) return false;
229   const TxtRecordRdata* txt_other = static_cast<const TxtRecordRdata*>(other);
230   return texts_ == txt_other->texts_;
231 }
232 
233 NsecRecordRdata::NsecRecordRdata() = default;
234 
235 NsecRecordRdata::~NsecRecordRdata() = default;
236 
237 // static
Create(std::string_view data,const DnsRecordParser & parser)238 std::unique_ptr<NsecRecordRdata> NsecRecordRdata::Create(
239     std::string_view data,
240     const DnsRecordParser& parser) {
241   auto rdata = base::WrapUnique(new NsecRecordRdata());
242 
243   // Read the "next domain". This part for the NSEC record format is
244   // ignored for mDNS, since it has no semantic meaning.
245   unsigned next_domain_length = parser.ReadName(data.data(), nullptr);
246 
247   // If we did not succeed in getting the next domain or the data length
248   // is too short for reading the bitmap header, return.
249   if (next_domain_length == 0 || data.length() < next_domain_length + 2)
250     return nullptr;
251 
252   struct BitmapHeader {
253     uint8_t block_number;  // The block number should be zero.
254     uint8_t length;        // Bitmap length in bytes. Between 1 and 32.
255   };
256 
257   const BitmapHeader* header = reinterpret_cast<const BitmapHeader*>(
258       data.data() + next_domain_length);
259 
260   // The block number must be zero in mDns-specific NSEC records. The bitmap
261   // length must be between 1 and 32.
262   if (header->block_number != 0 || header->length == 0 || header->length > 32)
263     return nullptr;
264 
265   std::string_view bitmap_data = data.substr(next_domain_length + 2);
266 
267   // Since we may only have one block, the data length must be exactly equal to
268   // the domain length plus bitmap size.
269   if (bitmap_data.length() != header->length)
270     return nullptr;
271 
272   rdata->bitmap_.insert(rdata->bitmap_.begin(),
273                         bitmap_data.begin(),
274                         bitmap_data.end());
275 
276   return rdata;
277 }
278 
Type() const279 uint16_t NsecRecordRdata::Type() const {
280   return NsecRecordRdata::kType;
281 }
282 
IsEqual(const RecordRdata * other) const283 bool NsecRecordRdata::IsEqual(const RecordRdata* other) const {
284   if (other->Type() != Type())
285     return false;
286   const NsecRecordRdata* nsec_other =
287       static_cast<const NsecRecordRdata*>(other);
288   return bitmap_ == nsec_other->bitmap_;
289 }
290 
GetBit(unsigned i) const291 bool NsecRecordRdata::GetBit(unsigned i) const {
292   unsigned byte_num = i/8;
293   if (bitmap_.size() < byte_num + 1)
294     return false;
295 
296   unsigned bit_num = 7 - i % 8;
297   return (bitmap_[byte_num] & (1 << bit_num)) != 0;
298 }
299 
300 }  // namespace net
301