xref: /aosp_15_r20/external/cronet/net/dns/dns_response_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2012 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #include "net/dns/dns_response.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include <algorithm>
8*6777b538SAndroid Build Coastguard Worker #include <memory>
9*6777b538SAndroid Build Coastguard Worker #include <optional>
10*6777b538SAndroid Build Coastguard Worker #include <string>
11*6777b538SAndroid Build Coastguard Worker #include <string_view>
12*6777b538SAndroid Build Coastguard Worker #include <vector>
13*6777b538SAndroid Build Coastguard Worker 
14*6777b538SAndroid Build Coastguard Worker #include "base/check.h"
15*6777b538SAndroid Build Coastguard Worker #include "base/containers/span.h"
16*6777b538SAndroid Build Coastguard Worker #include "base/containers/span_writer.h"
17*6777b538SAndroid Build Coastguard Worker #include "base/time/time.h"
18*6777b538SAndroid Build Coastguard Worker #include "net/base/io_buffer.h"
19*6777b538SAndroid Build Coastguard Worker #include "net/dns/dns_names_util.h"
20*6777b538SAndroid Build Coastguard Worker #include "net/dns/dns_query.h"
21*6777b538SAndroid Build Coastguard Worker #include "net/dns/dns_test_util.h"
22*6777b538SAndroid Build Coastguard Worker #include "net/dns/public/dns_protocol.h"
23*6777b538SAndroid Build Coastguard Worker #include "net/dns/record_rdata.h"
24*6777b538SAndroid Build Coastguard Worker #include "testing/gmock/include/gmock/gmock.h"
25*6777b538SAndroid Build Coastguard Worker #include "testing/gtest/include/gtest/gtest.h"
26*6777b538SAndroid Build Coastguard Worker 
27*6777b538SAndroid Build Coastguard Worker namespace net {
28*6777b538SAndroid Build Coastguard Worker 
29*6777b538SAndroid Build Coastguard Worker namespace {
30*6777b538SAndroid Build Coastguard Worker 
TEST(DnsRecordParserTest,Constructor)31*6777b538SAndroid Build Coastguard Worker TEST(DnsRecordParserTest, Constructor) {
32*6777b538SAndroid Build Coastguard Worker   const char data[] = { 0 };
33*6777b538SAndroid Build Coastguard Worker 
34*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(DnsRecordParser().IsValid());
35*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(DnsRecordParser(data, 1, 0, 0).IsValid());
36*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(DnsRecordParser(data, 1, 1, 0).IsValid());
37*6777b538SAndroid Build Coastguard Worker 
38*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(DnsRecordParser(data, 1, 0, 0).AtEnd());
39*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(DnsRecordParser(data, 1, 1, 0).AtEnd());
40*6777b538SAndroid Build Coastguard Worker }
41*6777b538SAndroid Build Coastguard Worker 
TEST(DnsRecordParserTest,ReadName)42*6777b538SAndroid Build Coastguard Worker TEST(DnsRecordParserTest, ReadName) {
43*6777b538SAndroid Build Coastguard Worker   const uint8_t data[] = {
44*6777b538SAndroid Build Coastguard Worker       // all labels "foo.example.com"
45*6777b538SAndroid Build Coastguard Worker       0x03, 'f', 'o', 'o', 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0x03, 'c',
46*6777b538SAndroid Build Coastguard Worker       'o', 'm',
47*6777b538SAndroid Build Coastguard Worker       // byte 0x10
48*6777b538SAndroid Build Coastguard Worker       0x00,
49*6777b538SAndroid Build Coastguard Worker       // byte 0x11
50*6777b538SAndroid Build Coastguard Worker       // part label, part pointer, "bar.example.com"
51*6777b538SAndroid Build Coastguard Worker       0x03, 'b', 'a', 'r', 0xc0, 0x04,
52*6777b538SAndroid Build Coastguard Worker       // byte 0x17
53*6777b538SAndroid Build Coastguard Worker       // all pointer to "bar.example.com", 2 jumps
54*6777b538SAndroid Build Coastguard Worker       0xc0, 0x11,
55*6777b538SAndroid Build Coastguard Worker       // byte 0x1a
56*6777b538SAndroid Build Coastguard Worker   };
57*6777b538SAndroid Build Coastguard Worker 
58*6777b538SAndroid Build Coastguard Worker   std::string out;
59*6777b538SAndroid Build Coastguard Worker   DnsRecordParser parser(data, sizeof(data), 0, /*num_records=*/0);
60*6777b538SAndroid Build Coastguard Worker   ASSERT_TRUE(parser.IsValid());
61*6777b538SAndroid Build Coastguard Worker 
62*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(0x11u, parser.ReadName(data + 0x00, &out));
63*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ("foo.example.com", out);
64*6777b538SAndroid Build Coastguard Worker   // Check that the last "." is never stored.
65*6777b538SAndroid Build Coastguard Worker   out.clear();
66*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(0x1u, parser.ReadName(data + 0x10, &out));
67*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ("", out);
68*6777b538SAndroid Build Coastguard Worker   out.clear();
69*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(0x6u, parser.ReadName(data + 0x11, &out));
70*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ("bar.example.com", out);
71*6777b538SAndroid Build Coastguard Worker   out.clear();
72*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(0x2u, parser.ReadName(data + 0x17, &out));
73*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ("bar.example.com", out);
74*6777b538SAndroid Build Coastguard Worker 
75*6777b538SAndroid Build Coastguard Worker   // Parse name without storing it.
76*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(0x11u, parser.ReadName(data + 0x00, nullptr));
77*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(0x1u, parser.ReadName(data + 0x10, nullptr));
78*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(0x6u, parser.ReadName(data + 0x11, nullptr));
79*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(0x2u, parser.ReadName(data + 0x17, nullptr));
80*6777b538SAndroid Build Coastguard Worker 
81*6777b538SAndroid Build Coastguard Worker   // Check that it works even if initial position is different.
82*6777b538SAndroid Build Coastguard Worker   parser = DnsRecordParser(data, sizeof(data), 0x12, /*num_records=*/0);
83*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(0x6u, parser.ReadName(data + 0x11, nullptr));
84*6777b538SAndroid Build Coastguard Worker }
85*6777b538SAndroid Build Coastguard Worker 
TEST(DnsRecordParserTest,ReadNameFail)86*6777b538SAndroid Build Coastguard Worker TEST(DnsRecordParserTest, ReadNameFail) {
87*6777b538SAndroid Build Coastguard Worker   const uint8_t data[] = {
88*6777b538SAndroid Build Coastguard Worker       // label length beyond packet
89*6777b538SAndroid Build Coastguard Worker       0x30, 'x', 'x', 0x00,
90*6777b538SAndroid Build Coastguard Worker       // pointer offset beyond packet
91*6777b538SAndroid Build Coastguard Worker       0xc0, 0x20,
92*6777b538SAndroid Build Coastguard Worker       // pointer loop
93*6777b538SAndroid Build Coastguard Worker       0xc0, 0x08, 0xc0, 0x06,
94*6777b538SAndroid Build Coastguard Worker       // incorrect label type (currently supports only direct and pointer)
95*6777b538SAndroid Build Coastguard Worker       0x80, 0x00,
96*6777b538SAndroid Build Coastguard Worker       // truncated name (missing root label)
97*6777b538SAndroid Build Coastguard Worker       0x02, 'x', 'x',
98*6777b538SAndroid Build Coastguard Worker   };
99*6777b538SAndroid Build Coastguard Worker 
100*6777b538SAndroid Build Coastguard Worker   DnsRecordParser parser(data, sizeof(data), 0, /*num_records=*/0);
101*6777b538SAndroid Build Coastguard Worker   ASSERT_TRUE(parser.IsValid());
102*6777b538SAndroid Build Coastguard Worker 
103*6777b538SAndroid Build Coastguard Worker   std::string out;
104*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(0u, parser.ReadName(data + 0x00, &out));
105*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(0u, parser.ReadName(data + 0x04, &out));
106*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(0u, parser.ReadName(data + 0x08, &out));
107*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(0u, parser.ReadName(data + 0x0a, &out));
108*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(0u, parser.ReadName(data + 0x0c, &out));
109*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(0u, parser.ReadName(data + 0x0e, &out));
110*6777b538SAndroid Build Coastguard Worker }
111*6777b538SAndroid Build Coastguard Worker 
112*6777b538SAndroid Build Coastguard Worker // Returns an RFC 1034 style domain name with a length of |name_len|.
113*6777b538SAndroid Build Coastguard Worker // Also writes the expected dotted string representation into |dotted_str|,
114*6777b538SAndroid Build Coastguard Worker // which must be non-null.
BuildRfc1034Name(const size_t name_len,std::string * dotted_str)115*6777b538SAndroid Build Coastguard Worker std::vector<uint8_t> BuildRfc1034Name(const size_t name_len,
116*6777b538SAndroid Build Coastguard Worker                                       std::string* dotted_str) {
117*6777b538SAndroid Build Coastguard Worker   // Impossible length. If length not zero, need at least 2 to allow label
118*6777b538SAndroid Build Coastguard Worker   // length and label contents.
119*6777b538SAndroid Build Coastguard Worker   CHECK_NE(name_len, 1u);
120*6777b538SAndroid Build Coastguard Worker 
121*6777b538SAndroid Build Coastguard Worker   CHECK(dotted_str != nullptr);
122*6777b538SAndroid Build Coastguard Worker   auto ChoosePrintableCharLambda = [](uint8_t n) { return n % 26 + 'A'; };
123*6777b538SAndroid Build Coastguard Worker   const size_t max_label_len = 63;
124*6777b538SAndroid Build Coastguard Worker   std::vector<uint8_t> data;
125*6777b538SAndroid Build Coastguard Worker 
126*6777b538SAndroid Build Coastguard Worker   dotted_str->clear();
127*6777b538SAndroid Build Coastguard Worker   while (data.size() < name_len) {
128*6777b538SAndroid Build Coastguard Worker     // Compute the size of the next label.
129*6777b538SAndroid Build Coastguard Worker     //
130*6777b538SAndroid Build Coastguard Worker     // No need to account for next label length because the final zero length is
131*6777b538SAndroid Build Coastguard Worker     // not considered included in overall length.
132*6777b538SAndroid Build Coastguard Worker     size_t label_len = std::min(name_len - data.size() - 1, max_label_len);
133*6777b538SAndroid Build Coastguard Worker     // Need to ensure the remainder is not 1 because that would leave room for a
134*6777b538SAndroid Build Coastguard Worker     // label length but not a label.
135*6777b538SAndroid Build Coastguard Worker     if (name_len - data.size() - label_len - 1 == 1) {
136*6777b538SAndroid Build Coastguard Worker       CHECK_GT(label_len, 1u);
137*6777b538SAndroid Build Coastguard Worker       label_len -= 1;
138*6777b538SAndroid Build Coastguard Worker     }
139*6777b538SAndroid Build Coastguard Worker 
140*6777b538SAndroid Build Coastguard Worker     // Write the length octet
141*6777b538SAndroid Build Coastguard Worker     data.push_back(label_len);
142*6777b538SAndroid Build Coastguard Worker 
143*6777b538SAndroid Build Coastguard Worker     // Write |label_len| bytes of label data
144*6777b538SAndroid Build Coastguard Worker     const size_t size_with_label = data.size() + label_len;
145*6777b538SAndroid Build Coastguard Worker     while (data.size() < size_with_label) {
146*6777b538SAndroid Build Coastguard Worker       const uint8_t chr = ChoosePrintableCharLambda(data.size());
147*6777b538SAndroid Build Coastguard Worker       data.push_back(chr);
148*6777b538SAndroid Build Coastguard Worker       dotted_str->push_back(chr);
149*6777b538SAndroid Build Coastguard Worker 
150*6777b538SAndroid Build Coastguard Worker       CHECK(data.size() <= name_len);
151*6777b538SAndroid Build Coastguard Worker     }
152*6777b538SAndroid Build Coastguard Worker 
153*6777b538SAndroid Build Coastguard Worker     // Write a trailing dot after every label
154*6777b538SAndroid Build Coastguard Worker     dotted_str->push_back('.');
155*6777b538SAndroid Build Coastguard Worker   }
156*6777b538SAndroid Build Coastguard Worker 
157*6777b538SAndroid Build Coastguard Worker   // Omit the final dot
158*6777b538SAndroid Build Coastguard Worker   if (!dotted_str->empty())
159*6777b538SAndroid Build Coastguard Worker     dotted_str->pop_back();
160*6777b538SAndroid Build Coastguard Worker 
161*6777b538SAndroid Build Coastguard Worker   CHECK(data.size() == name_len);
162*6777b538SAndroid Build Coastguard Worker 
163*6777b538SAndroid Build Coastguard Worker   // Final zero-length label (not considered included in overall length).
164*6777b538SAndroid Build Coastguard Worker   data.push_back(0);
165*6777b538SAndroid Build Coastguard Worker 
166*6777b538SAndroid Build Coastguard Worker   return data;
167*6777b538SAndroid Build Coastguard Worker }
168*6777b538SAndroid Build Coastguard Worker 
TEST(DnsRecordParserTest,ReadNameGoodLength)169*6777b538SAndroid Build Coastguard Worker TEST(DnsRecordParserTest, ReadNameGoodLength) {
170*6777b538SAndroid Build Coastguard Worker   const size_t name_len_cases[] = {2, 10, 40, 250, 254, 255};
171*6777b538SAndroid Build Coastguard Worker 
172*6777b538SAndroid Build Coastguard Worker   for (auto name_len : name_len_cases) {
173*6777b538SAndroid Build Coastguard Worker     std::string expected_name;
174*6777b538SAndroid Build Coastguard Worker     const std::vector<uint8_t> data_vector =
175*6777b538SAndroid Build Coastguard Worker         BuildRfc1034Name(name_len, &expected_name);
176*6777b538SAndroid Build Coastguard Worker     ASSERT_EQ(data_vector.size(), name_len + 1);
177*6777b538SAndroid Build Coastguard Worker     const uint8_t* data = data_vector.data();
178*6777b538SAndroid Build Coastguard Worker 
179*6777b538SAndroid Build Coastguard Worker     DnsRecordParser parser(data, data_vector.size(), 0, /*num_records=*/0);
180*6777b538SAndroid Build Coastguard Worker     ASSERT_TRUE(parser.IsValid());
181*6777b538SAndroid Build Coastguard Worker 
182*6777b538SAndroid Build Coastguard Worker     std::string out;
183*6777b538SAndroid Build Coastguard Worker     EXPECT_EQ(data_vector.size(), parser.ReadName(data, &out));
184*6777b538SAndroid Build Coastguard Worker     EXPECT_EQ(expected_name, out);
185*6777b538SAndroid Build Coastguard Worker   }
186*6777b538SAndroid Build Coastguard Worker }
187*6777b538SAndroid Build Coastguard Worker 
188*6777b538SAndroid Build Coastguard Worker // Tests against incorrect name length validation, which is anti-pattern #3 from
189*6777b538SAndroid Build Coastguard Worker // the "NAME:WRECK" report:
190*6777b538SAndroid Build Coastguard Worker // https://www.forescout.com/company/resources/namewreck-breaking-and-fixing-dns-implementations/
TEST(DnsRecordParserTest,ReadNameTooLongFail)191*6777b538SAndroid Build Coastguard Worker TEST(DnsRecordParserTest, ReadNameTooLongFail) {
192*6777b538SAndroid Build Coastguard Worker   const size_t name_len_cases[] = {256, 257, 258, 300, 10000};
193*6777b538SAndroid Build Coastguard Worker 
194*6777b538SAndroid Build Coastguard Worker   for (auto name_len : name_len_cases) {
195*6777b538SAndroid Build Coastguard Worker     std::string expected_name;
196*6777b538SAndroid Build Coastguard Worker     const std::vector<uint8_t> data_vector =
197*6777b538SAndroid Build Coastguard Worker         BuildRfc1034Name(name_len, &expected_name);
198*6777b538SAndroid Build Coastguard Worker     ASSERT_EQ(data_vector.size(), name_len + 1);
199*6777b538SAndroid Build Coastguard Worker     const uint8_t* data = data_vector.data();
200*6777b538SAndroid Build Coastguard Worker 
201*6777b538SAndroid Build Coastguard Worker     DnsRecordParser parser(data, data_vector.size(), 0, /*num_records=*/0);
202*6777b538SAndroid Build Coastguard Worker     ASSERT_TRUE(parser.IsValid());
203*6777b538SAndroid Build Coastguard Worker 
204*6777b538SAndroid Build Coastguard Worker     std::string out;
205*6777b538SAndroid Build Coastguard Worker     EXPECT_EQ(0u, parser.ReadName(data, &out));
206*6777b538SAndroid Build Coastguard Worker   }
207*6777b538SAndroid Build Coastguard Worker }
208*6777b538SAndroid Build Coastguard Worker 
209*6777b538SAndroid Build Coastguard Worker // Tests against incorrect name compression pointer validation, which is anti-
210*6777b538SAndroid Build Coastguard Worker // pattern #6 from the "NAME:WRECK" report:
211*6777b538SAndroid Build Coastguard Worker // https://www.forescout.com/company/resources/namewreck-breaking-and-fixing-dns-implementations/
TEST(DnsRecordParserTest,RejectsNamesWithLoops)212*6777b538SAndroid Build Coastguard Worker TEST(DnsRecordParserTest, RejectsNamesWithLoops) {
213*6777b538SAndroid Build Coastguard Worker   const char kData[] =
214*6777b538SAndroid Build Coastguard Worker       "\003www\007example\300\031"  // www.example with pointer to byte 25
215*6777b538SAndroid Build Coastguard Worker       "aaaaaaaaaaa"                 // Garbage data to spread things out.
216*6777b538SAndroid Build Coastguard Worker       "\003foo\300\004";            // foo with pointer to byte 4.
217*6777b538SAndroid Build Coastguard Worker 
218*6777b538SAndroid Build Coastguard Worker   DnsRecordParser parser(kData, /*length=*/sizeof(kData) - 1, /*offset=*/0,
219*6777b538SAndroid Build Coastguard Worker                          /*num_records=*/0);
220*6777b538SAndroid Build Coastguard Worker   ASSERT_TRUE(parser.IsValid());
221*6777b538SAndroid Build Coastguard Worker 
222*6777b538SAndroid Build Coastguard Worker   std::string out;
223*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(0u, parser.ReadName(kData, &out));
224*6777b538SAndroid Build Coastguard Worker }
225*6777b538SAndroid Build Coastguard Worker 
226*6777b538SAndroid Build Coastguard Worker // Tests against incorrect name compression pointer validation, which is anti-
227*6777b538SAndroid Build Coastguard Worker // pattern #6 from the "NAME:WRECK" report:
228*6777b538SAndroid Build Coastguard Worker // https://www.forescout.com/company/resources/namewreck-breaking-and-fixing-dns-implementations/
TEST(DnsRecordParserTest,RejectsNamesPointingOutsideData)229*6777b538SAndroid Build Coastguard Worker TEST(DnsRecordParserTest, RejectsNamesPointingOutsideData) {
230*6777b538SAndroid Build Coastguard Worker   const char kData[] =
231*6777b538SAndroid Build Coastguard Worker       "\003www\007example\300\031";  // www.example with pointer to byte 25
232*6777b538SAndroid Build Coastguard Worker 
233*6777b538SAndroid Build Coastguard Worker   DnsRecordParser parser(kData, /*length=*/sizeof(kData) - 1, /*offset=*/0,
234*6777b538SAndroid Build Coastguard Worker                          /*num_records=*/0);
235*6777b538SAndroid Build Coastguard Worker   ASSERT_TRUE(parser.IsValid());
236*6777b538SAndroid Build Coastguard Worker 
237*6777b538SAndroid Build Coastguard Worker   std::string out;
238*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(0u, parser.ReadName(kData, &out));
239*6777b538SAndroid Build Coastguard Worker }
240*6777b538SAndroid Build Coastguard Worker 
TEST(DnsRecordParserTest,ParsesValidPointer)241*6777b538SAndroid Build Coastguard Worker TEST(DnsRecordParserTest, ParsesValidPointer) {
242*6777b538SAndroid Build Coastguard Worker   const char kData[] =
243*6777b538SAndroid Build Coastguard Worker       "\003www\007example\300\022"  // www.example with pointer to byte 25.
244*6777b538SAndroid Build Coastguard Worker       "aaaa"                        // Garbage data to spread things out.
245*6777b538SAndroid Build Coastguard Worker       "\004test\000";               // .test
246*6777b538SAndroid Build Coastguard Worker 
247*6777b538SAndroid Build Coastguard Worker   DnsRecordParser parser(kData, /*length=*/sizeof(kData) - 1, /*offset=*/0,
248*6777b538SAndroid Build Coastguard Worker                          /*num_records=*/0);
249*6777b538SAndroid Build Coastguard Worker   ASSERT_TRUE(parser.IsValid());
250*6777b538SAndroid Build Coastguard Worker 
251*6777b538SAndroid Build Coastguard Worker   std::string out;
252*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(14u, parser.ReadName(kData, &out));
253*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(out, "www.example.test");
254*6777b538SAndroid Build Coastguard Worker }
255*6777b538SAndroid Build Coastguard Worker 
256*6777b538SAndroid Build Coastguard Worker // Per RFC 1035, section 4.1.4, the first 2 bits of a DNS name label determine
257*6777b538SAndroid Build Coastguard Worker // if it is a length label (if the bytes are 00) or a pointer label (if the
258*6777b538SAndroid Build Coastguard Worker // bytes are 11). It is a common DNS parsing bug to treat 01 or 10 as pointer
259*6777b538SAndroid Build Coastguard Worker // labels, but these are reserved and invalid. Such labels should always result
260*6777b538SAndroid Build Coastguard Worker // in DnsRecordParser rejecting the name.
261*6777b538SAndroid Build Coastguard Worker //
262*6777b538SAndroid Build Coastguard Worker // Tests against incorrect name compression pointer validation, which is anti-
263*6777b538SAndroid Build Coastguard Worker // pattern #6 from the "NAME:WRECK" report:
264*6777b538SAndroid Build Coastguard Worker // https://www.forescout.com/company/resources/namewreck-breaking-and-fixing-dns-implementations/
TEST(DnsRecordParserTest,RejectsNamesWithInvalidLabelTypeAsPointer)265*6777b538SAndroid Build Coastguard Worker TEST(DnsRecordParserTest, RejectsNamesWithInvalidLabelTypeAsPointer) {
266*6777b538SAndroid Build Coastguard Worker   const char kData[] =
267*6777b538SAndroid Build Coastguard Worker       "\003www\007example\200\022"  // www.example with invalid label as pointer
268*6777b538SAndroid Build Coastguard Worker       "aaaa"                        // Garbage data to spread things out.
269*6777b538SAndroid Build Coastguard Worker       "\004test\000";               // .test
270*6777b538SAndroid Build Coastguard Worker 
271*6777b538SAndroid Build Coastguard Worker   DnsRecordParser parser(kData, /*length=*/sizeof(kData) - 1, /*offset=*/0,
272*6777b538SAndroid Build Coastguard Worker                          /*num_records=*/0);
273*6777b538SAndroid Build Coastguard Worker   ASSERT_TRUE(parser.IsValid());
274*6777b538SAndroid Build Coastguard Worker 
275*6777b538SAndroid Build Coastguard Worker   std::string out;
276*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(0u, parser.ReadName(kData, &out));
277*6777b538SAndroid Build Coastguard Worker }
278*6777b538SAndroid Build Coastguard Worker 
279*6777b538SAndroid Build Coastguard Worker // Per RFC 1035, section 4.1.4, the first 2 bits of a DNS name label determine
280*6777b538SAndroid Build Coastguard Worker // if it is a length label (if the bytes are 00) or a pointer label (if the
281*6777b538SAndroid Build Coastguard Worker // bytes are 11). Such labels should always result in DnsRecordParser rejecting
282*6777b538SAndroid Build Coastguard Worker // the name.
283*6777b538SAndroid Build Coastguard Worker //
284*6777b538SAndroid Build Coastguard Worker // Tests against incorrect name compression pointer validation, which is anti-
285*6777b538SAndroid Build Coastguard Worker // pattern #6 from the "NAME:WRECK" report:
286*6777b538SAndroid Build Coastguard Worker // https://www.forescout.com/company/resources/namewreck-breaking-and-fixing-dns-implementations/
TEST(DnsRecordParserTest,RejectsNamesWithInvalidLabelTypeAsLength)287*6777b538SAndroid Build Coastguard Worker TEST(DnsRecordParserTest, RejectsNamesWithInvalidLabelTypeAsLength) {
288*6777b538SAndroid Build Coastguard Worker   const char kData[] =
289*6777b538SAndroid Build Coastguard Worker       "\003www\007example\104"  // www.example with invalid label as length
290*6777b538SAndroid Build Coastguard Worker       "test\000";  // test. (in case \104 is interpreted as length=4)
291*6777b538SAndroid Build Coastguard Worker 
292*6777b538SAndroid Build Coastguard Worker   // Append a bunch of zeroes to the buffer in case \104 is interpreted as a
293*6777b538SAndroid Build Coastguard Worker   // long length.
294*6777b538SAndroid Build Coastguard Worker   std::string data(kData, sizeof(kData) - 1);
295*6777b538SAndroid Build Coastguard Worker   data.append(256, '\000');
296*6777b538SAndroid Build Coastguard Worker 
297*6777b538SAndroid Build Coastguard Worker   DnsRecordParser parser(data.data(), data.size(), /*offset=*/0,
298*6777b538SAndroid Build Coastguard Worker                          /*num_records=*/0);
299*6777b538SAndroid Build Coastguard Worker   ASSERT_TRUE(parser.IsValid());
300*6777b538SAndroid Build Coastguard Worker 
301*6777b538SAndroid Build Coastguard Worker   std::string out;
302*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(0u, parser.ReadName(data.data(), &out));
303*6777b538SAndroid Build Coastguard Worker }
304*6777b538SAndroid Build Coastguard Worker 
TEST(DnsRecordParserTest,ReadRecord)305*6777b538SAndroid Build Coastguard Worker TEST(DnsRecordParserTest, ReadRecord) {
306*6777b538SAndroid Build Coastguard Worker   const uint8_t data[] = {
307*6777b538SAndroid Build Coastguard Worker       // Type CNAME record.
308*6777b538SAndroid Build Coastguard Worker       0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0x03, 'c', 'o', 'm', 0x00, 0x00,
309*6777b538SAndroid Build Coastguard Worker       0x05,                    // TYPE is CNAME.
310*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,              // CLASS is IN.
311*6777b538SAndroid Build Coastguard Worker       0x00, 0x01, 0x24, 0x74,  // TTL is 0x00012474.
312*6777b538SAndroid Build Coastguard Worker       0x00, 0x06,              // RDLENGTH is 6 bytes.
313*6777b538SAndroid Build Coastguard Worker       0x03, 'f', 'o', 'o',     // compressed name in record
314*6777b538SAndroid Build Coastguard Worker       0xc0, 0x00,
315*6777b538SAndroid Build Coastguard Worker       // Type A record.
316*6777b538SAndroid Build Coastguard Worker       0x03, 'b', 'a', 'r',     // compressed owner name
317*6777b538SAndroid Build Coastguard Worker       0xc0, 0x00, 0x00, 0x01,  // TYPE is A.
318*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,              // CLASS is IN.
319*6777b538SAndroid Build Coastguard Worker       0x00, 0x20, 0x13, 0x55,  // TTL is 0x00201355.
320*6777b538SAndroid Build Coastguard Worker       0x00, 0x04,              // RDLENGTH is 4 bytes.
321*6777b538SAndroid Build Coastguard Worker       0x7f, 0x02, 0x04, 0x01,  // IP is 127.2.4.1
322*6777b538SAndroid Build Coastguard Worker   };
323*6777b538SAndroid Build Coastguard Worker 
324*6777b538SAndroid Build Coastguard Worker   std::string out;
325*6777b538SAndroid Build Coastguard Worker   DnsRecordParser parser(data, 0, /*num_records=*/2);
326*6777b538SAndroid Build Coastguard Worker 
327*6777b538SAndroid Build Coastguard Worker   DnsResourceRecord record;
328*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(parser.ReadRecord(&record));
329*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ("example.com", record.name);
330*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(dns_protocol::kTypeCNAME, record.type);
331*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(dns_protocol::kClassIN, record.klass);
332*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(0x00012474u, record.ttl);
333*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(6u, record.rdata.length());
334*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(6u, parser.ReadName(record.rdata.data(), &out));
335*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ("foo.example.com", out);
336*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(parser.AtEnd());
337*6777b538SAndroid Build Coastguard Worker 
338*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(parser.ReadRecord(&record));
339*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ("bar.example.com", record.name);
340*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(dns_protocol::kTypeA, record.type);
341*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(dns_protocol::kClassIN, record.klass);
342*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(0x00201355u, record.ttl);
343*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(4u, record.rdata.length());
344*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(std::string_view("\x7f\x02\x04\x01"), record.rdata);
345*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(parser.AtEnd());
346*6777b538SAndroid Build Coastguard Worker 
347*6777b538SAndroid Build Coastguard Worker   // Test truncated record.
348*6777b538SAndroid Build Coastguard Worker   parser = DnsRecordParser(data, sizeof(data) - 2, 0, /*num_records=*/2);
349*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(parser.ReadRecord(&record));
350*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(parser.AtEnd());
351*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(parser.ReadRecord(&record));
352*6777b538SAndroid Build Coastguard Worker }
353*6777b538SAndroid Build Coastguard Worker 
TEST(DnsRecordParserTest,ReadsRecordWithLongName)354*6777b538SAndroid Build Coastguard Worker TEST(DnsRecordParserTest, ReadsRecordWithLongName) {
355*6777b538SAndroid Build Coastguard Worker   std::string dotted_name;
356*6777b538SAndroid Build Coastguard Worker   const std::vector<uint8_t> dns_name =
357*6777b538SAndroid Build Coastguard Worker       BuildRfc1034Name(dns_protocol::kMaxNameLength, &dotted_name);
358*6777b538SAndroid Build Coastguard Worker 
359*6777b538SAndroid Build Coastguard Worker   std::string data(reinterpret_cast<const char*>(dns_name.data()),
360*6777b538SAndroid Build Coastguard Worker                    dns_name.size());
361*6777b538SAndroid Build Coastguard Worker   data.append(
362*6777b538SAndroid Build Coastguard Worker       "\x00\x01"           // TYPE=A
363*6777b538SAndroid Build Coastguard Worker       "\x00\x01"           // CLASS=IN
364*6777b538SAndroid Build Coastguard Worker       "\x00\x01\x51\x80"   // TTL=1 day
365*6777b538SAndroid Build Coastguard Worker       "\x00\x04"           // RDLENGTH=4 bytes
366*6777b538SAndroid Build Coastguard Worker       "\xc0\xa8\x00\x01",  // 192.168.0.1
367*6777b538SAndroid Build Coastguard Worker       14);
368*6777b538SAndroid Build Coastguard Worker 
369*6777b538SAndroid Build Coastguard Worker   DnsRecordParser parser(data.data(), data.size(), 0, /*num_records=*/1);
370*6777b538SAndroid Build Coastguard Worker 
371*6777b538SAndroid Build Coastguard Worker   DnsResourceRecord record;
372*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(parser.ReadRecord(&record));
373*6777b538SAndroid Build Coastguard Worker }
374*6777b538SAndroid Build Coastguard Worker 
375*6777b538SAndroid Build Coastguard Worker // Tests against incorrect name length validation, which is anti-pattern #3 from
376*6777b538SAndroid Build Coastguard Worker // the "NAME:WRECK" report:
377*6777b538SAndroid Build Coastguard Worker // https://www.forescout.com/company/resources/namewreck-breaking-and-fixing-dns-implementations/
TEST(DnsRecordParserTest,RejectRecordWithTooLongName)378*6777b538SAndroid Build Coastguard Worker TEST(DnsRecordParserTest, RejectRecordWithTooLongName) {
379*6777b538SAndroid Build Coastguard Worker   std::string dotted_name;
380*6777b538SAndroid Build Coastguard Worker   const std::vector<uint8_t> dns_name =
381*6777b538SAndroid Build Coastguard Worker       BuildRfc1034Name(dns_protocol::kMaxNameLength + 1, &dotted_name);
382*6777b538SAndroid Build Coastguard Worker 
383*6777b538SAndroid Build Coastguard Worker   std::string data(reinterpret_cast<const char*>(dns_name.data()),
384*6777b538SAndroid Build Coastguard Worker                    dns_name.size());
385*6777b538SAndroid Build Coastguard Worker   data.append(
386*6777b538SAndroid Build Coastguard Worker       "\x00\x01"           // TYPE=A
387*6777b538SAndroid Build Coastguard Worker       "\x00\x01"           // CLASS=IN
388*6777b538SAndroid Build Coastguard Worker       "\x00\x01\x51\x80"   // TTL=1 day
389*6777b538SAndroid Build Coastguard Worker       "\x00\x04"           // RDLENGTH=4 bytes
390*6777b538SAndroid Build Coastguard Worker       "\xc0\xa8\x00\x01",  // 192.168.0.1
391*6777b538SAndroid Build Coastguard Worker       14);
392*6777b538SAndroid Build Coastguard Worker 
393*6777b538SAndroid Build Coastguard Worker   DnsRecordParser parser(data.data(), data.size(), 0, /*num_records=*/1);
394*6777b538SAndroid Build Coastguard Worker 
395*6777b538SAndroid Build Coastguard Worker   DnsResourceRecord record;
396*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(parser.ReadRecord(&record));
397*6777b538SAndroid Build Coastguard Worker }
398*6777b538SAndroid Build Coastguard Worker 
399*6777b538SAndroid Build Coastguard Worker // Test that a record cannot be parsed with a name extending past the end of the
400*6777b538SAndroid Build Coastguard Worker // data.
401*6777b538SAndroid Build Coastguard Worker // Tests against incorrect name length validation, which is anti-pattern #3 from
402*6777b538SAndroid Build Coastguard Worker // the "NAME:WRECK" report:
403*6777b538SAndroid Build Coastguard Worker // https://www.forescout.com/company/resources/namewreck-breaking-and-fixing-dns-implementations/
TEST(DnsRecordParserTest,RejectRecordWithNonendedName)404*6777b538SAndroid Build Coastguard Worker TEST(DnsRecordParserTest, RejectRecordWithNonendedName) {
405*6777b538SAndroid Build Coastguard Worker   const char kNonendedName[] = "\003www\006google\006www";
406*6777b538SAndroid Build Coastguard Worker 
407*6777b538SAndroid Build Coastguard Worker   DnsRecordParser parser(kNonendedName, sizeof(kNonendedName) - 1, 0,
408*6777b538SAndroid Build Coastguard Worker                          /*num_records=*/1);
409*6777b538SAndroid Build Coastguard Worker 
410*6777b538SAndroid Build Coastguard Worker   DnsResourceRecord record;
411*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(parser.ReadRecord(&record));
412*6777b538SAndroid Build Coastguard Worker }
413*6777b538SAndroid Build Coastguard Worker 
414*6777b538SAndroid Build Coastguard Worker // Test that a record cannot be parsed with a name without final null
415*6777b538SAndroid Build Coastguard Worker // termination. Parsing should assume the name has not ended and find the first
416*6777b538SAndroid Build Coastguard Worker // byte of the TYPE field instead, making the remainder of the record
417*6777b538SAndroid Build Coastguard Worker // unparsable.
418*6777b538SAndroid Build Coastguard Worker // Tests against incorrect name null termination, which is anti-pattern #4 from
419*6777b538SAndroid Build Coastguard Worker // the "NAME:WRECK" report:
420*6777b538SAndroid Build Coastguard Worker // https://www.forescout.com/company/resources/namewreck-breaking-and-fixing-dns-implementations/
TEST(DnsRecordParserTest,RejectRecordNameMissingNullTermination)421*6777b538SAndroid Build Coastguard Worker TEST(DnsRecordParserTest, RejectRecordNameMissingNullTermination) {
422*6777b538SAndroid Build Coastguard Worker   const char kData[] =
423*6777b538SAndroid Build Coastguard Worker       "\003www\006google\004test"  // Name without termination.
424*6777b538SAndroid Build Coastguard Worker       "\x00\x01"                   // TYPE=A
425*6777b538SAndroid Build Coastguard Worker       "\x00\x01"                   // CLASS=IN
426*6777b538SAndroid Build Coastguard Worker       "\x00\x01\x51\x80"           // TTL=1 day
427*6777b538SAndroid Build Coastguard Worker       "\x00\x04"                   // RDLENGTH=4 bytes
428*6777b538SAndroid Build Coastguard Worker       "\xc0\xa8\x00\x01";          // 192.168.0.1
429*6777b538SAndroid Build Coastguard Worker 
430*6777b538SAndroid Build Coastguard Worker   DnsRecordParser parser(kData, sizeof(kData) - 1, 0, /*num_records=*/1);
431*6777b538SAndroid Build Coastguard Worker 
432*6777b538SAndroid Build Coastguard Worker   DnsResourceRecord record;
433*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(parser.ReadRecord(&record));
434*6777b538SAndroid Build Coastguard Worker }
435*6777b538SAndroid Build Coastguard Worker 
436*6777b538SAndroid Build Coastguard Worker // Test that no more records can be parsed once the claimed number of records
437*6777b538SAndroid Build Coastguard Worker // have been parsed.
TEST(DnsRecordParserTest,RejectReadingTooManyRecords)438*6777b538SAndroid Build Coastguard Worker TEST(DnsRecordParserTest, RejectReadingTooManyRecords) {
439*6777b538SAndroid Build Coastguard Worker   const char kData[] =
440*6777b538SAndroid Build Coastguard Worker       "\003www\006google\004test\000"
441*6777b538SAndroid Build Coastguard Worker       "\x00\x01"          // TYPE=A
442*6777b538SAndroid Build Coastguard Worker       "\x00\x01"          // CLASS=IN
443*6777b538SAndroid Build Coastguard Worker       "\x00\x01\x51\x80"  // TTL=1 day
444*6777b538SAndroid Build Coastguard Worker       "\x00\x04"          // RDLENGTH=4 bytes
445*6777b538SAndroid Build Coastguard Worker       "\xc0\xa8\x00\x01"  // 192.168.0.1
446*6777b538SAndroid Build Coastguard Worker       "\003www\010chromium\004test\000"
447*6777b538SAndroid Build Coastguard Worker       "\x00\x01"           // TYPE=A
448*6777b538SAndroid Build Coastguard Worker       "\x00\x01"           // CLASS=IN
449*6777b538SAndroid Build Coastguard Worker       "\x00\x01\x51\x80"   // TTL=1 day
450*6777b538SAndroid Build Coastguard Worker       "\x00\x04"           // RDLENGTH=4 bytes
451*6777b538SAndroid Build Coastguard Worker       "\xc0\xa8\x00\x02";  // 192.168.0.2
452*6777b538SAndroid Build Coastguard Worker 
453*6777b538SAndroid Build Coastguard Worker   DnsRecordParser parser(
454*6777b538SAndroid Build Coastguard Worker       kData, /*length=*/sizeof(kData) - 1, /*offset=*/0,
455*6777b538SAndroid Build Coastguard Worker       /*num_records=*/1);  // Claim 1 record despite there being 2 in `kData`.
456*6777b538SAndroid Build Coastguard Worker 
457*6777b538SAndroid Build Coastguard Worker   DnsResourceRecord record1;
458*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(parser.ReadRecord(&record1));
459*6777b538SAndroid Build Coastguard Worker 
460*6777b538SAndroid Build Coastguard Worker   // Expect second record cannot be parsed because only 1 was expected.
461*6777b538SAndroid Build Coastguard Worker   DnsResourceRecord record2;
462*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(parser.ReadRecord(&record2));
463*6777b538SAndroid Build Coastguard Worker }
464*6777b538SAndroid Build Coastguard Worker 
465*6777b538SAndroid Build Coastguard Worker // Test that no more records can be parsed once the end of the buffer is
466*6777b538SAndroid Build Coastguard Worker // reached, even if more records are claimed.
TEST(DnsRecordParserTest,RejectReadingPastEnd)467*6777b538SAndroid Build Coastguard Worker TEST(DnsRecordParserTest, RejectReadingPastEnd) {
468*6777b538SAndroid Build Coastguard Worker   const char kData[] =
469*6777b538SAndroid Build Coastguard Worker       "\003www\006google\004test\000"
470*6777b538SAndroid Build Coastguard Worker       "\x00\x01"          // TYPE=A
471*6777b538SAndroid Build Coastguard Worker       "\x00\x01"          // CLASS=IN
472*6777b538SAndroid Build Coastguard Worker       "\x00\x01\x51\x80"  // TTL=1 day
473*6777b538SAndroid Build Coastguard Worker       "\x00\x04"          // RDLENGTH=4 bytes
474*6777b538SAndroid Build Coastguard Worker       "\xc0\xa8\x00\x01"  // 192.168.0.1
475*6777b538SAndroid Build Coastguard Worker       "\003www\010chromium\004test\000"
476*6777b538SAndroid Build Coastguard Worker       "\x00\x01"           // TYPE=A
477*6777b538SAndroid Build Coastguard Worker       "\x00\x01"           // CLASS=IN
478*6777b538SAndroid Build Coastguard Worker       "\x00\x01\x51\x80"   // TTL=1 day
479*6777b538SAndroid Build Coastguard Worker       "\x00\x04"           // RDLENGTH=4 bytes
480*6777b538SAndroid Build Coastguard Worker       "\xc0\xa8\x00\x02";  // 192.168.0.2
481*6777b538SAndroid Build Coastguard Worker 
482*6777b538SAndroid Build Coastguard Worker   DnsRecordParser parser(
483*6777b538SAndroid Build Coastguard Worker       kData, /*length=*/sizeof(kData) - 1, /*offset=*/0,
484*6777b538SAndroid Build Coastguard Worker       /*num_records=*/3);  // Claim 3 record despite there being 2 in `kData`.
485*6777b538SAndroid Build Coastguard Worker 
486*6777b538SAndroid Build Coastguard Worker   DnsResourceRecord record;
487*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(parser.ReadRecord(&record));
488*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(parser.ReadRecord(&record));
489*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(parser.ReadRecord(&record));
490*6777b538SAndroid Build Coastguard Worker }
491*6777b538SAndroid Build Coastguard Worker 
TEST(DnsResponseTest,InitParse)492*6777b538SAndroid Build Coastguard Worker TEST(DnsResponseTest, InitParse) {
493*6777b538SAndroid Build Coastguard Worker   // This includes \0 at the end.
494*6777b538SAndroid Build Coastguard Worker   const char qname[] =
495*6777b538SAndroid Build Coastguard Worker       "\x0A"
496*6777b538SAndroid Build Coastguard Worker       "codereview"
497*6777b538SAndroid Build Coastguard Worker       "\x08"
498*6777b538SAndroid Build Coastguard Worker       "chromium"
499*6777b538SAndroid Build Coastguard Worker       "\x03"
500*6777b538SAndroid Build Coastguard Worker       "org";
501*6777b538SAndroid Build Coastguard Worker   // Compilers want to copy when binding temporary to const &, so must use heap.
502*6777b538SAndroid Build Coastguard Worker   auto query = std::make_unique<DnsQuery>(0xcafe, base::as_byte_span(qname),
503*6777b538SAndroid Build Coastguard Worker                                           dns_protocol::kTypeA);
504*6777b538SAndroid Build Coastguard Worker 
505*6777b538SAndroid Build Coastguard Worker   const uint8_t response_data[] = {
506*6777b538SAndroid Build Coastguard Worker       // Header
507*6777b538SAndroid Build Coastguard Worker       0xca, 0xfe,  // ID
508*6777b538SAndroid Build Coastguard Worker       0x81, 0x80,  // Standard query response, RA, no error
509*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,  // 1 question
510*6777b538SAndroid Build Coastguard Worker       0x00, 0x02,  // 2 RRs (answers)
511*6777b538SAndroid Build Coastguard Worker       0x00, 0x00,  // 0 authority RRs
512*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,  // 1 additional RRs
513*6777b538SAndroid Build Coastguard Worker 
514*6777b538SAndroid Build Coastguard Worker       // Question
515*6777b538SAndroid Build Coastguard Worker       // This part is echoed back from the respective query.
516*6777b538SAndroid Build Coastguard Worker       0x0a, 'c', 'o', 'd', 'e', 'r', 'e', 'v', 'i', 'e', 'w', 0x08, 'c', 'h',
517*6777b538SAndroid Build Coastguard Worker       'r', 'o', 'm', 'i', 'u', 'm', 0x03, 'o', 'r', 'g', 0x00, 0x00,
518*6777b538SAndroid Build Coastguard Worker       0x01,        // TYPE is A.
519*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,  // CLASS is IN.
520*6777b538SAndroid Build Coastguard Worker 
521*6777b538SAndroid Build Coastguard Worker       // Answer 1
522*6777b538SAndroid Build Coastguard Worker       0xc0, 0x0c,  // NAME is a pointer to name in Question section.
523*6777b538SAndroid Build Coastguard Worker       0x00, 0x05,  // TYPE is CNAME.
524*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,  // CLASS is IN.
525*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,  // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
526*6777b538SAndroid Build Coastguard Worker       0x24, 0x74, 0x00, 0x12,  // RDLENGTH is 18 bytes.
527*6777b538SAndroid Build Coastguard Worker       // ghs.l.google.com in DNS format.
528*6777b538SAndroid Build Coastguard Worker       0x03, 'g', 'h', 's', 0x01, 'l', 0x06, 'g', 'o', 'o', 'g', 'l', 'e', 0x03,
529*6777b538SAndroid Build Coastguard Worker       'c', 'o', 'm', 0x00,
530*6777b538SAndroid Build Coastguard Worker 
531*6777b538SAndroid Build Coastguard Worker       // Answer 2
532*6777b538SAndroid Build Coastguard Worker       0xc0, 0x35,              // NAME is a pointer to name in Answer 1.
533*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,              // TYPE is A.
534*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,              // CLASS is IN.
535*6777b538SAndroid Build Coastguard Worker       0x00, 0x00,              // TTL (4 bytes) is 53 seconds.
536*6777b538SAndroid Build Coastguard Worker       0x00, 0x35, 0x00, 0x04,  // RDLENGTH is 4 bytes.
537*6777b538SAndroid Build Coastguard Worker       0x4a, 0x7d,              // RDATA is the IP: 74.125.95.121
538*6777b538SAndroid Build Coastguard Worker       0x5f, 0x79,
539*6777b538SAndroid Build Coastguard Worker 
540*6777b538SAndroid Build Coastguard Worker       // Additional 1
541*6777b538SAndroid Build Coastguard Worker       0x00,                    // NAME is empty (root domain).
542*6777b538SAndroid Build Coastguard Worker       0x00, 0x29,              // TYPE is OPT.
543*6777b538SAndroid Build Coastguard Worker       0x10, 0x00,              // CLASS is max UDP payload size (4096).
544*6777b538SAndroid Build Coastguard Worker       0x00, 0x00, 0x00, 0x00,  // TTL (4 bytes) is rcode, version and flags.
545*6777b538SAndroid Build Coastguard Worker       0x00, 0x08,              // RDLENGTH
546*6777b538SAndroid Build Coastguard Worker       0x00, 0xFF,              // OPT code
547*6777b538SAndroid Build Coastguard Worker       0x00, 0x04,              // OPT data size
548*6777b538SAndroid Build Coastguard Worker       0xDE, 0xAD, 0xBE, 0xEF   // OPT data
549*6777b538SAndroid Build Coastguard Worker   };
550*6777b538SAndroid Build Coastguard Worker 
551*6777b538SAndroid Build Coastguard Worker   DnsResponse resp;
552*6777b538SAndroid Build Coastguard Worker   memcpy(resp.io_buffer()->data(), response_data, sizeof(response_data));
553*6777b538SAndroid Build Coastguard Worker 
554*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(resp.id());
555*6777b538SAndroid Build Coastguard Worker 
556*6777b538SAndroid Build Coastguard Worker   // Reject too short.
557*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(resp.InitParse(query->io_buffer()->size() - 1, *query));
558*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(resp.IsValid());
559*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(resp.id());
560*6777b538SAndroid Build Coastguard Worker 
561*6777b538SAndroid Build Coastguard Worker   // Reject wrong id.
562*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<DnsQuery> other_query = query->CloneWithNewId(0xbeef);
563*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(resp.InitParse(sizeof(response_data), *other_query));
564*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(resp.IsValid());
565*6777b538SAndroid Build Coastguard Worker   EXPECT_THAT(resp.id(), testing::Optional(0xcafe));
566*6777b538SAndroid Build Coastguard Worker 
567*6777b538SAndroid Build Coastguard Worker   // Reject wrong question.
568*6777b538SAndroid Build Coastguard Worker   auto wrong_query = std::make_unique<DnsQuery>(
569*6777b538SAndroid Build Coastguard Worker       0xcafe, base::as_byte_span(qname), dns_protocol::kTypeCNAME);
570*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(resp.InitParse(sizeof(response_data), *wrong_query));
571*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(resp.IsValid());
572*6777b538SAndroid Build Coastguard Worker   EXPECT_THAT(resp.id(), testing::Optional(0xcafe));
573*6777b538SAndroid Build Coastguard Worker 
574*6777b538SAndroid Build Coastguard Worker   // Accept matching question.
575*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(resp.InitParse(sizeof(response_data), *query));
576*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(resp.IsValid());
577*6777b538SAndroid Build Coastguard Worker 
578*6777b538SAndroid Build Coastguard Worker   // Check header access.
579*6777b538SAndroid Build Coastguard Worker   EXPECT_THAT(resp.id(), testing::Optional(0xcafe));
580*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(0x8180, resp.flags());
581*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(0x0, resp.rcode());
582*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(2u, resp.answer_count());
583*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(1u, resp.additional_answer_count());
584*6777b538SAndroid Build Coastguard Worker 
585*6777b538SAndroid Build Coastguard Worker   // Check question access.
586*6777b538SAndroid Build Coastguard Worker   std::optional<std::vector<uint8_t>> response_qname =
587*6777b538SAndroid Build Coastguard Worker       dns_names_util::DottedNameToNetwork(resp.GetSingleDottedName());
588*6777b538SAndroid Build Coastguard Worker   ASSERT_TRUE(response_qname.has_value());
589*6777b538SAndroid Build Coastguard Worker   EXPECT_THAT(query->qname(),
590*6777b538SAndroid Build Coastguard Worker               testing::ElementsAreArray(response_qname.value()));
591*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(query->qtype(), resp.GetSingleQType());
592*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ("codereview.chromium.org", resp.GetSingleDottedName());
593*6777b538SAndroid Build Coastguard Worker 
594*6777b538SAndroid Build Coastguard Worker   DnsResourceRecord record;
595*6777b538SAndroid Build Coastguard Worker   DnsRecordParser parser = resp.Parser();
596*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(parser.ReadRecord(&record));
597*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(parser.AtEnd());
598*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(parser.ReadRecord(&record));
599*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(parser.AtEnd());
600*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(parser.ReadRecord(&record));
601*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(parser.AtEnd());
602*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(parser.ReadRecord(&record));
603*6777b538SAndroid Build Coastguard Worker }
604*6777b538SAndroid Build Coastguard Worker 
TEST(DnsResponseTest,InitParseInvalidFlags)605*6777b538SAndroid Build Coastguard Worker TEST(DnsResponseTest, InitParseInvalidFlags) {
606*6777b538SAndroid Build Coastguard Worker   // This includes \0 at the end.
607*6777b538SAndroid Build Coastguard Worker   const char qname[] =
608*6777b538SAndroid Build Coastguard Worker       "\x0A"
609*6777b538SAndroid Build Coastguard Worker       "codereview"
610*6777b538SAndroid Build Coastguard Worker       "\x08"
611*6777b538SAndroid Build Coastguard Worker       "chromium"
612*6777b538SAndroid Build Coastguard Worker       "\x03"
613*6777b538SAndroid Build Coastguard Worker       "org";
614*6777b538SAndroid Build Coastguard Worker   // Compilers want to copy when binding temporary to const &, so must use heap.
615*6777b538SAndroid Build Coastguard Worker   auto query = std::make_unique<DnsQuery>(0xcafe, base::as_byte_span(qname),
616*6777b538SAndroid Build Coastguard Worker                                           dns_protocol::kTypeA);
617*6777b538SAndroid Build Coastguard Worker 
618*6777b538SAndroid Build Coastguard Worker   const uint8_t response_data[] = {
619*6777b538SAndroid Build Coastguard Worker       // Header
620*6777b538SAndroid Build Coastguard Worker       0xca, 0xfe,  // ID
621*6777b538SAndroid Build Coastguard Worker       0x01, 0x80,  // RA, no error. Note the absence of the required QR bit.
622*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,  // 1 question
623*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,  // 1 RRs (answers)
624*6777b538SAndroid Build Coastguard Worker       0x00, 0x00,  // 0 authority RRs
625*6777b538SAndroid Build Coastguard Worker       0x00, 0x00,  // 0 additional RRs
626*6777b538SAndroid Build Coastguard Worker 
627*6777b538SAndroid Build Coastguard Worker       // Question
628*6777b538SAndroid Build Coastguard Worker       // This part is echoed back from the respective query.
629*6777b538SAndroid Build Coastguard Worker       0x0a, 'c', 'o', 'd', 'e', 'r', 'e', 'v', 'i', 'e', 'w', 0x08, 'c', 'h',
630*6777b538SAndroid Build Coastguard Worker       'r', 'o', 'm', 'i', 'u', 'm', 0x03, 'o', 'r', 'g', 0x00, 0x00,
631*6777b538SAndroid Build Coastguard Worker       0x01,        // TYPE is A.
632*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,  // CLASS is IN.
633*6777b538SAndroid Build Coastguard Worker 
634*6777b538SAndroid Build Coastguard Worker       // Answer 1
635*6777b538SAndroid Build Coastguard Worker       0xc0, 0x0c,  // NAME is a pointer to name in Question section.
636*6777b538SAndroid Build Coastguard Worker       0x00, 0x05,  // TYPE is CNAME.
637*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,  // CLASS is IN.
638*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,  // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
639*6777b538SAndroid Build Coastguard Worker       0x24, 0x74, 0x00, 0x12,  // RDLENGTH is 18 bytes.
640*6777b538SAndroid Build Coastguard Worker       // ghs.l.google.com in DNS format.
641*6777b538SAndroid Build Coastguard Worker       0x03, 'g', 'h', 's', 0x01, 'l', 0x06, 'g', 'o', 'o', 'g', 'l', 'e', 0x03,
642*6777b538SAndroid Build Coastguard Worker       'c', 'o', 'm', 0x00,
643*6777b538SAndroid Build Coastguard Worker   };
644*6777b538SAndroid Build Coastguard Worker 
645*6777b538SAndroid Build Coastguard Worker   DnsResponse resp;
646*6777b538SAndroid Build Coastguard Worker   memcpy(resp.io_buffer()->data(), response_data, sizeof(response_data));
647*6777b538SAndroid Build Coastguard Worker 
648*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(resp.InitParse(sizeof(response_data), *query));
649*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(resp.IsValid());
650*6777b538SAndroid Build Coastguard Worker   EXPECT_THAT(resp.id(), testing::Optional(0xcafe));
651*6777b538SAndroid Build Coastguard Worker }
652*6777b538SAndroid Build Coastguard Worker 
TEST(DnsResponseTest,InitParseRejectsResponseWithoutQuestions)653*6777b538SAndroid Build Coastguard Worker TEST(DnsResponseTest, InitParseRejectsResponseWithoutQuestions) {
654*6777b538SAndroid Build Coastguard Worker   const char kResponse[] =
655*6777b538SAndroid Build Coastguard Worker       "\x02\x45"                       // ID=581
656*6777b538SAndroid Build Coastguard Worker       "\x81\x80"                       // Standard query response, RA, no error
657*6777b538SAndroid Build Coastguard Worker       "\x00\x00"                       // 0 questions
658*6777b538SAndroid Build Coastguard Worker       "\x00\x01"                       // 1 answers
659*6777b538SAndroid Build Coastguard Worker       "\x00\x00"                       // 0 authority records
660*6777b538SAndroid Build Coastguard Worker       "\x00\x00"                       // 0 additional records
661*6777b538SAndroid Build Coastguard Worker       "\003www\006google\004test\000"  // www.google.test
662*6777b538SAndroid Build Coastguard Worker       "\x00\x01"                       // TYPE=A
663*6777b538SAndroid Build Coastguard Worker       "\x00\x01"                       // CLASS=IN
664*6777b538SAndroid Build Coastguard Worker       "\x00\x00\x2a\x30"               // TTL=3 hours
665*6777b538SAndroid Build Coastguard Worker       "\x00\x04"                       // RDLENGTH=4 bytes
666*6777b538SAndroid Build Coastguard Worker       "\xa0\xa0\xa0\xa0";              // 10.10.10.10
667*6777b538SAndroid Build Coastguard Worker 
668*6777b538SAndroid Build Coastguard Worker   DnsResponse resp;
669*6777b538SAndroid Build Coastguard Worker   memcpy(resp.io_buffer()->data(), kResponse, sizeof(kResponse) - 1);
670*6777b538SAndroid Build Coastguard Worker 
671*6777b538SAndroid Build Coastguard Worker   // Validate that the response is fine if not matching against a query.
672*6777b538SAndroid Build Coastguard Worker   ASSERT_TRUE(resp.InitParseWithoutQuery(sizeof(kResponse) - 1));
673*6777b538SAndroid Build Coastguard Worker 
674*6777b538SAndroid Build Coastguard Worker   const char kQueryName[] = "\003www\006google\004test";
675*6777b538SAndroid Build Coastguard Worker   DnsQuery query(
676*6777b538SAndroid Build Coastguard Worker       /*id=*/581, base::as_byte_span(kQueryName), dns_protocol::kTypeA);
677*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(resp.InitParse(sizeof(kResponse) - 1, query));
678*6777b538SAndroid Build Coastguard Worker }
679*6777b538SAndroid Build Coastguard Worker 
TEST(DnsResponseTest,InitParseRejectsResponseWithTooManyQuestions)680*6777b538SAndroid Build Coastguard Worker TEST(DnsResponseTest, InitParseRejectsResponseWithTooManyQuestions) {
681*6777b538SAndroid Build Coastguard Worker   const char kResponse[] =
682*6777b538SAndroid Build Coastguard Worker       "\x02\x46"                       // ID=582
683*6777b538SAndroid Build Coastguard Worker       "\x81\x80"                       // Standard query response, RA, no error
684*6777b538SAndroid Build Coastguard Worker       "\x00\x02"                       // 2 questions
685*6777b538SAndroid Build Coastguard Worker       "\x00\x00"                       // 0 answers
686*6777b538SAndroid Build Coastguard Worker       "\x00\x00"                       // 0 authority records
687*6777b538SAndroid Build Coastguard Worker       "\x00\x00"                       // 0 additional records
688*6777b538SAndroid Build Coastguard Worker       "\003www\006google\004test\000"  // www.google.test
689*6777b538SAndroid Build Coastguard Worker       "\x00\x01"                       // TYPE=A
690*6777b538SAndroid Build Coastguard Worker       "\x00\x01"                       // CLASS=IN
691*6777b538SAndroid Build Coastguard Worker       "\003www\010chromium\004test\000"  // www.chromium.test
692*6777b538SAndroid Build Coastguard Worker       "\x00\x01"                         // TYPE=A
693*6777b538SAndroid Build Coastguard Worker       "\x00\x01";                        // CLASS=IN
694*6777b538SAndroid Build Coastguard Worker 
695*6777b538SAndroid Build Coastguard Worker   DnsResponse resp;
696*6777b538SAndroid Build Coastguard Worker   memcpy(resp.io_buffer()->data(), kResponse, sizeof(kResponse) - 1);
697*6777b538SAndroid Build Coastguard Worker 
698*6777b538SAndroid Build Coastguard Worker   // Validate that the response is fine if not matching against a query.
699*6777b538SAndroid Build Coastguard Worker   ASSERT_TRUE(resp.InitParseWithoutQuery(sizeof(kResponse) - 1));
700*6777b538SAndroid Build Coastguard Worker 
701*6777b538SAndroid Build Coastguard Worker   const char kQueryName[] = "\003www\006google\004test";
702*6777b538SAndroid Build Coastguard Worker   DnsQuery query(
703*6777b538SAndroid Build Coastguard Worker       /*id=*/582, base::as_byte_span(kQueryName), dns_protocol::kTypeA);
704*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(resp.InitParse(sizeof(kResponse) - 1, query));
705*6777b538SAndroid Build Coastguard Worker }
706*6777b538SAndroid Build Coastguard Worker 
TEST(DnsResponseTest,InitParseWithoutQuery)707*6777b538SAndroid Build Coastguard Worker TEST(DnsResponseTest, InitParseWithoutQuery) {
708*6777b538SAndroid Build Coastguard Worker   DnsResponse resp;
709*6777b538SAndroid Build Coastguard Worker   memcpy(resp.io_buffer()->data(), kT0ResponseDatagram,
710*6777b538SAndroid Build Coastguard Worker          sizeof(kT0ResponseDatagram));
711*6777b538SAndroid Build Coastguard Worker 
712*6777b538SAndroid Build Coastguard Worker   // Accept matching question.
713*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(resp.InitParseWithoutQuery(sizeof(kT0ResponseDatagram)));
714*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(resp.IsValid());
715*6777b538SAndroid Build Coastguard Worker 
716*6777b538SAndroid Build Coastguard Worker   // Check header access.
717*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(0x8180, resp.flags());
718*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(0x0, resp.rcode());
719*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(kT0RecordCount, resp.answer_count());
720*6777b538SAndroid Build Coastguard Worker 
721*6777b538SAndroid Build Coastguard Worker   // Check question access.
722*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(kT0Qtype, resp.GetSingleQType());
723*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(kT0HostName, resp.GetSingleDottedName());
724*6777b538SAndroid Build Coastguard Worker 
725*6777b538SAndroid Build Coastguard Worker   DnsResourceRecord record;
726*6777b538SAndroid Build Coastguard Worker   DnsRecordParser parser = resp.Parser();
727*6777b538SAndroid Build Coastguard Worker   for (unsigned i = 0; i < kT0RecordCount; i ++) {
728*6777b538SAndroid Build Coastguard Worker     EXPECT_FALSE(parser.AtEnd());
729*6777b538SAndroid Build Coastguard Worker     EXPECT_TRUE(parser.ReadRecord(&record));
730*6777b538SAndroid Build Coastguard Worker   }
731*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(parser.AtEnd());
732*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(parser.ReadRecord(&record));
733*6777b538SAndroid Build Coastguard Worker }
734*6777b538SAndroid Build Coastguard Worker 
TEST(DnsResponseTest,InitParseWithoutQueryNoQuestions)735*6777b538SAndroid Build Coastguard Worker TEST(DnsResponseTest, InitParseWithoutQueryNoQuestions) {
736*6777b538SAndroid Build Coastguard Worker   const uint8_t response_data[] = {
737*6777b538SAndroid Build Coastguard Worker       // Header
738*6777b538SAndroid Build Coastguard Worker       0xca, 0xfe,  // ID
739*6777b538SAndroid Build Coastguard Worker       0x81, 0x80,  // Standard query response, RA, no error
740*6777b538SAndroid Build Coastguard Worker       0x00, 0x00,  // No question
741*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,  // 2 RRs (answers)
742*6777b538SAndroid Build Coastguard Worker       0x00, 0x00,  // 0 authority RRs
743*6777b538SAndroid Build Coastguard Worker       0x00, 0x00,  // 0 additional RRs
744*6777b538SAndroid Build Coastguard Worker 
745*6777b538SAndroid Build Coastguard Worker       // Answer 1
746*6777b538SAndroid Build Coastguard Worker       0x0a, 'c', 'o', 'd', 'e', 'r', 'e', 'v', 'i', 'e', 'w', 0x08, 'c', 'h',
747*6777b538SAndroid Build Coastguard Worker       'r', 'o', 'm', 'i', 'u', 'm', 0x03, 'o', 'r', 'g', 0x00, 0x00,
748*6777b538SAndroid Build Coastguard Worker       0x01,                    // TYPE is A.
749*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,              // CLASS is IN.
750*6777b538SAndroid Build Coastguard Worker       0x00, 0x00,              // TTL (4 bytes) is 53 seconds.
751*6777b538SAndroid Build Coastguard Worker       0x00, 0x35, 0x00, 0x04,  // RDLENGTH is 4 bytes.
752*6777b538SAndroid Build Coastguard Worker       0x4a, 0x7d,              // RDATA is the IP: 74.125.95.121
753*6777b538SAndroid Build Coastguard Worker       0x5f, 0x79,
754*6777b538SAndroid Build Coastguard Worker   };
755*6777b538SAndroid Build Coastguard Worker 
756*6777b538SAndroid Build Coastguard Worker   DnsResponse resp;
757*6777b538SAndroid Build Coastguard Worker   memcpy(resp.io_buffer()->data(), response_data, sizeof(response_data));
758*6777b538SAndroid Build Coastguard Worker 
759*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(resp.InitParseWithoutQuery(sizeof(response_data)));
760*6777b538SAndroid Build Coastguard Worker 
761*6777b538SAndroid Build Coastguard Worker   // Check header access.
762*6777b538SAndroid Build Coastguard Worker   EXPECT_THAT(resp.id(), testing::Optional(0xcafe));
763*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(0x8180, resp.flags());
764*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(0x0, resp.rcode());
765*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(0u, resp.question_count());
766*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(0x1u, resp.answer_count());
767*6777b538SAndroid Build Coastguard Worker 
768*6777b538SAndroid Build Coastguard Worker   EXPECT_THAT(resp.dotted_qnames(), testing::IsEmpty());
769*6777b538SAndroid Build Coastguard Worker   EXPECT_THAT(resp.qtypes(), testing::IsEmpty());
770*6777b538SAndroid Build Coastguard Worker 
771*6777b538SAndroid Build Coastguard Worker   DnsResourceRecord record;
772*6777b538SAndroid Build Coastguard Worker   DnsRecordParser parser = resp.Parser();
773*6777b538SAndroid Build Coastguard Worker 
774*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(parser.AtEnd());
775*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(parser.ReadRecord(&record));
776*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ("codereview.chromium.org", record.name);
777*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(0x00000035u, record.ttl);
778*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(dns_protocol::kTypeA, record.type);
779*6777b538SAndroid Build Coastguard Worker 
780*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(parser.AtEnd());
781*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(parser.ReadRecord(&record));
782*6777b538SAndroid Build Coastguard Worker }
783*6777b538SAndroid Build Coastguard Worker 
TEST(DnsResponseTest,InitParseWithoutQueryInvalidFlags)784*6777b538SAndroid Build Coastguard Worker TEST(DnsResponseTest, InitParseWithoutQueryInvalidFlags) {
785*6777b538SAndroid Build Coastguard Worker   const uint8_t response_data[] = {
786*6777b538SAndroid Build Coastguard Worker       // Header
787*6777b538SAndroid Build Coastguard Worker       0xca, 0xfe,  // ID
788*6777b538SAndroid Build Coastguard Worker       0x01, 0x80,  // RA, no error. Note the absence of the required QR bit.
789*6777b538SAndroid Build Coastguard Worker       0x00, 0x00,  // No question
790*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,  // 2 RRs (answers)
791*6777b538SAndroid Build Coastguard Worker       0x00, 0x00,  // 0 authority RRs
792*6777b538SAndroid Build Coastguard Worker       0x00, 0x00,  // 0 additional RRs
793*6777b538SAndroid Build Coastguard Worker 
794*6777b538SAndroid Build Coastguard Worker       // Answer 1
795*6777b538SAndroid Build Coastguard Worker       0x0a, 'c', 'o', 'd', 'e', 'r', 'e', 'v', 'i', 'e', 'w', 0x08, 'c', 'h',
796*6777b538SAndroid Build Coastguard Worker       'r', 'o', 'm', 'i', 'u', 'm', 0x03, 'o', 'r', 'g', 0x00, 0x00,
797*6777b538SAndroid Build Coastguard Worker       0x01,                    // TYPE is A.
798*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,              // CLASS is IN.
799*6777b538SAndroid Build Coastguard Worker       0x00, 0x00,              // TTL (4 bytes) is 53 seconds.
800*6777b538SAndroid Build Coastguard Worker       0x00, 0x35, 0x00, 0x04,  // RDLENGTH is 4 bytes.
801*6777b538SAndroid Build Coastguard Worker       0x4a, 0x7d,              // RDATA is the IP: 74.125.95.121
802*6777b538SAndroid Build Coastguard Worker       0x5f, 0x79,
803*6777b538SAndroid Build Coastguard Worker   };
804*6777b538SAndroid Build Coastguard Worker 
805*6777b538SAndroid Build Coastguard Worker   DnsResponse resp;
806*6777b538SAndroid Build Coastguard Worker   memcpy(resp.io_buffer()->data(), response_data, sizeof(response_data));
807*6777b538SAndroid Build Coastguard Worker 
808*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(resp.InitParseWithoutQuery(sizeof(response_data)));
809*6777b538SAndroid Build Coastguard Worker   EXPECT_THAT(resp.id(), testing::Optional(0xcafe));
810*6777b538SAndroid Build Coastguard Worker }
811*6777b538SAndroid Build Coastguard Worker 
TEST(DnsResponseTest,InitParseWithoutQueryTwoQuestions)812*6777b538SAndroid Build Coastguard Worker TEST(DnsResponseTest, InitParseWithoutQueryTwoQuestions) {
813*6777b538SAndroid Build Coastguard Worker   const uint8_t response_data[] = {
814*6777b538SAndroid Build Coastguard Worker       // Header
815*6777b538SAndroid Build Coastguard Worker       0xca,
816*6777b538SAndroid Build Coastguard Worker       0xfe,  // ID
817*6777b538SAndroid Build Coastguard Worker       0x81,
818*6777b538SAndroid Build Coastguard Worker       0x80,  // Standard query response, RA, no error
819*6777b538SAndroid Build Coastguard Worker       0x00,
820*6777b538SAndroid Build Coastguard Worker       0x02,  // 2 questions
821*6777b538SAndroid Build Coastguard Worker       0x00,
822*6777b538SAndroid Build Coastguard Worker       0x01,  // 2 RRs (answers)
823*6777b538SAndroid Build Coastguard Worker       0x00,
824*6777b538SAndroid Build Coastguard Worker       0x00,  // 0 authority RRs
825*6777b538SAndroid Build Coastguard Worker       0x00,
826*6777b538SAndroid Build Coastguard Worker       0x00,  // 0 additional RRs
827*6777b538SAndroid Build Coastguard Worker 
828*6777b538SAndroid Build Coastguard Worker       // Question 1
829*6777b538SAndroid Build Coastguard Worker       0x0a,
830*6777b538SAndroid Build Coastguard Worker       'c',
831*6777b538SAndroid Build Coastguard Worker       'o',
832*6777b538SAndroid Build Coastguard Worker       'd',
833*6777b538SAndroid Build Coastguard Worker       'e',
834*6777b538SAndroid Build Coastguard Worker       'r',
835*6777b538SAndroid Build Coastguard Worker       'e',
836*6777b538SAndroid Build Coastguard Worker       'v',
837*6777b538SAndroid Build Coastguard Worker       'i',
838*6777b538SAndroid Build Coastguard Worker       'e',
839*6777b538SAndroid Build Coastguard Worker       'w',
840*6777b538SAndroid Build Coastguard Worker       0x08,
841*6777b538SAndroid Build Coastguard Worker       'c',
842*6777b538SAndroid Build Coastguard Worker       'h',
843*6777b538SAndroid Build Coastguard Worker       'r',
844*6777b538SAndroid Build Coastguard Worker       'o',
845*6777b538SAndroid Build Coastguard Worker       'm',
846*6777b538SAndroid Build Coastguard Worker       'i',
847*6777b538SAndroid Build Coastguard Worker       'u',
848*6777b538SAndroid Build Coastguard Worker       'm',
849*6777b538SAndroid Build Coastguard Worker       0x03,
850*6777b538SAndroid Build Coastguard Worker       'o',
851*6777b538SAndroid Build Coastguard Worker       'r',
852*6777b538SAndroid Build Coastguard Worker       'g',
853*6777b538SAndroid Build Coastguard Worker       0x00,
854*6777b538SAndroid Build Coastguard Worker       0x00,
855*6777b538SAndroid Build Coastguard Worker       0x01,  // TYPE is A.
856*6777b538SAndroid Build Coastguard Worker       0x00,
857*6777b538SAndroid Build Coastguard Worker       0x01,  // CLASS is IN.
858*6777b538SAndroid Build Coastguard Worker 
859*6777b538SAndroid Build Coastguard Worker       // Question 2
860*6777b538SAndroid Build Coastguard Worker       0x0b,
861*6777b538SAndroid Build Coastguard Worker       'c',
862*6777b538SAndroid Build Coastguard Worker       'o',
863*6777b538SAndroid Build Coastguard Worker       'd',
864*6777b538SAndroid Build Coastguard Worker       'e',
865*6777b538SAndroid Build Coastguard Worker       'r',
866*6777b538SAndroid Build Coastguard Worker       'e',
867*6777b538SAndroid Build Coastguard Worker       'v',
868*6777b538SAndroid Build Coastguard Worker       'i',
869*6777b538SAndroid Build Coastguard Worker       'e',
870*6777b538SAndroid Build Coastguard Worker       'w',
871*6777b538SAndroid Build Coastguard Worker       '2',
872*6777b538SAndroid Build Coastguard Worker       0xc0,
873*6777b538SAndroid Build Coastguard Worker       0x17,  // pointer to "chromium.org"
874*6777b538SAndroid Build Coastguard Worker       0x00,
875*6777b538SAndroid Build Coastguard Worker       0x01,  // TYPE is A.
876*6777b538SAndroid Build Coastguard Worker       0x00,
877*6777b538SAndroid Build Coastguard Worker       0x01,  // CLASS is IN.
878*6777b538SAndroid Build Coastguard Worker 
879*6777b538SAndroid Build Coastguard Worker       // Answer 1
880*6777b538SAndroid Build Coastguard Worker       0xc0,
881*6777b538SAndroid Build Coastguard Worker       0x0c,  // NAME is a pointer to name in Question section.
882*6777b538SAndroid Build Coastguard Worker       0x00,
883*6777b538SAndroid Build Coastguard Worker       0x01,  // TYPE is A.
884*6777b538SAndroid Build Coastguard Worker       0x00,
885*6777b538SAndroid Build Coastguard Worker       0x01,  // CLASS is IN.
886*6777b538SAndroid Build Coastguard Worker       0x00,
887*6777b538SAndroid Build Coastguard Worker       0x00,  // TTL (4 bytes) is 53 seconds.
888*6777b538SAndroid Build Coastguard Worker       0x00,
889*6777b538SAndroid Build Coastguard Worker       0x35,
890*6777b538SAndroid Build Coastguard Worker       0x00,
891*6777b538SAndroid Build Coastguard Worker       0x04,  // RDLENGTH is 4 bytes.
892*6777b538SAndroid Build Coastguard Worker       0x4a,
893*6777b538SAndroid Build Coastguard Worker       0x7d,  // RDATA is the IP: 74.125.95.121
894*6777b538SAndroid Build Coastguard Worker       0x5f,
895*6777b538SAndroid Build Coastguard Worker       0x79,
896*6777b538SAndroid Build Coastguard Worker   };
897*6777b538SAndroid Build Coastguard Worker 
898*6777b538SAndroid Build Coastguard Worker   DnsResponse resp;
899*6777b538SAndroid Build Coastguard Worker   memcpy(resp.io_buffer()->data(), response_data, sizeof(response_data));
900*6777b538SAndroid Build Coastguard Worker 
901*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(resp.InitParseWithoutQuery(sizeof(response_data)));
902*6777b538SAndroid Build Coastguard Worker 
903*6777b538SAndroid Build Coastguard Worker   // Check header access.
904*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(0x8180, resp.flags());
905*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(0x0, resp.rcode());
906*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(2u, resp.question_count());
907*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(0x01u, resp.answer_count());
908*6777b538SAndroid Build Coastguard Worker 
909*6777b538SAndroid Build Coastguard Worker   EXPECT_THAT(resp.dotted_qnames(),
910*6777b538SAndroid Build Coastguard Worker               testing::ElementsAre("codereview.chromium.org",
911*6777b538SAndroid Build Coastguard Worker                                    "codereview2.chromium.org"));
912*6777b538SAndroid Build Coastguard Worker   EXPECT_THAT(resp.qtypes(),
913*6777b538SAndroid Build Coastguard Worker               testing::ElementsAre(dns_protocol::kTypeA, dns_protocol::kTypeA));
914*6777b538SAndroid Build Coastguard Worker 
915*6777b538SAndroid Build Coastguard Worker   DnsResourceRecord record;
916*6777b538SAndroid Build Coastguard Worker   DnsRecordParser parser = resp.Parser();
917*6777b538SAndroid Build Coastguard Worker 
918*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(parser.AtEnd());
919*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(parser.ReadRecord(&record));
920*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ("codereview.chromium.org", record.name);
921*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(0x35u, record.ttl);
922*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(dns_protocol::kTypeA, record.type);
923*6777b538SAndroid Build Coastguard Worker 
924*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(parser.AtEnd());
925*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(parser.ReadRecord(&record));
926*6777b538SAndroid Build Coastguard Worker }
927*6777b538SAndroid Build Coastguard Worker 
TEST(DnsResponseTest,InitParseWithoutQueryPacketTooShort)928*6777b538SAndroid Build Coastguard Worker TEST(DnsResponseTest, InitParseWithoutQueryPacketTooShort) {
929*6777b538SAndroid Build Coastguard Worker   const uint8_t response_data[] = {
930*6777b538SAndroid Build Coastguard Worker       // Header
931*6777b538SAndroid Build Coastguard Worker       0xca, 0xfe,  // ID
932*6777b538SAndroid Build Coastguard Worker       0x81, 0x80,  // Standard query response, RA, no error
933*6777b538SAndroid Build Coastguard Worker       0x00, 0x00,  // No question
934*6777b538SAndroid Build Coastguard Worker   };
935*6777b538SAndroid Build Coastguard Worker 
936*6777b538SAndroid Build Coastguard Worker   DnsResponse resp;
937*6777b538SAndroid Build Coastguard Worker   memcpy(resp.io_buffer()->data(), response_data, sizeof(response_data));
938*6777b538SAndroid Build Coastguard Worker 
939*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(resp.InitParseWithoutQuery(sizeof(response_data)));
940*6777b538SAndroid Build Coastguard Worker }
941*6777b538SAndroid Build Coastguard Worker 
TEST(DnsResponseTest,InitParseAllowsQuestionWithLongName)942*6777b538SAndroid Build Coastguard Worker TEST(DnsResponseTest, InitParseAllowsQuestionWithLongName) {
943*6777b538SAndroid Build Coastguard Worker   const char kResponseHeader[] =
944*6777b538SAndroid Build Coastguard Worker       "\x02\x45"   // ID=581
945*6777b538SAndroid Build Coastguard Worker       "\x81\x80"   // Standard query response, RA, no error
946*6777b538SAndroid Build Coastguard Worker       "\x00\x01"   // 1 question
947*6777b538SAndroid Build Coastguard Worker       "\x00\x00"   // 0 answers
948*6777b538SAndroid Build Coastguard Worker       "\x00\x00"   // 0 authority records
949*6777b538SAndroid Build Coastguard Worker       "\x00\x00";  // 0 additional records
950*6777b538SAndroid Build Coastguard Worker 
951*6777b538SAndroid Build Coastguard Worker   std::string dotted_name;
952*6777b538SAndroid Build Coastguard Worker   const std::vector<uint8_t> dns_name =
953*6777b538SAndroid Build Coastguard Worker       BuildRfc1034Name(dns_protocol::kMaxNameLength, &dotted_name);
954*6777b538SAndroid Build Coastguard Worker 
955*6777b538SAndroid Build Coastguard Worker   std::string response_data(kResponseHeader, sizeof(kResponseHeader) - 1);
956*6777b538SAndroid Build Coastguard Worker   response_data.append(reinterpret_cast<const char*>(dns_name.data()),
957*6777b538SAndroid Build Coastguard Worker                        dns_name.size());
958*6777b538SAndroid Build Coastguard Worker   response_data.append(
959*6777b538SAndroid Build Coastguard Worker       "\x00\x01"   // TYPE=A
960*6777b538SAndroid Build Coastguard Worker       "\x00\x01",  // CLASS=IN)
961*6777b538SAndroid Build Coastguard Worker       4);
962*6777b538SAndroid Build Coastguard Worker 
963*6777b538SAndroid Build Coastguard Worker   DnsResponse resp1;
964*6777b538SAndroid Build Coastguard Worker   memcpy(resp1.io_buffer()->data(), response_data.data(), response_data.size());
965*6777b538SAndroid Build Coastguard Worker 
966*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(resp1.InitParseWithoutQuery(response_data.size()));
967*6777b538SAndroid Build Coastguard Worker 
968*6777b538SAndroid Build Coastguard Worker   DnsQuery query(581, dns_name, dns_protocol::kTypeA);
969*6777b538SAndroid Build Coastguard Worker 
970*6777b538SAndroid Build Coastguard Worker   DnsResponse resp2(resp1.io_buffer(), response_data.size());
971*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(resp2.InitParse(response_data.size(), query));
972*6777b538SAndroid Build Coastguard Worker }
973*6777b538SAndroid Build Coastguard Worker 
974*6777b538SAndroid Build Coastguard Worker // Tests against incorrect name length validation, which is anti-pattern #3 from
975*6777b538SAndroid Build Coastguard Worker // the "NAME:WRECK" report:
976*6777b538SAndroid Build Coastguard Worker // https://www.forescout.com/company/resources/namewreck-breaking-and-fixing-dns-implementations/
TEST(DnsResponseTest,InitParseRejectsQuestionWithTooLongName)977*6777b538SAndroid Build Coastguard Worker TEST(DnsResponseTest, InitParseRejectsQuestionWithTooLongName) {
978*6777b538SAndroid Build Coastguard Worker   const char kResponseHeader[] =
979*6777b538SAndroid Build Coastguard Worker       "\x02\x45"   // ID=581
980*6777b538SAndroid Build Coastguard Worker       "\x81\x80"   // Standard query response, RA, no error
981*6777b538SAndroid Build Coastguard Worker       "\x00\x01"   // 1 question
982*6777b538SAndroid Build Coastguard Worker       "\x00\x00"   // 0 answers
983*6777b538SAndroid Build Coastguard Worker       "\x00\x00"   // 0 authority records
984*6777b538SAndroid Build Coastguard Worker       "\x00\x00";  // 0 additional records
985*6777b538SAndroid Build Coastguard Worker 
986*6777b538SAndroid Build Coastguard Worker   std::string dotted_name;
987*6777b538SAndroid Build Coastguard Worker   const std::vector<uint8_t> dns_name =
988*6777b538SAndroid Build Coastguard Worker       BuildRfc1034Name(dns_protocol::kMaxNameLength + 1, &dotted_name);
989*6777b538SAndroid Build Coastguard Worker 
990*6777b538SAndroid Build Coastguard Worker   std::string response_data(kResponseHeader, sizeof(kResponseHeader) - 1);
991*6777b538SAndroid Build Coastguard Worker   response_data.append(reinterpret_cast<const char*>(dns_name.data()),
992*6777b538SAndroid Build Coastguard Worker                        dns_name.size());
993*6777b538SAndroid Build Coastguard Worker   response_data.append(
994*6777b538SAndroid Build Coastguard Worker       "\x00\x01"   // TYPE=A
995*6777b538SAndroid Build Coastguard Worker       "\x00\x01",  // CLASS=IN)
996*6777b538SAndroid Build Coastguard Worker       4);
997*6777b538SAndroid Build Coastguard Worker 
998*6777b538SAndroid Build Coastguard Worker   DnsResponse resp;
999*6777b538SAndroid Build Coastguard Worker   memcpy(resp.io_buffer()->data(), response_data.data(), response_data.size());
1000*6777b538SAndroid Build Coastguard Worker 
1001*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(resp.InitParseWithoutQuery(response_data.size()));
1002*6777b538SAndroid Build Coastguard Worker 
1003*6777b538SAndroid Build Coastguard Worker   // Note that `DnsQuery` disallows construction without a valid name, so
1004*6777b538SAndroid Build Coastguard Worker   // `InitParse()` can never be tested with a `query` that matches against a
1005*6777b538SAndroid Build Coastguard Worker   // too-long name in the response. Test with an arbitrary valid query name to
1006*6777b538SAndroid Build Coastguard Worker   // ensure no issues if this code is exercised after receiving a response with
1007*6777b538SAndroid Build Coastguard Worker   // a too-long name.
1008*6777b538SAndroid Build Coastguard Worker   const char kQueryName[] = "\005query\004test";
1009*6777b538SAndroid Build Coastguard Worker   DnsQuery query(
1010*6777b538SAndroid Build Coastguard Worker       /*id=*/581, base::as_byte_span(kQueryName), dns_protocol::kTypeA);
1011*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(resp.InitParse(response_data.size(), query));
1012*6777b538SAndroid Build Coastguard Worker }
1013*6777b538SAndroid Build Coastguard Worker 
1014*6777b538SAndroid Build Coastguard Worker // Test that `InitParse[...]()` rejects a response with a question name
1015*6777b538SAndroid Build Coastguard Worker // extending past the end of the response.
1016*6777b538SAndroid Build Coastguard Worker // Tests against incorrect name length validation, which is anti-pattern #3 from
1017*6777b538SAndroid Build Coastguard Worker // the "NAME:WRECK" report:
1018*6777b538SAndroid Build Coastguard Worker // https://www.forescout.com/company/resources/namewreck-breaking-and-fixing-dns-implementations/
TEST(DnsResponseTest,InitParseRejectsQuestionWithNonendedName)1019*6777b538SAndroid Build Coastguard Worker TEST(DnsResponseTest, InitParseRejectsQuestionWithNonendedName) {
1020*6777b538SAndroid Build Coastguard Worker   const char kResponse[] =
1021*6777b538SAndroid Build Coastguard Worker       "\x02\x45"                    // ID
1022*6777b538SAndroid Build Coastguard Worker       "\x81\x80"                    // Standard query response, RA, no error
1023*6777b538SAndroid Build Coastguard Worker       "\x00\x01"                    // 1 question
1024*6777b538SAndroid Build Coastguard Worker       "\x00\x00"                    // 0 answers
1025*6777b538SAndroid Build Coastguard Worker       "\x00\x00"                    // 0 authority records
1026*6777b538SAndroid Build Coastguard Worker       "\x00\x00"                    // 0 additional records
1027*6777b538SAndroid Build Coastguard Worker       "\003www\006google\006test";  // Name extending past the end.
1028*6777b538SAndroid Build Coastguard Worker 
1029*6777b538SAndroid Build Coastguard Worker   DnsResponse resp;
1030*6777b538SAndroid Build Coastguard Worker   memcpy(resp.io_buffer()->data(), kResponse, sizeof(kResponse) - 1);
1031*6777b538SAndroid Build Coastguard Worker 
1032*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(resp.InitParseWithoutQuery(sizeof(kResponse) - 1));
1033*6777b538SAndroid Build Coastguard Worker 
1034*6777b538SAndroid Build Coastguard Worker   const char kQueryName[] = "\003www\006google\006testtt";
1035*6777b538SAndroid Build Coastguard Worker   DnsQuery query(
1036*6777b538SAndroid Build Coastguard Worker       /*id=*/581, base::as_byte_span(kQueryName), dns_protocol::kTypeA);
1037*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(resp.InitParse(sizeof(kResponse) - 1, query));
1038*6777b538SAndroid Build Coastguard Worker }
1039*6777b538SAndroid Build Coastguard Worker 
1040*6777b538SAndroid Build Coastguard Worker // Test that `InitParse[...]()` rejects responses that do not contain at least
1041*6777b538SAndroid Build Coastguard Worker // the claimed number of questions.
1042*6777b538SAndroid Build Coastguard Worker // Tests against incorrect record count field validation, which is anti-pattern
1043*6777b538SAndroid Build Coastguard Worker // #5 from the "NAME:WRECK" report:
1044*6777b538SAndroid Build Coastguard Worker // https://www.forescout.com/company/resources/namewreck-breaking-and-fixing-dns-implementations/
TEST(DnsResponseTest,InitParseRejectsResponseWithMissingQuestions)1045*6777b538SAndroid Build Coastguard Worker TEST(DnsResponseTest, InitParseRejectsResponseWithMissingQuestions) {
1046*6777b538SAndroid Build Coastguard Worker   const char kResponse[] =
1047*6777b538SAndroid Build Coastguard Worker       "\x02\x45"                       // ID
1048*6777b538SAndroid Build Coastguard Worker       "\x81\x80"                       // Standard query response, RA, no error
1049*6777b538SAndroid Build Coastguard Worker       "\x00\x03"                       // 3 questions
1050*6777b538SAndroid Build Coastguard Worker       "\x00\x00"                       // 0 answers
1051*6777b538SAndroid Build Coastguard Worker       "\x00\x00"                       // 0 authority records
1052*6777b538SAndroid Build Coastguard Worker       "\x00\x00"                       // 0 additional records
1053*6777b538SAndroid Build Coastguard Worker       "\003www\006google\004test\000"  // www.google.test
1054*6777b538SAndroid Build Coastguard Worker       "\x00\x01"                       // TYPE=A
1055*6777b538SAndroid Build Coastguard Worker       "\x00\x01"                       // CLASS=IN
1056*6777b538SAndroid Build Coastguard Worker       "\003www\010chromium\004test\000"  // www.chromium.test
1057*6777b538SAndroid Build Coastguard Worker       "\x00\x01"                         // TYPE=A
1058*6777b538SAndroid Build Coastguard Worker       "\x00\x01";                        // CLASS=IN
1059*6777b538SAndroid Build Coastguard Worker   // Missing third question.
1060*6777b538SAndroid Build Coastguard Worker 
1061*6777b538SAndroid Build Coastguard Worker   DnsResponse resp;
1062*6777b538SAndroid Build Coastguard Worker   memcpy(resp.io_buffer()->data(), kResponse, sizeof(kResponse) - 1);
1063*6777b538SAndroid Build Coastguard Worker 
1064*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(resp.InitParseWithoutQuery(sizeof(kResponse) - 1));
1065*6777b538SAndroid Build Coastguard Worker 
1066*6777b538SAndroid Build Coastguard Worker   const char kQueryName[] = "\003www\006google\004test";
1067*6777b538SAndroid Build Coastguard Worker   DnsQuery query(
1068*6777b538SAndroid Build Coastguard Worker       /*id=*/581, base::as_byte_span(kQueryName), dns_protocol::kTypeA);
1069*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(resp.InitParse(sizeof(kResponse) - 1, query));
1070*6777b538SAndroid Build Coastguard Worker }
1071*6777b538SAndroid Build Coastguard Worker 
1072*6777b538SAndroid Build Coastguard Worker // Test that a parsed DnsResponse only allows parsing the number of records
1073*6777b538SAndroid Build Coastguard Worker // claimed in the response header.
1074*6777b538SAndroid Build Coastguard Worker // Tests against incorrect record count field validation, which is anti-pattern
1075*6777b538SAndroid Build Coastguard Worker // #5 from the "NAME:WRECK" report:
1076*6777b538SAndroid Build Coastguard Worker // https://www.forescout.com/company/resources/namewreck-breaking-and-fixing-dns-implementations/
TEST(DnsResponseTest,ParserLimitedToNumClaimedRecords)1077*6777b538SAndroid Build Coastguard Worker TEST(DnsResponseTest, ParserLimitedToNumClaimedRecords) {
1078*6777b538SAndroid Build Coastguard Worker   const char kResponse[] =
1079*6777b538SAndroid Build Coastguard Worker       "\x02\x45"  // ID
1080*6777b538SAndroid Build Coastguard Worker       "\x81\x80"  // Standard query response, RA, no error
1081*6777b538SAndroid Build Coastguard Worker       "\x00\x01"  // 1 question
1082*6777b538SAndroid Build Coastguard Worker       "\x00\x01"  // 1 answers
1083*6777b538SAndroid Build Coastguard Worker       "\x00\x02"  // 2 authority records
1084*6777b538SAndroid Build Coastguard Worker       "\x00\x01"  // 1 additional records
1085*6777b538SAndroid Build Coastguard Worker       "\003www\006google\004test\000"
1086*6777b538SAndroid Build Coastguard Worker       "\x00\x01"  // TYPE=A
1087*6777b538SAndroid Build Coastguard Worker       "\x00\x01"  // CLASS=IN
1088*6777b538SAndroid Build Coastguard Worker       // 6 total records.
1089*6777b538SAndroid Build Coastguard Worker       "\003www\006google\004test\000"
1090*6777b538SAndroid Build Coastguard Worker       "\x00\x01"          // TYPE=A
1091*6777b538SAndroid Build Coastguard Worker       "\x00\x01"          // CLASS=IN
1092*6777b538SAndroid Build Coastguard Worker       "\x00\x01\x51\x80"  // TTL=1 day
1093*6777b538SAndroid Build Coastguard Worker       "\x00\x04"          // RDLENGTH=4 bytes
1094*6777b538SAndroid Build Coastguard Worker       "\xc0\xa8\x00\x01"  // 192.168.0.1
1095*6777b538SAndroid Build Coastguard Worker       "\003www\010chromium\004test\000"
1096*6777b538SAndroid Build Coastguard Worker       "\x00\x01"          // TYPE=A
1097*6777b538SAndroid Build Coastguard Worker       "\x00\x01"          // CLASS=IN
1098*6777b538SAndroid Build Coastguard Worker       "\x00\x01\x51\x80"  // TTL=1 day
1099*6777b538SAndroid Build Coastguard Worker       "\x00\x04"          // RDLENGTH=4 bytes
1100*6777b538SAndroid Build Coastguard Worker       "\xc0\xa8\x00\x02"  // 192.168.0.2
1101*6777b538SAndroid Build Coastguard Worker       "\003www\007google1\004test\000"
1102*6777b538SAndroid Build Coastguard Worker       "\x00\x01"          // TYPE=A
1103*6777b538SAndroid Build Coastguard Worker       "\x00\x01"          // CLASS=IN
1104*6777b538SAndroid Build Coastguard Worker       "\x00\x01\x51\x80"  // TTL=1 day
1105*6777b538SAndroid Build Coastguard Worker       "\x00\x04"          // RDLENGTH=4 bytes
1106*6777b538SAndroid Build Coastguard Worker       "\xc0\xa8\x00\x03"  // 192.168.0.3
1107*6777b538SAndroid Build Coastguard Worker       "\003www\011chromium1\004test\000"
1108*6777b538SAndroid Build Coastguard Worker       "\x00\x01"          // TYPE=A
1109*6777b538SAndroid Build Coastguard Worker       "\x00\x01"          // CLASS=IN
1110*6777b538SAndroid Build Coastguard Worker       "\x00\x01\x51\x80"  // TTL=1 day
1111*6777b538SAndroid Build Coastguard Worker       "\x00\x04"          // RDLENGTH=4 bytes
1112*6777b538SAndroid Build Coastguard Worker       "\xc0\xa8\x00\x04"  // 192.168.0.4
1113*6777b538SAndroid Build Coastguard Worker       "\003www\007google2\004test\000"
1114*6777b538SAndroid Build Coastguard Worker       "\x00\x01"          // TYPE=A
1115*6777b538SAndroid Build Coastguard Worker       "\x00\x01"          // CLASS=IN
1116*6777b538SAndroid Build Coastguard Worker       "\x00\x01\x51\x80"  // TTL=1 day
1117*6777b538SAndroid Build Coastguard Worker       "\x00\x04"          // RDLENGTH=4 bytes
1118*6777b538SAndroid Build Coastguard Worker       "\xc0\xa8\x00\x05"  // 192.168.0.5
1119*6777b538SAndroid Build Coastguard Worker       "\003www\011chromium2\004test\000"
1120*6777b538SAndroid Build Coastguard Worker       "\x00\x01"           // TYPE=A
1121*6777b538SAndroid Build Coastguard Worker       "\x00\x01"           // CLASS=IN
1122*6777b538SAndroid Build Coastguard Worker       "\x00\x01\x51\x80"   // TTL=1 day
1123*6777b538SAndroid Build Coastguard Worker       "\x00\x04"           // RDLENGTH=4 bytes
1124*6777b538SAndroid Build Coastguard Worker       "\xc0\xa8\x00\x06";  // 192.168.0.6
1125*6777b538SAndroid Build Coastguard Worker 
1126*6777b538SAndroid Build Coastguard Worker   DnsResponse resp1;
1127*6777b538SAndroid Build Coastguard Worker   memcpy(resp1.io_buffer()->data(), kResponse, sizeof(kResponse) - 1);
1128*6777b538SAndroid Build Coastguard Worker 
1129*6777b538SAndroid Build Coastguard Worker   ASSERT_TRUE(resp1.InitParseWithoutQuery(sizeof(kResponse) - 1));
1130*6777b538SAndroid Build Coastguard Worker   DnsRecordParser parser1 = resp1.Parser();
1131*6777b538SAndroid Build Coastguard Worker   ASSERT_TRUE(parser1.IsValid());
1132*6777b538SAndroid Build Coastguard Worker 
1133*6777b538SAndroid Build Coastguard Worker   // Response header only claims 4 records, so expect parser to only allow
1134*6777b538SAndroid Build Coastguard Worker   // parsing that many, ignoring extra records in the data.
1135*6777b538SAndroid Build Coastguard Worker   DnsResourceRecord record;
1136*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(parser1.ReadRecord(&record));
1137*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(parser1.ReadRecord(&record));
1138*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(parser1.ReadRecord(&record));
1139*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(parser1.ReadRecord(&record));
1140*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(parser1.ReadRecord(&record));
1141*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(parser1.ReadRecord(&record));
1142*6777b538SAndroid Build Coastguard Worker 
1143*6777b538SAndroid Build Coastguard Worker   // Repeat using InitParse()
1144*6777b538SAndroid Build Coastguard Worker   DnsResponse resp2;
1145*6777b538SAndroid Build Coastguard Worker   memcpy(resp2.io_buffer()->data(), kResponse, sizeof(kResponse) - 1);
1146*6777b538SAndroid Build Coastguard Worker 
1147*6777b538SAndroid Build Coastguard Worker   const char kQueryName[] = "\003www\006google\004test";
1148*6777b538SAndroid Build Coastguard Worker   DnsQuery query(
1149*6777b538SAndroid Build Coastguard Worker       /*id=*/581, base::as_byte_span(kQueryName), dns_protocol::kTypeA);
1150*6777b538SAndroid Build Coastguard Worker 
1151*6777b538SAndroid Build Coastguard Worker   ASSERT_TRUE(resp2.InitParse(sizeof(kResponse) - 1, query));
1152*6777b538SAndroid Build Coastguard Worker   DnsRecordParser parser2 = resp2.Parser();
1153*6777b538SAndroid Build Coastguard Worker   ASSERT_TRUE(parser2.IsValid());
1154*6777b538SAndroid Build Coastguard Worker 
1155*6777b538SAndroid Build Coastguard Worker   // Response header only claims 4 records, so expect parser to only allow
1156*6777b538SAndroid Build Coastguard Worker   // parsing that many, ignoring extra records in the data.
1157*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(parser2.ReadRecord(&record));
1158*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(parser2.ReadRecord(&record));
1159*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(parser2.ReadRecord(&record));
1160*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(parser2.ReadRecord(&record));
1161*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(parser2.ReadRecord(&record));
1162*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(parser2.ReadRecord(&record));
1163*6777b538SAndroid Build Coastguard Worker }
1164*6777b538SAndroid Build Coastguard Worker 
1165*6777b538SAndroid Build Coastguard Worker // Test that a parsed DnsResponse does not allow parsing past the end of the
1166*6777b538SAndroid Build Coastguard Worker // input, even if more records are claimed in the response header.
1167*6777b538SAndroid Build Coastguard Worker // Tests against incorrect record count field validation, which is anti-pattern
1168*6777b538SAndroid Build Coastguard Worker // #5 from the "NAME:WRECK" report:
1169*6777b538SAndroid Build Coastguard Worker // https://www.forescout.com/company/resources/namewreck-breaking-and-fixing-dns-implementations/
TEST(DnsResponseTest,ParserLimitedToBufferSize)1170*6777b538SAndroid Build Coastguard Worker TEST(DnsResponseTest, ParserLimitedToBufferSize) {
1171*6777b538SAndroid Build Coastguard Worker   const char kResponse[] =
1172*6777b538SAndroid Build Coastguard Worker       "\x02\x45"  // ID
1173*6777b538SAndroid Build Coastguard Worker       "\x81\x80"  // Standard query response, RA, no error
1174*6777b538SAndroid Build Coastguard Worker       "\x00\x01"  // 1 question
1175*6777b538SAndroid Build Coastguard Worker       "\x00\x01"  // 1 answers
1176*6777b538SAndroid Build Coastguard Worker       "\x00\x02"  // 2 authority records
1177*6777b538SAndroid Build Coastguard Worker       "\x00\x01"  // 1 additional records
1178*6777b538SAndroid Build Coastguard Worker       "\003www\006google\004test\000"
1179*6777b538SAndroid Build Coastguard Worker       "\x00\x01"  // TYPE=A
1180*6777b538SAndroid Build Coastguard Worker       "\x00\x01"  // CLASS=IN
1181*6777b538SAndroid Build Coastguard Worker       // 2 total records.
1182*6777b538SAndroid Build Coastguard Worker       "\003www\006google\004test\000"
1183*6777b538SAndroid Build Coastguard Worker       "\x00\x01"          // TYPE=A
1184*6777b538SAndroid Build Coastguard Worker       "\x00\x01"          // CLASS=IN
1185*6777b538SAndroid Build Coastguard Worker       "\x00\x01\x51\x80"  // TTL=1 day
1186*6777b538SAndroid Build Coastguard Worker       "\x00\x04"          // RDLENGTH=4 bytes
1187*6777b538SAndroid Build Coastguard Worker       "\xc0\xa8\x00\x01"  // 192.168.0.1
1188*6777b538SAndroid Build Coastguard Worker       "\003www\010chromium\004test\000"
1189*6777b538SAndroid Build Coastguard Worker       "\x00\x01"           // TYPE=A
1190*6777b538SAndroid Build Coastguard Worker       "\x00\x01"           // CLASS=IN
1191*6777b538SAndroid Build Coastguard Worker       "\x00\x01\x51\x80"   // TTL=1 day
1192*6777b538SAndroid Build Coastguard Worker       "\x00\x04"           // RDLENGTH=4 bytes
1193*6777b538SAndroid Build Coastguard Worker       "\xc0\xa8\x00\x02";  // 192.168.0.2
1194*6777b538SAndroid Build Coastguard Worker 
1195*6777b538SAndroid Build Coastguard Worker   DnsResponse resp1;
1196*6777b538SAndroid Build Coastguard Worker   memcpy(resp1.io_buffer()->data(), kResponse, sizeof(kResponse) - 1);
1197*6777b538SAndroid Build Coastguard Worker 
1198*6777b538SAndroid Build Coastguard Worker   ASSERT_TRUE(resp1.InitParseWithoutQuery(sizeof(kResponse) - 1));
1199*6777b538SAndroid Build Coastguard Worker   DnsRecordParser parser1 = resp1.Parser();
1200*6777b538SAndroid Build Coastguard Worker   ASSERT_TRUE(parser1.IsValid());
1201*6777b538SAndroid Build Coastguard Worker 
1202*6777b538SAndroid Build Coastguard Worker   // Response header claims 4 records, but only 2 present in input.
1203*6777b538SAndroid Build Coastguard Worker   DnsResourceRecord record;
1204*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(parser1.ReadRecord(&record));
1205*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(parser1.ReadRecord(&record));
1206*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(parser1.ReadRecord(&record));
1207*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(parser1.ReadRecord(&record));
1208*6777b538SAndroid Build Coastguard Worker 
1209*6777b538SAndroid Build Coastguard Worker   // Repeat using InitParse()
1210*6777b538SAndroid Build Coastguard Worker   DnsResponse resp2;
1211*6777b538SAndroid Build Coastguard Worker   memcpy(resp2.io_buffer()->data(), kResponse, sizeof(kResponse) - 1);
1212*6777b538SAndroid Build Coastguard Worker 
1213*6777b538SAndroid Build Coastguard Worker   ASSERT_TRUE(resp2.InitParseWithoutQuery(sizeof(kResponse) - 1));
1214*6777b538SAndroid Build Coastguard Worker   DnsRecordParser parser2 = resp2.Parser();
1215*6777b538SAndroid Build Coastguard Worker   ASSERT_TRUE(parser2.IsValid());
1216*6777b538SAndroid Build Coastguard Worker 
1217*6777b538SAndroid Build Coastguard Worker   // Response header claims 4 records, but only 2 present in input.
1218*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(parser2.ReadRecord(&record));
1219*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(parser2.ReadRecord(&record));
1220*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(parser2.ReadRecord(&record));
1221*6777b538SAndroid Build Coastguard Worker   EXPECT_FALSE(parser2.ReadRecord(&record));
1222*6777b538SAndroid Build Coastguard Worker }
1223*6777b538SAndroid Build Coastguard Worker 
TEST(DnsResponseWriteTest,SingleARecordAnswer)1224*6777b538SAndroid Build Coastguard Worker TEST(DnsResponseWriteTest, SingleARecordAnswer) {
1225*6777b538SAndroid Build Coastguard Worker   const uint8_t response_data[] = {
1226*6777b538SAndroid Build Coastguard Worker       0x12, 0x34,  // ID
1227*6777b538SAndroid Build Coastguard Worker       0x84, 0x00,  // flags, response with authoritative answer
1228*6777b538SAndroid Build Coastguard Worker       0x00, 0x00,  // number of questions
1229*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,  // number of answer rr
1230*6777b538SAndroid Build Coastguard Worker       0x00, 0x00,  // number of name server rr
1231*6777b538SAndroid Build Coastguard Worker       0x00, 0x00,  // number of additional rr
1232*6777b538SAndroid Build Coastguard Worker       0x03, 'w',  'w',  'w',  0x07, 'e', 'x', 'a',
1233*6777b538SAndroid Build Coastguard Worker       'm',  'p',  'l',  'e',  0x03, 'c', 'o', 'm',
1234*6777b538SAndroid Build Coastguard Worker       0x00,                    // null label
1235*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,              // type A Record
1236*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,              // class IN
1237*6777b538SAndroid Build Coastguard Worker       0x00, 0x00, 0x00, 0x78,  // TTL, 120 seconds
1238*6777b538SAndroid Build Coastguard Worker       0x00, 0x04,              // rdlength, 32 bits
1239*6777b538SAndroid Build Coastguard Worker       0xc0, 0xa8, 0x00, 0x01,  // 192.168.0.1
1240*6777b538SAndroid Build Coastguard Worker   };
1241*6777b538SAndroid Build Coastguard Worker   net::DnsResourceRecord answer;
1242*6777b538SAndroid Build Coastguard Worker   answer.name = "www.example.com";
1243*6777b538SAndroid Build Coastguard Worker   answer.type = dns_protocol::kTypeA;
1244*6777b538SAndroid Build Coastguard Worker   answer.klass = dns_protocol::kClassIN;
1245*6777b538SAndroid Build Coastguard Worker   answer.ttl = 120;  // 120 seconds.
1246*6777b538SAndroid Build Coastguard Worker   answer.SetOwnedRdata(std::string("\xc0\xa8\x00\x01", 4));
1247*6777b538SAndroid Build Coastguard Worker   std::vector<DnsResourceRecord> answers(1, answer);
1248*6777b538SAndroid Build Coastguard Worker   DnsResponse response(0x1234 /* response_id */, true /* is_authoritative*/,
1249*6777b538SAndroid Build Coastguard Worker                        answers, {} /* authority_records */,
1250*6777b538SAndroid Build Coastguard Worker                        {} /* additional records */, std::nullopt);
1251*6777b538SAndroid Build Coastguard Worker   ASSERT_NE(nullptr, response.io_buffer());
1252*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(response.IsValid());
1253*6777b538SAndroid Build Coastguard Worker   std::string expected_response(reinterpret_cast<const char*>(response_data),
1254*6777b538SAndroid Build Coastguard Worker                                 sizeof(response_data));
1255*6777b538SAndroid Build Coastguard Worker   std::string actual_response(response.io_buffer()->data(),
1256*6777b538SAndroid Build Coastguard Worker                               response.io_buffer_size());
1257*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(expected_response, actual_response);
1258*6777b538SAndroid Build Coastguard Worker }
1259*6777b538SAndroid Build Coastguard Worker 
TEST(DnsResponseWriteTest,SingleARecordAnswerWithFinalDotInName)1260*6777b538SAndroid Build Coastguard Worker TEST(DnsResponseWriteTest, SingleARecordAnswerWithFinalDotInName) {
1261*6777b538SAndroid Build Coastguard Worker   const uint8_t response_data[] = {
1262*6777b538SAndroid Build Coastguard Worker       0x12, 0x34,  // ID
1263*6777b538SAndroid Build Coastguard Worker       0x84, 0x00,  // flags, response with authoritative answer
1264*6777b538SAndroid Build Coastguard Worker       0x00, 0x00,  // number of questions
1265*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,  // number of answer rr
1266*6777b538SAndroid Build Coastguard Worker       0x00, 0x00,  // number of name server rr
1267*6777b538SAndroid Build Coastguard Worker       0x00, 0x00,  // number of additional rr
1268*6777b538SAndroid Build Coastguard Worker       0x03, 'w',  'w',  'w',  0x07, 'e', 'x', 'a',
1269*6777b538SAndroid Build Coastguard Worker       'm',  'p',  'l',  'e',  0x03, 'c', 'o', 'm',
1270*6777b538SAndroid Build Coastguard Worker       0x00,                    // null label
1271*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,              // type A Record
1272*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,              // class IN
1273*6777b538SAndroid Build Coastguard Worker       0x00, 0x00, 0x00, 0x78,  // TTL, 120 seconds
1274*6777b538SAndroid Build Coastguard Worker       0x00, 0x04,              // rdlength, 32 bits
1275*6777b538SAndroid Build Coastguard Worker       0xc0, 0xa8, 0x00, 0x01,  // 192.168.0.1
1276*6777b538SAndroid Build Coastguard Worker   };
1277*6777b538SAndroid Build Coastguard Worker   net::DnsResourceRecord answer;
1278*6777b538SAndroid Build Coastguard Worker   answer.name = "www.example.com.";  // FQDN with the final dot.
1279*6777b538SAndroid Build Coastguard Worker   answer.type = dns_protocol::kTypeA;
1280*6777b538SAndroid Build Coastguard Worker   answer.klass = dns_protocol::kClassIN;
1281*6777b538SAndroid Build Coastguard Worker   answer.ttl = 120;  // 120 seconds.
1282*6777b538SAndroid Build Coastguard Worker   answer.SetOwnedRdata(std::string("\xc0\xa8\x00\x01", 4));
1283*6777b538SAndroid Build Coastguard Worker   std::vector<DnsResourceRecord> answers(1, answer);
1284*6777b538SAndroid Build Coastguard Worker   DnsResponse response(0x1234 /* response_id */, true /* is_authoritative*/,
1285*6777b538SAndroid Build Coastguard Worker                        answers, {} /* authority_records */,
1286*6777b538SAndroid Build Coastguard Worker                        {} /* additional records */, std::nullopt);
1287*6777b538SAndroid Build Coastguard Worker   ASSERT_NE(nullptr, response.io_buffer());
1288*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(response.IsValid());
1289*6777b538SAndroid Build Coastguard Worker   std::string expected_response(reinterpret_cast<const char*>(response_data),
1290*6777b538SAndroid Build Coastguard Worker                                 sizeof(response_data));
1291*6777b538SAndroid Build Coastguard Worker   std::string actual_response(response.io_buffer()->data(),
1292*6777b538SAndroid Build Coastguard Worker                               response.io_buffer_size());
1293*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(expected_response, actual_response);
1294*6777b538SAndroid Build Coastguard Worker }
1295*6777b538SAndroid Build Coastguard Worker 
TEST(DnsResponseWriteTest,SingleARecordAnswerWithQuestion)1296*6777b538SAndroid Build Coastguard Worker TEST(DnsResponseWriteTest, SingleARecordAnswerWithQuestion) {
1297*6777b538SAndroid Build Coastguard Worker   const uint8_t response_data[] = {
1298*6777b538SAndroid Build Coastguard Worker       0x12, 0x34,  // ID
1299*6777b538SAndroid Build Coastguard Worker       0x84, 0x00,  // flags, response with authoritative answer
1300*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,  // number of questions
1301*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,  // number of answer rr
1302*6777b538SAndroid Build Coastguard Worker       0x00, 0x00,  // number of name server rr
1303*6777b538SAndroid Build Coastguard Worker       0x00, 0x00,  // number of additional rr
1304*6777b538SAndroid Build Coastguard Worker       0x03, 'w',  'w',  'w',  0x07, 'e', 'x', 'a',
1305*6777b538SAndroid Build Coastguard Worker       'm',  'p',  'l',  'e',  0x03, 'c', 'o', 'm',
1306*6777b538SAndroid Build Coastguard Worker       0x00,        // null label
1307*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,  // type A Record
1308*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,  // class IN
1309*6777b538SAndroid Build Coastguard Worker       0x03, 'w',  'w',  'w',  0x07, 'e', 'x', 'a',
1310*6777b538SAndroid Build Coastguard Worker       'm',  'p',  'l',  'e',  0x03, 'c', 'o', 'm',
1311*6777b538SAndroid Build Coastguard Worker       0x00,                    // null label
1312*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,              // type A Record
1313*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,              // class IN
1314*6777b538SAndroid Build Coastguard Worker       0x00, 0x00, 0x00, 0x78,  // TTL, 120 seconds
1315*6777b538SAndroid Build Coastguard Worker       0x00, 0x04,              // rdlength, 32 bits
1316*6777b538SAndroid Build Coastguard Worker       0xc0, 0xa8, 0x00, 0x01,  // 192.168.0.1
1317*6777b538SAndroid Build Coastguard Worker   };
1318*6777b538SAndroid Build Coastguard Worker   std::string dotted_name("www.example.com");
1319*6777b538SAndroid Build Coastguard Worker   std::optional<std::vector<uint8_t>> dns_name =
1320*6777b538SAndroid Build Coastguard Worker       dns_names_util::DottedNameToNetwork(dotted_name);
1321*6777b538SAndroid Build Coastguard Worker   ASSERT_TRUE(dns_name.has_value());
1322*6777b538SAndroid Build Coastguard Worker 
1323*6777b538SAndroid Build Coastguard Worker   OptRecordRdata opt_rdata;
1324*6777b538SAndroid Build Coastguard Worker   opt_rdata.AddOpt(
1325*6777b538SAndroid Build Coastguard Worker       OptRecordRdata::UnknownOpt::CreateForTesting(255, "\xde\xad\xbe\xef"));
1326*6777b538SAndroid Build Coastguard Worker 
1327*6777b538SAndroid Build Coastguard Worker   std::optional<DnsQuery> query;
1328*6777b538SAndroid Build Coastguard Worker   query.emplace(0x1234 /* id */, dns_name.value(), dns_protocol::kTypeA,
1329*6777b538SAndroid Build Coastguard Worker                 &opt_rdata);
1330*6777b538SAndroid Build Coastguard Worker   net::DnsResourceRecord answer;
1331*6777b538SAndroid Build Coastguard Worker   answer.name = dotted_name;
1332*6777b538SAndroid Build Coastguard Worker   answer.type = dns_protocol::kTypeA;
1333*6777b538SAndroid Build Coastguard Worker   answer.klass = dns_protocol::kClassIN;
1334*6777b538SAndroid Build Coastguard Worker   answer.ttl = 120;  // 120 seconds.
1335*6777b538SAndroid Build Coastguard Worker   answer.SetOwnedRdata(std::string("\xc0\xa8\x00\x01", 4));
1336*6777b538SAndroid Build Coastguard Worker   std::vector<DnsResourceRecord> answers(1, answer);
1337*6777b538SAndroid Build Coastguard Worker   DnsResponse response(0x1234 /* id */, true /* is_authoritative*/, answers,
1338*6777b538SAndroid Build Coastguard Worker                        {} /* authority_records */, {} /* additional records */,
1339*6777b538SAndroid Build Coastguard Worker                        query);
1340*6777b538SAndroid Build Coastguard Worker   ASSERT_NE(nullptr, response.io_buffer());
1341*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(response.IsValid());
1342*6777b538SAndroid Build Coastguard Worker   std::string expected_response(reinterpret_cast<const char*>(response_data),
1343*6777b538SAndroid Build Coastguard Worker                                 sizeof(response_data));
1344*6777b538SAndroid Build Coastguard Worker   std::string actual_response(response.io_buffer()->data(),
1345*6777b538SAndroid Build Coastguard Worker                               response.io_buffer_size());
1346*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(expected_response, actual_response);
1347*6777b538SAndroid Build Coastguard Worker }
1348*6777b538SAndroid Build Coastguard Worker 
TEST(DnsResponseWriteTest,SingleAnswerWithQuestionConstructedFromSizeInflatedQuery)1349*6777b538SAndroid Build Coastguard Worker TEST(DnsResponseWriteTest,
1350*6777b538SAndroid Build Coastguard Worker      SingleAnswerWithQuestionConstructedFromSizeInflatedQuery) {
1351*6777b538SAndroid Build Coastguard Worker   const uint8_t response_data[] = {
1352*6777b538SAndroid Build Coastguard Worker       0x12, 0x34,  // ID
1353*6777b538SAndroid Build Coastguard Worker       0x84, 0x00,  // flags, response with authoritative answer
1354*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,  // number of questions
1355*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,  // number of answer rr
1356*6777b538SAndroid Build Coastguard Worker       0x00, 0x00,  // number of name server rr
1357*6777b538SAndroid Build Coastguard Worker       0x00, 0x00,  // number of additional rr
1358*6777b538SAndroid Build Coastguard Worker       0x03, 'w',  'w',  'w',  0x07, 'e', 'x', 'a',
1359*6777b538SAndroid Build Coastguard Worker       'm',  'p',  'l',  'e',  0x03, 'c', 'o', 'm',
1360*6777b538SAndroid Build Coastguard Worker       0x00,        // null label
1361*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,  // type A Record
1362*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,  // class IN
1363*6777b538SAndroid Build Coastguard Worker       0x03, 'w',  'w',  'w',  0x07, 'e', 'x', 'a',
1364*6777b538SAndroid Build Coastguard Worker       'm',  'p',  'l',  'e',  0x03, 'c', 'o', 'm',
1365*6777b538SAndroid Build Coastguard Worker       0x00,                    // null label
1366*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,              // type A Record
1367*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,              // class IN
1368*6777b538SAndroid Build Coastguard Worker       0x00, 0x00, 0x00, 0x78,  // TTL, 120 seconds
1369*6777b538SAndroid Build Coastguard Worker       0x00, 0x04,              // rdlength, 32 bits
1370*6777b538SAndroid Build Coastguard Worker       0xc0, 0xa8, 0x00, 0x01,  // 192.168.0.1
1371*6777b538SAndroid Build Coastguard Worker   };
1372*6777b538SAndroid Build Coastguard Worker   std::string dotted_name("www.example.com");
1373*6777b538SAndroid Build Coastguard Worker   std::optional<std::vector<uint8_t>> dns_name =
1374*6777b538SAndroid Build Coastguard Worker       dns_names_util::DottedNameToNetwork(dotted_name);
1375*6777b538SAndroid Build Coastguard Worker   ASSERT_TRUE(dns_name.has_value());
1376*6777b538SAndroid Build Coastguard Worker   size_t buf_size =
1377*6777b538SAndroid Build Coastguard Worker       sizeof(dns_protocol::Header) + dns_name.value().size() + 2 /* qtype */ +
1378*6777b538SAndroid Build Coastguard Worker       2 /* qclass */ +
1379*6777b538SAndroid Build Coastguard Worker       10 /* extra bytes that inflate the internal buffer of a query */;
1380*6777b538SAndroid Build Coastguard Worker   auto buf = base::MakeRefCounted<IOBufferWithSize>(buf_size);
1381*6777b538SAndroid Build Coastguard Worker   std::ranges::fill(buf->span(), char{0});
1382*6777b538SAndroid Build Coastguard Worker   auto writer = base::SpanWriter(base::as_writable_bytes(buf->span()));
1383*6777b538SAndroid Build Coastguard Worker   writer.WriteU16BigEndian(0x1234);                  // id
1384*6777b538SAndroid Build Coastguard Worker   writer.WriteU16BigEndian(0);                       // flags, is query
1385*6777b538SAndroid Build Coastguard Worker   writer.WriteU16BigEndian(1);                       // qdcount
1386*6777b538SAndroid Build Coastguard Worker   writer.WriteU16BigEndian(0);                       // ancount
1387*6777b538SAndroid Build Coastguard Worker   writer.WriteU16BigEndian(0);                       // nscount
1388*6777b538SAndroid Build Coastguard Worker   writer.WriteU16BigEndian(0);                       // arcount
1389*6777b538SAndroid Build Coastguard Worker   writer.Write(dns_name.value());                    // qname
1390*6777b538SAndroid Build Coastguard Worker   writer.WriteU16BigEndian(dns_protocol::kTypeA);    // qtype
1391*6777b538SAndroid Build Coastguard Worker   writer.WriteU16BigEndian(dns_protocol::kClassIN);  // qclass
1392*6777b538SAndroid Build Coastguard Worker   // buf contains 10 extra zero bytes.
1393*6777b538SAndroid Build Coastguard Worker   std::optional<DnsQuery> query;
1394*6777b538SAndroid Build Coastguard Worker   query.emplace(buf);
1395*6777b538SAndroid Build Coastguard Worker   query->Parse(buf_size);
1396*6777b538SAndroid Build Coastguard Worker   net::DnsResourceRecord answer;
1397*6777b538SAndroid Build Coastguard Worker   answer.name = dotted_name;
1398*6777b538SAndroid Build Coastguard Worker   answer.type = dns_protocol::kTypeA;
1399*6777b538SAndroid Build Coastguard Worker   answer.klass = dns_protocol::kClassIN;
1400*6777b538SAndroid Build Coastguard Worker   answer.ttl = 120;  // 120 seconds.
1401*6777b538SAndroid Build Coastguard Worker   answer.SetOwnedRdata(std::string("\xc0\xa8\x00\x01", 4));
1402*6777b538SAndroid Build Coastguard Worker   std::vector<DnsResourceRecord> answers(1, answer);
1403*6777b538SAndroid Build Coastguard Worker   DnsResponse response(0x1234 /* id */, true /* is_authoritative*/, answers,
1404*6777b538SAndroid Build Coastguard Worker                        {} /* authority_records */, {} /* additional records */,
1405*6777b538SAndroid Build Coastguard Worker                        query);
1406*6777b538SAndroid Build Coastguard Worker   ASSERT_NE(nullptr, response.io_buffer());
1407*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(response.IsValid());
1408*6777b538SAndroid Build Coastguard Worker   std::string expected_response(reinterpret_cast<const char*>(response_data),
1409*6777b538SAndroid Build Coastguard Worker                                 sizeof(response_data));
1410*6777b538SAndroid Build Coastguard Worker   std::string actual_response(response.io_buffer()->data(),
1411*6777b538SAndroid Build Coastguard Worker                               response.io_buffer_size());
1412*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(expected_response, actual_response);
1413*6777b538SAndroid Build Coastguard Worker }
1414*6777b538SAndroid Build Coastguard Worker 
TEST(DnsResponseWriteTest,SingleQuadARecordAnswer)1415*6777b538SAndroid Build Coastguard Worker TEST(DnsResponseWriteTest, SingleQuadARecordAnswer) {
1416*6777b538SAndroid Build Coastguard Worker   const uint8_t response_data[] = {
1417*6777b538SAndroid Build Coastguard Worker       0x12, 0x34,  // ID
1418*6777b538SAndroid Build Coastguard Worker       0x84, 0x00,  // flags, response with authoritative answer
1419*6777b538SAndroid Build Coastguard Worker       0x00, 0x00,  // number of questions
1420*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,  // number of answer rr
1421*6777b538SAndroid Build Coastguard Worker       0x00, 0x00,  // number of name server rr
1422*6777b538SAndroid Build Coastguard Worker       0x00, 0x00,  // number of additional rr
1423*6777b538SAndroid Build Coastguard Worker       0x03, 'w',  'w',  'w',  0x07, 'e',  'x',  'a',
1424*6777b538SAndroid Build Coastguard Worker       'm',  'p',  'l',  'e',  0x03, 'c',  'o',  'm',
1425*6777b538SAndroid Build Coastguard Worker       0x00,                                            // null label
1426*6777b538SAndroid Build Coastguard Worker       0x00, 0x1c,                                      // type AAAA Record
1427*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,                                      // class IN
1428*6777b538SAndroid Build Coastguard Worker       0x00, 0x00, 0x00, 0x78,                          // TTL, 120 seconds
1429*6777b538SAndroid Build Coastguard Worker       0x00, 0x10,                                      // rdlength, 128 bits
1430*6777b538SAndroid Build Coastguard Worker       0xfd, 0x12, 0x34, 0x56, 0x78, 0x9a, 0x00, 0x01,  // fd12:3456:789a:1::1
1431*6777b538SAndroid Build Coastguard Worker       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
1432*6777b538SAndroid Build Coastguard Worker   };
1433*6777b538SAndroid Build Coastguard Worker   net::DnsResourceRecord answer;
1434*6777b538SAndroid Build Coastguard Worker   answer.name = "www.example.com";
1435*6777b538SAndroid Build Coastguard Worker   answer.type = dns_protocol::kTypeAAAA;
1436*6777b538SAndroid Build Coastguard Worker   answer.klass = dns_protocol::kClassIN;
1437*6777b538SAndroid Build Coastguard Worker   answer.ttl = 120;  // 120 seconds.
1438*6777b538SAndroid Build Coastguard Worker   answer.SetOwnedRdata(std::string(
1439*6777b538SAndroid Build Coastguard Worker       "\xfd\x12\x34\x56\x78\x9a\x00\x01\x00\x00\x00\x00\x00\x00\x00\x01", 16));
1440*6777b538SAndroid Build Coastguard Worker   std::vector<DnsResourceRecord> answers(1, answer);
1441*6777b538SAndroid Build Coastguard Worker   DnsResponse response(0x1234 /* id */, true /* is_authoritative*/, answers,
1442*6777b538SAndroid Build Coastguard Worker                        {} /* authority_records */, {} /* additional records */,
1443*6777b538SAndroid Build Coastguard Worker                        std::nullopt);
1444*6777b538SAndroid Build Coastguard Worker   ASSERT_NE(nullptr, response.io_buffer());
1445*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(response.IsValid());
1446*6777b538SAndroid Build Coastguard Worker   std::string expected_response(reinterpret_cast<const char*>(response_data),
1447*6777b538SAndroid Build Coastguard Worker                                 sizeof(response_data));
1448*6777b538SAndroid Build Coastguard Worker   std::string actual_response(response.io_buffer()->data(),
1449*6777b538SAndroid Build Coastguard Worker                               response.io_buffer_size());
1450*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(expected_response, actual_response);
1451*6777b538SAndroid Build Coastguard Worker }
1452*6777b538SAndroid Build Coastguard Worker 
TEST(DnsResponseWriteTest,SingleARecordAnswerWithQuestionAndNsecAdditionalRecord)1453*6777b538SAndroid Build Coastguard Worker TEST(DnsResponseWriteTest,
1454*6777b538SAndroid Build Coastguard Worker      SingleARecordAnswerWithQuestionAndNsecAdditionalRecord) {
1455*6777b538SAndroid Build Coastguard Worker   const uint8_t response_data[] = {
1456*6777b538SAndroid Build Coastguard Worker       0x12, 0x34,  // ID
1457*6777b538SAndroid Build Coastguard Worker       0x84, 0x00,  // flags, response with authoritative answer
1458*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,  // number of questions
1459*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,  // number of answer rr
1460*6777b538SAndroid Build Coastguard Worker       0x00, 0x00,  // number of name server rr
1461*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,  // number of additional rr
1462*6777b538SAndroid Build Coastguard Worker       0x03, 'w',  'w',  'w',  0x07, 'e', 'x', 'a',
1463*6777b538SAndroid Build Coastguard Worker       'm',  'p',  'l',  'e',  0x03, 'c', 'o', 'm',
1464*6777b538SAndroid Build Coastguard Worker       0x00,        // null label
1465*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,  // type A Record
1466*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,  // class IN
1467*6777b538SAndroid Build Coastguard Worker       0x03, 'w',  'w',  'w',  0x07, 'e', 'x', 'a',
1468*6777b538SAndroid Build Coastguard Worker       'm',  'p',  'l',  'e',  0x03, 'c', 'o', 'm',
1469*6777b538SAndroid Build Coastguard Worker       0x00,                    // null label
1470*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,              // type A Record
1471*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,              // class IN
1472*6777b538SAndroid Build Coastguard Worker       0x00, 0x00, 0x00, 0x78,  // TTL, 120 seconds
1473*6777b538SAndroid Build Coastguard Worker       0x00, 0x04,              // rdlength, 32 bits
1474*6777b538SAndroid Build Coastguard Worker       0xc0, 0xa8, 0x00, 0x01,  // 192.168.0.1
1475*6777b538SAndroid Build Coastguard Worker       0x03, 'w',  'w',  'w',  0x07, 'e', 'x', 'a',
1476*6777b538SAndroid Build Coastguard Worker       'm',  'p',  'l',  'e',  0x03, 'c', 'o', 'm',
1477*6777b538SAndroid Build Coastguard Worker       0x00,                    // null label
1478*6777b538SAndroid Build Coastguard Worker       0x00, 0x2f,              // type NSEC Record
1479*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,              // class IN
1480*6777b538SAndroid Build Coastguard Worker       0x00, 0x00, 0x00, 0x78,  // TTL, 120 seconds
1481*6777b538SAndroid Build Coastguard Worker       0x00, 0x05,              // rdlength, 5 bytes
1482*6777b538SAndroid Build Coastguard Worker       0xc0, 0x0c,              // pointer to the previous "www.example.com"
1483*6777b538SAndroid Build Coastguard Worker       0x00, 0x01, 0x40,        // type bit map of type A: window block 0, bitmap
1484*6777b538SAndroid Build Coastguard Worker                                // length 1, bitmap with bit 1 set
1485*6777b538SAndroid Build Coastguard Worker   };
1486*6777b538SAndroid Build Coastguard Worker   std::string dotted_name("www.example.com");
1487*6777b538SAndroid Build Coastguard Worker   std::optional<std::vector<uint8_t>> dns_name =
1488*6777b538SAndroid Build Coastguard Worker       dns_names_util::DottedNameToNetwork(dotted_name);
1489*6777b538SAndroid Build Coastguard Worker   ASSERT_TRUE(dns_name.has_value());
1490*6777b538SAndroid Build Coastguard Worker   std::optional<DnsQuery> query;
1491*6777b538SAndroid Build Coastguard Worker   query.emplace(0x1234 /* id */, dns_name.value(), dns_protocol::kTypeA);
1492*6777b538SAndroid Build Coastguard Worker   net::DnsResourceRecord answer;
1493*6777b538SAndroid Build Coastguard Worker   answer.name = dotted_name;
1494*6777b538SAndroid Build Coastguard Worker   answer.type = dns_protocol::kTypeA;
1495*6777b538SAndroid Build Coastguard Worker   answer.klass = dns_protocol::kClassIN;
1496*6777b538SAndroid Build Coastguard Worker   answer.ttl = 120;  // 120 seconds.
1497*6777b538SAndroid Build Coastguard Worker   answer.SetOwnedRdata(std::string("\xc0\xa8\x00\x01", 4));
1498*6777b538SAndroid Build Coastguard Worker   std::vector<DnsResourceRecord> answers(1, answer);
1499*6777b538SAndroid Build Coastguard Worker   net::DnsResourceRecord additional_record;
1500*6777b538SAndroid Build Coastguard Worker   additional_record.name = dotted_name;
1501*6777b538SAndroid Build Coastguard Worker   additional_record.type = dns_protocol::kTypeNSEC;
1502*6777b538SAndroid Build Coastguard Worker   additional_record.klass = dns_protocol::kClassIN;
1503*6777b538SAndroid Build Coastguard Worker   additional_record.ttl = 120;  // 120 seconds.
1504*6777b538SAndroid Build Coastguard Worker   // Bitmap for "www.example.com" with type A set.
1505*6777b538SAndroid Build Coastguard Worker   additional_record.SetOwnedRdata(std::string("\xc0\x0c\x00\x01\x40", 5));
1506*6777b538SAndroid Build Coastguard Worker   std::vector<DnsResourceRecord> additional_records(1, additional_record);
1507*6777b538SAndroid Build Coastguard Worker   DnsResponse response(0x1234 /* id */, true /* is_authoritative*/, answers,
1508*6777b538SAndroid Build Coastguard Worker                        {} /* authority_records */, additional_records, query);
1509*6777b538SAndroid Build Coastguard Worker   ASSERT_NE(nullptr, response.io_buffer());
1510*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(response.IsValid());
1511*6777b538SAndroid Build Coastguard Worker   std::string expected_response(reinterpret_cast<const char*>(response_data),
1512*6777b538SAndroid Build Coastguard Worker                                 sizeof(response_data));
1513*6777b538SAndroid Build Coastguard Worker   std::string actual_response(response.io_buffer()->data(),
1514*6777b538SAndroid Build Coastguard Worker                               response.io_buffer_size());
1515*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(expected_response, actual_response);
1516*6777b538SAndroid Build Coastguard Worker }
1517*6777b538SAndroid Build Coastguard Worker 
TEST(DnsResponseWriteTest,TwoAnswersWithAAndQuadARecords)1518*6777b538SAndroid Build Coastguard Worker TEST(DnsResponseWriteTest, TwoAnswersWithAAndQuadARecords) {
1519*6777b538SAndroid Build Coastguard Worker   const uint8_t response_data[] = {
1520*6777b538SAndroid Build Coastguard Worker       0x12, 0x34,  // ID
1521*6777b538SAndroid Build Coastguard Worker       0x84, 0x00,  // flags, response with authoritative answer
1522*6777b538SAndroid Build Coastguard Worker       0x00, 0x00,  // number of questions
1523*6777b538SAndroid Build Coastguard Worker       0x00, 0x02,  // number of answer rr
1524*6777b538SAndroid Build Coastguard Worker       0x00, 0x00,  // number of name server rr
1525*6777b538SAndroid Build Coastguard Worker       0x00, 0x00,  // number of additional rr
1526*6777b538SAndroid Build Coastguard Worker       0x03, 'w',  'w',  'w',  0x07, 'e',  'x',  'a',  'm',  'p', 'l', 'e',
1527*6777b538SAndroid Build Coastguard Worker       0x03, 'c',  'o',  'm',
1528*6777b538SAndroid Build Coastguard Worker       0x00,                    // null label
1529*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,              // type A Record
1530*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,              // class IN
1531*6777b538SAndroid Build Coastguard Worker       0x00, 0x00, 0x00, 0x78,  // TTL, 120 seconds
1532*6777b538SAndroid Build Coastguard Worker       0x00, 0x04,              // rdlength, 32 bits
1533*6777b538SAndroid Build Coastguard Worker       0xc0, 0xa8, 0x00, 0x01,  // 192.168.0.1
1534*6777b538SAndroid Build Coastguard Worker       0x07, 'e',  'x',  'a',  'm',  'p',  'l',  'e',  0x03, 'o', 'r', 'g',
1535*6777b538SAndroid Build Coastguard Worker       0x00,                                            // null label
1536*6777b538SAndroid Build Coastguard Worker       0x00, 0x1c,                                      // type AAAA Record
1537*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,                                      // class IN
1538*6777b538SAndroid Build Coastguard Worker       0x00, 0x00, 0x00, 0x3c,                          // TTL, 60 seconds
1539*6777b538SAndroid Build Coastguard Worker       0x00, 0x10,                                      // rdlength, 128 bits
1540*6777b538SAndroid Build Coastguard Worker       0xfd, 0x12, 0x34, 0x56, 0x78, 0x9a, 0x00, 0x01,  // fd12:3456:789a:1::1
1541*6777b538SAndroid Build Coastguard Worker       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
1542*6777b538SAndroid Build Coastguard Worker   };
1543*6777b538SAndroid Build Coastguard Worker   net::DnsResourceRecord answer1;
1544*6777b538SAndroid Build Coastguard Worker   answer1.name = "www.example.com";
1545*6777b538SAndroid Build Coastguard Worker   answer1.type = dns_protocol::kTypeA;
1546*6777b538SAndroid Build Coastguard Worker   answer1.klass = dns_protocol::kClassIN;
1547*6777b538SAndroid Build Coastguard Worker   answer1.ttl = 120;  // 120 seconds.
1548*6777b538SAndroid Build Coastguard Worker   answer1.SetOwnedRdata(std::string("\xc0\xa8\x00\x01", 4));
1549*6777b538SAndroid Build Coastguard Worker   net::DnsResourceRecord answer2;
1550*6777b538SAndroid Build Coastguard Worker   answer2.name = "example.org";
1551*6777b538SAndroid Build Coastguard Worker   answer2.type = dns_protocol::kTypeAAAA;
1552*6777b538SAndroid Build Coastguard Worker   answer2.klass = dns_protocol::kClassIN;
1553*6777b538SAndroid Build Coastguard Worker   answer2.ttl = 60;
1554*6777b538SAndroid Build Coastguard Worker   answer2.SetOwnedRdata(std::string(
1555*6777b538SAndroid Build Coastguard Worker       "\xfd\x12\x34\x56\x78\x9a\x00\x01\x00\x00\x00\x00\x00\x00\x00\x01", 16));
1556*6777b538SAndroid Build Coastguard Worker   std::vector<DnsResourceRecord> answers(2);
1557*6777b538SAndroid Build Coastguard Worker   answers[0] = answer1;
1558*6777b538SAndroid Build Coastguard Worker   answers[1] = answer2;
1559*6777b538SAndroid Build Coastguard Worker   DnsResponse response(0x1234 /* id */, true /* is_authoritative*/, answers,
1560*6777b538SAndroid Build Coastguard Worker                        {} /* authority_records */, {} /* additional records */,
1561*6777b538SAndroid Build Coastguard Worker                        std::nullopt);
1562*6777b538SAndroid Build Coastguard Worker   ASSERT_NE(nullptr, response.io_buffer());
1563*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(response.IsValid());
1564*6777b538SAndroid Build Coastguard Worker   std::string expected_response(reinterpret_cast<const char*>(response_data),
1565*6777b538SAndroid Build Coastguard Worker                                 sizeof(response_data));
1566*6777b538SAndroid Build Coastguard Worker   std::string actual_response(response.io_buffer()->data(),
1567*6777b538SAndroid Build Coastguard Worker                               response.io_buffer_size());
1568*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(expected_response, actual_response);
1569*6777b538SAndroid Build Coastguard Worker }
1570*6777b538SAndroid Build Coastguard Worker 
TEST(DnsResponseWriteTest,AnswerWithAuthorityRecord)1571*6777b538SAndroid Build Coastguard Worker TEST(DnsResponseWriteTest, AnswerWithAuthorityRecord) {
1572*6777b538SAndroid Build Coastguard Worker   const uint8_t response_data[] = {
1573*6777b538SAndroid Build Coastguard Worker       0x12, 0x35,  // ID
1574*6777b538SAndroid Build Coastguard Worker       0x84, 0x00,  // flags, response with authoritative answer
1575*6777b538SAndroid Build Coastguard Worker       0x00, 0x00,  // number of questions
1576*6777b538SAndroid Build Coastguard Worker       0x00, 0x00,  // number of answer rr
1577*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,  // number of name server rr
1578*6777b538SAndroid Build Coastguard Worker       0x00, 0x00,  // number of additional rr
1579*6777b538SAndroid Build Coastguard Worker       0x03, 'w',  'w',  'w',  0x07, 'e', 'x', 'a',
1580*6777b538SAndroid Build Coastguard Worker       'm',  'p',  'l',  'e',  0x03, 'c', 'o', 'm',
1581*6777b538SAndroid Build Coastguard Worker       0x00,                    // null label
1582*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,              // type A Record
1583*6777b538SAndroid Build Coastguard Worker       0x00, 0x01,              // class IN
1584*6777b538SAndroid Build Coastguard Worker       0x00, 0x00, 0x00, 0x78,  // TTL, 120 seconds
1585*6777b538SAndroid Build Coastguard Worker       0x00, 0x04,              // rdlength, 32 bits
1586*6777b538SAndroid Build Coastguard Worker       0xc0, 0xa8, 0x00, 0x01,  // 192.168.0.1
1587*6777b538SAndroid Build Coastguard Worker   };
1588*6777b538SAndroid Build Coastguard Worker   DnsResourceRecord record;
1589*6777b538SAndroid Build Coastguard Worker   record.name = "www.example.com";
1590*6777b538SAndroid Build Coastguard Worker   record.type = dns_protocol::kTypeA;
1591*6777b538SAndroid Build Coastguard Worker   record.klass = dns_protocol::kClassIN;
1592*6777b538SAndroid Build Coastguard Worker   record.ttl = 120;  // 120 seconds.
1593*6777b538SAndroid Build Coastguard Worker   record.SetOwnedRdata(std::string("\xc0\xa8\x00\x01", 4));
1594*6777b538SAndroid Build Coastguard Worker   std::vector<DnsResourceRecord> authority_records(1, record);
1595*6777b538SAndroid Build Coastguard Worker   DnsResponse response(0x1235 /* response_id */, true /* is_authoritative*/,
1596*6777b538SAndroid Build Coastguard Worker                        {} /* answers */, authority_records,
1597*6777b538SAndroid Build Coastguard Worker                        {} /* additional records */, std::nullopt);
1598*6777b538SAndroid Build Coastguard Worker   ASSERT_NE(nullptr, response.io_buffer());
1599*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(response.IsValid());
1600*6777b538SAndroid Build Coastguard Worker   std::string expected_response(reinterpret_cast<const char*>(response_data),
1601*6777b538SAndroid Build Coastguard Worker                                 sizeof(response_data));
1602*6777b538SAndroid Build Coastguard Worker   std::string actual_response(response.io_buffer()->data(),
1603*6777b538SAndroid Build Coastguard Worker                               response.io_buffer_size());
1604*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(expected_response, actual_response);
1605*6777b538SAndroid Build Coastguard Worker }
1606*6777b538SAndroid Build Coastguard Worker 
TEST(DnsResponseWriteTest,AnswerWithRcode)1607*6777b538SAndroid Build Coastguard Worker TEST(DnsResponseWriteTest, AnswerWithRcode) {
1608*6777b538SAndroid Build Coastguard Worker   const uint8_t response_data[] = {
1609*6777b538SAndroid Build Coastguard Worker       0x12, 0x12,  // ID
1610*6777b538SAndroid Build Coastguard Worker       0x80, 0x03,  // flags (response with non-existent domain)
1611*6777b538SAndroid Build Coastguard Worker       0x00, 0x00,  // number of questions
1612*6777b538SAndroid Build Coastguard Worker       0x00, 0x00,  // number of answer rr
1613*6777b538SAndroid Build Coastguard Worker       0x00, 0x00,  // number of name server rr
1614*6777b538SAndroid Build Coastguard Worker       0x00, 0x00,  // number of additional rr
1615*6777b538SAndroid Build Coastguard Worker   };
1616*6777b538SAndroid Build Coastguard Worker   DnsResponse response(0x1212 /* response_id */, false /* is_authoritative*/,
1617*6777b538SAndroid Build Coastguard Worker                        {} /* answers */, {} /* authority_records */,
1618*6777b538SAndroid Build Coastguard Worker                        {} /* additional records */, std::nullopt,
1619*6777b538SAndroid Build Coastguard Worker                        dns_protocol::kRcodeNXDOMAIN);
1620*6777b538SAndroid Build Coastguard Worker   ASSERT_NE(nullptr, response.io_buffer());
1621*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(response.IsValid());
1622*6777b538SAndroid Build Coastguard Worker   std::string expected_response(reinterpret_cast<const char*>(response_data),
1623*6777b538SAndroid Build Coastguard Worker                                 sizeof(response_data));
1624*6777b538SAndroid Build Coastguard Worker   std::string actual_response(response.io_buffer()->data(),
1625*6777b538SAndroid Build Coastguard Worker                               response.io_buffer_size());
1626*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(expected_response, actual_response);
1627*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(dns_protocol::kRcodeNXDOMAIN, response.rcode());
1628*6777b538SAndroid Build Coastguard Worker }
1629*6777b538SAndroid Build Coastguard Worker 
1630*6777b538SAndroid Build Coastguard Worker // CNAME answers are always allowed for any question.
TEST(DnsResponseWriteTest,AAAAQuestionAndCnameAnswer)1631*6777b538SAndroid Build Coastguard Worker TEST(DnsResponseWriteTest, AAAAQuestionAndCnameAnswer) {
1632*6777b538SAndroid Build Coastguard Worker   const std::string kName = "www.example.com";
1633*6777b538SAndroid Build Coastguard Worker   std::optional<std::vector<uint8_t>> dns_name =
1634*6777b538SAndroid Build Coastguard Worker       dns_names_util::DottedNameToNetwork(kName);
1635*6777b538SAndroid Build Coastguard Worker   ASSERT_TRUE(dns_name.has_value());
1636*6777b538SAndroid Build Coastguard Worker 
1637*6777b538SAndroid Build Coastguard Worker   DnsResourceRecord answer;
1638*6777b538SAndroid Build Coastguard Worker   answer.name = kName;
1639*6777b538SAndroid Build Coastguard Worker   answer.type = dns_protocol::kTypeCNAME;
1640*6777b538SAndroid Build Coastguard Worker   answer.klass = dns_protocol::kClassIN;
1641*6777b538SAndroid Build Coastguard Worker   answer.ttl = 120;  // 120 seconds.
1642*6777b538SAndroid Build Coastguard Worker   answer.SetOwnedRdata(
1643*6777b538SAndroid Build Coastguard Worker       std::string(reinterpret_cast<char*>(dns_name.value().data()),
1644*6777b538SAndroid Build Coastguard Worker                   dns_name.value().size()));
1645*6777b538SAndroid Build Coastguard Worker   std::vector<DnsResourceRecord> answers(1, answer);
1646*6777b538SAndroid Build Coastguard Worker 
1647*6777b538SAndroid Build Coastguard Worker   std::optional<DnsQuery> query(std::in_place, 114 /* id */, dns_name.value(),
1648*6777b538SAndroid Build Coastguard Worker                                 dns_protocol::kTypeAAAA);
1649*6777b538SAndroid Build Coastguard Worker 
1650*6777b538SAndroid Build Coastguard Worker   DnsResponse response(114 /* response_id */, true /* is_authoritative*/,
1651*6777b538SAndroid Build Coastguard Worker                        answers, {} /* authority_records */,
1652*6777b538SAndroid Build Coastguard Worker                        {} /* additional records */, query);
1653*6777b538SAndroid Build Coastguard Worker 
1654*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(response.IsValid());
1655*6777b538SAndroid Build Coastguard Worker }
1656*6777b538SAndroid Build Coastguard Worker 
TEST(DnsResponseWriteTest,WrittenResponseCanBeParsed)1657*6777b538SAndroid Build Coastguard Worker TEST(DnsResponseWriteTest, WrittenResponseCanBeParsed) {
1658*6777b538SAndroid Build Coastguard Worker   std::string dotted_name("www.example.com");
1659*6777b538SAndroid Build Coastguard Worker   net::DnsResourceRecord answer;
1660*6777b538SAndroid Build Coastguard Worker   answer.name = dotted_name;
1661*6777b538SAndroid Build Coastguard Worker   answer.type = dns_protocol::kTypeA;
1662*6777b538SAndroid Build Coastguard Worker   answer.klass = dns_protocol::kClassIN;
1663*6777b538SAndroid Build Coastguard Worker   answer.ttl = 120;  // 120 seconds.
1664*6777b538SAndroid Build Coastguard Worker   answer.SetOwnedRdata(std::string("\xc0\xa8\x00\x01", 4));
1665*6777b538SAndroid Build Coastguard Worker   std::vector<DnsResourceRecord> answers(1, answer);
1666*6777b538SAndroid Build Coastguard Worker   net::DnsResourceRecord additional_record;
1667*6777b538SAndroid Build Coastguard Worker   additional_record.name = dotted_name;
1668*6777b538SAndroid Build Coastguard Worker   additional_record.type = dns_protocol::kTypeNSEC;
1669*6777b538SAndroid Build Coastguard Worker   additional_record.klass = dns_protocol::kClassIN;
1670*6777b538SAndroid Build Coastguard Worker   additional_record.ttl = 120;  // 120 seconds.
1671*6777b538SAndroid Build Coastguard Worker   additional_record.SetOwnedRdata(std::string("\xc0\x0c\x00\x01\x04", 5));
1672*6777b538SAndroid Build Coastguard Worker   std::vector<DnsResourceRecord> additional_records(1, additional_record);
1673*6777b538SAndroid Build Coastguard Worker   DnsResponse response(0x1234 /* response_id */, true /* is_authoritative*/,
1674*6777b538SAndroid Build Coastguard Worker                        answers, {} /* authority_records */, additional_records,
1675*6777b538SAndroid Build Coastguard Worker                        std::nullopt);
1676*6777b538SAndroid Build Coastguard Worker   ASSERT_NE(nullptr, response.io_buffer());
1677*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(response.IsValid());
1678*6777b538SAndroid Build Coastguard Worker   EXPECT_THAT(response.id(), testing::Optional(0x1234));
1679*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(1u, response.answer_count());
1680*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(1u, response.additional_answer_count());
1681*6777b538SAndroid Build Coastguard Worker   auto parser = response.Parser();
1682*6777b538SAndroid Build Coastguard Worker   net::DnsResourceRecord parsed_record;
1683*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(parser.ReadRecord(&parsed_record));
1684*6777b538SAndroid Build Coastguard Worker   // Answer with an A record.
1685*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(answer.name, parsed_record.name);
1686*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(answer.type, parsed_record.type);
1687*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(answer.klass, parsed_record.klass);
1688*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(answer.ttl, parsed_record.ttl);
1689*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(answer.owned_rdata, parsed_record.rdata);
1690*6777b538SAndroid Build Coastguard Worker   // Additional NSEC record.
1691*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(parser.ReadRecord(&parsed_record));
1692*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(additional_record.name, parsed_record.name);
1693*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(additional_record.type, parsed_record.type);
1694*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(additional_record.klass, parsed_record.klass);
1695*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(additional_record.ttl, parsed_record.ttl);
1696*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(additional_record.owned_rdata, parsed_record.rdata);
1697*6777b538SAndroid Build Coastguard Worker }
1698*6777b538SAndroid Build Coastguard Worker 
TEST(DnsResponseWriteTest,CreateEmptyNoDataResponse)1699*6777b538SAndroid Build Coastguard Worker TEST(DnsResponseWriteTest, CreateEmptyNoDataResponse) {
1700*6777b538SAndroid Build Coastguard Worker   DnsResponse response = DnsResponse::CreateEmptyNoDataResponse(
1701*6777b538SAndroid Build Coastguard Worker       /*id=*/4,
1702*6777b538SAndroid Build Coastguard Worker       /*is_authoritative=*/true, base::as_byte_span("\x04name\x04test\x00"),
1703*6777b538SAndroid Build Coastguard Worker       dns_protocol::kTypeA);
1704*6777b538SAndroid Build Coastguard Worker 
1705*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(response.IsValid());
1706*6777b538SAndroid Build Coastguard Worker   EXPECT_THAT(response.id(), testing::Optional(4));
1707*6777b538SAndroid Build Coastguard Worker   EXPECT_TRUE(response.flags() & dns_protocol::kFlagAA);
1708*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(response.question_count(), 1u);
1709*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(response.answer_count(), 0u);
1710*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(response.authority_count(), 0u);
1711*6777b538SAndroid Build Coastguard Worker   EXPECT_EQ(response.additional_answer_count(), 0u);
1712*6777b538SAndroid Build Coastguard Worker 
1713*6777b538SAndroid Build Coastguard Worker   EXPECT_THAT(response.qtypes(), testing::ElementsAre(dns_protocol::kTypeA));
1714*6777b538SAndroid Build Coastguard Worker   EXPECT_THAT(response.dotted_qnames(), testing::ElementsAre("name.test"));
1715*6777b538SAndroid Build Coastguard Worker }
1716*6777b538SAndroid Build Coastguard Worker 
1717*6777b538SAndroid Build Coastguard Worker }  // namespace
1718*6777b538SAndroid Build Coastguard Worker 
1719*6777b538SAndroid Build Coastguard Worker }  // namespace net
1720