1 // Copyright 2011 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_query.h"
6
7 #include <cstdint>
8 #include <memory>
9 #include <string>
10 #include <tuple>
11 #include <vector>
12
13 #include "base/containers/span.h"
14 #include "base/memory/scoped_refptr.h"
15 #include "net/base/io_buffer.h"
16 #include "net/dns/dns_names_util.h"
17 #include "net/dns/opt_record_rdata.h"
18 #include "net/dns/public/dns_protocol.h"
19 #include "net/dns/record_rdata.h"
20 #include "testing/gmock/include/gmock/gmock.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22 #include "third_party/abseil-cpp/absl/types/optional.h"
23
24 namespace net {
25
26 namespace {
27
28 using ::testing::ElementsAreArray;
29
AsTuple(const IOBufferWithSize * buf)30 std::tuple<char*, size_t> AsTuple(const IOBufferWithSize* buf) {
31 return std::make_tuple(buf->data(), buf->size());
32 }
33
ParseAndCreateDnsQueryFromRawPacket(const uint8_t * data,size_t length,std::unique_ptr<DnsQuery> * out)34 bool ParseAndCreateDnsQueryFromRawPacket(const uint8_t* data,
35 size_t length,
36 std::unique_ptr<DnsQuery>* out) {
37 auto packet = base::MakeRefCounted<IOBufferWithSize>(length);
38 memcpy(packet->data(), data, length);
39 *out = std::make_unique<DnsQuery>(packet);
40 return (*out)->Parse(length);
41 }
42
43 // This includes \0 at the end.
44 const char kQNameData[] =
45 "\x03"
46 "www"
47 "\x07"
48 "example"
49 "\x03"
50 "com";
51 const base::span<const uint8_t> kQName =
52 base::as_bytes(base::make_span(kQNameData));
53
TEST(DnsQueryTest,Constructor)54 TEST(DnsQueryTest, Constructor) {
55 // This includes \0 at the end.
56 const uint8_t query_data[] = {
57 // Header
58 0xbe, 0xef, 0x01, 0x00, // Flags -- set RD (recursion desired) bit.
59 0x00, 0x01, // Set QDCOUNT (question count) to 1, all the
60 // rest are 0 for a query.
61 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
62
63 // Question
64 0x03, 'w', 'w', 'w', // QNAME: www.example.com in DNS format.
65 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0x03, 'c', 'o', 'm', 0x00,
66
67 0x00, 0x01, // QTYPE: A query.
68 0x00, 0x01, // QCLASS: IN class.
69 };
70
71 DnsQuery q1(0xbeef, kQName, dns_protocol::kTypeA);
72 EXPECT_EQ(dns_protocol::kTypeA, q1.qtype());
73 EXPECT_THAT(AsTuple(q1.io_buffer()), ElementsAreArray(query_data));
74 EXPECT_THAT(q1.qname(), ElementsAreArray(kQName));
75
76 base::StringPiece question(reinterpret_cast<const char*>(query_data) + 12,
77 21);
78 EXPECT_EQ(question, q1.question());
79 }
80
TEST(DnsQueryTest,CopiesAreIndependent)81 TEST(DnsQueryTest, CopiesAreIndependent) {
82 DnsQuery q1(26 /* id */, kQName, dns_protocol::kTypeAAAA);
83
84 DnsQuery q2(q1);
85
86 EXPECT_EQ(q1.id(), q2.id());
87 EXPECT_EQ(base::StringPiece(q1.io_buffer()->data(), q1.io_buffer()->size()),
88 base::StringPiece(q2.io_buffer()->data(), q2.io_buffer()->size()));
89 EXPECT_NE(q1.io_buffer(), q2.io_buffer());
90 }
91
TEST(DnsQueryTest,Clone)92 TEST(DnsQueryTest, Clone) {
93 DnsQuery q1(0, kQName, dns_protocol::kTypeA);
94 EXPECT_EQ(0, q1.id());
95 std::unique_ptr<DnsQuery> q2 = q1.CloneWithNewId(42);
96 EXPECT_EQ(42, q2->id());
97 EXPECT_EQ(q1.io_buffer()->size(), q2->io_buffer()->size());
98 EXPECT_EQ(q1.qtype(), q2->qtype());
99 EXPECT_EQ(q1.question(), q2->question());
100 }
101
TEST(DnsQueryTest,EDNS0)102 TEST(DnsQueryTest, EDNS0) {
103 const uint8_t query_data[] = {
104 // Header
105 0xbe, 0xef, 0x01, 0x00, // Flags -- set RD (recursion desired) bit.
106 // Set QDCOUNT (question count) and ARCOUNT (additional count) to 1, all
107 // the rest are 0 for a query.
108 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
109 // Question
110 0x03, 'w', 'w', 'w', // QNAME: www.example.com in DNS format.
111 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0x03, 'c', 'o', 'm', 0x00,
112
113 0x00, 0x01, // QTYPE: A query.
114 0x00, 0x01, // QCLASS: IN class.
115
116 // Additional
117 0x00, // QNAME: empty (root domain)
118 0x00, 0x29, // TYPE: OPT
119 0x10, 0x00, // CLASS: max UDP payload size
120 0x00, 0x00, 0x00, 0x00, // TTL: rcode, version and flags
121 0x00, 0x08, // RDATA length
122 0x00, 0xFF, // OPT code
123 0x00, 0x04, // OPT data size
124 0xDE, 0xAD, 0xBE, 0xEF // OPT data
125 };
126
127 OptRecordRdata opt_rdata;
128 opt_rdata.AddOpt(
129 OptRecordRdata::UnknownOpt::CreateForTesting(255, "\xde\xad\xbe\xef"));
130 DnsQuery q1(0xbeef, kQName, dns_protocol::kTypeA, &opt_rdata);
131 EXPECT_EQ(dns_protocol::kTypeA, q1.qtype());
132
133 EXPECT_THAT(AsTuple(q1.io_buffer()), ElementsAreArray(query_data));
134
135 base::StringPiece question(reinterpret_cast<const char*>(query_data) + 12,
136 21);
137 EXPECT_EQ(question, q1.question());
138 }
139
TEST(DnsQueryTest,Block128Padding)140 TEST(DnsQueryTest, Block128Padding) {
141 DnsQuery query(46 /* id */, kQName, dns_protocol::kTypeAAAA,
142 nullptr /* opt_rdata */,
143 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
144
145 // Query is expected to be short and fit in a single 128-byte padded block.
146 EXPECT_EQ(128, query.io_buffer()->size());
147
148 // Ensure created query still parses as expected.
149 DnsQuery parsed_query(query.io_buffer());
150 ASSERT_TRUE(parsed_query.Parse(query.io_buffer()->size()));
151 EXPECT_THAT(parsed_query.qname(), ElementsAreArray(kQName));
152 EXPECT_EQ(parsed_query.qtype(), dns_protocol::kTypeAAAA);
153 }
154
TEST(DnsQueryTest,Block128Padding_LongName)155 TEST(DnsQueryTest, Block128Padding_LongName) {
156 absl::optional<std::vector<uint8_t>> qname =
157 dns_names_util::DottedNameToNetwork(
158 "really.long.domain.name.that.will.push.us.past.the.128.byte.block."
159 "size.because.it.would.be.nice.to.test.something.realy.long.like."
160 "that.com");
161 ASSERT_TRUE(qname.has_value());
162 DnsQuery query(112 /* id */, qname.value(), dns_protocol::kTypeAAAA,
163 nullptr /* opt_rdata */,
164 DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
165
166 // Query is expected to pad into a second 128-byte block.
167 EXPECT_EQ(query.io_buffer()->size(), 256);
168 EXPECT_THAT(query.qname(), ElementsAreArray(qname.value()));
169
170 // Ensure created query still parses as expected.
171 DnsQuery parsed_query(query.io_buffer());
172 ASSERT_TRUE(parsed_query.Parse(query.io_buffer()->size()));
173 EXPECT_THAT(parsed_query.qname(), ElementsAreArray(qname.value()));
174 EXPECT_EQ(parsed_query.qtype(), dns_protocol::kTypeAAAA);
175 }
176
TEST(DnsQueryParseTest,SingleQuestionForTypeARecord)177 TEST(DnsQueryParseTest, SingleQuestionForTypeARecord) {
178 const uint8_t query_data[] = {
179 0x12, 0x34, // ID
180 0x00, 0x00, // flags
181 0x00, 0x01, // number of questions
182 0x00, 0x00, // number of answer rr
183 0x00, 0x00, // number of name server rr
184 0x00, 0x00, // number of additional rr
185 0x03, 'w', 'w', 'w', 0x07, 'e', 'x', 'a',
186 'm', 'p', 'l', 'e', 0x03, 'c', 'o', 'm',
187 0x00, // null label
188 0x00, 0x01, // type A Record
189 0x00, 0x01, // class IN
190 };
191 std::unique_ptr<DnsQuery> query;
192 EXPECT_TRUE(ParseAndCreateDnsQueryFromRawPacket(query_data,
193 sizeof(query_data), &query));
194 EXPECT_EQ(query->id(), 0x1234);
195 EXPECT_THAT(query->qname(), ElementsAreArray(kQName));
196 EXPECT_EQ(query->qtype(), dns_protocol::kTypeA);
197 }
198
TEST(DnsQueryParseTest,SingleQuestionForTypeAAAARecord)199 TEST(DnsQueryParseTest, SingleQuestionForTypeAAAARecord) {
200 const uint8_t query_data[] = {
201 0x12, 0x34, // ID
202 0x00, 0x00, // flags
203 0x00, 0x01, // number of questions
204 0x00, 0x00, // number of answer rr
205 0x00, 0x00, // number of name server rr
206 0x00, 0x00, // number of additional rr
207 0x03, 'w', 'w', 'w', 0x07, 'e', 'x', 'a',
208 'm', 'p', 'l', 'e', 0x03, 'c', 'o', 'm',
209 0x00, // null label
210 0x00, 0x1c, // type AAAA Record
211 0x00, 0x01, // class IN
212 };
213 std::unique_ptr<DnsQuery> query;
214 EXPECT_TRUE(ParseAndCreateDnsQueryFromRawPacket(query_data,
215 sizeof(query_data), &query));
216 EXPECT_EQ(query->id(), 0x1234);
217 EXPECT_THAT(query->qname(), ElementsAreArray(kQName));
218 EXPECT_EQ(query->qtype(), dns_protocol::kTypeAAAA);
219 }
220
221 const uint8_t kQueryTruncatedQuestion[] = {
222 0x12, 0x34, // ID
223 0x00, 0x00, // flags
224 0x00, 0x02, // number of questions
225 0x00, 0x00, // number of answer rr
226 0x00, 0x00, // number of name server rr
227 0x00, 0x00, // number of additional rr
228 0x03, 'w', 'w', 'w', 0x07, 'e', 'x', 'a',
229 'm', 'p', 'l', 'e', 0x03, 'c', 'o', 'm',
230 0x00, // null label
231 0x00, 0x01, // type A Record
232 0x00, // class IN, truncated
233 };
234
235 const uint8_t kQueryTwoQuestions[] = {
236 0x12, 0x34, // ID
237 0x00, 0x00, // flags
238 0x00, 0x02, // number of questions
239 0x00, 0x00, // number of answer rr
240 0x00, 0x00, // number of name server rr
241 0x00, 0x00, // number of additional rr
242 0x03, 'w', 'w', 'w', 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e',
243 0x03, 'c', 'o', 'm',
244 0x00, // null label
245 0x00, 0x01, // type A Record
246 0x00, 0x01, // class IN
247 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0x03, 'o', 'r', 'g',
248 0x00, // null label
249 0x00, 0x1c, // type AAAA Record
250 0x00, 0x01, // class IN
251 };
252
253 const uint8_t kQueryInvalidDNSDomainName1[] = {
254 0x12, 0x34, // ID
255 0x00, 0x00, // flags
256 0x00, 0x01, // number of questions
257 0x00, 0x00, // number of answer rr
258 0x00, 0x00, // number of name server rr
259 0x00, 0x00, // number of additional rr
260 0x02, 'w', 'w', 'w', // wrong label length
261 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0x03, 'c', 'o', 'm',
262 0x00, // null label
263 0x00, 0x01, // type A Record
264 0x00, 0x01, // class IN
265 };
266
267 const uint8_t kQueryInvalidDNSDomainName2[] = {
268 0x12, 0x34, // ID
269 0x00, 0x00, // flags
270 0x00, 0x01, // number of questions
271 0x00, 0x00, // number of answer rr
272 0x00, 0x00, // number of name server rr
273 0x00, 0x00, // number of additional rr
274 0xc0, 0x02, // illegal name pointer
275 0x00, 0x01, // type A Record
276 0x00, 0x01, // class IN
277 };
278
TEST(DnsQueryParseTest,FailsInvalidQueries)279 TEST(DnsQueryParseTest, FailsInvalidQueries) {
280 const struct TestCase {
281 const uint8_t* data;
282 size_t size;
283 } testcases[] = {
284 {kQueryTruncatedQuestion, std::size(kQueryTruncatedQuestion)},
285 {kQueryTwoQuestions, std::size(kQueryTwoQuestions)},
286 {kQueryInvalidDNSDomainName1, std::size(kQueryInvalidDNSDomainName1)},
287 {kQueryInvalidDNSDomainName2, std::size(kQueryInvalidDNSDomainName2)}};
288 std::unique_ptr<DnsQuery> query;
289 for (const auto& testcase : testcases) {
290 EXPECT_FALSE(ParseAndCreateDnsQueryFromRawPacket(testcase.data,
291 testcase.size, &query));
292 }
293 }
294
TEST(DnsQueryParseTest,ParsesLongName)295 TEST(DnsQueryParseTest, ParsesLongName) {
296 const char kHeader[] =
297 "\x6f\x15" // ID
298 "\x00\x00" // FLAGS
299 "\x00\x01" // 1 question
300 "\x00\x00" // 0 answers
301 "\x00\x00" // 0 authority records
302 "\x00\x00"; // 0 additional records
303
304 std::string long_name;
305 for (int i = 0; i <= dns_protocol::kMaxNameLength - 10; i += 10) {
306 long_name.append("\x09loongname");
307 }
308 uint8_t remaining = dns_protocol::kMaxNameLength - long_name.size() - 1;
309 long_name.append(1, remaining);
310 for (int i = 0; i < remaining; ++i) {
311 long_name.append("a", 1);
312 }
313 ASSERT_LE(long_name.size(),
314 static_cast<size_t>(dns_protocol::kMaxNameLength));
315 long_name.append("\x00", 1);
316
317 std::string data(kHeader, sizeof(kHeader) - 1);
318 data.append(long_name);
319 data.append(
320 "\x00\x01" // TYPE=A
321 "\x00\x01", // CLASS=IN
322 4);
323
324 auto packet = base::MakeRefCounted<IOBufferWithSize>(data.size());
325 memcpy(packet->data(), data.data(), data.size());
326 DnsQuery query(packet);
327
328 EXPECT_TRUE(query.Parse(data.size()));
329 }
330
331 // Tests against incorrect name length validation, which is anti-pattern #3 from
332 // the "NAME:WRECK" report:
333 // https://www.forescout.com/company/resources/namewreck-breaking-and-fixing-dns-implementations/
TEST(DnsQueryParseTest,FailsTooLongName)334 TEST(DnsQueryParseTest, FailsTooLongName) {
335 const char kHeader[] =
336 "\x5f\x15" // ID
337 "\x00\x00" // FLAGS
338 "\x00\x01" // 1 question
339 "\x00\x00" // 0 answers
340 "\x00\x00" // 0 authority records
341 "\x00\x00"; // 0 additional records
342
343 std::string long_name;
344 for (int i = 0; i <= dns_protocol::kMaxNameLength; i += 10) {
345 long_name.append("\x09loongname");
346 }
347 ASSERT_GT(long_name.size(),
348 static_cast<size_t>(dns_protocol::kMaxNameLength));
349 long_name.append("\x00", 1);
350
351 std::string data(kHeader, sizeof(kHeader) - 1);
352 data.append(long_name);
353 data.append(
354 "\x00\x01" // TYPE=A
355 "\x00\x01", // CLASS=IN
356 4);
357
358 auto packet = base::MakeRefCounted<IOBufferWithSize>(data.size());
359 memcpy(packet->data(), data.data(), data.size());
360 DnsQuery query(packet);
361
362 EXPECT_FALSE(query.Parse(data.size()));
363 }
364
365 // Tests against incorrect name length validation, which is anti-pattern #3 from
366 // the "NAME:WRECK" report:
367 // https://www.forescout.com/company/resources/namewreck-breaking-and-fixing-dns-implementations/
TEST(DnsQueryParseTest,FailsTooLongSingleLabelName)368 TEST(DnsQueryParseTest, FailsTooLongSingleLabelName) {
369 const char kHeader[] =
370 "\x5f\x15" // ID
371 "\x00\x00" // FLAGS
372 "\x00\x01" // 1 question
373 "\x00\x00" // 0 answers
374 "\x00\x00" // 0 authority records
375 "\x00\x00"; // 0 additional records
376
377 std::string long_name;
378 long_name.append(1, static_cast<char>(dns_protocol::kMaxNameLength));
379 long_name.append(dns_protocol::kMaxNameLength, 'a');
380 ASSERT_GT(long_name.size(),
381 static_cast<size_t>(dns_protocol::kMaxNameLength));
382 long_name.append("\x00", 1);
383
384 std::string data(kHeader, sizeof(kHeader) - 1);
385 data.append(long_name);
386 data.append(
387 "\x00\x01" // TYPE=A
388 "\x00\x01", // CLASS=IN
389 4);
390
391 auto packet = base::MakeRefCounted<IOBufferWithSize>(data.size());
392 memcpy(packet->data(), data.data(), data.size());
393 DnsQuery query(packet);
394
395 EXPECT_FALSE(query.Parse(data.size()));
396 }
397
398 // Test that a query cannot be parsed with a name extending past the end of the
399 // data.
400 // Tests against incorrect name length validation, which is anti-pattern #3 from
401 // the "NAME:WRECK" report:
402 // https://www.forescout.com/company/resources/namewreck-breaking-and-fixing-dns-implementations/
TEST(DnsQueryParseTest,FailsNonendedName)403 TEST(DnsQueryParseTest, FailsNonendedName) {
404 const char kData[] =
405 "\x5f\x15" // ID
406 "\x00\x00" // FLAGS
407 "\x00\x01" // 1 question
408 "\x00\x00" // 0 answers
409 "\x00\x00" // 0 authority records
410 "\x00\x00" // 0 additional records
411 "\003www\006google\006test"; // Nonended name.
412
413 auto packet = base::MakeRefCounted<IOBufferWithSize>(sizeof(kData) - 1);
414 memcpy(packet->data(), kData, sizeof(kData) - 1);
415 DnsQuery query(packet);
416
417 EXPECT_FALSE(query.Parse(sizeof(kData) - 1));
418 }
419
420 // Test that a query 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 actual type unparsable.
423 // Tests against incorrect name null termination, which is anti-pattern #4 from
424 // the "NAME:WRECK" report:
425 // https://www.forescout.com/company/resources/namewreck-breaking-and-fixing-dns-implementations/
TEST(DnsQueryParseTest,FailsNameWithoutTerminator)426 TEST(DnsQueryParseTest, FailsNameWithoutTerminator) {
427 const char kData[] =
428 "\x5f\x15" // ID
429 "\x00\x00" // FLAGS
430 "\x00\x01" // 1 question
431 "\x00\x00" // 0 answers
432 "\x00\x00" // 0 authority records
433 "\x00\x00" // 0 additional records
434 "\003www\006google\004test" // Name without termination.
435 "\x00\x01" // TYPE=A
436 "\x00\x01"; // CLASS=IN
437
438 auto packet = base::MakeRefCounted<IOBufferWithSize>(sizeof(kData) - 1);
439 memcpy(packet->data(), kData, sizeof(kData) - 1);
440 DnsQuery query(packet);
441
442 EXPECT_FALSE(query.Parse(sizeof(kData) - 1));
443 }
444
TEST(DnsQueryParseTest,FailsQueryWithNoQuestions)445 TEST(DnsQueryParseTest, FailsQueryWithNoQuestions) {
446 const char kData[] =
447 "\x5f\x15" // ID
448 "\x00\x00" // FLAGS
449 "\x00\x00" // 0 questions
450 "\x00\x00" // 0 answers
451 "\x00\x00" // 0 authority records
452 "\x00\x00"; // 0 additional records
453
454 auto packet = base::MakeRefCounted<IOBufferWithSize>(sizeof(kData) - 1);
455 memcpy(packet->data(), kData, sizeof(kData) - 1);
456 DnsQuery query(packet);
457
458 EXPECT_FALSE(query.Parse(sizeof(kData) - 1));
459 }
460
TEST(DnsQueryParseTest,FailsQueryWithMultipleQuestions)461 TEST(DnsQueryParseTest, FailsQueryWithMultipleQuestions) {
462 const char kData[] =
463 "\x5f\x15" // ID
464 "\x00\x00" // FLAGS
465 "\x00\x02" // 2 questions
466 "\x00\x00" // 0 answers
467 "\x00\x00" // 0 authority records
468 "\x00\x00" // 0 additional records
469 "\003www\006google\004test\000" // www.google.test
470 "\x00\x01" // TYPE=A
471 "\x00\x01" // CLASS=IN
472 "\003www\006google\004test\000" // www.google.test
473 "\x00\x1c" // TYPE=AAAA
474 "\x00\x01"; // CLASS=IN
475
476 auto packet = base::MakeRefCounted<IOBufferWithSize>(sizeof(kData) - 1);
477 memcpy(packet->data(), kData, sizeof(kData) - 1);
478 DnsQuery query(packet);
479
480 EXPECT_FALSE(query.Parse(sizeof(kData) - 1));
481 }
482
483 // Test that if more questions are at the end of the buffer than the number of
484 // questions claimed in the query header, the extra questions are safely
485 // ignored.
TEST(DnsQueryParseTest,IgnoresExtraQuestion)486 TEST(DnsQueryParseTest, IgnoresExtraQuestion) {
487 const char kData[] =
488 "\x5f\x15" // ID
489 "\x00\x00" // FLAGS
490 "\x00\x01" // 1 question
491 "\x00\x00" // 0 answers
492 "\x00\x00" // 0 authority records
493 "\x00\x00" // 0 additional records
494 "\003www\006google\004test\000" // www.google.test
495 "\x00\x01" // TYPE=A
496 "\x00\x01" // CLASS=IN
497 "\003www\006google\004test\000" // www.google.test
498 "\x00\x1c" // TYPE=AAAA
499 "\x00\x01"; // CLASS=IN
500
501 auto packet = base::MakeRefCounted<IOBufferWithSize>(sizeof(kData) - 1);
502 memcpy(packet->data(), kData, sizeof(kData) - 1);
503 DnsQuery query(packet);
504
505 EXPECT_TRUE(query.Parse(sizeof(kData) - 1));
506
507 std::string expected_qname("\003www\006google\004test\000", 17);
508 EXPECT_THAT(query.qname(), ElementsAreArray(expected_qname));
509
510 EXPECT_EQ(query.qtype(), dns_protocol::kTypeA);
511 }
512
513 // Test that the query fails to parse if it does not contain the number of
514 // questions claimed in the query header.
515 // Tests against incorrect record count field validation, which is anti-pattern
516 // #5 from the "NAME:WRECK" report:
517 // https://www.forescout.com/company/resources/namewreck-breaking-and-fixing-dns-implementations/
TEST(DnsQueryParseTest,FailsQueryWithMissingQuestion)518 TEST(DnsQueryParseTest, FailsQueryWithMissingQuestion) {
519 const char kData[] =
520 "\x5f\x15" // ID
521 "\x00\x00" // FLAGS
522 "\x00\x01" // 1 question
523 "\x00\x00" // 0 answers
524 "\x00\x00" // 0 authority records
525 "\x00\x00"; // 0 additional records
526
527 auto packet = base::MakeRefCounted<IOBufferWithSize>(sizeof(kData) - 1);
528 memcpy(packet->data(), kData, sizeof(kData) - 1);
529 DnsQuery query(packet);
530
531 EXPECT_FALSE(query.Parse(sizeof(kData) - 1));
532 }
533
534 // Test that DnsQuery parsing disallows name compression pointers (which should
535 // never be useful when only single-question queries are parsed).
536 // Indirectly tests against incorrect name compression pointer validation, which
537 // is anti-pattern #6 from the "NAME:WRECK" report:
538 // https://www.forescout.com/company/resources/namewreck-breaking-and-fixing-dns-implementations/
TEST(DnsQueryParseTest,FailsQueryWithNamePointer)539 TEST(DnsQueryParseTest, FailsQueryWithNamePointer) {
540 const char kData[] =
541 "\x5f\x15" // ID
542 "\x00\x00" // FLAGS
543 "\x00\x01" // 1 question
544 "\x00\x00" // 0 answers
545 "\x00\x00" // 0 authority records
546 "\x00\x00" // 0 additional records
547 "\003www\006google\300\035" // Name with pointer to byte 29
548 "\x00\x01" // TYPE=A
549 "\x00\x01" // CLASS=IN
550 "\004test\000"; // Byte 29 (name pointer destination): test.
551
552 auto packet = base::MakeRefCounted<IOBufferWithSize>(sizeof(kData) - 1);
553 memcpy(packet->data(), kData, sizeof(kData) - 1);
554 DnsQuery query(packet);
555
556 EXPECT_FALSE(query.Parse(sizeof(kData) - 1));
557 }
558
559 } // namespace
560
561 } // namespace net
562