xref: /aosp_15_r20/external/cronet/net/dns/dns_query_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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