xref: /aosp_15_r20/external/openscreen/discovery/mdns/mdns_reader_unittest.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 <memory>
8*3f982cf4SFabien Sanglard 
9*3f982cf4SFabien Sanglard #include "discovery/common/config.h"
10*3f982cf4SFabien Sanglard #include "discovery/mdns/testing/mdns_test_util.h"
11*3f982cf4SFabien Sanglard #include "gmock/gmock.h"
12*3f982cf4SFabien Sanglard #include "gtest/gtest.h"
13*3f982cf4SFabien Sanglard 
14*3f982cf4SFabien Sanglard namespace openscreen {
15*3f982cf4SFabien Sanglard namespace discovery {
16*3f982cf4SFabien Sanglard 
17*3f982cf4SFabien Sanglard namespace {
18*3f982cf4SFabien Sanglard 
19*3f982cf4SFabien Sanglard constexpr std::chrono::seconds kTtl{120};
20*3f982cf4SFabien Sanglard 
21*3f982cf4SFabien Sanglard template <class T>
TestReadEntrySucceeds(const uint8_t * data,size_t size,const T & expected)22*3f982cf4SFabien Sanglard void TestReadEntrySucceeds(const uint8_t* data,
23*3f982cf4SFabien Sanglard                            size_t size,
24*3f982cf4SFabien Sanglard                            const T& expected) {
25*3f982cf4SFabien Sanglard   Config config;
26*3f982cf4SFabien Sanglard   MdnsReader reader(config, data, size);
27*3f982cf4SFabien Sanglard   T entry;
28*3f982cf4SFabien Sanglard   EXPECT_TRUE(reader.Read(&entry));
29*3f982cf4SFabien Sanglard   EXPECT_EQ(entry, expected);
30*3f982cf4SFabien Sanglard   EXPECT_EQ(reader.remaining(), UINT64_C(0));
31*3f982cf4SFabien Sanglard }
32*3f982cf4SFabien Sanglard 
33*3f982cf4SFabien Sanglard template <>
TestReadEntrySucceeds(const uint8_t * data,size_t size,const MdnsMessage & expected)34*3f982cf4SFabien Sanglard void TestReadEntrySucceeds<MdnsMessage>(const uint8_t* data,
35*3f982cf4SFabien Sanglard                                         size_t size,
36*3f982cf4SFabien Sanglard                                         const MdnsMessage& expected) {
37*3f982cf4SFabien Sanglard   MdnsReader reader(Config{}, data, size);
38*3f982cf4SFabien Sanglard   const ErrorOr<MdnsMessage> message = reader.Read();
39*3f982cf4SFabien Sanglard   EXPECT_TRUE(message.is_value());
40*3f982cf4SFabien Sanglard   EXPECT_EQ(message.value(), expected);
41*3f982cf4SFabien Sanglard   EXPECT_EQ(reader.remaining(), UINT64_C(0));
42*3f982cf4SFabien Sanglard }
43*3f982cf4SFabien Sanglard 
44*3f982cf4SFabien Sanglard template <class T>
TestReadEntryFails(const uint8_t * data,size_t size)45*3f982cf4SFabien Sanglard void TestReadEntryFails(const uint8_t* data, size_t size) {
46*3f982cf4SFabien Sanglard   Config config;
47*3f982cf4SFabien Sanglard   MdnsReader reader(config, data, size);
48*3f982cf4SFabien Sanglard   T entry;
49*3f982cf4SFabien Sanglard   EXPECT_FALSE(reader.Read(&entry));
50*3f982cf4SFabien Sanglard   // There should be no side effects for failing to read an entry. The
51*3f982cf4SFabien Sanglard   // underlying pointer should not have changed.
52*3f982cf4SFabien Sanglard   EXPECT_EQ(reader.offset(), UINT64_C(0));
53*3f982cf4SFabien Sanglard }
54*3f982cf4SFabien Sanglard 
55*3f982cf4SFabien Sanglard template <>
TestReadEntryFails(const uint8_t * data,size_t size)56*3f982cf4SFabien Sanglard void TestReadEntryFails<MdnsMessage>(const uint8_t* data, size_t size) {
57*3f982cf4SFabien Sanglard   Config config;
58*3f982cf4SFabien Sanglard   MdnsReader reader(config, data, size);
59*3f982cf4SFabien Sanglard   const ErrorOr<MdnsMessage> message = reader.Read();
60*3f982cf4SFabien Sanglard   EXPECT_TRUE(message.is_error());
61*3f982cf4SFabien Sanglard 
62*3f982cf4SFabien Sanglard   // There should be no side effects for failing to read an entry. The
63*3f982cf4SFabien Sanglard   // underlying pointer should not have changed.
64*3f982cf4SFabien Sanglard   EXPECT_EQ(reader.offset(), UINT64_C(0));
65*3f982cf4SFabien Sanglard }
66*3f982cf4SFabien Sanglard }  // namespace
67*3f982cf4SFabien Sanglard 
TEST(MdnsReaderTest,ReadDomainName)68*3f982cf4SFabien Sanglard TEST(MdnsReaderTest, ReadDomainName) {
69*3f982cf4SFabien Sanglard   constexpr uint8_t kMessage[] = {
70*3f982cf4SFabien Sanglard       // First name
71*3f982cf4SFabien Sanglard       0x07, 't', 'e', 's', 't', 'i', 'n', 'g',  // Byte: 0
72*3f982cf4SFabien Sanglard       0x05, 'l', 'o', 'c', 'a', 'l',            // Byte: 8
73*3f982cf4SFabien Sanglard       0x00,                                     // Byte: 14
74*3f982cf4SFabien Sanglard       // Second name
75*3f982cf4SFabien Sanglard       0x07, 's', 'e', 'r', 'v', 'i', 'c', 'e',  // Byte: 15
76*3f982cf4SFabien Sanglard       0xc0, 0x00,                               // Byte: 23
77*3f982cf4SFabien Sanglard       // Third name
78*3f982cf4SFabien Sanglard       0x06, 'd', 'e', 'v', 'i', 'c', 'e',  // Byte: 25
79*3f982cf4SFabien Sanglard       0xc0, 0x0f,                          // Byte: 32
80*3f982cf4SFabien Sanglard       // Fourth name
81*3f982cf4SFabien Sanglard       0xc0, 0x20,  // Byte: 34
82*3f982cf4SFabien Sanglard   };
83*3f982cf4SFabien Sanglard   Config config;
84*3f982cf4SFabien Sanglard   MdnsReader reader(config, kMessage, sizeof(kMessage));
85*3f982cf4SFabien Sanglard   EXPECT_EQ(reader.begin(), kMessage);
86*3f982cf4SFabien Sanglard   EXPECT_EQ(reader.length(), sizeof(kMessage));
87*3f982cf4SFabien Sanglard   EXPECT_EQ(reader.offset(), 0u);
88*3f982cf4SFabien Sanglard   DomainName name;
89*3f982cf4SFabien Sanglard   EXPECT_TRUE(reader.Read(&name));
90*3f982cf4SFabien Sanglard   EXPECT_EQ(name.ToString(), "testing.local");
91*3f982cf4SFabien Sanglard   EXPECT_TRUE(reader.Read(&name));
92*3f982cf4SFabien Sanglard   EXPECT_EQ(name.ToString(), "service.testing.local");
93*3f982cf4SFabien Sanglard   EXPECT_TRUE(reader.Read(&name));
94*3f982cf4SFabien Sanglard   EXPECT_EQ(name.ToString(), "device.service.testing.local");
95*3f982cf4SFabien Sanglard   EXPECT_TRUE(reader.Read(&name));
96*3f982cf4SFabien Sanglard   EXPECT_EQ(name.ToString(), "service.testing.local");
97*3f982cf4SFabien Sanglard   EXPECT_EQ(reader.offset(), sizeof(kMessage));
98*3f982cf4SFabien Sanglard   EXPECT_EQ(0UL, reader.remaining());
99*3f982cf4SFabien Sanglard   EXPECT_FALSE(reader.Read(&name));
100*3f982cf4SFabien Sanglard }
101*3f982cf4SFabien Sanglard 
TEST(MdnsReaderTest,ReadDomainName_Empty)102*3f982cf4SFabien Sanglard TEST(MdnsReaderTest, ReadDomainName_Empty) {
103*3f982cf4SFabien Sanglard   constexpr uint8_t kDomainName[] = {0x00};
104*3f982cf4SFabien Sanglard   TestReadEntrySucceeds(kDomainName, sizeof(kDomainName), DomainName());
105*3f982cf4SFabien Sanglard }
106*3f982cf4SFabien Sanglard 
TEST(MdnsReaderTest,ReadDomainName_TooShort)107*3f982cf4SFabien Sanglard TEST(MdnsReaderTest, ReadDomainName_TooShort) {
108*3f982cf4SFabien Sanglard   // Length 0x03 is longer than available data for the domain name
109*3f982cf4SFabien Sanglard   constexpr uint8_t kDomainName[] = {0x03, 'a', 'b'};
110*3f982cf4SFabien Sanglard   TestReadEntryFails<DomainName>(kDomainName, sizeof(kDomainName));
111*3f982cf4SFabien Sanglard }
112*3f982cf4SFabien Sanglard 
TEST(MdnsReaderTest,ReadDomainName_TooLong)113*3f982cf4SFabien Sanglard TEST(MdnsReaderTest, ReadDomainName_TooLong) {
114*3f982cf4SFabien Sanglard   std::vector<uint8_t> kDomainName;
115*3f982cf4SFabien Sanglard   for (uint8_t letter = 'a'; letter <= 'z'; ++letter) {
116*3f982cf4SFabien Sanglard     constexpr uint8_t repetitions = 10;
117*3f982cf4SFabien Sanglard     kDomainName.push_back(repetitions);
118*3f982cf4SFabien Sanglard     kDomainName.insert(kDomainName.end(), repetitions, letter);
119*3f982cf4SFabien Sanglard   }
120*3f982cf4SFabien Sanglard   kDomainName.push_back(0);
121*3f982cf4SFabien Sanglard   TestReadEntryFails<DomainName>(kDomainName.data(), kDomainName.size());
122*3f982cf4SFabien Sanglard }
123*3f982cf4SFabien Sanglard 
TEST(MdnsReaderTest,ReadDomainName_LabelPointerOutOfBounds)124*3f982cf4SFabien Sanglard TEST(MdnsReaderTest, ReadDomainName_LabelPointerOutOfBounds) {
125*3f982cf4SFabien Sanglard   constexpr uint8_t kDomainName[] = {0xc0, 0x02};
126*3f982cf4SFabien Sanglard   TestReadEntryFails<DomainName>(kDomainName, sizeof(kDomainName));
127*3f982cf4SFabien Sanglard }
128*3f982cf4SFabien Sanglard 
TEST(MdnsReaderTest,ReadDomainName_InvalidLabel)129*3f982cf4SFabien Sanglard TEST(MdnsReaderTest, ReadDomainName_InvalidLabel) {
130*3f982cf4SFabien Sanglard   constexpr uint8_t kDomainName[] = {0x80};
131*3f982cf4SFabien Sanglard   TestReadEntryFails<DomainName>(kDomainName, sizeof(kDomainName));
132*3f982cf4SFabien Sanglard }
133*3f982cf4SFabien Sanglard 
TEST(MdnsReaderTest,ReadDomainName_CircularCompression)134*3f982cf4SFabien Sanglard TEST(MdnsReaderTest, ReadDomainName_CircularCompression) {
135*3f982cf4SFabien Sanglard   // clang-format off
136*3f982cf4SFabien Sanglard   constexpr uint8_t kDomainName[] = {
137*3f982cf4SFabien Sanglard       // NOTE: Circular label pointer at end of name.
138*3f982cf4SFabien Sanglard       0x07, 't', 'e', 's', 't', 'i', 'n', 'g',  // Byte: 0
139*3f982cf4SFabien Sanglard       0x05, 'l', 'o', 'c', 'a', 'l',            // Byte: 8
140*3f982cf4SFabien Sanglard       0xc0, 0x00,                               // Byte: 14
141*3f982cf4SFabien Sanglard   };
142*3f982cf4SFabien Sanglard   // clang-format on
143*3f982cf4SFabien Sanglard   TestReadEntryFails<DomainName>(kDomainName, sizeof(kDomainName));
144*3f982cf4SFabien Sanglard }
145*3f982cf4SFabien Sanglard 
TEST(MdnsReaderTest,ReadRawRecordRdata)146*3f982cf4SFabien Sanglard TEST(MdnsReaderTest, ReadRawRecordRdata) {
147*3f982cf4SFabien Sanglard   // clang-format off
148*3f982cf4SFabien Sanglard   constexpr uint8_t kRawRecordRdata[] = {
149*3f982cf4SFabien Sanglard       0x00, 0x08,  // RDLENGTH = 8 bytes
150*3f982cf4SFabien Sanglard       0x05, 'c', 'n', 'a', 'm', 'e', 0xc0, 0x00,
151*3f982cf4SFabien Sanglard   };
152*3f982cf4SFabien Sanglard   // clang-format on
153*3f982cf4SFabien Sanglard   TestReadEntrySucceeds(
154*3f982cf4SFabien Sanglard       kRawRecordRdata, sizeof(kRawRecordRdata),
155*3f982cf4SFabien Sanglard       RawRecordRdata(kRawRecordRdata + 2, sizeof(kRawRecordRdata) - 2));
156*3f982cf4SFabien Sanglard }
157*3f982cf4SFabien Sanglard 
TEST(MdnsReaderTest,ReadRawRecordRdata_TooLong)158*3f982cf4SFabien Sanglard TEST(MdnsReaderTest, ReadRawRecordRdata_TooLong) {
159*3f982cf4SFabien Sanglard   // clang-format off
160*3f982cf4SFabien Sanglard   constexpr uint8_t kRawRecordRdata[] = {
161*3f982cf4SFabien Sanglard       0x00, 0x08,  // RDLENGTH = 8 bytes
162*3f982cf4SFabien Sanglard       0x05, 'c', 'n', 'a', 'm', 'e', 0xc0, 0x00,
163*3f982cf4SFabien Sanglard   };
164*3f982cf4SFabien Sanglard   // clang-format on
165*3f982cf4SFabien Sanglard 
166*3f982cf4SFabien Sanglard   Config config;
167*3f982cf4SFabien Sanglard   config.maximum_valid_rdata_size = 1;
168*3f982cf4SFabien Sanglard   MdnsReader reader(config, kRawRecordRdata, sizeof(kRawRecordRdata));
169*3f982cf4SFabien Sanglard   RawRecordRdata entry;
170*3f982cf4SFabien Sanglard   EXPECT_FALSE(reader.Read(&entry));
171*3f982cf4SFabien Sanglard   // There should be no side effects for failing to read an entry. The
172*3f982cf4SFabien Sanglard   // underlying pointer should not have changed.
173*3f982cf4SFabien Sanglard   EXPECT_EQ(reader.offset(), UINT64_C(0));
174*3f982cf4SFabien Sanglard }
175*3f982cf4SFabien Sanglard 
TEST(MdnsReaderTest,ReadRawRecord_Empty)176*3f982cf4SFabien Sanglard TEST(MdnsReaderTest, ReadRawRecord_Empty) {
177*3f982cf4SFabien Sanglard   // clang-format off
178*3f982cf4SFabien Sanglard   constexpr uint8_t kRawRecordRdata[] = {
179*3f982cf4SFabien Sanglard       0x00, 0x00,  // RDLENGTH = 0 bytes
180*3f982cf4SFabien Sanglard   };
181*3f982cf4SFabien Sanglard   // clang-format on
182*3f982cf4SFabien Sanglard   TestReadEntrySucceeds(kRawRecordRdata, sizeof(kRawRecordRdata),
183*3f982cf4SFabien Sanglard                         RawRecordRdata());
184*3f982cf4SFabien Sanglard }
185*3f982cf4SFabien Sanglard 
TEST(MdnsReaderTest,ReadRawRecordRdata_TooShort)186*3f982cf4SFabien Sanglard TEST(MdnsReaderTest, ReadRawRecordRdata_TooShort) {
187*3f982cf4SFabien Sanglard   // clang-format off
188*3f982cf4SFabien Sanglard   constexpr uint8_t kRawRecordRdata[] = {
189*3f982cf4SFabien Sanglard       0x00, 0x05,  // RDLENGTH = 5 bytes is longer that available data
190*3f982cf4SFabien Sanglard       0x03, 'f', 'o', 'o'
191*3f982cf4SFabien Sanglard   };
192*3f982cf4SFabien Sanglard   // clang-format on
193*3f982cf4SFabien Sanglard   TestReadEntryFails<RawRecordRdata>(kRawRecordRdata, sizeof(kRawRecordRdata));
194*3f982cf4SFabien Sanglard }
195*3f982cf4SFabien Sanglard 
TEST(MdnsReaderTest,ReadSrvRecordRdata)196*3f982cf4SFabien Sanglard TEST(MdnsReaderTest, ReadSrvRecordRdata) {
197*3f982cf4SFabien Sanglard   // clang-format off
198*3f982cf4SFabien Sanglard   constexpr uint8_t kSrvRecordRdata[] = {
199*3f982cf4SFabien Sanglard       0x00, 0x15,  // RDLENGTH = 21
200*3f982cf4SFabien Sanglard       0x00, 0x05,  // PRIORITY = 5
201*3f982cf4SFabien Sanglard       0x00, 0x06,  // WEIGHT = 6
202*3f982cf4SFabien Sanglard       0x1f, 0x49,  // PORT = 8009
203*3f982cf4SFabien Sanglard       0x07, 't', 'e', 's', 't', 'i', 'n', 'g',
204*3f982cf4SFabien Sanglard       0x05, 'l', 'o', 'c', 'a', 'l', 0x00,
205*3f982cf4SFabien Sanglard   };
206*3f982cf4SFabien Sanglard   // clang-format on
207*3f982cf4SFabien Sanglard   TestReadEntrySucceeds(
208*3f982cf4SFabien Sanglard       kSrvRecordRdata, sizeof(kSrvRecordRdata),
209*3f982cf4SFabien Sanglard       SrvRecordRdata(5, 6, 8009, DomainName{"testing", "local"}));
210*3f982cf4SFabien Sanglard }
211*3f982cf4SFabien Sanglard 
TEST(MdnsReaderTest,ReadSrvRecordRdata_TooShort)212*3f982cf4SFabien Sanglard TEST(MdnsReaderTest, ReadSrvRecordRdata_TooShort) {
213*3f982cf4SFabien Sanglard   // clang-format off
214*3f982cf4SFabien Sanglard   constexpr uint8_t kSrvRecordRdata[] = {
215*3f982cf4SFabien Sanglard       0x00, 0x14,  // RDLENGTH = 21
216*3f982cf4SFabien Sanglard       0x00, 0x05,  // PRIORITY = 5
217*3f982cf4SFabien Sanglard       0x00, 0x06,  // WEIGHT = 6
218*3f982cf4SFabien Sanglard                    // Missing bytes
219*3f982cf4SFabien Sanglard   };
220*3f982cf4SFabien Sanglard   // clang-format on
221*3f982cf4SFabien Sanglard   TestReadEntryFails<SrvRecordRdata>(kSrvRecordRdata, sizeof(kSrvRecordRdata));
222*3f982cf4SFabien Sanglard }
223*3f982cf4SFabien Sanglard 
TEST(MdnsReaderTest,ReadSrvRecordRdata_WrongLength)224*3f982cf4SFabien Sanglard TEST(MdnsReaderTest, ReadSrvRecordRdata_WrongLength) {
225*3f982cf4SFabien Sanglard   // clang-format off
226*3f982cf4SFabien Sanglard   constexpr uint8_t kSrvRecordRdata[] = {
227*3f982cf4SFabien Sanglard       0x00, 0x14,  // RDLENGTH = 20
228*3f982cf4SFabien Sanglard       0x00, 0x05,  // PRIORITY = 5
229*3f982cf4SFabien Sanglard       0x00, 0x06,  // WEIGHT = 6
230*3f982cf4SFabien Sanglard       0x1f, 0x49,  // PORT = 8009
231*3f982cf4SFabien Sanglard       0x07, 't', 'e', 's', 't', 'i', 'n', 'g',
232*3f982cf4SFabien Sanglard       0x05, 'l', 'o', 'c', 'a', 'l', 0x00,
233*3f982cf4SFabien Sanglard   };
234*3f982cf4SFabien Sanglard   // clang-format on
235*3f982cf4SFabien Sanglard   TestReadEntryFails<SrvRecordRdata>(kSrvRecordRdata, sizeof(kSrvRecordRdata));
236*3f982cf4SFabien Sanglard }
237*3f982cf4SFabien Sanglard 
TEST(MdnsReaderTest,ReadARecordRdata)238*3f982cf4SFabien Sanglard TEST(MdnsReaderTest, ReadARecordRdata) {
239*3f982cf4SFabien Sanglard   constexpr uint8_t kARecordRdata[] = {
240*3f982cf4SFabien Sanglard       0x00, 0x4,               // RDLENGTH = 4
241*3f982cf4SFabien Sanglard       0x08, 0x08, 0x08, 0x08,  // ADDRESS = 8.8.8.8
242*3f982cf4SFabien Sanglard   };
243*3f982cf4SFabien Sanglard   TestReadEntrySucceeds(kARecordRdata, sizeof(kARecordRdata),
244*3f982cf4SFabien Sanglard                         ARecordRdata(IPAddress{8, 8, 8, 8}));
245*3f982cf4SFabien Sanglard }
246*3f982cf4SFabien Sanglard 
TEST(MdnsReaderTest,ReadARecordRdata_TooShort)247*3f982cf4SFabien Sanglard TEST(MdnsReaderTest, ReadARecordRdata_TooShort) {
248*3f982cf4SFabien Sanglard   constexpr uint8_t kARecordRdata[] = {
249*3f982cf4SFabien Sanglard       0x00, 0x4,   // RDLENGTH = 4
250*3f982cf4SFabien Sanglard       0x08, 0x08,  // Address missing bytes
251*3f982cf4SFabien Sanglard   };
252*3f982cf4SFabien Sanglard   TestReadEntryFails<ARecordRdata>(kARecordRdata, sizeof(kARecordRdata));
253*3f982cf4SFabien Sanglard }
254*3f982cf4SFabien Sanglard 
TEST(MdnsReaderTest,ReadARecordRdata_WrongLength)255*3f982cf4SFabien Sanglard TEST(MdnsReaderTest, ReadARecordRdata_WrongLength) {
256*3f982cf4SFabien Sanglard   constexpr uint8_t kARecordRdata[] = {
257*3f982cf4SFabien Sanglard       0x00, 0x5,               // RDLENGTH = 5
258*3f982cf4SFabien Sanglard       0x08, 0x08, 0x08, 0x08,  // ADDRESS = 8.8.8.8
259*3f982cf4SFabien Sanglard   };
260*3f982cf4SFabien Sanglard   TestReadEntryFails<ARecordRdata>(kARecordRdata, sizeof(kARecordRdata));
261*3f982cf4SFabien Sanglard }
262*3f982cf4SFabien Sanglard 
TEST(MdnsReaderTest,ReadAAAARecordRdata)263*3f982cf4SFabien Sanglard TEST(MdnsReaderTest, ReadAAAARecordRdata) {
264*3f982cf4SFabien Sanglard   // clang-format off
265*3f982cf4SFabien Sanglard   constexpr uint8_t kAAAARecordRdata[] = {
266*3f982cf4SFabien Sanglard       0x00, 0x10,  // RDLENGTH = 16
267*3f982cf4SFabien Sanglard       // ADDRESS = FE80:0000:0000:0000:0202:B3FF:FE1E:8329
268*3f982cf4SFabien Sanglard       0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
269*3f982cf4SFabien Sanglard       0x02, 0x02, 0xb3, 0xff, 0xfe, 0x1e, 0x83, 0x29,
270*3f982cf4SFabien Sanglard   };
271*3f982cf4SFabien Sanglard   // clang-format on
272*3f982cf4SFabien Sanglard   TestReadEntrySucceeds(kAAAARecordRdata, sizeof(kAAAARecordRdata),
273*3f982cf4SFabien Sanglard                         AAAARecordRdata(IPAddress(IPAddress::Version::kV6,
274*3f982cf4SFabien Sanglard                                                   kAAAARecordRdata + 2)));
275*3f982cf4SFabien Sanglard }
276*3f982cf4SFabien Sanglard 
TEST(MdnsReaderTest,ReadAAAARecordRdata_TooShort)277*3f982cf4SFabien Sanglard TEST(MdnsReaderTest, ReadAAAARecordRdata_TooShort) {
278*3f982cf4SFabien Sanglard   // clang-format off
279*3f982cf4SFabien Sanglard   constexpr uint8_t kAAAARecordRdata[] = {
280*3f982cf4SFabien Sanglard       0x00, 0x10,  // RDLENGTH = 16
281*3f982cf4SFabien Sanglard       // ADDRESS missing bytes
282*3f982cf4SFabien Sanglard       0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
283*3f982cf4SFabien Sanglard   };
284*3f982cf4SFabien Sanglard   // clang-format on
285*3f982cf4SFabien Sanglard   TestReadEntryFails<AAAARecordRdata>(kAAAARecordRdata,
286*3f982cf4SFabien Sanglard                                       sizeof(kAAAARecordRdata));
287*3f982cf4SFabien Sanglard }
288*3f982cf4SFabien Sanglard 
TEST(MdnsReaderTest,ReadAAAARecordRdata_WrongLength)289*3f982cf4SFabien Sanglard TEST(MdnsReaderTest, ReadAAAARecordRdata_WrongLength) {
290*3f982cf4SFabien Sanglard   // clang-format off
291*3f982cf4SFabien Sanglard   constexpr uint8_t kAAAARecordRdata[] = {
292*3f982cf4SFabien Sanglard       0x00, 0x11,  // RDLENGTH = 17
293*3f982cf4SFabien Sanglard       // ADDRESS = FE80:0000:0000:0000:0202:B3FF:FE1E:8329
294*3f982cf4SFabien Sanglard       0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
295*3f982cf4SFabien Sanglard       0x02, 0x02, 0xb3, 0xff, 0xfe, 0x1e, 0x83, 0x29,
296*3f982cf4SFabien Sanglard   };
297*3f982cf4SFabien Sanglard   // clang-format on
298*3f982cf4SFabien Sanglard   TestReadEntryFails<AAAARecordRdata>(kAAAARecordRdata,
299*3f982cf4SFabien Sanglard                                       sizeof(kAAAARecordRdata));
300*3f982cf4SFabien Sanglard }
301*3f982cf4SFabien Sanglard 
TEST(MdnsReaderTest,ReadPtrRecordRdata)302*3f982cf4SFabien Sanglard TEST(MdnsReaderTest, ReadPtrRecordRdata) {
303*3f982cf4SFabien Sanglard   // clang-format off
304*3f982cf4SFabien Sanglard   constexpr uint8_t kPtrRecordRdata[] = {
305*3f982cf4SFabien Sanglard       0x00, 0x18,  // RDLENGTH = 24
306*3f982cf4SFabien Sanglard       0x08, 'm', 'y', 'd', 'e', 'v', 'i', 'c', 'e',
307*3f982cf4SFabien Sanglard       0x07, 't', 'e', 's', 't', 'i', 'n', 'g',
308*3f982cf4SFabien Sanglard       0x05, 'l', 'o', 'c', 'a',  'l',
309*3f982cf4SFabien Sanglard       0x00,
310*3f982cf4SFabien Sanglard   };
311*3f982cf4SFabien Sanglard   // clang-format on
312*3f982cf4SFabien Sanglard   TestReadEntrySucceeds(
313*3f982cf4SFabien Sanglard       kPtrRecordRdata, sizeof(kPtrRecordRdata),
314*3f982cf4SFabien Sanglard       PtrRecordRdata(DomainName{"mydevice", "testing", "local"}));
315*3f982cf4SFabien Sanglard }
316*3f982cf4SFabien Sanglard 
TEST(MdnsReaderTest,ReadPtrRecordRdata_TooShort)317*3f982cf4SFabien Sanglard TEST(MdnsReaderTest, ReadPtrRecordRdata_TooShort) {
318*3f982cf4SFabien Sanglard   // clang-format off
319*3f982cf4SFabien Sanglard   constexpr uint8_t kPtrRecordRdata[] = {
320*3f982cf4SFabien Sanglard       0x00, 0x18,  // RDLENGTH = 24
321*3f982cf4SFabien Sanglard       0x08, 'm', 'y', 'd', 'e', 'v', 'i', 'c', 'e',
322*3f982cf4SFabien Sanglard       0x07, 't', 'e', 's', 't', 'i', 'n', 'g',
323*3f982cf4SFabien Sanglard       0x05, 'l', 'o', 'c'
324*3f982cf4SFabien Sanglard       // Missing bytes
325*3f982cf4SFabien Sanglard   };
326*3f982cf4SFabien Sanglard   // clang-format on
327*3f982cf4SFabien Sanglard   TestReadEntryFails<PtrRecordRdata>(kPtrRecordRdata, sizeof(kPtrRecordRdata));
328*3f982cf4SFabien Sanglard }
329*3f982cf4SFabien Sanglard 
TEST(MdnsReaderTest,ReadPtrRecordRdata_WrongLength)330*3f982cf4SFabien Sanglard TEST(MdnsReaderTest, ReadPtrRecordRdata_WrongLength) {
331*3f982cf4SFabien Sanglard   // clang-format off
332*3f982cf4SFabien Sanglard   constexpr uint8_t kPtrRecordRdata[] = {
333*3f982cf4SFabien Sanglard       0x00, 0x18,  // RDLENGTH = 24
334*3f982cf4SFabien Sanglard       0x07, 't', 'e', 's', 't', 'i', 'n', 'g',
335*3f982cf4SFabien Sanglard       0x05, 'l', 'o', 'c', 'a',  'l',
336*3f982cf4SFabien Sanglard       0x00,
337*3f982cf4SFabien Sanglard   };
338*3f982cf4SFabien Sanglard   // clang-format on
339*3f982cf4SFabien Sanglard   TestReadEntryFails<PtrRecordRdata>(kPtrRecordRdata, sizeof(kPtrRecordRdata));
340*3f982cf4SFabien Sanglard }
341*3f982cf4SFabien Sanglard 
TEST(MdnsReaderTest,ReadTxtRecordRdata)342*3f982cf4SFabien Sanglard TEST(MdnsReaderTest, ReadTxtRecordRdata) {
343*3f982cf4SFabien Sanglard   // clang-format off
344*3f982cf4SFabien Sanglard   constexpr uint8_t kTxtRecordRdata[] = {
345*3f982cf4SFabien Sanglard       0x00, 0x0C,  // RDLENGTH = 12
346*3f982cf4SFabien Sanglard       0x05, 'f', 'o', 'o', '=', '1',
347*3f982cf4SFabien Sanglard       0x05, 'b', 'a', 'r', '=', '2',
348*3f982cf4SFabien Sanglard   };
349*3f982cf4SFabien Sanglard   // clang-format on
350*3f982cf4SFabien Sanglard   TestReadEntrySucceeds(kTxtRecordRdata, sizeof(kTxtRecordRdata),
351*3f982cf4SFabien Sanglard                         MakeTxtRecord({"foo=1", "bar=2"}));
352*3f982cf4SFabien Sanglard }
353*3f982cf4SFabien Sanglard 
TEST(MdnsReaderTest,ReadTxtRecordRdata_Empty)354*3f982cf4SFabien Sanglard TEST(MdnsReaderTest, ReadTxtRecordRdata_Empty) {
355*3f982cf4SFabien Sanglard   constexpr uint8_t kTxtRecordRdata[] = {
356*3f982cf4SFabien Sanglard       0x00, 0x01,  // RDLENGTH = 1
357*3f982cf4SFabien Sanglard       0x00,        // empty string
358*3f982cf4SFabien Sanglard   };
359*3f982cf4SFabien Sanglard   TestReadEntrySucceeds(kTxtRecordRdata, sizeof(kTxtRecordRdata),
360*3f982cf4SFabien Sanglard                         TxtRecordRdata());
361*3f982cf4SFabien Sanglard }
362*3f982cf4SFabien Sanglard 
TEST(MdnsReaderTest,ReadTxtRecordRdata_WithNullInTheMiddle)363*3f982cf4SFabien Sanglard TEST(MdnsReaderTest, ReadTxtRecordRdata_WithNullInTheMiddle) {
364*3f982cf4SFabien Sanglard   // clang-format off
365*3f982cf4SFabien Sanglard   constexpr uint8_t kTxtRecordRdata[] = {
366*3f982cf4SFabien Sanglard       0x00, 0x10,  // RDLENGTH = 16
367*3f982cf4SFabien Sanglard       0x09, 'w', 'i', 't', 'h', '\0', 'N', 'U', 'L', 'L',
368*3f982cf4SFabien Sanglard       0x05, 'o', 't', 'h', 'e', 'r',
369*3f982cf4SFabien Sanglard   };
370*3f982cf4SFabien Sanglard   // clang-format on
371*3f982cf4SFabien Sanglard   TestReadEntrySucceeds(
372*3f982cf4SFabien Sanglard       kTxtRecordRdata, sizeof(kTxtRecordRdata),
373*3f982cf4SFabien Sanglard       MakeTxtRecord({absl::string_view("with\0NULL", 9), "other"}));
374*3f982cf4SFabien Sanglard }
375*3f982cf4SFabien Sanglard 
TEST(MdnsReaderTest,ReadTxtRecordRdata_EmptyEntries)376*3f982cf4SFabien Sanglard TEST(MdnsReaderTest, ReadTxtRecordRdata_EmptyEntries) {
377*3f982cf4SFabien Sanglard   // clang-format off
378*3f982cf4SFabien Sanglard   constexpr uint8_t kTxtRecordRdata[] = {
379*3f982cf4SFabien Sanglard       0x00, 0x0F,  // RDLENGTH = 12
380*3f982cf4SFabien Sanglard       0x05, 'f', 'o', 'o', '=', '1',
381*3f982cf4SFabien Sanglard       0x00,
382*3f982cf4SFabien Sanglard       0x00,
383*3f982cf4SFabien Sanglard       0x05, 'b', 'a', 'r', '=', '2',
384*3f982cf4SFabien Sanglard       0x00,
385*3f982cf4SFabien Sanglard   };
386*3f982cf4SFabien Sanglard   // clang-format on
387*3f982cf4SFabien Sanglard   TestReadEntrySucceeds(kTxtRecordRdata, sizeof(kTxtRecordRdata),
388*3f982cf4SFabien Sanglard                         MakeTxtRecord({"foo=1", "bar=2"}));
389*3f982cf4SFabien Sanglard }
390*3f982cf4SFabien Sanglard 
TEST(MdnsReaderTest,ReadTxtRecordRdata_TooLong)391*3f982cf4SFabien Sanglard TEST(MdnsReaderTest, ReadTxtRecordRdata_TooLong) {
392*3f982cf4SFabien Sanglard   // clang-format off
393*3f982cf4SFabien Sanglard   constexpr uint8_t kTxtRecordRdata[] = {
394*3f982cf4SFabien Sanglard       0x00, 0x0C,  // RDLENGTH = 12
395*3f982cf4SFabien Sanglard       0x05, 'f', 'o', 'o', '=', '1',
396*3f982cf4SFabien Sanglard       0x05, 'b', 'a', 'r', '=', '2',
397*3f982cf4SFabien Sanglard   };
398*3f982cf4SFabien Sanglard   // clang-format on
399*3f982cf4SFabien Sanglard 
400*3f982cf4SFabien Sanglard   Config config;
401*3f982cf4SFabien Sanglard   config.maximum_valid_rdata_size = 1;
402*3f982cf4SFabien Sanglard   MdnsReader reader(config, kTxtRecordRdata, sizeof(kTxtRecordRdata));
403*3f982cf4SFabien Sanglard   TxtRecordRdata entry;
404*3f982cf4SFabien Sanglard   EXPECT_FALSE(reader.Read(&entry));
405*3f982cf4SFabien Sanglard   // There should be no side effects for failing to read an entry. The
406*3f982cf4SFabien Sanglard   // underlying pointer should not have changed.
407*3f982cf4SFabien Sanglard   EXPECT_EQ(reader.offset(), UINT64_C(0));
408*3f982cf4SFabien Sanglard }
409*3f982cf4SFabien Sanglard 
TEST(MdnsReaderTest,ReadNsecRecordRdata)410*3f982cf4SFabien Sanglard TEST(MdnsReaderTest, ReadNsecRecordRdata) {
411*3f982cf4SFabien Sanglard   // clang-format off
412*3f982cf4SFabien Sanglard   constexpr uint8_t kExpectedRdata[] = {
413*3f982cf4SFabien Sanglard     0x00, 0x20,  // RDLENGTH = 32
414*3f982cf4SFabien Sanglard     0x08, 'm', 'y', 'd', 'e', 'v', 'i', 'c', 'e',
415*3f982cf4SFabien Sanglard     0x07, 't', 'e', 's', 't', 'i', 'n', 'g',
416*3f982cf4SFabien Sanglard     0x05, 'l', 'o', 'c', 'a',  'l',
417*3f982cf4SFabien Sanglard     0x00,
418*3f982cf4SFabien Sanglard     // It takes 8 bytes to encode the kA and kSRV records because:
419*3f982cf4SFabien Sanglard     // - Both record types have value less than 256, so they are both in window
420*3f982cf4SFabien Sanglard     //   block 1.
421*3f982cf4SFabien Sanglard     // - The bitmap length for this block is always a single byte
422*3f982cf4SFabien Sanglard     // - DnsTypes have the following values:
423*3f982cf4SFabien Sanglard     //   - kA = 1 (encoded in byte 1)
424*3f982cf4SFabien Sanglard     //     kTXT = 16 (encoded in byte 3)
425*3f982cf4SFabien Sanglard     //   - kSRV = 33 (encoded in byte 5)
426*3f982cf4SFabien Sanglard     //   - kNSEC = 47 (encoded in 6 bytes)
427*3f982cf4SFabien Sanglard     // - The largest of these is 47, so 6 bytes are needed to encode this data.
428*3f982cf4SFabien Sanglard     // So the full encoded version is:
429*3f982cf4SFabien Sanglard     //   00000000 00000110 01000000 00000000 10000000 00000000 0100000  00000001
430*3f982cf4SFabien Sanglard     //   |window| | size | | 0-7  | | 8-15 | |16-23 | |24-31 | |32-39 | |40-47 |
431*3f982cf4SFabien Sanglard           0x00,    0x06,    0x40,    0x00,    0x80,    0x00,    0x40,    0x01
432*3f982cf4SFabien Sanglard   };
433*3f982cf4SFabien Sanglard   // clang-format on
434*3f982cf4SFabien Sanglard   TestReadEntrySucceeds(
435*3f982cf4SFabien Sanglard       kExpectedRdata, sizeof(kExpectedRdata),
436*3f982cf4SFabien Sanglard       NsecRecordRdata(DomainName{"mydevice", "testing", "local"}, DnsType::kA,
437*3f982cf4SFabien Sanglard                       DnsType::kTXT, DnsType::kSRV, DnsType::kNSEC));
438*3f982cf4SFabien Sanglard }
439*3f982cf4SFabien Sanglard 
TEST(MdnsReaderTest,ReadNsecRecordRdata_TooShort)440*3f982cf4SFabien Sanglard TEST(MdnsReaderTest, ReadNsecRecordRdata_TooShort) {
441*3f982cf4SFabien Sanglard   // clang-format off
442*3f982cf4SFabien Sanglard   constexpr uint8_t kNsecRecordRdata[] = {
443*3f982cf4SFabien Sanglard     0x00, 0x20,  // RDLENGTH = 32
444*3f982cf4SFabien Sanglard     0x08, 'm', 'y', 'd', 'e', 'v', 'i', 'c', 'e',
445*3f982cf4SFabien Sanglard     0x07, 't', 'e', 's', 't', 'i', 'n', 'g',
446*3f982cf4SFabien Sanglard     0x05, 'l', 'o', 'c', 'a',  'l',
447*3f982cf4SFabien Sanglard     0x00,
448*3f982cf4SFabien Sanglard     0x00, 0x06, 0x40, 0x00
449*3f982cf4SFabien Sanglard   };
450*3f982cf4SFabien Sanglard   // clang-format on
451*3f982cf4SFabien Sanglard   TestReadEntryFails<NsecRecordRdata>(kNsecRecordRdata,
452*3f982cf4SFabien Sanglard                                       sizeof(kNsecRecordRdata));
453*3f982cf4SFabien Sanglard }
454*3f982cf4SFabien Sanglard 
TEST(MdnsReaderTest,ReadNsecRecordRdata_WrongLength)455*3f982cf4SFabien Sanglard TEST(MdnsReaderTest, ReadNsecRecordRdata_WrongLength) {
456*3f982cf4SFabien Sanglard   // clang-format off
457*3f982cf4SFabien Sanglard   constexpr uint8_t kNsecRecordRdata[] = {
458*3f982cf4SFabien Sanglard     0x00, 0x21,  // RDLENGTH = 33
459*3f982cf4SFabien Sanglard     0x08, 'm', 'y', 'd', 'e', 'v', 'i', 'c', 'e',
460*3f982cf4SFabien Sanglard     0x07, 't', 'e', 's', 't', 'i', 'n', 'g',
461*3f982cf4SFabien Sanglard     0x05, 'l', 'o', 'c', 'a',  'l',
462*3f982cf4SFabien Sanglard     0x00,
463*3f982cf4SFabien Sanglard     0x00, 0x06, 0x40, 0x00, 0x80, 0x00, 0x40, 0x01
464*3f982cf4SFabien Sanglard   };
465*3f982cf4SFabien Sanglard   // clang-format on
466*3f982cf4SFabien Sanglard   TestReadEntryFails<NsecRecordRdata>(kNsecRecordRdata,
467*3f982cf4SFabien Sanglard                                       sizeof(kNsecRecordRdata));
468*3f982cf4SFabien Sanglard }
469*3f982cf4SFabien Sanglard 
TEST(MdnsReaderTest,ReadMdnsRecord_ARecordRdata)470*3f982cf4SFabien Sanglard TEST(MdnsReaderTest, ReadMdnsRecord_ARecordRdata) {
471*3f982cf4SFabien Sanglard   // clang-format off
472*3f982cf4SFabien Sanglard   constexpr uint8_t kTestRecord[] = {
473*3f982cf4SFabien Sanglard       0x07, 't', 'e', 's', 't', 'i', 'n', 'g',
474*3f982cf4SFabien Sanglard       0x05, 'l', 'o', 'c', 'a', 'l',
475*3f982cf4SFabien Sanglard       0x00,
476*3f982cf4SFabien Sanglard       0x00, 0x01,              // TYPE = A (1)
477*3f982cf4SFabien Sanglard       0x80, 0x01,              // CLASS = IN (1) | CACHE_FLUSH_BIT
478*3f982cf4SFabien Sanglard       0x00, 0x00, 0x00, 0x78,  // TTL = 120 seconds
479*3f982cf4SFabien Sanglard       0x00, 0x04,              // RDLENGTH = 4 bytes
480*3f982cf4SFabien Sanglard       0x08, 0x08, 0x08, 0x08,  // RDATA = 8.8.8.8
481*3f982cf4SFabien Sanglard   };
482*3f982cf4SFabien Sanglard   // clang-format on
483*3f982cf4SFabien Sanglard   TestReadEntrySucceeds(kTestRecord, sizeof(kTestRecord),
484*3f982cf4SFabien Sanglard                         MdnsRecord(DomainName{"testing", "local"}, DnsType::kA,
485*3f982cf4SFabien Sanglard                                    DnsClass::kIN, RecordType::kUnique, kTtl,
486*3f982cf4SFabien Sanglard                                    ARecordRdata(IPAddress{8, 8, 8, 8})));
487*3f982cf4SFabien Sanglard }
488*3f982cf4SFabien Sanglard 
TEST(MdnsReaderTest,ReadMdnsRecord_UnknownRecordType)489*3f982cf4SFabien Sanglard TEST(MdnsReaderTest, ReadMdnsRecord_UnknownRecordType) {
490*3f982cf4SFabien Sanglard   // clang-format off
491*3f982cf4SFabien Sanglard   constexpr uint8_t kTestRecord[] = {
492*3f982cf4SFabien Sanglard       0x07, 't', 'e', 's', 't', 'i', 'n', 'g',
493*3f982cf4SFabien Sanglard       0x05, 'l', 'o', 'c', 'a', 'l',
494*3f982cf4SFabien Sanglard       0x00,
495*3f982cf4SFabien Sanglard       0x00, 0x05,              // TYPE = CNAME (5)
496*3f982cf4SFabien Sanglard       0x80, 0x01,              // CLASS = IN (1) | CACHE_FLUSH_BIT
497*3f982cf4SFabien Sanglard       0x00, 0x00, 0x00, 0x78,  // TTL = 120 seconds
498*3f982cf4SFabien Sanglard       0x00, 0x08,              // RDLENGTH = 8 bytes
499*3f982cf4SFabien Sanglard       0x05, 'c', 'n', 'a', 'm', 'e', 0xc0, 0x00,
500*3f982cf4SFabien Sanglard   };
501*3f982cf4SFabien Sanglard   constexpr uint8_t kCnameRdata[] = {
502*3f982cf4SFabien Sanglard       0x05, 'c', 'n', 'a', 'm', 'e', 0xc0, 0x00,
503*3f982cf4SFabien Sanglard   };
504*3f982cf4SFabien Sanglard   // clang-format on
505*3f982cf4SFabien Sanglard   TestReadEntrySucceeds(
506*3f982cf4SFabien Sanglard       kTestRecord, sizeof(kTestRecord),
507*3f982cf4SFabien Sanglard       MdnsRecord(DomainName{"testing", "local"},
508*3f982cf4SFabien Sanglard                  static_cast<DnsType>(5) /*CNAME class*/, DnsClass::kIN,
509*3f982cf4SFabien Sanglard                  RecordType::kUnique, kTtl,
510*3f982cf4SFabien Sanglard                  RawRecordRdata(kCnameRdata, sizeof(kCnameRdata))));
511*3f982cf4SFabien Sanglard }
512*3f982cf4SFabien Sanglard 
TEST(MdnsReaderTest,ReadMdnsRecord_CompressedNames)513*3f982cf4SFabien Sanglard TEST(MdnsReaderTest, ReadMdnsRecord_CompressedNames) {
514*3f982cf4SFabien Sanglard   // clang-format off
515*3f982cf4SFabien Sanglard   constexpr uint8_t kTestRecord[] = {
516*3f982cf4SFabien Sanglard       // First message
517*3f982cf4SFabien Sanglard       0x07, 't', 'e', 's', 't', 'i', 'n', 'g',
518*3f982cf4SFabien Sanglard       0x05, 'l', 'o', 'c', 'a', 'l',
519*3f982cf4SFabien Sanglard       0x00,
520*3f982cf4SFabien Sanglard       0x00, 0x0c,              // TYPE = PTR (12)
521*3f982cf4SFabien Sanglard       0x00, 0x01,              // CLASS = IN (1)
522*3f982cf4SFabien Sanglard       0x00, 0x00, 0x00, 0x78,  // TTL = 120 seconds
523*3f982cf4SFabien Sanglard       0x00, 0x06,              // RDLENGTH = 6 bytes
524*3f982cf4SFabien Sanglard       0x03, 'p',  't',  'r',
525*3f982cf4SFabien Sanglard       0xc0, 0x00,              // Domain name label pointer to byte 0
526*3f982cf4SFabien Sanglard       // Second message
527*3f982cf4SFabien Sanglard       0x03, 'o', 'n', 'e',
528*3f982cf4SFabien Sanglard       0x03, 't', 'w', 'o',
529*3f982cf4SFabien Sanglard       0xc0, 0x00,              // Domain name label pointer to byte 0
530*3f982cf4SFabien Sanglard       0x00, 0x01,              // TYPE = A (1)
531*3f982cf4SFabien Sanglard       0x80, 0x01,              // CLASS = IN (1) | CACHE_FLUSH_BIT
532*3f982cf4SFabien Sanglard       0x00, 0x00, 0x00, 0x78,  // TTL = 120 seconds
533*3f982cf4SFabien Sanglard       0x00, 0x04,              // RDLENGTH = 4 bytes
534*3f982cf4SFabien Sanglard       0x08, 0x08, 0x08, 0x08,  // RDATA = 8.8.8.8
535*3f982cf4SFabien Sanglard   };
536*3f982cf4SFabien Sanglard   // clang-format on
537*3f982cf4SFabien Sanglard   Config config;
538*3f982cf4SFabien Sanglard   MdnsReader reader(config, kTestRecord, sizeof(kTestRecord));
539*3f982cf4SFabien Sanglard 
540*3f982cf4SFabien Sanglard   MdnsRecord record;
541*3f982cf4SFabien Sanglard   EXPECT_TRUE(reader.Read(&record));
542*3f982cf4SFabien Sanglard   EXPECT_EQ(record,
543*3f982cf4SFabien Sanglard             MdnsRecord(DomainName{"testing", "local"}, DnsType::kPTR,
544*3f982cf4SFabien Sanglard                        DnsClass::kIN, RecordType::kShared, kTtl,
545*3f982cf4SFabien Sanglard                        PtrRecordRdata(DomainName{"ptr", "testing", "local"})));
546*3f982cf4SFabien Sanglard   EXPECT_TRUE(reader.Read(&record));
547*3f982cf4SFabien Sanglard   EXPECT_EQ(record, MdnsRecord(DomainName{"one", "two", "testing", "local"},
548*3f982cf4SFabien Sanglard                                DnsType::kA, DnsClass::kIN, RecordType::kUnique,
549*3f982cf4SFabien Sanglard                                kTtl, ARecordRdata(IPAddress{8, 8, 8, 8})));
550*3f982cf4SFabien Sanglard }
551*3f982cf4SFabien Sanglard 
TEST(MdnsReaderTest,ReadMdnsRecord_MissingRdata)552*3f982cf4SFabien Sanglard TEST(MdnsReaderTest, ReadMdnsRecord_MissingRdata) {
553*3f982cf4SFabien Sanglard   // clang-format off
554*3f982cf4SFabien Sanglard   constexpr uint8_t kTestRecord[] = {
555*3f982cf4SFabien Sanglard       0x05, 'l', 'o', 'c', 'a', 'l',
556*3f982cf4SFabien Sanglard       0x00,
557*3f982cf4SFabien Sanglard       0x00, 0x01,              // TYPE = A (1)
558*3f982cf4SFabien Sanglard       0x00, 0x01,              // CLASS = IN (1)
559*3f982cf4SFabien Sanglard       0x00, 0x00, 0x00, 0x78,  // TTL = 120 seconds
560*3f982cf4SFabien Sanglard       0x00, 0x04,              // RDLENGTH = 4 bytes
561*3f982cf4SFabien Sanglard                                // Missing RDATA
562*3f982cf4SFabien Sanglard   };
563*3f982cf4SFabien Sanglard   // clang-format on
564*3f982cf4SFabien Sanglard   TestReadEntryFails<MdnsRecord>(kTestRecord, sizeof(kTestRecord));
565*3f982cf4SFabien Sanglard }
566*3f982cf4SFabien Sanglard 
TEST(MdnsReaderTest,ReadMdnsRecord_InvalidHostName)567*3f982cf4SFabien Sanglard TEST(MdnsReaderTest, ReadMdnsRecord_InvalidHostName) {
568*3f982cf4SFabien Sanglard   // clang-format off
569*3f982cf4SFabien Sanglard   constexpr uint8_t kTestRecord[] = {
570*3f982cf4SFabien Sanglard       // Invalid NAME: length byte too short
571*3f982cf4SFabien Sanglard       0x03, 'i', 'n', 'v', 'a', 'l', 'i', 'd',
572*3f982cf4SFabien Sanglard       0x00,
573*3f982cf4SFabien Sanglard       0x00, 0x01,              // TYPE = A (1)
574*3f982cf4SFabien Sanglard       0x00, 0x01,              // CLASS = IN (1)
575*3f982cf4SFabien Sanglard       0x00, 0x00, 0x00, 0x78,  // TTL = 120 seconds
576*3f982cf4SFabien Sanglard       0x00, 0x04,              // RDLENGTH = 4 bytes
577*3f982cf4SFabien Sanglard       0x08, 0x08, 0x08, 0x08,  // RDATA = 8.8.8.8
578*3f982cf4SFabien Sanglard   };
579*3f982cf4SFabien Sanglard   // clang-format on
580*3f982cf4SFabien Sanglard   TestReadEntryFails<MdnsRecord>(kTestRecord, sizeof(kTestRecord));
581*3f982cf4SFabien Sanglard }
582*3f982cf4SFabien Sanglard 
TEST(MdnsReaderTest,ReadMdnsQuestion)583*3f982cf4SFabien Sanglard TEST(MdnsReaderTest, ReadMdnsQuestion) {
584*3f982cf4SFabien Sanglard   // clang-format off
585*3f982cf4SFabien Sanglard   constexpr uint8_t kTestQuestion[] = {
586*3f982cf4SFabien Sanglard       0x07, 't', 'e', 's', 't', 'i', 'n', 'g',
587*3f982cf4SFabien Sanglard       0x05, 'l', 'o', 'c', 'a', 'l',
588*3f982cf4SFabien Sanglard       0x00,
589*3f982cf4SFabien Sanglard       0x00, 0x01,  // TYPE = A (1)
590*3f982cf4SFabien Sanglard       0x80, 0x01,  // CLASS = IN (1) | UNICAST_BIT
591*3f982cf4SFabien Sanglard   };
592*3f982cf4SFabien Sanglard   // clang-format on
593*3f982cf4SFabien Sanglard   TestReadEntrySucceeds(
594*3f982cf4SFabien Sanglard       kTestQuestion, sizeof(kTestQuestion),
595*3f982cf4SFabien Sanglard       MdnsQuestion(DomainName{"testing", "local"}, DnsType::kA, DnsClass::kIN,
596*3f982cf4SFabien Sanglard                    ResponseType::kUnicast));
597*3f982cf4SFabien Sanglard }
598*3f982cf4SFabien Sanglard 
TEST(MdnsReaderTest,ReadMdnsQuestion_CompressedNames)599*3f982cf4SFabien Sanglard TEST(MdnsReaderTest, ReadMdnsQuestion_CompressedNames) {
600*3f982cf4SFabien Sanglard   // clang-format off
601*3f982cf4SFabien Sanglard   constexpr uint8_t kTestQuestions[] = {
602*3f982cf4SFabien Sanglard       // First Question
603*3f982cf4SFabien Sanglard       0x05, 'f', 'i', 'r', 's', 't',
604*3f982cf4SFabien Sanglard       0x05, 'l', 'o', 'c', 'a', 'l',
605*3f982cf4SFabien Sanglard       0x00,
606*3f982cf4SFabien Sanglard       0x00, 0x01,  // TYPE = A (1)
607*3f982cf4SFabien Sanglard       0x80, 0x01,  // CLASS = IN (1) | UNICAST_BIT
608*3f982cf4SFabien Sanglard       // Second Question
609*3f982cf4SFabien Sanglard       0x06, 's', 'e', 'c', 'o', 'n', 'd',
610*3f982cf4SFabien Sanglard       0xc0, 0x06,  // Domain name label pointer
611*3f982cf4SFabien Sanglard       0x00, 0x0c,  // TYPE = PTR (12)
612*3f982cf4SFabien Sanglard       0x00, 0x01,  // CLASS = IN (1)
613*3f982cf4SFabien Sanglard   };
614*3f982cf4SFabien Sanglard   // clang-format on
615*3f982cf4SFabien Sanglard   Config config;
616*3f982cf4SFabien Sanglard   MdnsReader reader(config, kTestQuestions, sizeof(kTestQuestions));
617*3f982cf4SFabien Sanglard   MdnsQuestion question;
618*3f982cf4SFabien Sanglard   EXPECT_TRUE(reader.Read(&question));
619*3f982cf4SFabien Sanglard   EXPECT_EQ(question, MdnsQuestion(DomainName{"first", "local"}, DnsType::kA,
620*3f982cf4SFabien Sanglard                                    DnsClass::kIN, ResponseType::kUnicast));
621*3f982cf4SFabien Sanglard   EXPECT_TRUE(reader.Read(&question));
622*3f982cf4SFabien Sanglard   EXPECT_EQ(question, MdnsQuestion(DomainName{"second", "local"}, DnsType::kPTR,
623*3f982cf4SFabien Sanglard                                    DnsClass::kIN, ResponseType::kMulticast));
624*3f982cf4SFabien Sanglard   EXPECT_EQ(reader.remaining(), UINT64_C(0));
625*3f982cf4SFabien Sanglard }
626*3f982cf4SFabien Sanglard 
TEST(MdnsReaderTest,ReadMdnsQuestion_InvalidHostName)627*3f982cf4SFabien Sanglard TEST(MdnsReaderTest, ReadMdnsQuestion_InvalidHostName) {
628*3f982cf4SFabien Sanglard   // clang-format off
629*3f982cf4SFabien Sanglard   constexpr uint8_t kTestQuestion[] = {
630*3f982cf4SFabien Sanglard       // Invalid NAME: length byte too short
631*3f982cf4SFabien Sanglard       0x03, 'i', 'n', 'v', 'a', 'l', 'i', 'd',
632*3f982cf4SFabien Sanglard       0x00,
633*3f982cf4SFabien Sanglard       0x00, 0x01,  // TYPE = A (1)
634*3f982cf4SFabien Sanglard       0x00, 0x01,  // CLASS = IN (1)
635*3f982cf4SFabien Sanglard   };
636*3f982cf4SFabien Sanglard   // clang-format on
637*3f982cf4SFabien Sanglard   TestReadEntryFails<MdnsQuestion>(kTestQuestion, sizeof(kTestQuestion));
638*3f982cf4SFabien Sanglard }
639*3f982cf4SFabien Sanglard 
TEST(MdnsReaderTest,ReadMdnsMessage)640*3f982cf4SFabien Sanglard TEST(MdnsReaderTest, ReadMdnsMessage) {
641*3f982cf4SFabien Sanglard   // clang-format off
642*3f982cf4SFabien Sanglard   constexpr uint8_t kTestMessage[] = {
643*3f982cf4SFabien Sanglard       // Header
644*3f982cf4SFabien Sanglard       0x00, 0x01,  // ID = 1
645*3f982cf4SFabien Sanglard       0x84, 0x00,  // FLAGS = AA | RESPONSE
646*3f982cf4SFabien Sanglard       0x00, 0x00,  // Questions = 0
647*3f982cf4SFabien Sanglard       0x00, 0x01,  // Answers = 1
648*3f982cf4SFabien Sanglard       0x00, 0x00,  // Authority = 0
649*3f982cf4SFabien Sanglard       0x00, 0x01,  // Additional = 1
650*3f982cf4SFabien Sanglard       // Record 1
651*3f982cf4SFabien Sanglard       0x07, 'r', 'e', 'c', 'o', 'r', 'd', '1',
652*3f982cf4SFabien Sanglard       0x00,
653*3f982cf4SFabien Sanglard       0x00, 0x0c,              // TYPE = PTR (12)
654*3f982cf4SFabien Sanglard       0x00, 0x01,              // CLASS = IN (1)
655*3f982cf4SFabien Sanglard       0x00, 0x00, 0x00, 0x78,  // TTL = 120 seconds
656*3f982cf4SFabien Sanglard       0x00, 0x0f,              // RDLENGTH = 15 bytes
657*3f982cf4SFabien Sanglard       0x07, 't', 'e', 's', 't', 'i', 'n', 'g',
658*3f982cf4SFabien Sanglard       0x05, 'l', 'o', 'c', 'a', 'l',
659*3f982cf4SFabien Sanglard       0x00,
660*3f982cf4SFabien Sanglard       // Record 2
661*3f982cf4SFabien Sanglard       0x07, 'r', 'e', 'c', 'o', 'r', 'd', '2',
662*3f982cf4SFabien Sanglard       0x00,
663*3f982cf4SFabien Sanglard       0x00, 0x01,              // TYPE = A (1)
664*3f982cf4SFabien Sanglard       0x00, 0x01,              // CLASS = IN (1)
665*3f982cf4SFabien Sanglard       0x00, 0x00, 0x00, 0x78,  // TTL = 120 seconds
666*3f982cf4SFabien Sanglard       0x00, 0x04,              // RDLENGTH = 4 bytes
667*3f982cf4SFabien Sanglard       0xac, 0x00, 0x00, 0x01,  // 172.0.0.1
668*3f982cf4SFabien Sanglard   };
669*3f982cf4SFabien Sanglard   // clang-format on
670*3f982cf4SFabien Sanglard 
671*3f982cf4SFabien Sanglard   MdnsRecord record1(DomainName{"record1"}, DnsType::kPTR, DnsClass::kIN,
672*3f982cf4SFabien Sanglard                      RecordType::kShared, kTtl,
673*3f982cf4SFabien Sanglard                      PtrRecordRdata(DomainName{"testing", "local"}));
674*3f982cf4SFabien Sanglard   MdnsRecord record2(DomainName{"record2"}, DnsType::kA, DnsClass::kIN,
675*3f982cf4SFabien Sanglard                      RecordType::kShared, kTtl,
676*3f982cf4SFabien Sanglard                      ARecordRdata(IPAddress{172, 0, 0, 1}));
677*3f982cf4SFabien Sanglard   MdnsMessage message(1, MessageType::Response, std::vector<MdnsQuestion>{},
678*3f982cf4SFabien Sanglard                       std::vector<MdnsRecord>{record1},
679*3f982cf4SFabien Sanglard                       std::vector<MdnsRecord>{},
680*3f982cf4SFabien Sanglard                       std::vector<MdnsRecord>{record2});
681*3f982cf4SFabien Sanglard   TestReadEntrySucceeds(kTestMessage, sizeof(kTestMessage), message);
682*3f982cf4SFabien Sanglard }
683*3f982cf4SFabien Sanglard 
TEST(MdnsReaderTest,ReadMdnsMessage_MissingAnswerRecord)684*3f982cf4SFabien Sanglard TEST(MdnsReaderTest, ReadMdnsMessage_MissingAnswerRecord) {
685*3f982cf4SFabien Sanglard   // clang-format off
686*3f982cf4SFabien Sanglard   constexpr uint8_t kInvalidMessage[] = {
687*3f982cf4SFabien Sanglard       0x00, 0x00,  // ID = 0
688*3f982cf4SFabien Sanglard       0x00, 0x00,  // FLAGS = 0
689*3f982cf4SFabien Sanglard       0x00, 0x01,  // Questions = 1
690*3f982cf4SFabien Sanglard       0x00, 0x01,  // Answers = 1
691*3f982cf4SFabien Sanglard       0x00, 0x00,  // Authority = 0
692*3f982cf4SFabien Sanglard       0x00, 0x00,  // Additional = 0
693*3f982cf4SFabien Sanglard       0x07, 't', 'e', 's', 't', 'i', 'n', 'g',
694*3f982cf4SFabien Sanglard       0x05, 'l', 'o', 'c', 'a', 'l',
695*3f982cf4SFabien Sanglard       0x00,
696*3f982cf4SFabien Sanglard       0x00, 0x0c,  // TYPE = PTR (12)
697*3f982cf4SFabien Sanglard       0x00, 0x01,  // CLASS = IN (1)
698*3f982cf4SFabien Sanglard       // NOTE: Missing answer record
699*3f982cf4SFabien Sanglard   };
700*3f982cf4SFabien Sanglard   // clang-format on
701*3f982cf4SFabien Sanglard   TestReadEntryFails<MdnsMessage>(kInvalidMessage, sizeof(kInvalidMessage));
702*3f982cf4SFabien Sanglard }
703*3f982cf4SFabien Sanglard 
TEST(MdnsReaderTest,ReadMdnsMessage_MissingAdditionalRecord)704*3f982cf4SFabien Sanglard TEST(MdnsReaderTest, ReadMdnsMessage_MissingAdditionalRecord) {
705*3f982cf4SFabien Sanglard   // clang-format off
706*3f982cf4SFabien Sanglard   constexpr uint8_t kInvalidMessage[] = {
707*3f982cf4SFabien Sanglard       0x00, 0x00,  // ID = 0
708*3f982cf4SFabien Sanglard       0x00, 0x00,  // FLAGS = 0
709*3f982cf4SFabien Sanglard       0x00, 0x00,  // Questions = 0
710*3f982cf4SFabien Sanglard       0x00, 0x00,  // Answers = 0
711*3f982cf4SFabien Sanglard       0x00, 0x00,  // Authority = 0
712*3f982cf4SFabien Sanglard       0x00, 0x02,  // Additional = 2
713*3f982cf4SFabien Sanglard       0x07, 't', 'e', 's', 't', 'i', 'n', 'g',
714*3f982cf4SFabien Sanglard       0x05, 'l', 'o', 'c', 'a', 'l',
715*3f982cf4SFabien Sanglard       0x00,
716*3f982cf4SFabien Sanglard       0x00, 0x0c,              // TYPE = PTR (12)
717*3f982cf4SFabien Sanglard       0x00, 0x01,              // CLASS = IN (1)
718*3f982cf4SFabien Sanglard       0x00, 0x00, 0x00, 0x78,  // TTL = 120 seconds
719*3f982cf4SFabien Sanglard       0x00, 0x00,              // RDLENGTH = 0
720*3f982cf4SFabien Sanglard       // NOTE: Only 1 answer record is given.
721*3f982cf4SFabien Sanglard   };
722*3f982cf4SFabien Sanglard   // clang-format on
723*3f982cf4SFabien Sanglard   TestReadEntryFails<MdnsMessage>(kInvalidMessage, sizeof(kInvalidMessage));
724*3f982cf4SFabien Sanglard }
725*3f982cf4SFabien Sanglard 
726*3f982cf4SFabien Sanglard }  // namespace discovery
727*3f982cf4SFabien Sanglard }  // namespace openscreen
728