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