blob: 2e4ee8f952273de4edc6659957bf3703f81a9e46 [file] [log] [blame]
[email protected]f6a9add2013-05-23 00:56:361// Copyright (c) 2013 The Chromium 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
dchengc7eeda422015-12-26 03:56:485#include "net/dns/mdns_cache.h"
6
[email protected]21df16962013-07-01 17:39:537#include <algorithm>
dchengc7eeda422015-12-26 03:56:488#include <utility>
[email protected]21df16962013-07-01 17:39:539
[email protected]f6a9add2013-05-23 00:56:3610#include "base/bind.h"
11#include "net/dns/dns_response.h"
12#include "net/dns/dns_test_util.h"
[email protected]f6a9add2013-05-23 00:56:3613#include "net/dns/record_parsed.h"
14#include "net/dns/record_rdata.h"
15#include "testing/gmock/include/gmock/gmock.h"
16#include "testing/gtest/include/gtest/gtest.h"
17
18using ::testing::Return;
19using ::testing::StrictMock;
20
21namespace net {
22
Avi Drissman13fc8932015-12-20 04:40:4623static const uint8_t kTestResponsesDifferentAnswers[] = {
24 // Answer 1
25 // ghs.l.google.com in DNS format.
26 3, 'g', 'h', 's', 1, 'l', 6, 'g', 'o', 'o', 'g', 'l', 'e', 3, 'c', 'o', 'm',
27 0x00, 0x00, 0x01, // TYPE is A.
28 0x00, 0x01, // CLASS is IN.
29 0, 0, 0, 53, // TTL (4 bytes) is 53 seconds.
30 0, 4, // RDLENGTH is 4 bytes.
31 74, 125, 95, 121, // RDATA is the IP: 74.125.95.121
[email protected]f6a9add2013-05-23 00:56:3632
Avi Drissman13fc8932015-12-20 04:40:4633 // Answer 2
34 // Pointer to answer 1
35 0xc0, 0x00, 0x00, 0x01, // TYPE is A.
36 0x00, 0x01, // CLASS is IN.
37 0, 0, 0, 53, // TTL (4 bytes) is 53 seconds.
38 0, 4, // RDLENGTH is 4 bytes.
39 74, 125, 95, 122, // RDATA is the IP: 74.125.95.122
[email protected]f6a9add2013-05-23 00:56:3640};
41
Avi Drissman13fc8932015-12-20 04:40:4642static const uint8_t kTestResponsesSameAnswers[] = {
43 // Answer 1
44 // ghs.l.google.com in DNS format.
45 3, 'g', 'h', 's', 1, 'l', 6, 'g', 'o', 'o', 'g', 'l', 'e', 3, 'c', 'o', 'm',
46 0x00, 0x00, 0x01, // TYPE is A.
47 0x00, 0x01, // CLASS is IN.
48 0, 0, 0, 53, // TTL (4 bytes) is 53 seconds.
49 0, 4, // RDLENGTH is 4 bytes.
50 74, 125, 95, 121, // RDATA is the IP: 74.125.95.121
[email protected]f6a9add2013-05-23 00:56:3651
Avi Drissman13fc8932015-12-20 04:40:4652 // Answer 2
53 // Pointer to answer 1
54 0xc0, 0x00, 0x00, 0x01, // TYPE is A.
55 0x00, 0x01, // CLASS is IN.
56 0, 0, 0, 112, // TTL (4 bytes) is 112 seconds.
57 0, 4, // RDLENGTH is 4 bytes.
58 74, 125, 95, 121, // RDATA is the IP: 74.125.95.121
[email protected]f6a9add2013-05-23 00:56:3659};
60
Avi Drissman13fc8932015-12-20 04:40:4661static const uint8_t kTestResponseTwoRecords[] = {
62 // Answer 1
63 // ghs.l.google.com in DNS format. (A)
64 3, 'g', 'h', 's', 1, 'l', 6, 'g', 'o', 'o', 'g', 'l', 'e', 3, 'c', 'o', 'm',
65 0x00, 0x00, 0x01, // TYPE is A.
66 0x00, 0x01, // CLASS is IN.
67 0, 0, 0, 53, // TTL (4 bytes) is 53 seconds.
68 0, 4, // RDLENGTH is 4 bytes.
69 74, 125, 95, 121, // RDATA is the IP: 74.125.95.121
[email protected]5942c9b92013-07-31 10:31:1070
Avi Drissman13fc8932015-12-20 04:40:4671 // Answer 2
72 // ghs.l.google.com in DNS format. (AAAA)
73 3, 'g', 'h', 's', 1, 'l', 6, 'g', 'o', 'o', 'g', 'l', 'e', 3, 'c', 'o', 'm',
74 0x00, 0x00, 0x1c, // TYPE is AAA.
75 0x00, 0x01, // CLASS is IN.
76 0, 0, 0, 53, // TTL (4 bytes) is 53 seconds.
77 0, 16, // RDLENGTH is 16 bytes.
78 0x4a, 0x7d, 0x4a, 0x7d, 0x5f, 0x79, 0x5f, 0x79, 0x5f, 0x79, 0x5f, 0x79,
79 0x5f, 0x79, 0x5f, 0x79,
[email protected]21df16962013-07-01 17:39:5380};
81
Avi Drissman13fc8932015-12-20 04:40:4682static const uint8_t kTestResponsesGoodbyePacket[] = {
83 // Answer 1
84 // ghs.l.google.com in DNS format. (Goodbye packet)
85 3, 'g', 'h', 's', 1, 'l', 6, 'g', 'o', 'o', 'g', 'l', 'e', 3, 'c', 'o', 'm',
86 0x00, 0x00, 0x01, // TYPE is A.
87 0x00, 0x01, // CLASS is IN.
88 0, 0, 0, 0, // TTL (4 bytes) is zero.
89 0, 4, // RDLENGTH is 4 bytes.
90 74, 125, 95, 121, // RDATA is the IP: 74.125.95.121
[email protected]35f3a6b2013-07-11 19:59:0391
Avi Drissman13fc8932015-12-20 04:40:4692 // Answer 2
93 // ghs.l.google.com in DNS format.
94 3, 'g', 'h', 's', 1, 'l', 6, 'g', 'o', 'o', 'g', 'l', 'e', 3, 'c', 'o', 'm',
95 0x00, 0x00, 0x01, // TYPE is A.
96 0x00, 0x01, // CLASS is IN.
97 0, 0, 0, 53, // TTL (4 bytes) is 53 seconds.
98 0, 4, // RDLENGTH is 4 bytes.
99 74, 125, 95, 121, // RDATA is the IP: 74.125.95.121
[email protected]35f3a6b2013-07-11 19:59:03100};
101
[email protected]f6a9add2013-05-23 00:56:36102class RecordRemovalMock {
103 public:
104 MOCK_METHOD1(OnRecordRemoved, void(const RecordParsed*));
105};
106
107class MDnsCacheTest : public ::testing::Test {
108 public:
109 MDnsCacheTest()
110 : default_time_(base::Time::FromDoubleT(1234.0)) {}
Daniel Cheng4496d0822018-04-26 21:52:15111 ~MDnsCacheTest() override = default;
[email protected]f6a9add2013-05-23 00:56:36112
113 protected:
114 base::Time default_time_;
115 StrictMock<RecordRemovalMock> record_removal_;
116 MDnsCache cache_;
117};
118
119// Test a single insert, corresponding lookup, and unsuccessful lookup.
120TEST_F(MDnsCacheTest, InsertLookupSingle) {
121 DnsRecordParser parser(kT1ResponseDatagram, sizeof(kT1ResponseDatagram),
122 sizeof(dns_protocol::Header));
123 parser.SkipQuestion();
124
danakj22f90e72016-04-16 01:55:40125 std::unique_ptr<const RecordParsed> record1;
126 std::unique_ptr<const RecordParsed> record2;
[email protected]f6a9add2013-05-23 00:56:36127 std::vector<const RecordParsed*> results;
128
129 record1 = RecordParsed::CreateFrom(&parser, default_time_);
130 record2 = RecordParsed::CreateFrom(&parser, default_time_);
131
dchengc7eeda422015-12-26 03:56:48132 EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(std::move(record1)));
[email protected]f6a9add2013-05-23 00:56:36133
dchengc7eeda422015-12-26 03:56:48134 EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(std::move(record2)));
[email protected]f6a9add2013-05-23 00:56:36135
136 cache_.FindDnsRecords(ARecordRdata::kType, "ghs.l.google.com", &results,
137 default_time_);
138
139 EXPECT_EQ(1u, results.size());
140 EXPECT_EQ(default_time_, results.front()->time_created());
141
142 EXPECT_EQ("ghs.l.google.com", results.front()->name());
143
144 results.clear();
145 cache_.FindDnsRecords(PtrRecordRdata::kType, "ghs.l.google.com", &results,
146 default_time_);
147
148 EXPECT_EQ(0u, results.size());
149}
150
151// Test that records expire when their ttl has passed.
152TEST_F(MDnsCacheTest, Expiration) {
153 DnsRecordParser parser(kT1ResponseDatagram, sizeof(kT1ResponseDatagram),
154 sizeof(dns_protocol::Header));
155 parser.SkipQuestion();
danakj22f90e72016-04-16 01:55:40156 std::unique_ptr<const RecordParsed> record1;
157 std::unique_ptr<const RecordParsed> record2;
[email protected]f6a9add2013-05-23 00:56:36158
159 std::vector<const RecordParsed*> results;
160 const RecordParsed* record_to_be_deleted;
161
162 record1 = RecordParsed::CreateFrom(&parser, default_time_);
163 base::TimeDelta ttl1 = base::TimeDelta::FromSeconds(record1->ttl());
164
165 record2 = RecordParsed::CreateFrom(&parser, default_time_);
166 base::TimeDelta ttl2 = base::TimeDelta::FromSeconds(record2->ttl());
167 record_to_be_deleted = record2.get();
168
dchengc7eeda422015-12-26 03:56:48169 EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(std::move(record1)));
170 EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(std::move(record2)));
[email protected]f6a9add2013-05-23 00:56:36171
172 cache_.FindDnsRecords(ARecordRdata::kType, "ghs.l.google.com", &results,
173 default_time_);
174
175 EXPECT_EQ(1u, results.size());
176
177 EXPECT_EQ(default_time_ + ttl2, cache_.next_expiration());
178
179
180 cache_.FindDnsRecords(ARecordRdata::kType, "ghs.l.google.com", &results,
181 default_time_ + ttl2);
182
183 EXPECT_EQ(0u, results.size());
184
185 EXPECT_CALL(record_removal_, OnRecordRemoved(record_to_be_deleted));
186
187 cache_.CleanupRecords(default_time_ + ttl2, base::Bind(
188 &RecordRemovalMock::OnRecordRemoved, base::Unretained(&record_removal_)));
189
190 // To make sure that we've indeed removed them from the map, check no funny
191 // business happens once they're deleted for good.
192
193 EXPECT_EQ(default_time_ + ttl1, cache_.next_expiration());
194 cache_.FindDnsRecords(ARecordRdata::kType, "ghs.l.google.com", &results,
195 default_time_ + ttl2);
196
197 EXPECT_EQ(0u, results.size());
198}
199
200// Test that a new record replacing one with the same identity (name/rrtype for
201// unique records) causes the cache to output a "record changed" event.
202TEST_F(MDnsCacheTest, RecordChange) {
203 DnsRecordParser parser(kTestResponsesDifferentAnswers,
204 sizeof(kTestResponsesDifferentAnswers),
205 0);
206
danakj22f90e72016-04-16 01:55:40207 std::unique_ptr<const RecordParsed> record1;
208 std::unique_ptr<const RecordParsed> record2;
[email protected]f6a9add2013-05-23 00:56:36209 std::vector<const RecordParsed*> results;
210
211 record1 = RecordParsed::CreateFrom(&parser, default_time_);
212 record2 = RecordParsed::CreateFrom(&parser, default_time_);
213
dchengc7eeda422015-12-26 03:56:48214 EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(std::move(record1)));
[email protected]f6a9add2013-05-23 00:56:36215 EXPECT_EQ(MDnsCache::RecordChanged,
dchengc7eeda422015-12-26 03:56:48216 cache_.UpdateDnsRecord(std::move(record2)));
[email protected]f6a9add2013-05-23 00:56:36217}
218
219// Test that a new record replacing an otherwise identical one already in the
220// cache causes the cache to output a "no change" event.
221TEST_F(MDnsCacheTest, RecordNoChange) {
222 DnsRecordParser parser(kTestResponsesSameAnswers,
223 sizeof(kTestResponsesSameAnswers),
224 0);
225
danakj22f90e72016-04-16 01:55:40226 std::unique_ptr<const RecordParsed> record1;
227 std::unique_ptr<const RecordParsed> record2;
[email protected]f6a9add2013-05-23 00:56:36228 std::vector<const RecordParsed*> results;
229
230 record1 = RecordParsed::CreateFrom(&parser, default_time_);
231 record2 = RecordParsed::CreateFrom(&parser, default_time_ +
232 base::TimeDelta::FromSeconds(1));
233
dchengc7eeda422015-12-26 03:56:48234 EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(std::move(record1)));
235 EXPECT_EQ(MDnsCache::NoChange, cache_.UpdateDnsRecord(std::move(record2)));
[email protected]f6a9add2013-05-23 00:56:36236}
237
238// Test that the next expiration time of the cache is updated properly on record
239// insertion.
240TEST_F(MDnsCacheTest, RecordPreemptExpirationTime) {
241 DnsRecordParser parser(kTestResponsesSameAnswers,
242 sizeof(kTestResponsesSameAnswers),
243 0);
244
danakj22f90e72016-04-16 01:55:40245 std::unique_ptr<const RecordParsed> record1;
246 std::unique_ptr<const RecordParsed> record2;
[email protected]f6a9add2013-05-23 00:56:36247 std::vector<const RecordParsed*> results;
248
249 record1 = RecordParsed::CreateFrom(&parser, default_time_);
250 record2 = RecordParsed::CreateFrom(&parser, default_time_);
251 base::TimeDelta ttl1 = base::TimeDelta::FromSeconds(record1->ttl());
252 base::TimeDelta ttl2 = base::TimeDelta::FromSeconds(record2->ttl());
253
254 EXPECT_EQ(base::Time(), cache_.next_expiration());
dchengc7eeda422015-12-26 03:56:48255 EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(std::move(record2)));
[email protected]f6a9add2013-05-23 00:56:36256 EXPECT_EQ(default_time_ + ttl2, cache_.next_expiration());
dchengc7eeda422015-12-26 03:56:48257 EXPECT_EQ(MDnsCache::NoChange, cache_.UpdateDnsRecord(std::move(record1)));
[email protected]f6a9add2013-05-23 00:56:36258 EXPECT_EQ(default_time_ + ttl1, cache_.next_expiration());
259}
260
[email protected]35f3a6b2013-07-11 19:59:03261// Test that the cache handles mDNS "goodbye" packets correctly, not adding the
262// records to the cache if they are not already there, and eventually removing
263// records from the cache if they are.
264TEST_F(MDnsCacheTest, GoodbyePacket) {
265 DnsRecordParser parser(kTestResponsesGoodbyePacket,
266 sizeof(kTestResponsesGoodbyePacket),
267 0);
268
danakj22f90e72016-04-16 01:55:40269 std::unique_ptr<const RecordParsed> record_goodbye;
270 std::unique_ptr<const RecordParsed> record_hello;
271 std::unique_ptr<const RecordParsed> record_goodbye2;
[email protected]35f3a6b2013-07-11 19:59:03272 std::vector<const RecordParsed*> results;
273
274 record_goodbye = RecordParsed::CreateFrom(&parser, default_time_);
275 record_hello = RecordParsed::CreateFrom(&parser, default_time_);
276 parser = DnsRecordParser(kTestResponsesGoodbyePacket,
277 sizeof(kTestResponsesGoodbyePacket),
278 0);
279 record_goodbye2 = RecordParsed::CreateFrom(&parser, default_time_);
280
281 base::TimeDelta ttl = base::TimeDelta::FromSeconds(record_hello->ttl());
282
283 EXPECT_EQ(base::Time(), cache_.next_expiration());
dchengc7eeda422015-12-26 03:56:48284 EXPECT_EQ(MDnsCache::NoChange,
285 cache_.UpdateDnsRecord(std::move(record_goodbye)));
[email protected]35f3a6b2013-07-11 19:59:03286 EXPECT_EQ(base::Time(), cache_.next_expiration());
287 EXPECT_EQ(MDnsCache::RecordAdded,
dchengc7eeda422015-12-26 03:56:48288 cache_.UpdateDnsRecord(std::move(record_hello)));
[email protected]35f3a6b2013-07-11 19:59:03289 EXPECT_EQ(default_time_ + ttl, cache_.next_expiration());
290 EXPECT_EQ(MDnsCache::NoChange,
dchengc7eeda422015-12-26 03:56:48291 cache_.UpdateDnsRecord(std::move(record_goodbye2)));
[email protected]35f3a6b2013-07-11 19:59:03292 EXPECT_EQ(default_time_ + base::TimeDelta::FromSeconds(1),
293 cache_.next_expiration());
294}
295
[email protected]21df16962013-07-01 17:39:53296TEST_F(MDnsCacheTest, AnyRRType) {
297 DnsRecordParser parser(kTestResponseTwoRecords,
298 sizeof(kTestResponseTwoRecords),
299 0);
300
danakj22f90e72016-04-16 01:55:40301 std::unique_ptr<const RecordParsed> record1;
302 std::unique_ptr<const RecordParsed> record2;
[email protected]21df16962013-07-01 17:39:53303 std::vector<const RecordParsed*> results;
304
305 record1 = RecordParsed::CreateFrom(&parser, default_time_);
306 record2 = RecordParsed::CreateFrom(&parser, default_time_);
dchengc7eeda422015-12-26 03:56:48307 EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(std::move(record1)));
308 EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(std::move(record2)));
[email protected]21df16962013-07-01 17:39:53309
310 cache_.FindDnsRecords(0, "ghs.l.google.com", &results, default_time_);
311
312 EXPECT_EQ(2u, results.size());
313 EXPECT_EQ(default_time_, results.front()->time_created());
314
315 EXPECT_EQ("ghs.l.google.com", results[0]->name());
316 EXPECT_EQ("ghs.l.google.com", results[1]->name());
317 EXPECT_EQ(dns_protocol::kTypeA,
318 std::min(results[0]->type(), results[1]->type()));
319 EXPECT_EQ(dns_protocol::kTypeAAAA,
320 std::max(results[0]->type(), results[1]->type()));
321}
322
323TEST_F(MDnsCacheTest, RemoveRecord) {
324 DnsRecordParser parser(kT1ResponseDatagram, sizeof(kT1ResponseDatagram),
325 sizeof(dns_protocol::Header));
326 parser.SkipQuestion();
327
danakj22f90e72016-04-16 01:55:40328 std::unique_ptr<const RecordParsed> record1;
[email protected]21df16962013-07-01 17:39:53329 std::vector<const RecordParsed*> results;
330
331 record1 = RecordParsed::CreateFrom(&parser, default_time_);
dchengc7eeda422015-12-26 03:56:48332 EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(std::move(record1)));
[email protected]21df16962013-07-01 17:39:53333
334 cache_.FindDnsRecords(dns_protocol::kTypeCNAME, "codereview.chromium.org",
335 &results, default_time_);
336
337 EXPECT_EQ(1u, results.size());
338
danakj22f90e72016-04-16 01:55:40339 std::unique_ptr<const RecordParsed> record_out =
[email protected]21df16962013-07-01 17:39:53340 cache_.RemoveRecord(results.front());
341
342 EXPECT_EQ(record_out.get(), results.front());
343
344 cache_.FindDnsRecords(dns_protocol::kTypeCNAME, "codereview.chromium.org",
345 &results, default_time_);
346
347 EXPECT_EQ(0u, results.size());
348}
349
Eric Orthacdd8ae2019-03-29 22:07:19350TEST_F(MDnsCacheTest, IsCacheOverfilled) {
351 DnsRecordParser parser(kTestResponseTwoRecords,
352 sizeof(kTestResponseTwoRecords), 0);
353 std::unique_ptr<const RecordParsed> record1 =
354 RecordParsed::CreateFrom(&parser, default_time_);
355 const RecordParsed* record1_ptr = record1.get();
356 std::unique_ptr<const RecordParsed> record2 =
357 RecordParsed::CreateFrom(&parser, default_time_);
358
359 cache_.set_entry_limit_for_testing(1);
360 EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(std::move(record1)));
361 EXPECT_FALSE(cache_.IsCacheOverfilled());
362 EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(std::move(record2)));
363 EXPECT_TRUE(cache_.IsCacheOverfilled());
364
365 record1 = cache_.RemoveRecord(record1_ptr);
366 EXPECT_TRUE(record1);
367 EXPECT_FALSE(cache_.IsCacheOverfilled());
368}
369
370TEST_F(MDnsCacheTest, ClearOnOverfilledCleanup) {
371 DnsRecordParser parser(kTestResponseTwoRecords,
372 sizeof(kTestResponseTwoRecords), 0);
373 std::unique_ptr<const RecordParsed> record1 =
374 RecordParsed::CreateFrom(&parser, default_time_);
375 const RecordParsed* record1_ptr = record1.get();
376 std::unique_ptr<const RecordParsed> record2 =
377 RecordParsed::CreateFrom(&parser, default_time_);
378 const RecordParsed* record2_ptr = record2.get();
379
380 cache_.set_entry_limit_for_testing(1);
381 EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(std::move(record1)));
382 EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(std::move(record2)));
383
384 ASSERT_TRUE(cache_.IsCacheOverfilled());
385
386 // Expect everything to be removed on CleanupRecords() with overfilled cache.
387 EXPECT_CALL(record_removal_, OnRecordRemoved(record1_ptr));
388 EXPECT_CALL(record_removal_, OnRecordRemoved(record2_ptr));
389 cache_.CleanupRecords(
390 default_time_, base::BindRepeating(&RecordRemovalMock::OnRecordRemoved,
391 base::Unretained(&record_removal_)));
392
393 EXPECT_FALSE(cache_.IsCacheOverfilled());
394 std::vector<const RecordParsed*> results;
395 cache_.FindDnsRecords(dns_protocol::kTypeA, "ghs.l.google.com", &results,
396 default_time_);
397 EXPECT_TRUE(results.empty());
398 cache_.FindDnsRecords(dns_protocol::kTypeAAAA, "ghs.l.google.com", &results,
399 default_time_);
400 EXPECT_TRUE(results.empty());
401}
402
[email protected]21df16962013-07-01 17:39:53403} // namespace net