• 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 #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