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(dns_protocol::Header),
143 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(dns_protocol::Header),
177 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, 0,
231 /*num_records=*/2);
232
233 std::unique_ptr<const RecordParsed> record1;
234 std::unique_ptr<const RecordParsed> record2;
235 std::vector<const RecordParsed*> results;
236
237 record1 = RecordParsed::CreateFrom(&parser, default_time_);
238 record2 = RecordParsed::CreateFrom(&parser, default_time_);
239
240 EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(std::move(record1)));
241 EXPECT_EQ(MDnsCache::RecordChanged,
242 cache_.UpdateDnsRecord(std::move(record2)));
243 }
244
245 // Test that a new record replacing an otherwise identical one already in the
246 // cache causes the cache to output a "no change" event.
TEST_F(MDnsCacheTest,RecordNoChange)247 TEST_F(MDnsCacheTest, RecordNoChange) {
248 DnsRecordParser parser(kTestResponsesSameAnswers, 0,
249 /*num_records=*/2);
250
251 std::unique_ptr<const RecordParsed> record1;
252 std::unique_ptr<const RecordParsed> record2;
253 std::vector<const RecordParsed*> results;
254
255 record1 = RecordParsed::CreateFrom(&parser, default_time_);
256 record2 = RecordParsed::CreateFrom(&parser, default_time_ + base::Seconds(1));
257
258 EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(std::move(record1)));
259 EXPECT_EQ(MDnsCache::NoChange, cache_.UpdateDnsRecord(std::move(record2)));
260 }
261
262 // Test that the next expiration time of the cache is updated properly on record
263 // insertion.
TEST_F(MDnsCacheTest,RecordPreemptExpirationTime)264 TEST_F(MDnsCacheTest, RecordPreemptExpirationTime) {
265 DnsRecordParser parser(kTestResponsesSameAnswers, 0,
266 /*num_records=*/2);
267
268 std::unique_ptr<const RecordParsed> record1;
269 std::unique_ptr<const RecordParsed> record2;
270 std::vector<const RecordParsed*> results;
271
272 record1 = RecordParsed::CreateFrom(&parser, default_time_);
273 record2 = RecordParsed::CreateFrom(&parser, default_time_);
274 base::TimeDelta ttl1 = base::Seconds(record1->ttl());
275 base::TimeDelta ttl2 = base::Seconds(record2->ttl());
276
277 EXPECT_EQ(base::Time(), cache_.next_expiration());
278 EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(std::move(record2)));
279 EXPECT_EQ(default_time_ + ttl2, cache_.next_expiration());
280 EXPECT_EQ(MDnsCache::NoChange, cache_.UpdateDnsRecord(std::move(record1)));
281 EXPECT_EQ(default_time_ + ttl1, cache_.next_expiration());
282 }
283
284 // Test that the cache handles mDNS "goodbye" packets correctly, not adding the
285 // records to the cache if they are not already there, and eventually removing
286 // records from the cache if they are.
TEST_F(MDnsCacheTest,GoodbyePacket)287 TEST_F(MDnsCacheTest, GoodbyePacket) {
288 DnsRecordParser parser(kTestResponsesGoodbyePacket, 0,
289 /*num_records=*/2);
290
291 std::unique_ptr<const RecordParsed> record_goodbye;
292 std::unique_ptr<const RecordParsed> record_hello;
293 std::unique_ptr<const RecordParsed> record_goodbye2;
294 std::vector<const RecordParsed*> results;
295
296 record_goodbye = RecordParsed::CreateFrom(&parser, default_time_);
297 record_hello = RecordParsed::CreateFrom(&parser, default_time_);
298 parser = DnsRecordParser(kTestResponsesGoodbyePacket, 0,
299 /*num_records=*/2);
300 record_goodbye2 = RecordParsed::CreateFrom(&parser, default_time_);
301
302 base::TimeDelta ttl = base::Seconds(record_hello->ttl());
303
304 EXPECT_EQ(base::Time(), cache_.next_expiration());
305 EXPECT_EQ(MDnsCache::NoChange,
306 cache_.UpdateDnsRecord(std::move(record_goodbye)));
307 EXPECT_EQ(base::Time(), cache_.next_expiration());
308 EXPECT_EQ(MDnsCache::RecordAdded,
309 cache_.UpdateDnsRecord(std::move(record_hello)));
310 EXPECT_EQ(default_time_ + ttl, cache_.next_expiration());
311 EXPECT_EQ(MDnsCache::NoChange,
312 cache_.UpdateDnsRecord(std::move(record_goodbye2)));
313 EXPECT_EQ(default_time_ + base::Seconds(1), cache_.next_expiration());
314 }
315
TEST_F(MDnsCacheTest,AnyRRType)316 TEST_F(MDnsCacheTest, AnyRRType) {
317 DnsRecordParser parser(kTestResponseTwoRecords, 0, /*num_records=*/2);
318
319 std::unique_ptr<const RecordParsed> record1;
320 std::unique_ptr<const RecordParsed> record2;
321 std::vector<const RecordParsed*> results;
322
323 record1 = RecordParsed::CreateFrom(&parser, default_time_);
324 record2 = RecordParsed::CreateFrom(&parser, default_time_);
325 EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(std::move(record1)));
326 EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(std::move(record2)));
327
328 cache_.FindDnsRecords(0, "ghs.l.google.com", &results, default_time_);
329
330 EXPECT_EQ(2u, results.size());
331 EXPECT_EQ(default_time_, results.front()->time_created());
332
333 EXPECT_EQ("ghs.l.google.com", results[0]->name());
334 EXPECT_EQ("ghs.l.google.com", results[1]->name());
335 EXPECT_EQ(dns_protocol::kTypeA,
336 std::min(results[0]->type(), results[1]->type()));
337 EXPECT_EQ(dns_protocol::kTypeAAAA,
338 std::max(results[0]->type(), results[1]->type()));
339 }
340
TEST_F(MDnsCacheTest,RemoveRecord)341 TEST_F(MDnsCacheTest, RemoveRecord) {
342 DnsRecordParser parser(kT1ResponseDatagram, sizeof(dns_protocol::Header),
343 kT1RecordCount);
344 std::string dotted_qname;
345 uint16_t qtype;
346 parser.ReadQuestion(dotted_qname, qtype);
347
348 std::unique_ptr<const RecordParsed> record1;
349 std::vector<const RecordParsed*> results;
350
351 record1 = RecordParsed::CreateFrom(&parser, default_time_);
352 EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(std::move(record1)));
353
354 cache_.FindDnsRecords(dns_protocol::kTypeCNAME, "codereview.chromium.org",
355 &results, default_time_);
356
357 EXPECT_EQ(1u, results.size());
358
359 std::unique_ptr<const RecordParsed> record_out =
360 cache_.RemoveRecord(results.front());
361
362 EXPECT_EQ(record_out.get(), results.front());
363
364 cache_.FindDnsRecords(dns_protocol::kTypeCNAME, "codereview.chromium.org",
365 &results, default_time_);
366
367 EXPECT_EQ(0u, results.size());
368 }
369
TEST_F(MDnsCacheTest,IsCacheOverfilled)370 TEST_F(MDnsCacheTest, IsCacheOverfilled) {
371 DnsRecordParser parser(kTestResponseTwoRecords, 0, /*num_records=*/2);
372 std::unique_ptr<const RecordParsed> record1 =
373 RecordParsed::CreateFrom(&parser, default_time_);
374 const RecordParsed* record1_ptr = record1.get();
375 std::unique_ptr<const RecordParsed> record2 =
376 RecordParsed::CreateFrom(&parser, default_time_);
377
378 cache_.set_entry_limit_for_testing(1);
379 EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(std::move(record1)));
380 EXPECT_FALSE(cache_.IsCacheOverfilled());
381 EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(std::move(record2)));
382 EXPECT_TRUE(cache_.IsCacheOverfilled());
383
384 record1 = cache_.RemoveRecord(record1_ptr);
385 EXPECT_TRUE(record1);
386 EXPECT_FALSE(cache_.IsCacheOverfilled());
387 }
388
TEST_F(MDnsCacheTest,ClearOnOverfilledCleanup)389 TEST_F(MDnsCacheTest, ClearOnOverfilledCleanup) {
390 DnsRecordParser parser(kTestResponseTwoRecords, 0, /*num_records=*/2);
391 std::unique_ptr<const RecordParsed> record1 =
392 RecordParsed::CreateFrom(&parser, default_time_);
393 const RecordParsed* record1_ptr = record1.get();
394 std::unique_ptr<const RecordParsed> record2 =
395 RecordParsed::CreateFrom(&parser, default_time_);
396 const RecordParsed* record2_ptr = record2.get();
397
398 cache_.set_entry_limit_for_testing(1);
399 EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(std::move(record1)));
400 EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(std::move(record2)));
401
402 ASSERT_TRUE(cache_.IsCacheOverfilled());
403
404 // Expect everything to be removed on CleanupRecords() with overfilled cache.
405 EXPECT_CALL(record_removal_, OnRecordRemoved(record1_ptr));
406 EXPECT_CALL(record_removal_, OnRecordRemoved(record2_ptr));
407 cache_.CleanupRecords(
408 default_time_, base::BindRepeating(&RecordRemovalMock::OnRecordRemoved,
409 base::Unretained(&record_removal_)));
410
411 EXPECT_FALSE(cache_.IsCacheOverfilled());
412 std::vector<const RecordParsed*> results;
413 cache_.FindDnsRecords(dns_protocol::kTypeA, "ghs.l.google.com", &results,
414 default_time_);
415 EXPECT_TRUE(results.empty());
416 cache_.FindDnsRecords(dns_protocol::kTypeAAAA, "ghs.l.google.com", &results,
417 default_time_);
418 EXPECT_TRUE(results.empty());
419 }
420
TEST_F(MDnsCacheTest,CaseInsensitive)421 TEST_F(MDnsCacheTest, CaseInsensitive) {
422 DnsRecordParser parser(kTestResponsesDifferentCapitalization, 0,
423 /*num_records=*/2);
424
425 std::unique_ptr<const RecordParsed> record1;
426 std::unique_ptr<const RecordParsed> record2;
427 std::vector<const RecordParsed*> results;
428
429 record1 = RecordParsed::CreateFrom(&parser, default_time_);
430 record2 = RecordParsed::CreateFrom(&parser, default_time_);
431 EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(std::move(record1)));
432 EXPECT_EQ(MDnsCache::RecordChanged,
433 cache_.UpdateDnsRecord(std::move(record2)));
434
435 cache_.FindDnsRecords(0, "ghs.l.google.com", &results, default_time_);
436
437 EXPECT_EQ(1u, results.size());
438 EXPECT_EQ("ghs.l.GOOGLE.com", results[0]->name());
439
440 std::vector<const RecordParsed*> results2;
441 cache_.FindDnsRecords(0, "GHS.L.google.COM", &results2, default_time_);
442 EXPECT_EQ(results, results2);
443 }
444
445 } // namespace net
446