• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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