blob: b4106f923d4d50374965d84c7e8e99d34fccbff8 [file] [log] [blame]
Jason Jeremy Imana21be272020-10-21 17:53:45 +09001// Copyright 2020 The Chromium OS 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 "patchpanel/dns/dns_response.h"
6
7#include <algorithm>
8#include <memory>
9
10#include "base/big_endian.h"
11#include "base/optional.h"
12#include "base/stl_util.h"
13#include "base/time/time.h"
14
15#include "patchpanel/dns/dns_protocol.h"
16#include "patchpanel/dns/dns_query.h"
17#include "patchpanel/dns/dns_util.h"
18#include "patchpanel/dns/io_buffer.h"
19
20#include "testing/gmock/include/gmock/gmock.h"
21#include "testing/gtest/include/gtest/gtest.h"
22
23namespace patchpanel {
24
25namespace {
26
27// Taken from Chromium's "net/dns/dns_test_util.h".
28// Query/response set for www.google.com, ID is fixed to 0.
29static const char kT0HostName[] = "www.google.com";
30static const uint16_t kT0Qtype = dns_protocol::kTypeA;
31static const uint8_t kT0ResponseDatagram[] = {
32 // response contains one CNAME for www.l.google.com and the following
33 // IP addresses: 74.125.226.{179,180,176,177,178}
34 0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00,
35 0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03,
36 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05,
37 0x00, 0x01, 0x00, 0x01, 0x4d, 0x13, 0x00, 0x08, 0x03, 0x77, 0x77, 0x77,
38 0x01, 0x6c, 0xc0, 0x10, 0xc0, 0x2c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
39 0x00, 0xe4, 0x00, 0x04, 0x4a, 0x7d, 0xe2, 0xb3, 0xc0, 0x2c, 0x00, 0x01,
40 0x00, 0x01, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x04, 0x4a, 0x7d, 0xe2, 0xb4,
41 0xc0, 0x2c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x04,
42 0x4a, 0x7d, 0xe2, 0xb0, 0xc0, 0x2c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
43 0x00, 0xe4, 0x00, 0x04, 0x4a, 0x7d, 0xe2, 0xb1, 0xc0, 0x2c, 0x00, 0x01,
44 0x00, 0x01, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x04, 0x4a, 0x7d, 0xe2, 0xb2};
45static const char* const kT0IpAddresses[] = {
46 "74.125.226.179", "74.125.226.180", "74.125.226.176",
47 "74.125.226.177", "74.125.226.178"
48};
49// +1 for the CNAME record.
50static const unsigned kT0RecordCount = base::size(kT0IpAddresses) + 1;
51
52TEST(DnsRecordParserTest, Constructor) {
53 const char data[] = { 0 };
54
55 EXPECT_FALSE(DnsRecordParser().IsValid());
56 EXPECT_TRUE(DnsRecordParser(data, 1, 0).IsValid());
57 EXPECT_TRUE(DnsRecordParser(data, 1, 1).IsValid());
58
59 EXPECT_FALSE(DnsRecordParser(data, 1, 0).AtEnd());
60 EXPECT_TRUE(DnsRecordParser(data, 1, 1).AtEnd());
61}
62
63TEST(DnsRecordParserTest, ReadName) {
64 const uint8_t data[] = {
65 // all labels "foo.example.com"
66 0x03, 'f', 'o', 'o', 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0x03, 'c',
67 'o', 'm',
68 // byte 0x10
69 0x00,
70 // byte 0x11
71 // part label, part pointer, "bar.example.com"
72 0x03, 'b', 'a', 'r', 0xc0, 0x04,
73 // byte 0x17
74 // all pointer to "bar.example.com", 2 jumps
75 0xc0, 0x11,
76 // byte 0x1a
77 };
78
79 std::string out;
80 DnsRecordParser parser(data, sizeof(data), 0);
81 ASSERT_TRUE(parser.IsValid());
82
83 EXPECT_EQ(0x11u, parser.ReadName(data + 0x00, &out));
84 EXPECT_EQ("foo.example.com", out);
85 // Check that the last "." is never stored.
86 out.clear();
87 EXPECT_EQ(0x1u, parser.ReadName(data + 0x10, &out));
88 EXPECT_EQ("", out);
89 out.clear();
90 EXPECT_EQ(0x6u, parser.ReadName(data + 0x11, &out));
91 EXPECT_EQ("bar.example.com", out);
92 out.clear();
93 EXPECT_EQ(0x2u, parser.ReadName(data + 0x17, &out));
94 EXPECT_EQ("bar.example.com", out);
95
96 // Parse name without storing it.
97 EXPECT_EQ(0x11u, parser.ReadName(data + 0x00, nullptr));
98 EXPECT_EQ(0x1u, parser.ReadName(data + 0x10, nullptr));
99 EXPECT_EQ(0x6u, parser.ReadName(data + 0x11, nullptr));
100 EXPECT_EQ(0x2u, parser.ReadName(data + 0x17, nullptr));
101
102 // Check that it works even if initial position is different.
103 parser = DnsRecordParser(data, sizeof(data), 0x12);
104 EXPECT_EQ(0x6u, parser.ReadName(data + 0x11, nullptr));
105}
106
107TEST(DnsRecordParserTest, ReadNameFail) {
108 const uint8_t data[] = {
109 // label length beyond packet
110 0x30, 'x', 'x', 0x00,
111 // pointer offset beyond packet
112 0xc0, 0x20,
113 // pointer loop
114 0xc0, 0x08, 0xc0, 0x06,
115 // incorrect label type (currently supports only direct and pointer)
116 0x80, 0x00,
117 // truncated name (missing root label)
118 0x02, 'x', 'x',
119 };
120
121 DnsRecordParser parser(data, sizeof(data), 0);
122 ASSERT_TRUE(parser.IsValid());
123
124 std::string out;
125 EXPECT_EQ(0u, parser.ReadName(data + 0x00, &out));
126 EXPECT_EQ(0u, parser.ReadName(data + 0x04, &out));
127 EXPECT_EQ(0u, parser.ReadName(data + 0x08, &out));
128 EXPECT_EQ(0u, parser.ReadName(data + 0x0a, &out));
129 EXPECT_EQ(0u, parser.ReadName(data + 0x0c, &out));
130 EXPECT_EQ(0u, parser.ReadName(data + 0x0e, &out));
131}
132
133// Returns an RFC 1034 style domain name with a length of |name_len|.
134// Also writes the expected dotted string representation into |dotted_str|,
135// which must be non-null.
136std::vector<uint8_t> BuildRfc1034Name(const size_t name_len,
137 std::string* dotted_str) {
138 CHECK(dotted_str != nullptr);
139 auto ChoosePrintableCharLambda = [](uint8_t n) { return n % 26 + 'A'; };
140 const size_t max_label_len = 63;
141 std::vector<uint8_t> data;
142
143 dotted_str->clear();
144 while (data.size() < name_len) {
145 // Write the null label representing the root node.
146 if (data.size() == name_len - 1) {
147 data.push_back(0);
148 break;
149 }
150
151 // Compute the size of the next label.
152 //
153 // Suppose |name_len| is 8 and |data.size()| is 4. We want |label_len| to be
154 // 2 so that we are correctly aligned to put 0 in the final position.
155 //
156 // 3 'A' 'B' 'C' _ _ _ _
157 // 0 1 2 3 4 5 6 7
158 const size_t label_len =
159 std::min(name_len - data.size() - 2, max_label_len);
160 // Write the length octet
161 data.push_back(label_len);
162
163 // Write |label_len| bytes of label data
164 const size_t size_with_label = data.size() + label_len;
165 while (data.size() < size_with_label) {
166 const uint8_t chr = ChoosePrintableCharLambda(data.size());
167 data.push_back(chr);
168 dotted_str->push_back(chr);
169
170 CHECK(data.size() <= name_len);
171 }
172
173 // Write a trailing dot after every label
174 dotted_str->push_back('.');
175 }
176
177 // Omit the final dot
178 if (!dotted_str->empty())
179 dotted_str->pop_back();
180
181 CHECK(data.size() == name_len);
182 return data;
183}
184
185TEST(DnsRecordParserTest, ReadNameGoodLength) {
186 const size_t name_len_cases[] = {1, 10, 40, 250, 254, 255};
187
188 for (auto name_len : name_len_cases) {
189 std::string expected_name;
190 const std::vector<uint8_t> data_vector =
191 BuildRfc1034Name(name_len, &expected_name);
192 const uint8_t* data = data_vector.data();
193
194 DnsRecordParser parser(data, name_len, 0);
195 ASSERT_TRUE(parser.IsValid());
196
197 std::string out;
198 EXPECT_EQ(name_len, parser.ReadName(data, &out));
199 EXPECT_EQ(expected_name, out);
200 }
201}
202
203TEST(DnsRecordParserTest, ReadNameTooLongFail) {
204 const size_t name_len_cases[] = {256, 257, 258, 300, 10000};
205
206 for (auto name_len : name_len_cases) {
207 std::string expected_name;
208 const std::vector<uint8_t> data_vector =
209 BuildRfc1034Name(name_len, &expected_name);
210 const uint8_t* data = data_vector.data();
211
212 DnsRecordParser parser(data, name_len, 0);
213 ASSERT_TRUE(parser.IsValid());
214
215 std::string out;
216 EXPECT_EQ(0u, parser.ReadName(data, &out));
217 }
218}
219
220TEST(DnsRecordParserTest, ReadRecord) {
221 const uint8_t data[] = {
222 // Type CNAME record.
223 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0x03, 'c', 'o', 'm', 0x00, 0x00,
224 0x05, // TYPE is CNAME.
225 0x00, 0x01, // CLASS is IN.
226 0x00, 0x01, 0x24, 0x74, // TTL is 0x00012474.
227 0x00, 0x06, // RDLENGTH is 6 bytes.
228 0x03, 'f', 'o', 'o', // compressed name in record
229 0xc0, 0x00,
230 // Type A record.
231 0x03, 'b', 'a', 'r', // compressed owner name
232 0xc0, 0x00, 0x00, 0x01, // TYPE is A.
233 0x00, 0x01, // CLASS is IN.
234 0x00, 0x20, 0x13, 0x55, // TTL is 0x00201355.
235 0x00, 0x04, // RDLENGTH is 4 bytes.
236 0x7f, 0x02, 0x04, 0x01, // IP is 127.2.4.1
237 };
238
239 std::string out;
240 DnsRecordParser parser(data, sizeof(data), 0);
241
242 DnsResourceRecord record;
243 EXPECT_TRUE(parser.ReadRecord(&record));
244 EXPECT_EQ("example.com", record.name);
245 EXPECT_EQ(dns_protocol::kTypeCNAME, record.type);
246 EXPECT_EQ(dns_protocol::kClassIN, record.klass);
247 EXPECT_EQ(0x00012474u, record.ttl);
248 EXPECT_EQ(6u, record.rdata.length());
249 EXPECT_EQ(6u, parser.ReadName(record.rdata.data(), &out));
250 EXPECT_EQ("foo.example.com", out);
251 EXPECT_FALSE(parser.AtEnd());
252
253 EXPECT_TRUE(parser.ReadRecord(&record));
254 EXPECT_EQ("bar.example.com", record.name);
255 EXPECT_EQ(dns_protocol::kTypeA, record.type);
256 EXPECT_EQ(dns_protocol::kClassIN, record.klass);
257 EXPECT_EQ(0x00201355u, record.ttl);
258 EXPECT_EQ(4u, record.rdata.length());
259 EXPECT_EQ(base::StringPiece("\x7f\x02\x04\x01"), record.rdata);
260 EXPECT_TRUE(parser.AtEnd());
261
262 // Test truncated record.
263 parser = DnsRecordParser(data, sizeof(data) - 2, 0);
264 EXPECT_TRUE(parser.ReadRecord(&record));
265 EXPECT_FALSE(parser.AtEnd());
266 EXPECT_FALSE(parser.ReadRecord(&record));
267}
268
269TEST(DnsResponseTest, InitParseWithoutQuery) {
270 DnsResponse resp;
271 memcpy(resp.io_buffer()->data(), kT0ResponseDatagram,
272 sizeof(kT0ResponseDatagram));
273
274 // Accept matching question.
275 EXPECT_TRUE(resp.InitParseWithoutQuery(sizeof(kT0ResponseDatagram)));
276 EXPECT_TRUE(resp.IsValid());
277
278 // Check header access.
279 EXPECT_EQ(0x8180, resp.flags());
280 EXPECT_EQ(0x0, resp.rcode());
281 EXPECT_EQ(kT0RecordCount, resp.answer_count());
282
283 // Check question access.
284 EXPECT_EQ(kT0Qtype, resp.qtype());
285 EXPECT_EQ(kT0HostName, resp.GetDottedName());
286
287 DnsResourceRecord record;
288 DnsRecordParser parser = resp.Parser();
289 for (unsigned i = 0; i < kT0RecordCount; i ++) {
290 EXPECT_FALSE(parser.AtEnd());
291 EXPECT_TRUE(parser.ReadRecord(&record));
292 }
293 EXPECT_TRUE(parser.AtEnd());
294 EXPECT_FALSE(parser.ReadRecord(&record));
295}
296
297TEST(DnsResponseTest, InitParseWithoutQueryNoQuestions) {
298 const uint8_t response_data[] = {
299 // Header
300 0xca, 0xfe, // ID
301 0x81, 0x80, // Standard query response, RA, no error
302 0x00, 0x00, // No question
303 0x00, 0x01, // 2 RRs (answers)
304 0x00, 0x00, // 0 authority RRs
305 0x00, 0x00, // 0 additional RRs
306
307 // Answer 1
308 0x0a, 'c', 'o', 'd', 'e', 'r', 'e', 'v', 'i', 'e', 'w', 0x08, 'c', 'h',
309 'r', 'o', 'm', 'i', 'u', 'm', 0x03, 'o', 'r', 'g', 0x00, 0x00,
310 0x01, // TYPE is A.
311 0x00, 0x01, // CLASS is IN.
312 0x00, 0x00, // TTL (4 bytes) is 53 seconds.
313 0x00, 0x35, 0x00, 0x04, // RDLENGTH is 4 bytes.
314 0x4a, 0x7d, // RDATA is the IP: 74.125.95.121
315 0x5f, 0x79,
316 };
317
318 DnsResponse resp;
319 memcpy(resp.io_buffer()->data(), response_data, sizeof(response_data));
320
321 EXPECT_TRUE(resp.InitParseWithoutQuery(sizeof(response_data)));
322
323 // Check header access.
324 EXPECT_THAT(resp.id(), testing::Optional(0xcafe));
325 EXPECT_EQ(0x8180, resp.flags());
326 EXPECT_EQ(0x0, resp.rcode());
327 EXPECT_EQ(0x1u, resp.answer_count());
328
329 DnsResourceRecord record;
330 DnsRecordParser parser = resp.Parser();
331
332 EXPECT_FALSE(parser.AtEnd());
333 EXPECT_TRUE(parser.ReadRecord(&record));
334 EXPECT_EQ("codereview.chromium.org", record.name);
335 EXPECT_EQ(0x00000035u, record.ttl);
336 EXPECT_EQ(dns_protocol::kTypeA, record.type);
337
338 EXPECT_TRUE(parser.AtEnd());
339 EXPECT_FALSE(parser.ReadRecord(&record));
340}
341
342TEST(DnsResponseTest, InitParseWithoutQueryInvalidFlags) {
343 const uint8_t response_data[] = {
344 // Header
345 0xca, 0xfe, // ID
346 0x01, 0x80, // RA, no error. Note the absence of the required QR bit.
347 0x00, 0x00, // No question
348 0x00, 0x01, // 2 RRs (answers)
349 0x00, 0x00, // 0 authority RRs
350 0x00, 0x00, // 0 additional RRs
351
352 // Answer 1
353 0x0a, 'c', 'o', 'd', 'e', 'r', 'e', 'v', 'i', 'e', 'w', 0x08, 'c', 'h',
354 'r', 'o', 'm', 'i', 'u', 'm', 0x03, 'o', 'r', 'g', 0x00, 0x00,
355 0x01, // TYPE is A.
356 0x00, 0x01, // CLASS is IN.
357 0x00, 0x00, // TTL (4 bytes) is 53 seconds.
358 0x00, 0x35, 0x00, 0x04, // RDLENGTH is 4 bytes.
359 0x4a, 0x7d, // RDATA is the IP: 74.125.95.121
360 0x5f, 0x79,
361 };
362
363 DnsResponse resp;
364 memcpy(resp.io_buffer()->data(), response_data, sizeof(response_data));
365
366 EXPECT_FALSE(resp.InitParseWithoutQuery(sizeof(response_data)));
367 EXPECT_THAT(resp.id(), testing::Optional(0xcafe));
368}
369
370TEST(DnsResponseTest, InitParseWithoutQueryTwoQuestions) {
371 const uint8_t response_data[] = {
372 // Header
373 0xca, 0xfe, // ID
374 0x81, 0x80, // Standard query response, RA, no error
375 0x00, 0x02, // 2 questions
376 0x00, 0x01, // 2 RRs (answers)
377 0x00, 0x00, // 0 authority RRs
378 0x00, 0x00, // 0 additional RRs
379
380 // Question 1
381 0x0a, 'c', 'o', 'd', 'e', 'r', 'e', 'v', 'i', 'e', 'w', 0x08, 'c', 'h',
382 'r', 'o', 'm', 'i', 'u', 'm', 0x03, 'o', 'r', 'g', 0x00, 0x00,
383 0x01, // TYPE is A.
384 0x00, 0x01, // CLASS is IN.
385
386 // Question 2
387 0x0b, 'c', 'o', 'd', 'e', 'r', 'e', 'v', 'i', 'e', 'w', '2', 0xc0,
388 0x18, // pointer to "chromium.org"
389 0x00, 0x01, // TYPE is A.
390 0x00, 0x01, // CLASS is IN.
391
392 // Answer 1
393 0xc0, 0x0c, // NAME is a pointer to name in Question section.
394 0x00, 0x01, // TYPE is A.
395 0x00, 0x01, // CLASS is IN.
396 0x00, 0x00, // TTL (4 bytes) is 53 seconds.
397 0x00, 0x35, 0x00, 0x04, // RDLENGTH is 4 bytes.
398 0x4a, 0x7d, // RDATA is the IP: 74.125.95.121
399 0x5f, 0x79,
400 };
401
402 DnsResponse resp;
403 memcpy(resp.io_buffer()->data(), response_data, sizeof(response_data));
404
405 EXPECT_TRUE(resp.InitParseWithoutQuery(sizeof(response_data)));
406
407 // Check header access.
408 EXPECT_EQ(0x8180, resp.flags());
409 EXPECT_EQ(0x0, resp.rcode());
410 EXPECT_EQ(0x01u, resp.answer_count());
411
412 DnsResourceRecord record;
413 DnsRecordParser parser = resp.Parser();
414
415 EXPECT_FALSE(parser.AtEnd());
416 EXPECT_TRUE(parser.ReadRecord(&record));
417 EXPECT_EQ("codereview.chromium.org", record.name);
418 EXPECT_EQ(0x35u, record.ttl);
419 EXPECT_EQ(dns_protocol::kTypeA, record.type);
420
421 EXPECT_TRUE(parser.AtEnd());
422 EXPECT_FALSE(parser.ReadRecord(&record));
423}
424
425TEST(DnsResponseTest, InitParseWithoutQueryPacketTooShort) {
426 const uint8_t response_data[] = {
427 // Header
428 0xca, 0xfe, // ID
429 0x81, 0x80, // Standard query response, RA, no error
430 0x00, 0x00, // No question
431 };
432
433 DnsResponse resp;
434 memcpy(resp.io_buffer()->data(), response_data, sizeof(response_data));
435
436 EXPECT_FALSE(resp.InitParseWithoutQuery(sizeof(response_data)));
437}
438
439TEST(DnsResponseWriteTest, SingleARecordAnswer) {
440 const uint8_t response_data[] = {
441 0x12, 0x34, // ID
442 0x84, 0x00, // flags, response with authoritative answer
443 0x00, 0x00, // number of questions
444 0x00, 0x01, // number of answer rr
445 0x00, 0x00, // number of name server rr
446 0x00, 0x00, // number of additional rr
447 0x03, 'w', 'w', 'w', 0x07, 'e', 'x', 'a',
448 'm', 'p', 'l', 'e', 0x03, 'c', 'o', 'm',
449 0x00, // null label
450 0x00, 0x01, // type A Record
451 0x00, 0x01, // class IN
452 0x00, 0x00, 0x00, 0x78, // TTL, 120 seconds
453 0x00, 0x04, // rdlength, 32 bits
454 0xc0, 0xa8, 0x00, 0x01, // 192.168.0.1
455 };
456 patchpanel::DnsResourceRecord answer;
457 answer.name = "www.example.com";
458 answer.type = dns_protocol::kTypeA;
459 answer.klass = dns_protocol::kClassIN;
460 answer.ttl = 120; // 120 seconds.
461 answer.SetOwnedRdata(std::string("\xc0\xa8\x00\x01", 4));
462 std::vector<DnsResourceRecord> answers(1, answer);
463 DnsResponse response(0x1234 /* response_id */, true /* is_authoritative*/,
464 answers, {} /* authority_records */,
465 {} /* additional records */, base::nullopt);
466 ASSERT_NE(nullptr, response.io_buffer());
467 EXPECT_TRUE(response.IsValid());
468 std::string expected_response(reinterpret_cast<const char*>(response_data),
469 sizeof(response_data));
470 std::string actual_response(response.io_buffer()->data(),
471 response.io_buffer_size());
472 EXPECT_EQ(expected_response, actual_response);
473}
474
475TEST(DnsResponseWriteTest, SingleARecordAnswerWithFinalDotInName) {
476 const uint8_t response_data[] = {
477 0x12, 0x34, // ID
478 0x84, 0x00, // flags, response with authoritative answer
479 0x00, 0x00, // number of questions
480 0x00, 0x01, // number of answer rr
481 0x00, 0x00, // number of name server rr
482 0x00, 0x00, // number of additional rr
483 0x03, 'w', 'w', 'w', 0x07, 'e', 'x', 'a',
484 'm', 'p', 'l', 'e', 0x03, 'c', 'o', 'm',
485 0x00, // null label
486 0x00, 0x01, // type A Record
487 0x00, 0x01, // class IN
488 0x00, 0x00, 0x00, 0x78, // TTL, 120 seconds
489 0x00, 0x04, // rdlength, 32 bits
490 0xc0, 0xa8, 0x00, 0x01, // 192.168.0.1
491 };
492 patchpanel::DnsResourceRecord answer;
493 answer.name = "www.example.com."; // FQDN with the final dot.
494 answer.type = dns_protocol::kTypeA;
495 answer.klass = dns_protocol::kClassIN;
496 answer.ttl = 120; // 120 seconds.
497 answer.SetOwnedRdata(std::string("\xc0\xa8\x00\x01", 4));
498 std::vector<DnsResourceRecord> answers(1, answer);
499 DnsResponse response(0x1234 /* response_id */, true /* is_authoritative*/,
500 answers, {} /* authority_records */,
501 {} /* additional records */, base::nullopt);
502 ASSERT_NE(nullptr, response.io_buffer());
503 EXPECT_TRUE(response.IsValid());
504 std::string expected_response(reinterpret_cast<const char*>(response_data),
505 sizeof(response_data));
506 std::string actual_response(response.io_buffer()->data(),
507 response.io_buffer_size());
508 EXPECT_EQ(expected_response, actual_response);
509}
510
511TEST(DnsResponseWriteTest,
512 SingleAnswerWithQuestionConstructedFromSizeInflatedQuery) {
513 const uint8_t response_data[] = {
514 0x12, 0x34, // ID
515 0x84, 0x00, // flags, response with authoritative answer
516 0x00, 0x01, // number of questions
517 0x00, 0x01, // number of answer rr
518 0x00, 0x00, // number of name server rr
519 0x00, 0x00, // number of additional rr
520 0x03, 'w', 'w', 'w', 0x07, 'e', 'x', 'a',
521 'm', 'p', 'l', 'e', 0x03, 'c', 'o', 'm',
522 0x00, // null label
523 0x00, 0x01, // type A Record
524 0x00, 0x01, // class IN
525 0x03, 'w', 'w', 'w', 0x07, 'e', 'x', 'a',
526 'm', 'p', 'l', 'e', 0x03, 'c', 'o', 'm',
527 0x00, // null label
528 0x00, 0x01, // type A Record
529 0x00, 0x01, // class IN
530 0x00, 0x00, 0x00, 0x78, // TTL, 120 seconds
531 0x00, 0x04, // rdlength, 32 bits
532 0xc0, 0xa8, 0x00, 0x01, // 192.168.0.1
533 };
534 std::string dotted_name("www.example.com");
535 std::string dns_name;
536 ASSERT_TRUE(DNSDomainFromDot(dotted_name, &dns_name));
537 size_t buf_size =
538 sizeof(dns_protocol::Header) + dns_name.size() + 2 /* qtype */ +
539 2 /* qclass */ +
540 10 /* extra bytes that inflate the internal buffer of a query */;
541 auto buf = base::MakeRefCounted<IOBufferWithSize>(buf_size);
542 memset(buf->data(), 0, buf->size());
543 base::BigEndianWriter writer(buf->data(), buf_size);
544 writer.WriteU16(0x1234); // id
545 writer.WriteU16(0); // flags, is query
546 writer.WriteU16(1); // qdcount
547 writer.WriteU16(0); // ancount
548 writer.WriteU16(0); // nscount
549 writer.WriteU16(0); // arcount
550 writer.WriteBytes(dns_name.data(), dns_name.size()); // qname
551 writer.WriteU16(dns_protocol::kTypeA); // qtype
552 writer.WriteU16(dns_protocol::kClassIN); // qclass
553 // buf contains 10 extra zero bytes.
554 base::Optional<DnsQuery> query;
555 query.emplace(buf);
556 query->Parse(buf_size);
557 patchpanel::DnsResourceRecord answer;
558 answer.name = dotted_name;
559 answer.type = dns_protocol::kTypeA;
560 answer.klass = dns_protocol::kClassIN;
561 answer.ttl = 120; // 120 seconds.
562 answer.SetOwnedRdata(std::string("\xc0\xa8\x00\x01", 4));
563 std::vector<DnsResourceRecord> answers(1, answer);
564 DnsResponse response(0x1234 /* id */, true /* is_authoritative*/, answers,
565 {} /* authority_records */, {} /* additional records */,
566 query);
567 ASSERT_NE(nullptr, response.io_buffer());
568 EXPECT_TRUE(response.IsValid());
569 std::string expected_response(reinterpret_cast<const char*>(response_data),
570 sizeof(response_data));
571 std::string actual_response(response.io_buffer()->data(),
572 response.io_buffer_size());
573 EXPECT_EQ(expected_response, actual_response);
574}
575
576TEST(DnsResponseWriteTest, SingleQuadARecordAnswer) {
577 const uint8_t response_data[] = {
578 0x12, 0x34, // ID
579 0x84, 0x00, // flags, response with authoritative answer
580 0x00, 0x00, // number of questions
581 0x00, 0x01, // number of answer rr
582 0x00, 0x00, // number of name server rr
583 0x00, 0x00, // number of additional rr
584 0x03, 'w', 'w', 'w', 0x07, 'e', 'x', 'a',
585 'm', 'p', 'l', 'e', 0x03, 'c', 'o', 'm',
586 0x00, // null label
587 0x00, 0x1c, // type AAAA Record
588 0x00, 0x01, // class IN
589 0x00, 0x00, 0x00, 0x78, // TTL, 120 seconds
590 0x00, 0x10, // rdlength, 128 bits
591 0xfd, 0x12, 0x34, 0x56, 0x78, 0x9a, 0x00, 0x01, // fd12:3456:789a:1::1
592 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
593 };
594 patchpanel::DnsResourceRecord answer;
595 answer.name = "www.example.com";
596 answer.type = dns_protocol::kTypeAAAA;
597 answer.klass = dns_protocol::kClassIN;
598 answer.ttl = 120; // 120 seconds.
599 answer.SetOwnedRdata(std::string(
600 "\xfd\x12\x34\x56\x78\x9a\x00\x01\x00\x00\x00\x00\x00\x00\x00\x01", 16));
601 std::vector<DnsResourceRecord> answers(1, answer);
602 DnsResponse response(0x1234 /* id */, true /* is_authoritative*/, answers,
603 {} /* authority_records */, {} /* additional records */,
604 base::nullopt);
605 ASSERT_NE(nullptr, response.io_buffer());
606 EXPECT_TRUE(response.IsValid());
607 std::string expected_response(reinterpret_cast<const char*>(response_data),
608 sizeof(response_data));
609 std::string actual_response(response.io_buffer()->data(),
610 response.io_buffer_size());
611 EXPECT_EQ(expected_response, actual_response);
612}
613
614TEST(DnsResponseWriteTest, TwoAnswersWithAAndQuadARecords) {
615 const uint8_t response_data[] = {
616 0x12, 0x34, // ID
617 0x84, 0x00, // flags, response with authoritative answer
618 0x00, 0x00, // number of questions
619 0x00, 0x02, // number of answer rr
620 0x00, 0x00, // number of name server rr
621 0x00, 0x00, // number of additional rr
622 0x03, 'w', 'w', 'w', 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e',
623 0x03, 'c', 'o', 'm',
624 0x00, // null label
625 0x00, 0x01, // type A Record
626 0x00, 0x01, // class IN
627 0x00, 0x00, 0x00, 0x78, // TTL, 120 seconds
628 0x00, 0x04, // rdlength, 32 bits
629 0xc0, 0xa8, 0x00, 0x01, // 192.168.0.1
630 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0x03, 'o', 'r', 'g',
631 0x00, // null label
632 0x00, 0x1c, // type AAAA Record
633 0x00, 0x01, // class IN
634 0x00, 0x00, 0x00, 0x3c, // TTL, 60 seconds
635 0x00, 0x10, // rdlength, 128 bits
636 0xfd, 0x12, 0x34, 0x56, 0x78, 0x9a, 0x00, 0x01, // fd12:3456:789a:1::1
637 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
638 };
639 patchpanel::DnsResourceRecord answer1;
640 answer1.name = "www.example.com";
641 answer1.type = dns_protocol::kTypeA;
642 answer1.klass = dns_protocol::kClassIN;
643 answer1.ttl = 120; // 120 seconds.
644 answer1.SetOwnedRdata(std::string("\xc0\xa8\x00\x01", 4));
645 patchpanel::DnsResourceRecord answer2;
646 answer2.name = "example.org";
647 answer2.type = dns_protocol::kTypeAAAA;
648 answer2.klass = dns_protocol::kClassIN;
649 answer2.ttl = 60;
650 answer2.SetOwnedRdata(std::string(
651 "\xfd\x12\x34\x56\x78\x9a\x00\x01\x00\x00\x00\x00\x00\x00\x00\x01", 16));
652 std::vector<DnsResourceRecord> answers(2);
653 answers[0] = answer1;
654 answers[1] = answer2;
655 DnsResponse response(0x1234 /* id */, true /* is_authoritative*/, answers,
656 {} /* authority_records */, {} /* additional records */,
657 base::nullopt);
658 ASSERT_NE(nullptr, response.io_buffer());
659 EXPECT_TRUE(response.IsValid());
660 std::string expected_response(reinterpret_cast<const char*>(response_data),
661 sizeof(response_data));
662 std::string actual_response(response.io_buffer()->data(),
663 response.io_buffer_size());
664 EXPECT_EQ(expected_response, actual_response);
665}
666
667TEST(DnsResponseWriteTest, AnswerWithAuthorityRecord) {
668 const uint8_t response_data[] = {
669 0x12, 0x35, // ID
670 0x84, 0x00, // flags, response with authoritative answer
671 0x00, 0x00, // number of questions
672 0x00, 0x00, // number of answer rr
673 0x00, 0x01, // number of name server rr
674 0x00, 0x00, // number of additional rr
675 0x03, 'w', 'w', 'w', 0x07, 'e', 'x', 'a',
676 'm', 'p', 'l', 'e', 0x03, 'c', 'o', 'm',
677 0x00, // null label
678 0x00, 0x01, // type A Record
679 0x00, 0x01, // class IN
680 0x00, 0x00, 0x00, 0x78, // TTL, 120 seconds
681 0x00, 0x04, // rdlength, 32 bits
682 0xc0, 0xa8, 0x00, 0x01, // 192.168.0.1
683 };
684 DnsResourceRecord record;
685 record.name = "www.example.com";
686 record.type = dns_protocol::kTypeA;
687 record.klass = dns_protocol::kClassIN;
688 record.ttl = 120; // 120 seconds.
689 record.SetOwnedRdata(std::string("\xc0\xa8\x00\x01", 4));
690 std::vector<DnsResourceRecord> authority_records(1, record);
691 DnsResponse response(0x1235 /* response_id */, true /* is_authoritative*/,
692 {} /* answers */, authority_records,
693 {} /* additional records */, base::nullopt);
694 ASSERT_NE(nullptr, response.io_buffer());
695 EXPECT_TRUE(response.IsValid());
696 std::string expected_response(reinterpret_cast<const char*>(response_data),
697 sizeof(response_data));
698 std::string actual_response(response.io_buffer()->data(),
699 response.io_buffer_size());
700 EXPECT_EQ(expected_response, actual_response);
701}
702
703TEST(DnsResponseWriteTest, AnswerWithRcode) {
704 const uint8_t response_data[] = {
705 0x12, 0x12, // ID
706 0x80, 0x03, // flags (response with non-existent domain)
707 0x00, 0x00, // number of questions
708 0x00, 0x00, // number of answer rr
709 0x00, 0x00, // number of name server rr
710 0x00, 0x00, // number of additional rr
711 };
712 DnsResponse response(0x1212 /* response_id */, false /* is_authoritative*/,
713 {} /* answers */, {} /* authority_records */,
714 {} /* additional records */, base::nullopt,
715 dns_protocol::kRcodeNXDOMAIN);
716 ASSERT_NE(nullptr, response.io_buffer());
717 EXPECT_TRUE(response.IsValid());
718 std::string expected_response(reinterpret_cast<const char*>(response_data),
719 sizeof(response_data));
720 std::string actual_response(response.io_buffer()->data(),
721 response.io_buffer_size());
722 EXPECT_EQ(expected_response, actual_response);
723 EXPECT_EQ(dns_protocol::kRcodeNXDOMAIN, response.rcode());
724}
725
726TEST(DnsResponseWriteTest, WrittenResponseCanBeParsed) {
727 std::string dotted_name("www.example.com");
728 patchpanel::DnsResourceRecord answer;
729 answer.name = dotted_name;
730 answer.type = dns_protocol::kTypeA;
731 answer.klass = dns_protocol::kClassIN;
732 answer.ttl = 120; // 120 seconds.
733 answer.SetOwnedRdata(std::string("\xc0\xa8\x00\x01", 4));
734 std::vector<DnsResourceRecord> answers(1, answer);
735 patchpanel::DnsResourceRecord additional_record;
736 additional_record.name = dotted_name;
737 additional_record.type = dns_protocol::kTypeNSEC;
738 additional_record.klass = dns_protocol::kClassIN;
739 additional_record.ttl = 120; // 120 seconds.
740 additional_record.SetOwnedRdata(std::string("\xc0\x0c\x00\x01\x04", 5));
741 std::vector<DnsResourceRecord> additional_records(1, additional_record);
742 DnsResponse response(0x1234 /* response_id */, true /* is_authoritative*/,
743 answers, {} /* authority_records */, additional_records,
744 base::nullopt);
745 ASSERT_NE(nullptr, response.io_buffer());
746 EXPECT_TRUE(response.IsValid());
747 EXPECT_THAT(response.id(), testing::Optional(0x1234));
748 EXPECT_EQ(1u, response.answer_count());
749 EXPECT_EQ(1u, response.additional_answer_count());
750 auto parser = response.Parser();
751 patchpanel::DnsResourceRecord parsed_record;
752 EXPECT_TRUE(parser.ReadRecord(&parsed_record));
753 // Answer with an A record.
754 EXPECT_EQ(answer.name, parsed_record.name);
755 EXPECT_EQ(answer.type, parsed_record.type);
756 EXPECT_EQ(answer.klass, parsed_record.klass);
757 EXPECT_EQ(answer.ttl, parsed_record.ttl);
758 EXPECT_EQ(answer.owned_rdata, parsed_record.rdata);
759 // Additional NSEC record.
760 EXPECT_TRUE(parser.ReadRecord(&parsed_record));
761 EXPECT_EQ(additional_record.name, parsed_record.name);
762 EXPECT_EQ(additional_record.type, parsed_record.type);
763 EXPECT_EQ(additional_record.klass, parsed_record.klass);
764 EXPECT_EQ(additional_record.ttl, parsed_record.ttl);
765 EXPECT_EQ(additional_record.owned_rdata, parsed_record.rdata);
766}
767
768} // namespace
769
770} // namespace patchpanel