OLD | NEW |
| (Empty) |
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 | |
16 namespace net { | |
17 | |
18 namespace { | |
19 | |
20 TEST(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 | |
31 TEST(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 | |
77 TEST(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 | |
105 TEST(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 | |
157 TEST(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 | |
248 TEST(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 | |
276 TEST(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 | |
323 TEST(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 | |
381 TEST(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 | |
395 void 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 | |
404 TEST(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(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 | |
460 const 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 | |
470 const 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 | |
480 const 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 | |
490 const 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 | |
506 const 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 | |
516 const 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 | |
529 const 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 | |
543 TEST(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(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 | |
OLD | NEW |