xref: /aosp_15_r20/external/openscreen/discovery/mdns/mdns_reader.cc (revision 3f982cf4871df8771c9d4abe6e9a6f8d829b2736)
1*3f982cf4SFabien Sanglard // Copyright 2019 The Chromium Authors. All rights reserved.
2*3f982cf4SFabien Sanglard // Use of this source code is governed by a BSD-style license that can be
3*3f982cf4SFabien Sanglard // found in the LICENSE file.
4*3f982cf4SFabien Sanglard 
5*3f982cf4SFabien Sanglard #include "discovery/mdns/mdns_reader.h"
6*3f982cf4SFabien Sanglard 
7*3f982cf4SFabien Sanglard #include <algorithm>
8*3f982cf4SFabien Sanglard #include <utility>
9*3f982cf4SFabien Sanglard 
10*3f982cf4SFabien Sanglard #include "discovery/common/config.h"
11*3f982cf4SFabien Sanglard #include "discovery/mdns/public/mdns_constants.h"
12*3f982cf4SFabien Sanglard #include "util/osp_logging.h"
13*3f982cf4SFabien Sanglard 
14*3f982cf4SFabien Sanglard namespace openscreen {
15*3f982cf4SFabien Sanglard namespace discovery {
16*3f982cf4SFabien Sanglard namespace {
17*3f982cf4SFabien Sanglard 
TryParseDnsType(uint16_t to_parse,DnsType * type)18*3f982cf4SFabien Sanglard bool TryParseDnsType(uint16_t to_parse, DnsType* type) {
19*3f982cf4SFabien Sanglard   auto it = std::find(kSupportedDnsTypes.begin(), kSupportedDnsTypes.end(),
20*3f982cf4SFabien Sanglard                       static_cast<DnsType>(to_parse));
21*3f982cf4SFabien Sanglard   if (it == kSupportedDnsTypes.end()) {
22*3f982cf4SFabien Sanglard     return false;
23*3f982cf4SFabien Sanglard   }
24*3f982cf4SFabien Sanglard 
25*3f982cf4SFabien Sanglard   *type = *it;
26*3f982cf4SFabien Sanglard   return true;
27*3f982cf4SFabien Sanglard }
28*3f982cf4SFabien Sanglard 
29*3f982cf4SFabien Sanglard }  // namespace
30*3f982cf4SFabien Sanglard 
MdnsReader(const Config & config,const uint8_t * buffer,size_t length)31*3f982cf4SFabien Sanglard MdnsReader::MdnsReader(const Config& config,
32*3f982cf4SFabien Sanglard                        const uint8_t* buffer,
33*3f982cf4SFabien Sanglard                        size_t length)
34*3f982cf4SFabien Sanglard     : BigEndianReader(buffer, length),
35*3f982cf4SFabien Sanglard       kMaximumAllowedRdataSize(
36*3f982cf4SFabien Sanglard           static_cast<size_t>(config.maximum_valid_rdata_size)) {
37*3f982cf4SFabien Sanglard   // TODO(rwkeane): Validate |maximum_valid_rdata_size| > MaxWireSize() for
38*3f982cf4SFabien Sanglard   // rdata types A, AAAA, SRV, PTR.
39*3f982cf4SFabien Sanglard   OSP_DCHECK_GT(config.maximum_valid_rdata_size, 0);
40*3f982cf4SFabien Sanglard }
41*3f982cf4SFabien Sanglard 
Read(TxtRecordRdata::Entry * out)42*3f982cf4SFabien Sanglard bool MdnsReader::Read(TxtRecordRdata::Entry* out) {
43*3f982cf4SFabien Sanglard   Cursor cursor(this);
44*3f982cf4SFabien Sanglard   uint8_t entry_length;
45*3f982cf4SFabien Sanglard   if (!Read(&entry_length)) {
46*3f982cf4SFabien Sanglard     return false;
47*3f982cf4SFabien Sanglard   }
48*3f982cf4SFabien Sanglard   const uint8_t* entry_begin = current();
49*3f982cf4SFabien Sanglard   if (!Skip(entry_length)) {
50*3f982cf4SFabien Sanglard     return false;
51*3f982cf4SFabien Sanglard   }
52*3f982cf4SFabien Sanglard   out->reserve(entry_length);
53*3f982cf4SFabien Sanglard   out->insert(out->end(), entry_begin, entry_begin + entry_length);
54*3f982cf4SFabien Sanglard   cursor.Commit();
55*3f982cf4SFabien Sanglard   return true;
56*3f982cf4SFabien Sanglard }
57*3f982cf4SFabien Sanglard 
58*3f982cf4SFabien Sanglard // RFC 1035: https://www.ietf.org/rfc/rfc1035.txt
59*3f982cf4SFabien Sanglard // See section 4.1.4. Message compression.
Read(DomainName * out)60*3f982cf4SFabien Sanglard bool MdnsReader::Read(DomainName* out) {
61*3f982cf4SFabien Sanglard   OSP_DCHECK(out);
62*3f982cf4SFabien Sanglard   const uint8_t* position = current();
63*3f982cf4SFabien Sanglard   // The number of bytes consumed reading from the starting position to either
64*3f982cf4SFabien Sanglard   // the first label pointer or the final termination byte, including the
65*3f982cf4SFabien Sanglard   // pointer or the termination byte. This is equal to the actual wire size of
66*3f982cf4SFabien Sanglard   // the DomainName accounting for compression.
67*3f982cf4SFabien Sanglard   size_t bytes_consumed = 0;
68*3f982cf4SFabien Sanglard   // The number of bytes that was processed when reading the DomainName,
69*3f982cf4SFabien Sanglard   // including all label pointers and direct labels. It is used to detect
70*3f982cf4SFabien Sanglard   // circular compression. The number of processed bytes cannot be possibly
71*3f982cf4SFabien Sanglard   // greater than the length of the buffer.
72*3f982cf4SFabien Sanglard   size_t bytes_processed = 0;
73*3f982cf4SFabien Sanglard   size_t domain_name_length = 0;
74*3f982cf4SFabien Sanglard   std::vector<absl::string_view> labels;
75*3f982cf4SFabien Sanglard   // If we are pointing before the beginning or past the end of the buffer, we
76*3f982cf4SFabien Sanglard   // hit a malformed pointer. If we have processed more bytes than there are in
77*3f982cf4SFabien Sanglard   // the buffer, we are in a circular compression loop.
78*3f982cf4SFabien Sanglard   while (position >= begin() && position < end() &&
79*3f982cf4SFabien Sanglard          bytes_processed <= length()) {
80*3f982cf4SFabien Sanglard     const uint8_t label_type = ReadBigEndian<uint8_t>(position);
81*3f982cf4SFabien Sanglard     if (IsTerminationLabel(label_type)) {
82*3f982cf4SFabien Sanglard       ErrorOr<DomainName> domain =
83*3f982cf4SFabien Sanglard           DomainName::TryCreate(labels.begin(), labels.end());
84*3f982cf4SFabien Sanglard       if (domain.is_error()) {
85*3f982cf4SFabien Sanglard         return false;
86*3f982cf4SFabien Sanglard       }
87*3f982cf4SFabien Sanglard       *out = std::move(domain.value());
88*3f982cf4SFabien Sanglard       if (!bytes_consumed) {
89*3f982cf4SFabien Sanglard         bytes_consumed = position + sizeof(uint8_t) - current();
90*3f982cf4SFabien Sanglard       }
91*3f982cf4SFabien Sanglard       return Skip(bytes_consumed);
92*3f982cf4SFabien Sanglard     } else if (IsPointerLabel(label_type)) {
93*3f982cf4SFabien Sanglard       if (position + sizeof(uint16_t) > end()) {
94*3f982cf4SFabien Sanglard         return false;
95*3f982cf4SFabien Sanglard       }
96*3f982cf4SFabien Sanglard       const uint16_t label_offset =
97*3f982cf4SFabien Sanglard           GetPointerLabelOffset(ReadBigEndian<uint16_t>(position));
98*3f982cf4SFabien Sanglard       if (!bytes_consumed) {
99*3f982cf4SFabien Sanglard         bytes_consumed = position + sizeof(uint16_t) - current();
100*3f982cf4SFabien Sanglard       }
101*3f982cf4SFabien Sanglard       bytes_processed += sizeof(uint16_t);
102*3f982cf4SFabien Sanglard       position = begin() + label_offset;
103*3f982cf4SFabien Sanglard     } else if (IsDirectLabel(label_type)) {
104*3f982cf4SFabien Sanglard       const uint8_t label_length = GetDirectLabelLength(label_type);
105*3f982cf4SFabien Sanglard       OSP_DCHECK_GT(label_length, 0);
106*3f982cf4SFabien Sanglard       bytes_processed += sizeof(uint8_t);
107*3f982cf4SFabien Sanglard       position += sizeof(uint8_t);
108*3f982cf4SFabien Sanglard       if (position + label_length >= end()) {
109*3f982cf4SFabien Sanglard         return false;
110*3f982cf4SFabien Sanglard       }
111*3f982cf4SFabien Sanglard       const absl::string_view label(reinterpret_cast<const char*>(position),
112*3f982cf4SFabien Sanglard                                     label_length);
113*3f982cf4SFabien Sanglard       domain_name_length += label_length + 1;  // including the length byte
114*3f982cf4SFabien Sanglard       if (!IsValidDomainLabel(label) ||
115*3f982cf4SFabien Sanglard           domain_name_length > kMaxDomainNameLength) {
116*3f982cf4SFabien Sanglard         return false;
117*3f982cf4SFabien Sanglard       }
118*3f982cf4SFabien Sanglard       labels.push_back(label);
119*3f982cf4SFabien Sanglard       bytes_processed += label_length;
120*3f982cf4SFabien Sanglard       position += label_length;
121*3f982cf4SFabien Sanglard     } else {
122*3f982cf4SFabien Sanglard       return false;
123*3f982cf4SFabien Sanglard     }
124*3f982cf4SFabien Sanglard   }
125*3f982cf4SFabien Sanglard   return false;
126*3f982cf4SFabien Sanglard }
127*3f982cf4SFabien Sanglard 
Read(RawRecordRdata * out)128*3f982cf4SFabien Sanglard bool MdnsReader::Read(RawRecordRdata* out) {
129*3f982cf4SFabien Sanglard   OSP_DCHECK(out);
130*3f982cf4SFabien Sanglard   Cursor cursor(this);
131*3f982cf4SFabien Sanglard   uint16_t record_length;
132*3f982cf4SFabien Sanglard   if (Read(&record_length)) {
133*3f982cf4SFabien Sanglard     if (record_length > kMaximumAllowedRdataSize) {
134*3f982cf4SFabien Sanglard       return false;
135*3f982cf4SFabien Sanglard     }
136*3f982cf4SFabien Sanglard 
137*3f982cf4SFabien Sanglard     std::vector<uint8_t> buffer(record_length);
138*3f982cf4SFabien Sanglard     if (Read(buffer.size(), buffer.data())) {
139*3f982cf4SFabien Sanglard       ErrorOr<RawRecordRdata> rdata =
140*3f982cf4SFabien Sanglard           RawRecordRdata::TryCreate(std::move(buffer));
141*3f982cf4SFabien Sanglard       if (rdata.is_error()) {
142*3f982cf4SFabien Sanglard         return false;
143*3f982cf4SFabien Sanglard       }
144*3f982cf4SFabien Sanglard       *out = std::move(rdata.value());
145*3f982cf4SFabien Sanglard       cursor.Commit();
146*3f982cf4SFabien Sanglard       return true;
147*3f982cf4SFabien Sanglard     }
148*3f982cf4SFabien Sanglard   }
149*3f982cf4SFabien Sanglard   return false;
150*3f982cf4SFabien Sanglard }
151*3f982cf4SFabien Sanglard 
Read(SrvRecordRdata * out)152*3f982cf4SFabien Sanglard bool MdnsReader::Read(SrvRecordRdata* out) {
153*3f982cf4SFabien Sanglard   OSP_DCHECK(out);
154*3f982cf4SFabien Sanglard   Cursor cursor(this);
155*3f982cf4SFabien Sanglard   uint16_t record_length;
156*3f982cf4SFabien Sanglard   uint16_t priority;
157*3f982cf4SFabien Sanglard   uint16_t weight;
158*3f982cf4SFabien Sanglard   uint16_t port;
159*3f982cf4SFabien Sanglard   DomainName target;
160*3f982cf4SFabien Sanglard   if (Read(&record_length) && Read(&priority) && Read(&weight) && Read(&port) &&
161*3f982cf4SFabien Sanglard       Read(&target) &&
162*3f982cf4SFabien Sanglard       (cursor.delta() == sizeof(record_length) + record_length)) {
163*3f982cf4SFabien Sanglard     *out = SrvRecordRdata(priority, weight, port, std::move(target));
164*3f982cf4SFabien Sanglard     cursor.Commit();
165*3f982cf4SFabien Sanglard     return true;
166*3f982cf4SFabien Sanglard   }
167*3f982cf4SFabien Sanglard   return false;
168*3f982cf4SFabien Sanglard }
169*3f982cf4SFabien Sanglard 
Read(ARecordRdata * out)170*3f982cf4SFabien Sanglard bool MdnsReader::Read(ARecordRdata* out) {
171*3f982cf4SFabien Sanglard   OSP_DCHECK(out);
172*3f982cf4SFabien Sanglard   Cursor cursor(this);
173*3f982cf4SFabien Sanglard   uint16_t record_length;
174*3f982cf4SFabien Sanglard   IPAddress address;
175*3f982cf4SFabien Sanglard   if (Read(&record_length) && (record_length == IPAddress::kV4Size) &&
176*3f982cf4SFabien Sanglard       Read(IPAddress::Version::kV4, &address)) {
177*3f982cf4SFabien Sanglard     *out = ARecordRdata(address);
178*3f982cf4SFabien Sanglard     cursor.Commit();
179*3f982cf4SFabien Sanglard     return true;
180*3f982cf4SFabien Sanglard   }
181*3f982cf4SFabien Sanglard   return false;
182*3f982cf4SFabien Sanglard }
183*3f982cf4SFabien Sanglard 
Read(AAAARecordRdata * out)184*3f982cf4SFabien Sanglard bool MdnsReader::Read(AAAARecordRdata* out) {
185*3f982cf4SFabien Sanglard   OSP_DCHECK(out);
186*3f982cf4SFabien Sanglard   Cursor cursor(this);
187*3f982cf4SFabien Sanglard   uint16_t record_length;
188*3f982cf4SFabien Sanglard   IPAddress address;
189*3f982cf4SFabien Sanglard   if (Read(&record_length) && (record_length == IPAddress::kV6Size) &&
190*3f982cf4SFabien Sanglard       Read(IPAddress::Version::kV6, &address)) {
191*3f982cf4SFabien Sanglard     *out = AAAARecordRdata(address);
192*3f982cf4SFabien Sanglard     cursor.Commit();
193*3f982cf4SFabien Sanglard     return true;
194*3f982cf4SFabien Sanglard   }
195*3f982cf4SFabien Sanglard   return false;
196*3f982cf4SFabien Sanglard }
197*3f982cf4SFabien Sanglard 
Read(PtrRecordRdata * out)198*3f982cf4SFabien Sanglard bool MdnsReader::Read(PtrRecordRdata* out) {
199*3f982cf4SFabien Sanglard   OSP_DCHECK(out);
200*3f982cf4SFabien Sanglard   Cursor cursor(this);
201*3f982cf4SFabien Sanglard   uint16_t record_length;
202*3f982cf4SFabien Sanglard   DomainName ptr_domain;
203*3f982cf4SFabien Sanglard   if (Read(&record_length) && Read(&ptr_domain) &&
204*3f982cf4SFabien Sanglard       (cursor.delta() == sizeof(record_length) + record_length)) {
205*3f982cf4SFabien Sanglard     *out = PtrRecordRdata(std::move(ptr_domain));
206*3f982cf4SFabien Sanglard     cursor.Commit();
207*3f982cf4SFabien Sanglard     return true;
208*3f982cf4SFabien Sanglard   }
209*3f982cf4SFabien Sanglard   return false;
210*3f982cf4SFabien Sanglard }
211*3f982cf4SFabien Sanglard 
Read(TxtRecordRdata * out)212*3f982cf4SFabien Sanglard bool MdnsReader::Read(TxtRecordRdata* out) {
213*3f982cf4SFabien Sanglard   OSP_DCHECK(out);
214*3f982cf4SFabien Sanglard   Cursor cursor(this);
215*3f982cf4SFabien Sanglard   uint16_t record_length;
216*3f982cf4SFabien Sanglard   if (!Read(&record_length)) {
217*3f982cf4SFabien Sanglard     return false;
218*3f982cf4SFabien Sanglard   }
219*3f982cf4SFabien Sanglard   if (record_length > kMaximumAllowedRdataSize) {
220*3f982cf4SFabien Sanglard     return false;
221*3f982cf4SFabien Sanglard   }
222*3f982cf4SFabien Sanglard   std::vector<TxtRecordRdata::Entry> texts;
223*3f982cf4SFabien Sanglard   while (cursor.delta() < sizeof(record_length) + record_length) {
224*3f982cf4SFabien Sanglard     TxtRecordRdata::Entry entry;
225*3f982cf4SFabien Sanglard     if (!Read(&entry)) {
226*3f982cf4SFabien Sanglard       return false;
227*3f982cf4SFabien Sanglard     }
228*3f982cf4SFabien Sanglard     OSP_DCHECK(entry.size() <= kTXTMaxEntrySize);
229*3f982cf4SFabien Sanglard     if (!entry.empty()) {
230*3f982cf4SFabien Sanglard       texts.emplace_back(entry);
231*3f982cf4SFabien Sanglard     }
232*3f982cf4SFabien Sanglard   }
233*3f982cf4SFabien Sanglard   if (cursor.delta() != sizeof(record_length) + record_length) {
234*3f982cf4SFabien Sanglard     return false;
235*3f982cf4SFabien Sanglard   }
236*3f982cf4SFabien Sanglard   ErrorOr<TxtRecordRdata> rdata = TxtRecordRdata::TryCreate(std::move(texts));
237*3f982cf4SFabien Sanglard   if (rdata.is_error()) {
238*3f982cf4SFabien Sanglard     return false;
239*3f982cf4SFabien Sanglard   }
240*3f982cf4SFabien Sanglard   *out = std::move(rdata.value());
241*3f982cf4SFabien Sanglard   cursor.Commit();
242*3f982cf4SFabien Sanglard   return true;
243*3f982cf4SFabien Sanglard }
244*3f982cf4SFabien Sanglard 
Read(NsecRecordRdata * out)245*3f982cf4SFabien Sanglard bool MdnsReader::Read(NsecRecordRdata* out) {
246*3f982cf4SFabien Sanglard   OSP_DCHECK(out);
247*3f982cf4SFabien Sanglard   Cursor cursor(this);
248*3f982cf4SFabien Sanglard 
249*3f982cf4SFabien Sanglard   const uint8_t* start_position = current();
250*3f982cf4SFabien Sanglard   uint16_t record_length;
251*3f982cf4SFabien Sanglard   DomainName next_record_name;
252*3f982cf4SFabien Sanglard   if (!Read(&record_length) || !Read(&next_record_name)) {
253*3f982cf4SFabien Sanglard     return false;
254*3f982cf4SFabien Sanglard   }
255*3f982cf4SFabien Sanglard   if (record_length > kMaximumAllowedRdataSize) {
256*3f982cf4SFabien Sanglard     return false;
257*3f982cf4SFabien Sanglard   }
258*3f982cf4SFabien Sanglard 
259*3f982cf4SFabien Sanglard   // Calculate the next record name length. This may not be equal to the length
260*3f982cf4SFabien Sanglard   // of |next_record_name| due to domain name compression.
261*3f982cf4SFabien Sanglard   const int encoded_next_name_length =
262*3f982cf4SFabien Sanglard       current() - start_position - sizeof(record_length);
263*3f982cf4SFabien Sanglard   const int remaining_length = record_length - encoded_next_name_length;
264*3f982cf4SFabien Sanglard   if (remaining_length <= 0) {
265*3f982cf4SFabien Sanglard     // This means either the length is invalid or the NSEC record has no
266*3f982cf4SFabien Sanglard     // associated types.
267*3f982cf4SFabien Sanglard     return false;
268*3f982cf4SFabien Sanglard   }
269*3f982cf4SFabien Sanglard 
270*3f982cf4SFabien Sanglard   std::vector<DnsType> types;
271*3f982cf4SFabien Sanglard   if (Read(&types, remaining_length)) {
272*3f982cf4SFabien Sanglard     *out = NsecRecordRdata(std::move(next_record_name), std::move(types));
273*3f982cf4SFabien Sanglard     cursor.Commit();
274*3f982cf4SFabien Sanglard     return true;
275*3f982cf4SFabien Sanglard   }
276*3f982cf4SFabien Sanglard 
277*3f982cf4SFabien Sanglard   return false;
278*3f982cf4SFabien Sanglard }
279*3f982cf4SFabien Sanglard 
Read(MdnsRecord * out)280*3f982cf4SFabien Sanglard bool MdnsReader::Read(MdnsRecord* out) {
281*3f982cf4SFabien Sanglard   OSP_DCHECK(out);
282*3f982cf4SFabien Sanglard   Cursor cursor(this);
283*3f982cf4SFabien Sanglard   DomainName name;
284*3f982cf4SFabien Sanglard   uint16_t type;
285*3f982cf4SFabien Sanglard   uint16_t rrclass;
286*3f982cf4SFabien Sanglard   uint32_t ttl;
287*3f982cf4SFabien Sanglard   Rdata rdata;
288*3f982cf4SFabien Sanglard   if (Read(&name) && Read(&type) && Read(&rrclass) && Read(&ttl) &&
289*3f982cf4SFabien Sanglard       Read(static_cast<DnsType>(type), &rdata)) {
290*3f982cf4SFabien Sanglard     ErrorOr<MdnsRecord> record = MdnsRecord::TryCreate(
291*3f982cf4SFabien Sanglard         std::move(name), static_cast<DnsType>(type), GetDnsClass(rrclass),
292*3f982cf4SFabien Sanglard         GetRecordType(rrclass), std::chrono::seconds(ttl), std::move(rdata));
293*3f982cf4SFabien Sanglard     if (record.is_error()) {
294*3f982cf4SFabien Sanglard       return false;
295*3f982cf4SFabien Sanglard     }
296*3f982cf4SFabien Sanglard     *out = std::move(record.value());
297*3f982cf4SFabien Sanglard 
298*3f982cf4SFabien Sanglard     cursor.Commit();
299*3f982cf4SFabien Sanglard     return true;
300*3f982cf4SFabien Sanglard   }
301*3f982cf4SFabien Sanglard   return false;
302*3f982cf4SFabien Sanglard }
303*3f982cf4SFabien Sanglard 
Read(MdnsQuestion * out)304*3f982cf4SFabien Sanglard bool MdnsReader::Read(MdnsQuestion* out) {
305*3f982cf4SFabien Sanglard   OSP_DCHECK(out);
306*3f982cf4SFabien Sanglard   Cursor cursor(this);
307*3f982cf4SFabien Sanglard   DomainName name;
308*3f982cf4SFabien Sanglard   uint16_t type;
309*3f982cf4SFabien Sanglard   uint16_t rrclass;
310*3f982cf4SFabien Sanglard   if (Read(&name) && Read(&type) && Read(&rrclass)) {
311*3f982cf4SFabien Sanglard     ErrorOr<MdnsQuestion> question =
312*3f982cf4SFabien Sanglard         MdnsQuestion::TryCreate(std::move(name), static_cast<DnsType>(type),
313*3f982cf4SFabien Sanglard                                 GetDnsClass(rrclass), GetResponseType(rrclass));
314*3f982cf4SFabien Sanglard     if (question.is_error()) {
315*3f982cf4SFabien Sanglard       return false;
316*3f982cf4SFabien Sanglard     }
317*3f982cf4SFabien Sanglard     *out = std::move(question.value());
318*3f982cf4SFabien Sanglard 
319*3f982cf4SFabien Sanglard     cursor.Commit();
320*3f982cf4SFabien Sanglard     return true;
321*3f982cf4SFabien Sanglard   }
322*3f982cf4SFabien Sanglard   return false;
323*3f982cf4SFabien Sanglard }
324*3f982cf4SFabien Sanglard 
Read()325*3f982cf4SFabien Sanglard ErrorOr<MdnsMessage> MdnsReader::Read() {
326*3f982cf4SFabien Sanglard   MdnsMessage out;
327*3f982cf4SFabien Sanglard   Cursor cursor(this);
328*3f982cf4SFabien Sanglard   Header header;
329*3f982cf4SFabien Sanglard   std::vector<MdnsQuestion> questions;
330*3f982cf4SFabien Sanglard   std::vector<MdnsRecord> answers;
331*3f982cf4SFabien Sanglard   std::vector<MdnsRecord> authority_records;
332*3f982cf4SFabien Sanglard   std::vector<MdnsRecord> additional_records;
333*3f982cf4SFabien Sanglard   if (Read(&header) && Read(header.question_count, &questions) &&
334*3f982cf4SFabien Sanglard       Read(header.answer_count, &answers) &&
335*3f982cf4SFabien Sanglard       Read(header.authority_record_count, &authority_records) &&
336*3f982cf4SFabien Sanglard       Read(header.additional_record_count, &additional_records)) {
337*3f982cf4SFabien Sanglard     if (!IsValidFlagsSection(header.flags)) {
338*3f982cf4SFabien Sanglard       return Error::Code::kMdnsNonConformingFailure;
339*3f982cf4SFabien Sanglard     }
340*3f982cf4SFabien Sanglard 
341*3f982cf4SFabien Sanglard     ErrorOr<MdnsMessage> message = MdnsMessage::TryCreate(
342*3f982cf4SFabien Sanglard         header.id, GetMessageType(header.flags), questions, answers,
343*3f982cf4SFabien Sanglard         authority_records, additional_records);
344*3f982cf4SFabien Sanglard     if (message.is_error()) {
345*3f982cf4SFabien Sanglard       return std::move(message.error());
346*3f982cf4SFabien Sanglard     }
347*3f982cf4SFabien Sanglard     out = std::move(message.value());
348*3f982cf4SFabien Sanglard 
349*3f982cf4SFabien Sanglard     if (IsMessageTruncated(header.flags)) {
350*3f982cf4SFabien Sanglard       out.set_truncated();
351*3f982cf4SFabien Sanglard     }
352*3f982cf4SFabien Sanglard 
353*3f982cf4SFabien Sanglard     cursor.Commit();
354*3f982cf4SFabien Sanglard     return out;
355*3f982cf4SFabien Sanglard   }
356*3f982cf4SFabien Sanglard   return Error::Code::kMdnsReadFailure;
357*3f982cf4SFabien Sanglard }
358*3f982cf4SFabien Sanglard 
Read(IPAddress::Version version,IPAddress * out)359*3f982cf4SFabien Sanglard bool MdnsReader::Read(IPAddress::Version version, IPAddress* out) {
360*3f982cf4SFabien Sanglard   OSP_DCHECK(out);
361*3f982cf4SFabien Sanglard   size_t ipaddress_size = (version == IPAddress::Version::kV6)
362*3f982cf4SFabien Sanglard                               ? IPAddress::kV6Size
363*3f982cf4SFabien Sanglard                               : IPAddress::kV4Size;
364*3f982cf4SFabien Sanglard   const uint8_t* const address_bytes = current();
365*3f982cf4SFabien Sanglard   if (Skip(ipaddress_size)) {
366*3f982cf4SFabien Sanglard     *out = IPAddress(version, address_bytes);
367*3f982cf4SFabien Sanglard     return true;
368*3f982cf4SFabien Sanglard   }
369*3f982cf4SFabien Sanglard   return false;
370*3f982cf4SFabien Sanglard }
371*3f982cf4SFabien Sanglard 
Read(DnsType type,Rdata * out)372*3f982cf4SFabien Sanglard bool MdnsReader::Read(DnsType type, Rdata* out) {
373*3f982cf4SFabien Sanglard   OSP_DCHECK(out);
374*3f982cf4SFabien Sanglard   switch (type) {
375*3f982cf4SFabien Sanglard     case DnsType::kSRV:
376*3f982cf4SFabien Sanglard       return Read<SrvRecordRdata>(out);
377*3f982cf4SFabien Sanglard     case DnsType::kA:
378*3f982cf4SFabien Sanglard       return Read<ARecordRdata>(out);
379*3f982cf4SFabien Sanglard     case DnsType::kAAAA:
380*3f982cf4SFabien Sanglard       return Read<AAAARecordRdata>(out);
381*3f982cf4SFabien Sanglard     case DnsType::kPTR:
382*3f982cf4SFabien Sanglard       return Read<PtrRecordRdata>(out);
383*3f982cf4SFabien Sanglard     case DnsType::kTXT:
384*3f982cf4SFabien Sanglard       return Read<TxtRecordRdata>(out);
385*3f982cf4SFabien Sanglard     case DnsType::kNSEC:
386*3f982cf4SFabien Sanglard       return Read<NsecRecordRdata>(out);
387*3f982cf4SFabien Sanglard     default:
388*3f982cf4SFabien Sanglard       OSP_DCHECK(std::find(kSupportedDnsTypes.begin(), kSupportedDnsTypes.end(),
389*3f982cf4SFabien Sanglard                            type) == kSupportedDnsTypes.end());
390*3f982cf4SFabien Sanglard       return Read<RawRecordRdata>(out);
391*3f982cf4SFabien Sanglard   }
392*3f982cf4SFabien Sanglard }
393*3f982cf4SFabien Sanglard 
Read(Header * out)394*3f982cf4SFabien Sanglard bool MdnsReader::Read(Header* out) {
395*3f982cf4SFabien Sanglard   OSP_DCHECK(out);
396*3f982cf4SFabien Sanglard   Cursor cursor(this);
397*3f982cf4SFabien Sanglard   if (Read(&out->id) && Read(&out->flags) && Read(&out->question_count) &&
398*3f982cf4SFabien Sanglard       Read(&out->answer_count) && Read(&out->authority_record_count) &&
399*3f982cf4SFabien Sanglard       Read(&out->additional_record_count)) {
400*3f982cf4SFabien Sanglard     cursor.Commit();
401*3f982cf4SFabien Sanglard     return true;
402*3f982cf4SFabien Sanglard   }
403*3f982cf4SFabien Sanglard   return false;
404*3f982cf4SFabien Sanglard }
405*3f982cf4SFabien Sanglard 
Read(std::vector<DnsType> * out,int remaining_size)406*3f982cf4SFabien Sanglard bool MdnsReader::Read(std::vector<DnsType>* out, int remaining_size) {
407*3f982cf4SFabien Sanglard   OSP_DCHECK(out);
408*3f982cf4SFabien Sanglard   Cursor cursor(this);
409*3f982cf4SFabien Sanglard 
410*3f982cf4SFabien Sanglard   // Continue reading bitmaps until the entire input is read. If we have gone
411*3f982cf4SFabien Sanglard   // past the end of the record, it's malformed input so fail.
412*3f982cf4SFabien Sanglard   *out = std::vector<DnsType>();
413*3f982cf4SFabien Sanglard   int processed_bytes = 0;
414*3f982cf4SFabien Sanglard   while (processed_bytes < remaining_size) {
415*3f982cf4SFabien Sanglard     NsecBitMapField bitmap;
416*3f982cf4SFabien Sanglard     if (!Read(&bitmap)) {
417*3f982cf4SFabien Sanglard       return false;
418*3f982cf4SFabien Sanglard     }
419*3f982cf4SFabien Sanglard 
420*3f982cf4SFabien Sanglard     processed_bytes += bitmap.bitmap_length + 2;
421*3f982cf4SFabien Sanglard     if (processed_bytes > remaining_size) {
422*3f982cf4SFabien Sanglard       return false;
423*3f982cf4SFabien Sanglard     }
424*3f982cf4SFabien Sanglard 
425*3f982cf4SFabien Sanglard     // The ith bit of the bitmap represents DnsType with value i, shifted
426*3f982cf4SFabien Sanglard     // a multiple of 0x100 according to the window.
427*3f982cf4SFabien Sanglard     for (int32_t i = 0; i < bitmap.bitmap_length * 8; i++) {
428*3f982cf4SFabien Sanglard       int current_byte = i / 8;
429*3f982cf4SFabien Sanglard       uint8_t bitmask = 0x80 >> i % 8;
430*3f982cf4SFabien Sanglard 
431*3f982cf4SFabien Sanglard       // If this bit flag represents a type we support, add it to the vector.
432*3f982cf4SFabien Sanglard       // Else, we won't be able to use it later on in the code anyway, so drop
433*3f982cf4SFabien Sanglard       // it.
434*3f982cf4SFabien Sanglard       DnsType type;
435*3f982cf4SFabien Sanglard       uint16_t type_index = i | (bitmap.window_block << 8);
436*3f982cf4SFabien Sanglard       if ((bitmap.bitmap[current_byte] & bitmask) &&
437*3f982cf4SFabien Sanglard           TryParseDnsType(type_index, &type)) {
438*3f982cf4SFabien Sanglard         out->push_back(type);
439*3f982cf4SFabien Sanglard       }
440*3f982cf4SFabien Sanglard     }
441*3f982cf4SFabien Sanglard   }
442*3f982cf4SFabien Sanglard 
443*3f982cf4SFabien Sanglard   cursor.Commit();
444*3f982cf4SFabien Sanglard   return true;
445*3f982cf4SFabien Sanglard }
446*3f982cf4SFabien Sanglard 
Read(NsecBitMapField * out)447*3f982cf4SFabien Sanglard bool MdnsReader::Read(NsecBitMapField* out) {
448*3f982cf4SFabien Sanglard   OSP_DCHECK(out);
449*3f982cf4SFabien Sanglard   Cursor cursor(this);
450*3f982cf4SFabien Sanglard 
451*3f982cf4SFabien Sanglard   // Read the window and bitmap length, then one byte for each byte called out
452*3f982cf4SFabien Sanglard   // by the length.
453*3f982cf4SFabien Sanglard   if (Read(&out->window_block) && Read(&out->bitmap_length)) {
454*3f982cf4SFabien Sanglard     if (out->bitmap_length == 0 || out->bitmap_length > 32) {
455*3f982cf4SFabien Sanglard       return false;
456*3f982cf4SFabien Sanglard     }
457*3f982cf4SFabien Sanglard 
458*3f982cf4SFabien Sanglard     out->bitmap = current();
459*3f982cf4SFabien Sanglard     if (!Skip(out->bitmap_length)) {
460*3f982cf4SFabien Sanglard       return false;
461*3f982cf4SFabien Sanglard     }
462*3f982cf4SFabien Sanglard     cursor.Commit();
463*3f982cf4SFabien Sanglard     return true;
464*3f982cf4SFabien Sanglard   }
465*3f982cf4SFabien Sanglard 
466*3f982cf4SFabien Sanglard   return false;
467*3f982cf4SFabien Sanglard }
468*3f982cf4SFabien Sanglard 
469*3f982cf4SFabien Sanglard }  // namespace discovery
470*3f982cf4SFabien Sanglard }  // namespace openscreen
471