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