1 // Copyright 2013 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/mdns_cache.h"
6
7 #include <algorithm>
8 #include <utility>
9
10 #include "base/functional/bind.h"
11 #include "base/time/time.h"
12 #include "net/dns/dns_response.h"
13 #include "net/dns/dns_test_util.h"
14 #include "net/dns/record_parsed.h"
15 #include "net/dns/record_rdata.h"
16 #include "testing/gmock/include/gmock/gmock.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18
19 using ::testing::Return;
20 using ::testing::StrictMock;
21
22 namespace net {
23
24 static const uint8_t kTestResponsesDifferentAnswers[] = {
25 // Answer 1
26 // ghs.l.google.com in DNS format.
27 3, 'g', 'h', 's', 1, 'l', 6, 'g', 'o', 'o', 'g', 'l', 'e', 3, 'c', 'o', 'm',
28 0x00, 0x00, 0x01, // TYPE is A.
29 0x00, 0x01, // CLASS is IN.
30 0, 0, 0, 53, // TTL (4 bytes) is 53 seconds.
31 0, 4, // RDLENGTH is 4 bytes.
32 74, 125, 95, 121, // RDATA is the IP: 74.125.95.121
33
34 // Answer 2
35 // Pointer to answer 1
36 0xc0, 0x00, 0x00, 0x01, // TYPE is A.
37 0x00, 0x01, // CLASS is IN.
38 0, 0, 0, 53, // TTL (4 bytes) is 53 seconds.
39 0, 4, // RDLENGTH is 4 bytes.
40 74, 125, 95, 122, // RDATA is the IP: 74.125.95.122
41 };
42
43 static const uint8_t kTestResponsesSameAnswers[] = {
44 // Answer 1
45 // ghs.l.google.com in DNS format.
46 3, 'g', 'h', 's', 1, 'l', 6, 'g', 'o', 'o', 'g', 'l', 'e', 3, 'c', 'o', 'm',
47 0x00, 0x00, 0x01, // TYPE is A.
48 0x00, 0x01, // CLASS is IN.
49 0, 0, 0, 53, // TTL (4 bytes) is 53 seconds.
50 0, 4, // RDLENGTH is 4 bytes.
51 74, 125, 95, 121, // RDATA is the IP: 74.125.95.121
52
53 // Answer 2
54 // Pointer to answer 1
55 0xc0, 0x00, 0x00, 0x01, // TYPE is A.
56 0x00, 0x01, // CLASS is IN.
57 0, 0, 0, 112, // TTL (4 bytes) is 112 seconds.
58 0, 4, // RDLENGTH is 4 bytes.
59 74, 125, 95, 121, // RDATA is the IP: 74.125.95.121
60 };
61
62 static const uint8_t kTestResponseTwoRecords[] = {
63 // Answer 1
64 // ghs.l.google.com in DNS format. (A)
65 3, 'g', 'h', 's', 1, 'l', 6, 'g', 'o', 'o', 'g', 'l', 'e', 3, 'c', 'o', 'm',
66 0x00, 0x00, 0x01, // TYPE is A.
67 0x00, 0x01, // CLASS is IN.
68 0, 0, 0, 53, // TTL (4 bytes) is 53 seconds.
69 0, 4, // RDLENGTH is 4 bytes.
70 74, 125, 95, 121, // RDATA is the IP: 74.125.95.121
71
72 // Answer 2
73 // ghs.l.google.com in DNS format. (AAAA)
74 3, 'g', 'h', 's', 1, 'l', 6, 'g', 'o', 'o', 'g', 'l', 'e', 3, 'c', 'o', 'm',
75 0x00, 0x00, 0x1c, // TYPE is AAA.
76 0x00, 0x01, // CLASS is IN.
77 0, 0, 0, 53, // TTL (4 bytes) is 53 seconds.
78 0, 16, // RDLENGTH is 16 bytes.
79 0x4a, 0x7d, 0x4a, 0x7d, 0x5f, 0x79, 0x5f, 0x79, 0x5f, 0x79, 0x5f, 0x79,
80 0x5f, 0x79, 0x5f, 0x79,
81 };
82
83 static const uint8_t kTestResponsesGoodbyePacket[] = {
84 // Answer 1
85 // ghs.l.google.com in DNS format. (Goodbye packet)
86 3, 'g', 'h', 's', 1, 'l', 6, 'g', 'o', 'o', 'g', 'l', 'e', 3, 'c', 'o', 'm',
87 0x00, 0x00, 0x01, // TYPE is A.
88 0x00, 0x01, // CLASS is IN.
89 0, 0, 0, 0, // TTL (4 bytes) is zero.
90 0, 4, // RDLENGTH is 4 bytes.
91 74, 125, 95, 121, // RDATA is the IP: 74.125.95.121
92
93 // Answer 2
94 // ghs.l.google.com in DNS format.
95 3, 'g', 'h', 's', 1, 'l', 6, 'g', 'o', 'o', 'g', 'l', 'e', 3, 'c', 'o', 'm',
96 0x00, 0x00, 0x01, // TYPE is A.
97 0x00, 0x01, // CLASS is IN.
98 0, 0, 0, 53, // TTL (4 bytes) is 53 seconds.
99 0, 4, // RDLENGTH is 4 bytes.
100 74, 125, 95, 121, // RDATA is the IP: 74.125.95.121
101 };
102
103 static const uint8_t kTestResponsesDifferentCapitalization[] = {
104 // Answer 1
105 // GHS.l.google.com in DNS format.
106 3, 'G', 'H', 'S', 1, 'l', 6, 'g', 'o', 'o', 'g', 'l', 'e', 3, 'c', 'o', 'm',
107 0x00, 0x00, 0x01, // TYPE is A.
108 0x00, 0x01, // CLASS is IN.
109 0, 0, 0, 53, // TTL (4 bytes) is 53 seconds.
110 0, 4, // RDLENGTH is 4 bytes.
111 74, 125, 95, 121, // RDATA is the IP: 74.125.95.121
112
113 // Answer 2
114 // ghs.l.GOOGLE.com in DNS format.
115 3, 'g', 'h', 's', 1, 'l', 6, 'G', 'O', 'O', 'G', 'L', 'E', 3, 'c', 'o', 'm',
116 0x00, 0x00, 0x01, // TYPE is A.
117 0x00, 0x01, // CLASS is IN.
118 0, 0, 0, 53, // TTL (4 bytes) is 53 seconds.
119 0, 4, // RDLENGTH is 4 bytes.
120 74, 125, 95, 122, // RDATA is the IP: 74.125.95.122
121 };
122
123 class RecordRemovalMock {
124 public:
125 MOCK_METHOD1(OnRecordRemoved, void(const RecordParsed*));
126 };
127
128 class MDnsCacheTest : public ::testing::Test {
129 public:
MDnsCacheTest()130 MDnsCacheTest()
131 : default_time_(base::Time::FromSecondsSinceUnixEpoch(1234.0)) {}
132 ~MDnsCacheTest() override = default;
133
134 protected:
135 base::Time default_time_;
136 StrictMock<RecordRemovalMock> record_removal_;
137 MDnsCache cache_;
138 };
139
140 // Test a single insert, corresponding lookup, and unsuccessful lookup.
TEST_F(MDnsCacheTest,InsertLookupSingle)141 TEST_F(MDnsCacheTest, InsertLookupSingle) {
142 DnsRecordParser parser(kT1ResponseDatagram, sizeof(kT1ResponseDatagram),
143 sizeof(dns_protocol::Header), kT1RecordCount);
144 std::string dotted_qname;
145 uint16_t qtype;
146 parser.ReadQuestion(dotted_qname, qtype);
147
148 std::unique_ptr<const RecordParsed> record1;
149 std::unique_ptr<const RecordParsed> record2;
150 std::vector<const RecordParsed*> results;
151
152 record1 = RecordParsed::CreateFrom(&parser, default_time_);
153 record2 = RecordParsed::CreateFrom(&parser, default_time_);
154
155 EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(std::move(record1)));
156
157 EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(std::move(record2)));
158
159 cache_.FindDnsRecords(ARecordRdata::kType, "ghs.l.google.com", &results,
160 default_time_);
161
162 EXPECT_EQ(1u, results.size());
163 EXPECT_EQ(default_time_, results.front()->time_created());
164
165 EXPECT_EQ("ghs.l.google.com", results.front()->name());
166
167 results.clear();
168 cache_.FindDnsRecords(PtrRecordRdata::kType, "ghs.l.google.com", &results,
169 default_time_);
170
171 EXPECT_EQ(0u, results.size());
172 }
173
174 // Test that records expire when their ttl has passed.
TEST_F(MDnsCacheTest,Expiration)175 TEST_F(MDnsCacheTest, Expiration) {
176 DnsRecordParser parser(kT1ResponseDatagram, sizeof(kT1ResponseDatagram),
177 sizeof(dns_protocol::Header), kT1RecordCount);
178 std::string dotted_qname;
179 uint16_t qtype;
180 parser.ReadQuestion(dotted_qname, qtype);
181 std::unique_ptr<const RecordParsed> record1;
182 std::unique_ptr<const RecordParsed> record2;
183
184 std::vector<const RecordParsed*> results;
185 const RecordParsed* record_to_be_deleted;
186
187 record1 = RecordParsed::CreateFrom(&parser, default_time_);
188 base::TimeDelta ttl1 = base::Seconds(record1->ttl());
189
190 record2 = RecordParsed::CreateFrom(&parser, default_time_);
191 base::TimeDelta ttl2 = base::Seconds(record2->ttl());
192 record_to_be_deleted = record2.get();
193
194 EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(std::move(record1)));
195 EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(std::move(record2)));
196
197 cache_.FindDnsRecords(ARecordRdata::kType, "ghs.l.google.com", &results,
198 default_time_);
199
200 EXPECT_EQ(1u, results.size());
201
202 EXPECT_EQ(default_time_ + ttl2, cache_.next_expiration());
203
204
205 cache_.FindDnsRecords(ARecordRdata::kType, "ghs.l.google.com", &results,
206 default_time_ + ttl2);
207
208 EXPECT_EQ(0u, results.size());
209
210 EXPECT_CALL(record_removal_, OnRecordRemoved(record_to_be_deleted));
211
212 cache_.CleanupRecords(
213 default_time_ + ttl2,
214 base::BindRepeating(&RecordRemovalMock::OnRecordRemoved,
215 base::Unretained(&record_removal_)));
216
217 // To make sure that we've indeed removed them from the map, check no funny
218 // business happens once they're deleted for good.
219
220 EXPECT_EQ(default_time_ + ttl1, cache_.next_expiration());
221 cache_.FindDnsRecords(ARecordRdata::kType, "ghs.l.google.com", &results,
222 default_time_ + ttl2);
223
224 EXPECT_EQ(0u, results.size());
225 }
226
227 // Test that a new record replacing one with the same identity (name/rrtype for
228 // unique records) causes the cache to output a "record changed" event.
TEST_F(MDnsCacheTest,RecordChange)229 TEST_F(MDnsCacheTest, RecordChange) {
230 DnsRecordParser parser(kTestResponsesDifferentAnswers,
231 sizeof(kTestResponsesDifferentAnswers), 0,
232 /*num_records=*/2);
233
234 std::unique_ptr<const RecordParsed> record1;
235 std::unique_ptr<const RecordParsed> record2;
236 std::vector<const RecordParsed*> results;
237
238 record1 = RecordParsed::CreateFrom(&parser, default_time_);
239 record2 = RecordParsed::CreateFrom(&parser, default_time_);
240
241 EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(std::move(record1)));
242 EXPECT_EQ(MDnsCache::RecordChanged,
243 cache_.UpdateDnsRecord(std::move(record2)));
244 }
245
246 // Test that a new record replacing an otherwise identical one already in the
247 // cache causes the cache to output a "no change" event.
TEST_F(MDnsCacheTest,RecordNoChange)248 TEST_F(MDnsCacheTest, RecordNoChange) {
249 DnsRecordParser parser(kTestResponsesSameAnswers,
250 sizeof(kTestResponsesSameAnswers), 0,
251 /*num_records=*/2);
252
253 std::unique_ptr<const RecordParsed> record1;
254 std::unique_ptr<const RecordParsed> record2;
255 std::vector<const RecordParsed*> results;
256
257 record1 = RecordParsed::CreateFrom(&parser, default_time_);
258 record2 = RecordParsed::CreateFrom(&parser, default_time_ + base::Seconds(1));
259
260 EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(std::move(record1)));
261 EXPECT_EQ(MDnsCache::NoChange, cache_.UpdateDnsRecord(std::move(record2)));
262 }
263
264 // Test that the next expiration time of the cache is updated properly on record
265 // insertion.
TEST_F(MDnsCacheTest,RecordPreemptExpirationTime)266 TEST_F(MDnsCacheTest, RecordPreemptExpirationTime) {
267 DnsRecordParser parser(kTestResponsesSameAnswers,
268 sizeof(kTestResponsesSameAnswers), 0,
269 /*num_records=*/2);
270
271 std::unique_ptr<const RecordParsed> record1;
272 std::unique_ptr<const RecordParsed> record2;
273 std::vector<const RecordParsed*> results;
274
275 record1 = RecordParsed::CreateFrom(&parser, default_time_);
276 record2 = RecordParsed::CreateFrom(&parser, default_time_);
277 base::TimeDelta ttl1 = base::Seconds(record1->ttl());
278 base::TimeDelta ttl2 = base::Seconds(record2->ttl());
279
280 EXPECT_EQ(base::Time(), cache_.next_expiration());
281 EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(std::move(record2)));
282 EXPECT_EQ(default_time_ + ttl2, cache_.next_expiration());
283 EXPECT_EQ(MDnsCache::NoChange, cache_.UpdateDnsRecord(std::move(record1)));
284 EXPECT_EQ(default_time_ + ttl1, cache_.next_expiration());
285 }
286
287 // Test that the cache handles mDNS "goodbye" packets correctly, not adding the
288 // records to the cache if they are not already there, and eventually removing
289 // records from the cache if they are.
TEST_F(MDnsCacheTest,GoodbyePacket)290 TEST_F(MDnsCacheTest, GoodbyePacket) {
291 DnsRecordParser parser(kTestResponsesGoodbyePacket,
292 sizeof(kTestResponsesGoodbyePacket), 0,
293 /*num_records=*/2);
294
295 std::unique_ptr<const RecordParsed> record_goodbye;
296 std::unique_ptr<const RecordParsed> record_hello;
297 std::unique_ptr<const RecordParsed> record_goodbye2;
298 std::vector<const RecordParsed*> results;
299
300 record_goodbye = RecordParsed::CreateFrom(&parser, default_time_);
301 record_hello = RecordParsed::CreateFrom(&parser, default_time_);
302 parser = DnsRecordParser(kTestResponsesGoodbyePacket,
303 sizeof(kTestResponsesGoodbyePacket), 0,
304 /*num_records=*/2);
305 record_goodbye2 = RecordParsed::CreateFrom(&parser, default_time_);
306
307 base::TimeDelta ttl = base::Seconds(record_hello->ttl());
308
309 EXPECT_EQ(base::Time(), cache_.next_expiration());
310 EXPECT_EQ(MDnsCache::NoChange,
311 cache_.UpdateDnsRecord(std::move(record_goodbye)));
312 EXPECT_EQ(base::Time(), cache_.next_expiration());
313 EXPECT_EQ(MDnsCache::RecordAdded,
314 cache_.UpdateDnsRecord(std::move(record_hello)));
315 EXPECT_EQ(default_time_ + ttl, cache_.next_expiration());
316 EXPECT_EQ(MDnsCache::NoChange,
317 cache_.UpdateDnsRecord(std::move(record_goodbye2)));
318 EXPECT_EQ(default_time_ + base::Seconds(1), cache_.next_expiration());
319 }
320
TEST_F(MDnsCacheTest,AnyRRType)321 TEST_F(MDnsCacheTest, AnyRRType) {
322 DnsRecordParser parser(kTestResponseTwoRecords,
323 sizeof(kTestResponseTwoRecords), 0, /*num_records=*/2);
324
325 std::unique_ptr<const RecordParsed> record1;
326 std::unique_ptr<const RecordParsed> record2;
327 std::vector<const RecordParsed*> results;
328
329 record1 = RecordParsed::CreateFrom(&parser, default_time_);
330 record2 = RecordParsed::CreateFrom(&parser, default_time_);
331 EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(std::move(record1)));
332 EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(std::move(record2)));
333
334 cache_.FindDnsRecords(0, "ghs.l.google.com", &results, default_time_);
335
336 EXPECT_EQ(2u, results.size());
337 EXPECT_EQ(default_time_, results.front()->time_created());
338
339 EXPECT_EQ("ghs.l.google.com", results[0]->name());
340 EXPECT_EQ("ghs.l.google.com", results[1]->name());
341 EXPECT_EQ(dns_protocol::kTypeA,
342 std::min(results[0]->type(), results[1]->type()));
343 EXPECT_EQ(dns_protocol::kTypeAAAA,
344 std::max(results[0]->type(), results[1]->type()));
345 }
346
TEST_F(MDnsCacheTest,RemoveRecord)347 TEST_F(MDnsCacheTest, RemoveRecord) {
348 DnsRecordParser parser(kT1ResponseDatagram, sizeof(kT1ResponseDatagram),
349 sizeof(dns_protocol::Header), kT1RecordCount);
350 std::string dotted_qname;
351 uint16_t qtype;
352 parser.ReadQuestion(dotted_qname, qtype);
353
354 std::unique_ptr<const RecordParsed> record1;
355 std::vector<const RecordParsed*> results;
356
357 record1 = RecordParsed::CreateFrom(&parser, default_time_);
358 EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(std::move(record1)));
359
360 cache_.FindDnsRecords(dns_protocol::kTypeCNAME, "codereview.chromium.org",
361 &results, default_time_);
362
363 EXPECT_EQ(1u, results.size());
364
365 std::unique_ptr<const RecordParsed> record_out =
366 cache_.RemoveRecord(results.front());
367
368 EXPECT_EQ(record_out.get(), results.front());
369
370 cache_.FindDnsRecords(dns_protocol::kTypeCNAME, "codereview.chromium.org",
371 &results, default_time_);
372
373 EXPECT_EQ(0u, results.size());
374 }
375
TEST_F(MDnsCacheTest,IsCacheOverfilled)376 TEST_F(MDnsCacheTest, IsCacheOverfilled) {
377 DnsRecordParser parser(kTestResponseTwoRecords,
378 sizeof(kTestResponseTwoRecords), 0, /*num_records=*/2);
379 std::unique_ptr<const RecordParsed> record1 =
380 RecordParsed::CreateFrom(&parser, default_time_);
381 const RecordParsed* record1_ptr = record1.get();
382 std::unique_ptr<const RecordParsed> record2 =
383 RecordParsed::CreateFrom(&parser, default_time_);
384
385 cache_.set_entry_limit_for_testing(1);
386 EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(std::move(record1)));
387 EXPECT_FALSE(cache_.IsCacheOverfilled());
388 EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(std::move(record2)));
389 EXPECT_TRUE(cache_.IsCacheOverfilled());
390
391 record1 = cache_.RemoveRecord(record1_ptr);
392 EXPECT_TRUE(record1);
393 EXPECT_FALSE(cache_.IsCacheOverfilled());
394 }
395
TEST_F(MDnsCacheTest,ClearOnOverfilledCleanup)396 TEST_F(MDnsCacheTest, ClearOnOverfilledCleanup) {
397 DnsRecordParser parser(kTestResponseTwoRecords,
398 sizeof(kTestResponseTwoRecords), 0, /*num_records=*/2);
399 std::unique_ptr<const RecordParsed> record1 =
400 RecordParsed::CreateFrom(&parser, default_time_);
401 const RecordParsed* record1_ptr = record1.get();
402 std::unique_ptr<const RecordParsed> record2 =
403 RecordParsed::CreateFrom(&parser, default_time_);
404 const RecordParsed* record2_ptr = record2.get();
405
406 cache_.set_entry_limit_for_testing(1);
407 EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(std::move(record1)));
408 EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(std::move(record2)));
409
410 ASSERT_TRUE(cache_.IsCacheOverfilled());
411
412 // Expect everything to be removed on CleanupRecords() with overfilled cache.
413 EXPECT_CALL(record_removal_, OnRecordRemoved(record1_ptr));
414 EXPECT_CALL(record_removal_, OnRecordRemoved(record2_ptr));
415 cache_.CleanupRecords(
416 default_time_, base::BindRepeating(&RecordRemovalMock::OnRecordRemoved,
417 base::Unretained(&record_removal_)));
418
419 EXPECT_FALSE(cache_.IsCacheOverfilled());
420 std::vector<const RecordParsed*> results;
421 cache_.FindDnsRecords(dns_protocol::kTypeA, "ghs.l.google.com", &results,
422 default_time_);
423 EXPECT_TRUE(results.empty());
424 cache_.FindDnsRecords(dns_protocol::kTypeAAAA, "ghs.l.google.com", &results,
425 default_time_);
426 EXPECT_TRUE(results.empty());
427 }
428
TEST_F(MDnsCacheTest,CaseInsensitive)429 TEST_F(MDnsCacheTest, CaseInsensitive) {
430 DnsRecordParser parser(kTestResponsesDifferentCapitalization,
431 sizeof(kTestResponsesDifferentCapitalization), 0,
432 /*num_records=*/2);
433
434 std::unique_ptr<const RecordParsed> record1;
435 std::unique_ptr<const RecordParsed> record2;
436 std::vector<const RecordParsed*> results;
437
438 record1 = RecordParsed::CreateFrom(&parser, default_time_);
439 record2 = RecordParsed::CreateFrom(&parser, default_time_);
440 EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(std::move(record1)));
441 EXPECT_EQ(MDnsCache::RecordChanged,
442 cache_.UpdateDnsRecord(std::move(record2)));
443
444 cache_.FindDnsRecords(0, "ghs.l.google.com", &results, default_time_);
445
446 EXPECT_EQ(1u, results.size());
447 EXPECT_EQ("ghs.l.GOOGLE.com", results[0]->name());
448
449 std::vector<const RecordParsed*> results2;
450 cache_.FindDnsRecords(0, "GHS.L.google.COM", &results2, default_time_);
451 EXPECT_EQ(results, results2);
452 }
453
454 } // namespace net
455