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