1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
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_response.h"
6
7#include "base/time/time.h"
8#include "net/base/address_list.h"
9#include "net/base/io_buffer.h"
10#include "net/base/net_util.h"
11#include "net/dns/dns_protocol.h"
12#include "net/dns/dns_query.h"
13#include "net/dns/dns_test_util.h"
14#include "testing/gtest/include/gtest/gtest.h"
15
16namespace net {
17
18namespace {
19
20TEST(DnsRecordParserTest, Constructor) {
21  const char data[] = { 0 };
22
23  EXPECT_FALSE(DnsRecordParser().IsValid());
24  EXPECT_TRUE(DnsRecordParser(data, 1, 0).IsValid());
25  EXPECT_TRUE(DnsRecordParser(data, 1, 1).IsValid());
26
27  EXPECT_FALSE(DnsRecordParser(data, 1, 0).AtEnd());
28  EXPECT_TRUE(DnsRecordParser(data, 1, 1).AtEnd());
29}
30
31TEST(DnsRecordParserTest, ReadName) {
32  const uint8 data[] = {
33      // all labels "foo.example.com"
34      0x03, 'f', 'o', 'o',
35      0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e',
36      0x03, 'c', 'o', 'm',
37      // byte 0x10
38      0x00,
39      // byte 0x11
40      // part label, part pointer, "bar.example.com"
41      0x03, 'b', 'a', 'r',
42      0xc0, 0x04,
43      // byte 0x17
44      // all pointer to "bar.example.com", 2 jumps
45      0xc0, 0x11,
46      // byte 0x1a
47  };
48
49  std::string out;
50  DnsRecordParser parser(data, sizeof(data), 0);
51  ASSERT_TRUE(parser.IsValid());
52
53  EXPECT_EQ(0x11u, parser.ReadName(data + 0x00, &out));
54  EXPECT_EQ("foo.example.com", out);
55  // Check that the last "." is never stored.
56  out.clear();
57  EXPECT_EQ(0x1u, parser.ReadName(data + 0x10, &out));
58  EXPECT_EQ("", out);
59  out.clear();
60  EXPECT_EQ(0x6u, parser.ReadName(data + 0x11, &out));
61  EXPECT_EQ("bar.example.com", out);
62  out.clear();
63  EXPECT_EQ(0x2u, parser.ReadName(data + 0x17, &out));
64  EXPECT_EQ("bar.example.com", out);
65
66  // Parse name without storing it.
67  EXPECT_EQ(0x11u, parser.ReadName(data + 0x00, NULL));
68  EXPECT_EQ(0x1u, parser.ReadName(data + 0x10, NULL));
69  EXPECT_EQ(0x6u, parser.ReadName(data + 0x11, NULL));
70  EXPECT_EQ(0x2u, parser.ReadName(data + 0x17, NULL));
71
72  // Check that it works even if initial position is different.
73  parser = DnsRecordParser(data, sizeof(data), 0x12);
74  EXPECT_EQ(0x6u, parser.ReadName(data + 0x11, NULL));
75}
76
77TEST(DnsRecordParserTest, ReadNameFail) {
78  const uint8 data[] = {
79      // label length beyond packet
80      0x30, 'x', 'x',
81      0x00,
82      // pointer offset beyond packet
83      0xc0, 0x20,
84      // pointer loop
85      0xc0, 0x08,
86      0xc0, 0x06,
87      // incorrect label type (currently supports only direct and pointer)
88      0x80, 0x00,
89      // truncated name (missing root label)
90      0x02, 'x', 'x',
91  };
92
93  DnsRecordParser parser(data, sizeof(data), 0);
94  ASSERT_TRUE(parser.IsValid());
95
96  std::string out;
97  EXPECT_EQ(0u, parser.ReadName(data + 0x00, &out));
98  EXPECT_EQ(0u, parser.ReadName(data + 0x04, &out));
99  EXPECT_EQ(0u, parser.ReadName(data + 0x08, &out));
100  EXPECT_EQ(0u, parser.ReadName(data + 0x0a, &out));
101  EXPECT_EQ(0u, parser.ReadName(data + 0x0c, &out));
102  EXPECT_EQ(0u, parser.ReadName(data + 0x0e, &out));
103}
104
105TEST(DnsRecordParserTest, ReadRecord) {
106  const uint8 data[] = {
107      // Type CNAME record.
108      0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e',
109      0x03, 'c', 'o', 'm',
110      0x00,
111      0x00, 0x05,              // TYPE is CNAME.
112      0x00, 0x01,              // CLASS is IN.
113      0x00, 0x01, 0x24, 0x74,  // TTL is 0x00012474.
114      0x00, 0x06,              // RDLENGTH is 6 bytes.
115      0x03, 'f', 'o', 'o',     // compressed name in record
116      0xc0, 0x00,
117      // Type A record.
118      0x03, 'b', 'a', 'r',     // compressed owner name
119      0xc0, 0x00,
120      0x00, 0x01,              // TYPE is A.
121      0x00, 0x01,              // CLASS is IN.
122      0x00, 0x20, 0x13, 0x55,  // TTL is 0x00201355.
123      0x00, 0x04,              // RDLENGTH is 4 bytes.
124      0x7f, 0x02, 0x04, 0x01,  // IP is 127.2.4.1
125  };
126
127  std::string out;
128  DnsRecordParser parser(data, sizeof(data), 0);
129
130  DnsResourceRecord record;
131  EXPECT_TRUE(parser.ReadRecord(&record));
132  EXPECT_EQ("example.com", record.name);
133  EXPECT_EQ(dns_protocol::kTypeCNAME, record.type);
134  EXPECT_EQ(dns_protocol::kClassIN, record.klass);
135  EXPECT_EQ(0x00012474u, record.ttl);
136  EXPECT_EQ(6u, record.rdata.length());
137  EXPECT_EQ(6u, parser.ReadName(record.rdata.data(), &out));
138  EXPECT_EQ("foo.example.com", out);
139  EXPECT_FALSE(parser.AtEnd());
140
141  EXPECT_TRUE(parser.ReadRecord(&record));
142  EXPECT_EQ("bar.example.com", record.name);
143  EXPECT_EQ(dns_protocol::kTypeA, record.type);
144  EXPECT_EQ(dns_protocol::kClassIN, record.klass);
145  EXPECT_EQ(0x00201355u, record.ttl);
146  EXPECT_EQ(4u, record.rdata.length());
147  EXPECT_EQ(base::StringPiece("\x7f\x02\x04\x01"), record.rdata);
148  EXPECT_TRUE(parser.AtEnd());
149
150  // Test truncated record.
151  parser = DnsRecordParser(data, sizeof(data) - 2, 0);
152  EXPECT_TRUE(parser.ReadRecord(&record));
153  EXPECT_FALSE(parser.AtEnd());
154  EXPECT_FALSE(parser.ReadRecord(&record));
155}
156
157TEST(DnsResponseTest, InitParse) {
158  // This includes \0 at the end.
159  const char qname_data[] = "\x0A""codereview""\x08""chromium""\x03""org";
160  const base::StringPiece qname(qname_data, sizeof(qname_data));
161  // Compilers want to copy when binding temporary to const &, so must use heap.
162  scoped_ptr<DnsQuery> query(new DnsQuery(0xcafe, qname, dns_protocol::kTypeA));
163
164  const uint8 response_data[] = {
165    // Header
166    0xca, 0xfe,               // ID
167    0x81, 0x80,               // Standard query response, RA, no error
168    0x00, 0x01,               // 1 question
169    0x00, 0x02,               // 2 RRs (answers)
170    0x00, 0x00,               // 0 authority RRs
171    0x00, 0x00,               // 0 additional RRs
172
173    // Question
174    // This part is echoed back from the respective query.
175    0x0a, 'c', 'o', 'd', 'e', 'r', 'e', 'v', 'i', 'e', 'w',
176    0x08, 'c', 'h', 'r', 'o', 'm', 'i', 'u', 'm',
177    0x03, 'o', 'r', 'g',
178    0x00,
179    0x00, 0x01,        // TYPE is A.
180    0x00, 0x01,        // CLASS is IN.
181
182    // Answer 1
183    0xc0, 0x0c,        // NAME is a pointer to name in Question section.
184    0x00, 0x05,        // TYPE is CNAME.
185    0x00, 0x01,        // CLASS is IN.
186    0x00, 0x01,        // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
187    0x24, 0x74,
188    0x00, 0x12,        // RDLENGTH is 18 bytes.
189    // ghs.l.google.com in DNS format.
190    0x03, 'g', 'h', 's',
191    0x01, 'l',
192    0x06, 'g', 'o', 'o', 'g', 'l', 'e',
193    0x03, 'c', 'o', 'm',
194    0x00,
195
196    // Answer 2
197    0xc0, 0x35,         // NAME is a pointer to name in Answer 1.
198    0x00, 0x01,         // TYPE is A.
199    0x00, 0x01,         // CLASS is IN.
200    0x00, 0x00,         // TTL (4 bytes) is 53 seconds.
201    0x00, 0x35,
202    0x00, 0x04,         // RDLENGTH is 4 bytes.
203    0x4a, 0x7d,         // RDATA is the IP: 74.125.95.121
204    0x5f, 0x79,
205  };
206
207  DnsResponse resp;
208  memcpy(resp.io_buffer()->data(), response_data, sizeof(response_data));
209
210  // Reject too short.
211  EXPECT_FALSE(resp.InitParse(query->io_buffer()->size() - 1, *query));
212  EXPECT_FALSE(resp.IsValid());
213
214  // Reject wrong id.
215  scoped_ptr<DnsQuery> other_query(query->CloneWithNewId(0xbeef));
216  EXPECT_FALSE(resp.InitParse(sizeof(response_data), *other_query));
217  EXPECT_FALSE(resp.IsValid());
218
219  // Reject wrong question.
220  scoped_ptr<DnsQuery> wrong_query(
221      new DnsQuery(0xcafe, qname, dns_protocol::kTypeCNAME));
222  EXPECT_FALSE(resp.InitParse(sizeof(response_data), *wrong_query));
223  EXPECT_FALSE(resp.IsValid());
224
225  // Accept matching question.
226  EXPECT_TRUE(resp.InitParse(sizeof(response_data), *query));
227  EXPECT_TRUE(resp.IsValid());
228
229  // Check header access.
230  EXPECT_EQ(0x8180, resp.flags());
231  EXPECT_EQ(0x0, resp.rcode());
232  EXPECT_EQ(2u, resp.answer_count());
233
234  // Check question access.
235  EXPECT_EQ(query->qname(), resp.qname());
236  EXPECT_EQ(query->qtype(), resp.qtype());
237  EXPECT_EQ("codereview.chromium.org", resp.GetDottedName());
238
239  DnsResourceRecord record;
240  DnsRecordParser parser = resp.Parser();
241  EXPECT_TRUE(parser.ReadRecord(&record));
242  EXPECT_FALSE(parser.AtEnd());
243  EXPECT_TRUE(parser.ReadRecord(&record));
244  EXPECT_TRUE(parser.AtEnd());
245  EXPECT_FALSE(parser.ReadRecord(&record));
246}
247
248TEST(DnsResponseTest, InitParseWithoutQuery) {
249  DnsResponse resp;
250  memcpy(resp.io_buffer()->data(), kT0ResponseDatagram,
251         sizeof(kT0ResponseDatagram));
252
253  // Accept matching question.
254  EXPECT_TRUE(resp.InitParseWithoutQuery(sizeof(kT0ResponseDatagram)));
255  EXPECT_TRUE(resp.IsValid());
256
257  // Check header access.
258  EXPECT_EQ(0x8180, resp.flags());
259  EXPECT_EQ(0x0, resp.rcode());
260  EXPECT_EQ(kT0RecordCount, resp.answer_count());
261
262  // Check question access.
263  EXPECT_EQ(kT0Qtype, resp.qtype());
264  EXPECT_EQ(kT0HostName, resp.GetDottedName());
265
266  DnsResourceRecord record;
267  DnsRecordParser parser = resp.Parser();
268  for (unsigned i = 0; i < kT0RecordCount; i ++) {
269    EXPECT_FALSE(parser.AtEnd());
270    EXPECT_TRUE(parser.ReadRecord(&record));
271  }
272  EXPECT_TRUE(parser.AtEnd());
273  EXPECT_FALSE(parser.ReadRecord(&record));
274}
275
276TEST(DnsResponseTest, InitParseWithoutQueryNoQuestions) {
277  const uint8 response_data[] = {
278    // Header
279    0xca, 0xfe,               // ID
280    0x81, 0x80,               // Standard query response, RA, no error
281    0x00, 0x00,               // No question
282    0x00, 0x01,               // 2 RRs (answers)
283    0x00, 0x00,               // 0 authority RRs
284    0x00, 0x00,               // 0 additional RRs
285
286    // Answer 1
287    0x0a, 'c', 'o', 'd', 'e', 'r', 'e', 'v', 'i', 'e', 'w',
288    0x08, 'c', 'h', 'r', 'o', 'm', 'i', 'u', 'm',
289    0x03, 'o', 'r', 'g',
290    0x00,
291    0x00, 0x01,         // TYPE is A.
292    0x00, 0x01,         // CLASS is IN.
293    0x00, 0x00,         // TTL (4 bytes) is 53 seconds.
294    0x00, 0x35,
295    0x00, 0x04,         // RDLENGTH is 4 bytes.
296    0x4a, 0x7d,         // RDATA is the IP: 74.125.95.121
297    0x5f, 0x79,
298  };
299
300  DnsResponse resp;
301  memcpy(resp.io_buffer()->data(), response_data, sizeof(response_data));
302
303  EXPECT_TRUE(resp.InitParseWithoutQuery(sizeof(response_data)));
304
305  // Check header access.
306  EXPECT_EQ(0x8180, resp.flags());
307  EXPECT_EQ(0x0, resp.rcode());
308  EXPECT_EQ(0x1u, resp.answer_count());
309
310  DnsResourceRecord record;
311  DnsRecordParser parser = resp.Parser();
312
313  EXPECT_FALSE(parser.AtEnd());
314  EXPECT_TRUE(parser.ReadRecord(&record));
315  EXPECT_EQ("codereview.chromium.org", record.name);
316  EXPECT_EQ(0x00000035u, record.ttl);
317  EXPECT_EQ(dns_protocol::kTypeA, record.type);
318
319  EXPECT_TRUE(parser.AtEnd());
320  EXPECT_FALSE(parser.ReadRecord(&record));
321}
322
323TEST(DnsResponseTest, InitParseWithoutQueryTwoQuestions) {
324  const uint8 response_data[] = {
325    // Header
326    0xca, 0xfe,               // ID
327    0x81, 0x80,               // Standard query response, RA, no error
328    0x00, 0x02,               // 2 questions
329    0x00, 0x01,               // 2 RRs (answers)
330    0x00, 0x00,               // 0 authority RRs
331    0x00, 0x00,               // 0 additional RRs
332
333    // Question 1
334    0x0a, 'c', 'o', 'd', 'e', 'r', 'e', 'v', 'i', 'e', 'w',
335    0x08, 'c', 'h', 'r', 'o', 'm', 'i', 'u', 'm',
336    0x03, 'o', 'r', 'g',
337    0x00,
338    0x00, 0x01,        // TYPE is A.
339    0x00, 0x01,        // CLASS is IN.
340
341    // Question 2
342    0x0b, 'c', 'o', 'd', 'e', 'r', 'e', 'v', 'i', 'e', 'w', '2',
343    0xc0, 0x18,        // pointer to "chromium.org"
344    0x00, 0x01,        // TYPE is A.
345    0x00, 0x01,        // CLASS is IN.
346
347    // Answer 1
348    0xc0, 0x0c,         // NAME is a pointer to name in Question section.
349    0x00, 0x01,         // TYPE is A.
350    0x00, 0x01,         // CLASS is IN.
351    0x00, 0x00,         // TTL (4 bytes) is 53 seconds.
352    0x00, 0x35,
353    0x00, 0x04,         // RDLENGTH is 4 bytes.
354    0x4a, 0x7d,         // RDATA is the IP: 74.125.95.121
355    0x5f, 0x79,
356  };
357
358  DnsResponse resp;
359  memcpy(resp.io_buffer()->data(), response_data, sizeof(response_data));
360
361  EXPECT_TRUE(resp.InitParseWithoutQuery(sizeof(response_data)));
362
363  // Check header access.
364  EXPECT_EQ(0x8180, resp.flags());
365  EXPECT_EQ(0x0, resp.rcode());
366  EXPECT_EQ(0x01u, resp.answer_count());
367
368  DnsResourceRecord record;
369  DnsRecordParser parser = resp.Parser();
370
371  EXPECT_FALSE(parser.AtEnd());
372  EXPECT_TRUE(parser.ReadRecord(&record));
373  EXPECT_EQ("codereview.chromium.org", record.name);
374  EXPECT_EQ(0x35u, record.ttl);
375  EXPECT_EQ(dns_protocol::kTypeA, record.type);
376
377  EXPECT_TRUE(parser.AtEnd());
378  EXPECT_FALSE(parser.ReadRecord(&record));
379}
380
381TEST(DnsResponseTest, InitParseWithoutQueryPacketTooShort) {
382  const uint8 response_data[] = {
383    // Header
384    0xca, 0xfe,               // ID
385    0x81, 0x80,               // Standard query response, RA, no error
386    0x00, 0x00,               // No question
387  };
388
389  DnsResponse resp;
390  memcpy(resp.io_buffer()->data(), response_data, sizeof(response_data));
391
392  EXPECT_FALSE(resp.InitParseWithoutQuery(sizeof(response_data)));
393}
394
395void VerifyAddressList(const std::vector<const char*>& ip_addresses,
396                       const AddressList& addrlist) {
397  ASSERT_EQ(ip_addresses.size(), addrlist.size());
398
399  for (size_t i = 0; i < addrlist.size(); ++i) {
400    EXPECT_EQ(ip_addresses[i], addrlist[i].ToStringWithoutPort());
401  }
402}
403
404TEST(DnsResponseTest, ParseToAddressList) {
405  const struct TestCase {
406    size_t query_size;
407    const uint8* response_data;
408    size_t response_size;
409    const char* const* expected_addresses;
410    size_t num_expected_addresses;
411    const char* expected_cname;
412    int expected_ttl_sec;
413  } cases[] = {
414      {
415        kT0QuerySize,
416        kT0ResponseDatagram, arraysize(kT0ResponseDatagram),
417        kT0IpAddresses, arraysize(kT0IpAddresses),
418        kT0CanonName,
419        kT0TTL,
420      },
421      {
422        kT1QuerySize,
423        kT1ResponseDatagram, arraysize(kT1ResponseDatagram),
424        kT1IpAddresses, arraysize(kT1IpAddresses),
425        kT1CanonName,
426        kT1TTL,
427      },
428      {
429        kT2QuerySize,
430        kT2ResponseDatagram, arraysize(kT2ResponseDatagram),
431        kT2IpAddresses, arraysize(kT2IpAddresses),
432        kT2CanonName,
433        kT2TTL,
434      },
435      {
436        kT3QuerySize,
437        kT3ResponseDatagram, arraysize(kT3ResponseDatagram),
438        kT3IpAddresses, arraysize(kT3IpAddresses),
439        kT3CanonName,
440        kT3TTL,
441      },
442  };
443
444  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
445    const TestCase& t = cases[i];
446    DnsResponse response(t.response_data, t.response_size, t.query_size);
447    AddressList addr_list;
448    base::TimeDelta ttl;
449    EXPECT_EQ(DnsResponse::DNS_PARSE_OK,
450              response.ParseToAddressList(&addr_list, &ttl));
451    std::vector<const char*> expected_addresses(
452        t.expected_addresses,
453        t.expected_addresses + t.num_expected_addresses);
454    VerifyAddressList(expected_addresses, addr_list);
455    EXPECT_EQ(t.expected_cname, addr_list.canonical_name());
456    EXPECT_EQ(base::TimeDelta::FromSeconds(t.expected_ttl_sec), ttl);
457  }
458}
459
460const uint8 kResponseTruncatedRecord[] = {
461  // Header: 1 question, 1 answer RR
462  0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
463  // Question: name = 'a', type = A (0x1)
464  0x01,  'a', 0x00, 0x00, 0x01, 0x00, 0x01,
465  // Answer: name = 'a', type = A, TTL = 0xFF, RDATA = 10.10.10.10
466  0x01,  'a', 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF,
467  0x00, 0x04, 0x0A, 0x0A, 0x0A,  // Truncated RDATA.
468};
469
470const uint8 kResponseTruncatedCNAME[] = {
471  // Header: 1 question, 1 answer RR
472  0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
473  // Question: name = 'a', type = A (0x1)
474  0x01,  'a', 0x00, 0x00, 0x01, 0x00, 0x01,
475  // Answer: name = 'a', type = CNAME, TTL = 0xFF, RDATA = 'foo' (truncated)
476  0x01,  'a', 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF,
477  0x00, 0x03, 0x03,  'f',  'o',  // Truncated name.
478};
479
480const uint8 kResponseNameMismatch[] = {
481  // Header: 1 question, 1 answer RR
482  0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
483  // Question: name = 'a', type = A (0x1)
484  0x01,  'a', 0x00, 0x00, 0x01, 0x00, 0x01,
485  // Answer: name = 'b', type = A, TTL = 0xFF, RDATA = 10.10.10.10
486  0x01,  'b', 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF,
487  0x00, 0x04, 0x0A, 0x0A, 0x0A, 0x0A,
488};
489
490const uint8 kResponseNameMismatchInChain[] = {
491  // Header: 1 question, 3 answer RR
492  0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
493  // Question: name = 'a', type = A (0x1)
494  0x01,  'a', 0x00, 0x00, 0x01, 0x00, 0x01,
495  // Answer: name = 'a', type = CNAME, TTL = 0xFF, RDATA = 'b'
496  0x01,  'a', 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF,
497  0x00, 0x03, 0x01,  'b', 0x00,
498  // Answer: name = 'b', type = A, TTL = 0xFF, RDATA = 10.10.10.10
499  0x01,  'b', 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF,
500  0x00, 0x04, 0x0A, 0x0A, 0x0A, 0x0A,
501  // Answer: name = 'c', type = A, TTL = 0xFF, RDATA = 10.10.10.11
502  0x01,  'c', 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF,
503  0x00, 0x04, 0x0A, 0x0A, 0x0A, 0x0B,
504};
505
506const uint8 kResponseSizeMismatch[] = {
507  // Header: 1 answer RR
508  0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
509  // Question: name = 'a', type = AAAA (0x1c)
510  0x01,  'a', 0x00, 0x00, 0x1c, 0x00, 0x01,
511  // Answer: name = 'a', type = AAAA, TTL = 0xFF, RDATA = 10.10.10.10
512  0x01,  'a', 0x00, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF,
513  0x00, 0x04, 0x0A, 0x0A, 0x0A, 0x0A,
514};
515
516const uint8 kResponseCNAMEAfterAddress[] = {
517  // Header: 2 answer RR
518  0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
519  // Question: name = 'a', type = A (0x1)
520  0x01,  'a', 0x00, 0x00, 0x01, 0x00, 0x01,
521  // Answer: name = 'a', type = A, TTL = 0xFF, RDATA = 10.10.10.10.
522  0x01,  'a', 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF,
523  0x00, 0x04, 0x0A, 0x0A, 0x0A, 0x0A,
524  // Answer: name = 'a', type = CNAME, TTL = 0xFF, RDATA = 'b'
525  0x01,  'a', 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF,
526  0x00, 0x03, 0x01,  'b', 0x00,
527};
528
529const uint8 kResponseNoAddresses[] = {
530  // Header: 1 question, 1 answer RR, 1 authority RR
531  0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
532  // Question: name = 'a', type = A (0x1)
533  0x01,  'a', 0x00, 0x00, 0x01, 0x00, 0x01,
534  // Answer: name = 'a', type = CNAME, TTL = 0xFF, RDATA = 'b'
535  0x01,  'a', 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF,
536  0x00, 0x03, 0x01, 'b', 0x00,
537  // Authority section
538  // Answer: name = 'b', type = A, TTL = 0xFF, RDATA = 10.10.10.10
539  0x01,  'b', 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF,
540  0x00, 0x04, 0x0A, 0x0A, 0x0A, 0x0A,
541};
542
543TEST(DnsResponseTest, ParseToAddressListFail) {
544  const struct TestCase {
545    const uint8* data;
546    size_t size;
547    DnsResponse::Result expected_result;
548  } cases[] = {
549    { kResponseTruncatedRecord, arraysize(kResponseTruncatedRecord),
550      DnsResponse::DNS_MALFORMED_RESPONSE },
551    { kResponseTruncatedCNAME, arraysize(kResponseTruncatedCNAME),
552      DnsResponse::DNS_MALFORMED_CNAME },
553    { kResponseNameMismatch, arraysize(kResponseNameMismatch),
554      DnsResponse::DNS_NAME_MISMATCH },
555    { kResponseNameMismatchInChain, arraysize(kResponseNameMismatchInChain),
556      DnsResponse::DNS_NAME_MISMATCH },
557    { kResponseSizeMismatch, arraysize(kResponseSizeMismatch),
558      DnsResponse::DNS_SIZE_MISMATCH },
559    { kResponseCNAMEAfterAddress, arraysize(kResponseCNAMEAfterAddress),
560      DnsResponse::DNS_CNAME_AFTER_ADDRESS },
561    // Not actually a failure, just an empty result.
562    { kResponseNoAddresses, arraysize(kResponseNoAddresses),
563      DnsResponse::DNS_PARSE_OK },
564  };
565
566  const size_t kQuerySize = 12 + 7;
567
568  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
569    const TestCase& t = cases[i];
570
571    DnsResponse response(t.data, t.size, kQuerySize);
572    AddressList addr_list;
573    base::TimeDelta ttl;
574    EXPECT_EQ(t.expected_result,
575              response.ParseToAddressList(&addr_list, &ttl));
576  }
577}
578
579}  // namespace
580
581}  // namespace net
582