• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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