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