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