xref: /aosp_15_r20/external/cronet/net/dns/mdns_cache_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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