• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // 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 
5 #include <algorithm>
6 
7 #include "base/bind.h"
8 #include "net/dns/dns_response.h"
9 #include "net/dns/dns_test_util.h"
10 #include "net/dns/mdns_cache.h"
11 #include "net/dns/record_parsed.h"
12 #include "net/dns/record_rdata.h"
13 #include "testing/gmock/include/gmock/gmock.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 
16 using ::testing::Return;
17 using ::testing::StrictMock;
18 
19 namespace net {
20 
21 static const uint8 kTestResponsesDifferentAnswers[] = {
22   // Answer 1
23   // ghs.l.google.com in DNS format.
24   3, 'g', 'h', 's',
25   1, 'l',
26   6, 'g', 'o', 'o', 'g', 'l', 'e',
27   3, 'c', 'o', 'm',
28   0x00,
29   0x00, 0x01,         // TYPE is A.
30   0x00, 0x01,         // CLASS is IN.
31   0, 0, 0, 53,        // TTL (4 bytes) is 53 seconds.
32   0, 4,               // RDLENGTH is 4 bytes.
33   74, 125, 95, 121,   // RDATA is the IP: 74.125.95.121
34 
35   // Answer 2
36   // Pointer to answer 1
37   0xc0, 0x00,
38   0x00, 0x01,         // TYPE is A.
39   0x00, 0x01,         // CLASS is IN.
40   0, 0, 0, 53,        // TTL (4 bytes) is 53 seconds.
41   0, 4,               // RDLENGTH is 4 bytes.
42   74, 125, 95, 122,   // RDATA is the IP: 74.125.95.122
43 };
44 
45 static const uint8 kTestResponsesSameAnswers[] = {
46   // Answer 1
47   // ghs.l.google.com in DNS format.
48   3, 'g', 'h', 's',
49   1, 'l',
50   6, 'g', 'o', 'o', 'g', 'l', 'e',
51   3, 'c', 'o', 'm',
52   0x00,
53   0x00, 0x01,         // TYPE is A.
54   0x00, 0x01,         // CLASS is IN.
55   0, 0, 0, 53,        // TTL (4 bytes) is 53 seconds.
56   0, 4,               // RDLENGTH is 4 bytes.
57   74, 125, 95, 121,   // RDATA is the IP: 74.125.95.121
58 
59   // Answer 2
60   // Pointer to answer 1
61   0xc0, 0x00,
62   0x00, 0x01,         // TYPE is A.
63   0x00, 0x01,         // CLASS is IN.
64   0, 0, 0, 112,       // TTL (4 bytes) is 112 seconds.
65   0, 4,               // RDLENGTH is 4 bytes.
66   74, 125, 95, 121,   // RDATA is the IP: 74.125.95.121
67 };
68 
69 static const uint8 kTestResponseTwoRecords[] = {
70   // Answer 1
71   // ghs.l.google.com in DNS format. (A)
72   3, 'g', 'h', 's',
73   1, 'l',
74   6, 'g', 'o', 'o', 'g', 'l', 'e',
75   3, 'c', 'o', 'm',
76   0x00,
77   0x00, 0x01,         // TYPE is A.
78   0x00, 0x01,         // CLASS is IN.
79   0, 0, 0, 53,        // TTL (4 bytes) is 53 seconds.
80   0, 4,               // RDLENGTH is 4 bytes.
81   74, 125, 95, 121,   // RDATA is the IP: 74.125.95.121
82 
83   // Answer 2
84   // ghs.l.google.com in DNS format. (AAAA)
85   3, 'g', 'h', 's',
86   1, 'l',
87   6, 'g', 'o', 'o', 'g', 'l', 'e',
88   3, 'c', 'o', 'm',
89   0x00,
90   0x00, 0x1c,         // TYPE is AAA.
91   0x00, 0x01,         // CLASS is IN.
92   0, 0, 0, 53,        // TTL (4 bytes) is 53 seconds.
93   0, 16,              // RDLENGTH is 16 bytes.
94   0x4a, 0x7d, 0x4a, 0x7d,
95   0x5f, 0x79, 0x5f, 0x79,
96   0x5f, 0x79, 0x5f, 0x79,
97   0x5f, 0x79, 0x5f, 0x79,
98 };
99 
100 static const uint8 kTestResponsesGoodbyePacket[] = {
101   // Answer 1
102   // ghs.l.google.com in DNS format. (Goodbye packet)
103   3, 'g', 'h', 's',
104   1, 'l',
105   6, 'g', 'o', 'o', 'g', 'l', 'e',
106   3, 'c', 'o', 'm',
107   0x00,
108   0x00, 0x01,         // TYPE is A.
109   0x00, 0x01,         // CLASS is IN.
110   0, 0, 0, 0,         // TTL (4 bytes) is zero.
111   0, 4,               // RDLENGTH is 4 bytes.
112   74, 125, 95, 121,   // RDATA is the IP: 74.125.95.121
113 
114   // Answer 2
115   // ghs.l.google.com in DNS format.
116   3, 'g', 'h', 's',
117   1, 'l',
118   6, 'g', 'o', 'o', 'g', 'l', 'e',
119   3, 'c', 'o', 'm',
120   0x00,
121   0x00, 0x01,         // TYPE is A.
122   0x00, 0x01,         // CLASS is IN.
123   0, 0, 0, 53,        // TTL (4 bytes) is 53 seconds.
124   0, 4,               // RDLENGTH is 4 bytes.
125   74, 125, 95, 121,   // RDATA is the IP: 74.125.95.121
126 };
127 
128 class RecordRemovalMock {
129  public:
130   MOCK_METHOD1(OnRecordRemoved, void(const RecordParsed*));
131 };
132 
133 class MDnsCacheTest : public ::testing::Test {
134  public:
MDnsCacheTest()135   MDnsCacheTest()
136       : default_time_(base::Time::FromDoubleT(1234.0)) {}
~MDnsCacheTest()137   virtual ~MDnsCacheTest() {}
138 
139  protected:
140   base::Time default_time_;
141   StrictMock<RecordRemovalMock> record_removal_;
142   MDnsCache cache_;
143 };
144 
145 // Test a single insert, corresponding lookup, and unsuccessful lookup.
TEST_F(MDnsCacheTest,InsertLookupSingle)146 TEST_F(MDnsCacheTest, InsertLookupSingle) {
147   DnsRecordParser parser(kT1ResponseDatagram, sizeof(kT1ResponseDatagram),
148                          sizeof(dns_protocol::Header));
149   parser.SkipQuestion();
150 
151   scoped_ptr<const RecordParsed> record1;
152   scoped_ptr<const RecordParsed> record2;
153   std::vector<const RecordParsed*> results;
154 
155   record1 = RecordParsed::CreateFrom(&parser, default_time_);
156   record2 = RecordParsed::CreateFrom(&parser, default_time_);
157 
158   EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(record1.Pass()));
159 
160   EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(record2.Pass()));
161 
162   cache_.FindDnsRecords(ARecordRdata::kType, "ghs.l.google.com", &results,
163                         default_time_);
164 
165   EXPECT_EQ(1u, results.size());
166   EXPECT_EQ(default_time_, results.front()->time_created());
167 
168   EXPECT_EQ("ghs.l.google.com", results.front()->name());
169 
170   results.clear();
171   cache_.FindDnsRecords(PtrRecordRdata::kType, "ghs.l.google.com", &results,
172                         default_time_);
173 
174   EXPECT_EQ(0u, results.size());
175 }
176 
177 // Test that records expire when their ttl has passed.
TEST_F(MDnsCacheTest,Expiration)178 TEST_F(MDnsCacheTest, Expiration) {
179   DnsRecordParser parser(kT1ResponseDatagram, sizeof(kT1ResponseDatagram),
180                          sizeof(dns_protocol::Header));
181   parser.SkipQuestion();
182   scoped_ptr<const RecordParsed> record1;
183   scoped_ptr<const RecordParsed> record2;
184 
185   std::vector<const RecordParsed*> results;
186   const RecordParsed* record_to_be_deleted;
187 
188   record1 = RecordParsed::CreateFrom(&parser, default_time_);
189   base::TimeDelta ttl1 = base::TimeDelta::FromSeconds(record1->ttl());
190 
191   record2 = RecordParsed::CreateFrom(&parser, default_time_);
192   base::TimeDelta ttl2 = base::TimeDelta::FromSeconds(record2->ttl());
193   record_to_be_deleted = record2.get();
194 
195   EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(record1.Pass()));
196   EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(record2.Pass()));
197 
198   cache_.FindDnsRecords(ARecordRdata::kType, "ghs.l.google.com", &results,
199                         default_time_);
200 
201   EXPECT_EQ(1u, results.size());
202 
203   EXPECT_EQ(default_time_ + ttl2, cache_.next_expiration());
204 
205 
206   cache_.FindDnsRecords(ARecordRdata::kType, "ghs.l.google.com", &results,
207                         default_time_ + ttl2);
208 
209   EXPECT_EQ(0u, results.size());
210 
211   EXPECT_CALL(record_removal_, OnRecordRemoved(record_to_be_deleted));
212 
213   cache_.CleanupRecords(default_time_ + ttl2, base::Bind(
214       &RecordRemovalMock::OnRecordRemoved, base::Unretained(&record_removal_)));
215 
216   // To make sure that we've indeed removed them from the map, check no funny
217   // business happens once they're deleted for good.
218 
219   EXPECT_EQ(default_time_ + ttl1, cache_.next_expiration());
220   cache_.FindDnsRecords(ARecordRdata::kType, "ghs.l.google.com", &results,
221                         default_time_ + ttl2);
222 
223   EXPECT_EQ(0u, results.size());
224 }
225 
226 // Test that a new record replacing one with the same identity (name/rrtype for
227 // unique records) causes the cache to output a "record changed" event.
TEST_F(MDnsCacheTest,RecordChange)228 TEST_F(MDnsCacheTest, RecordChange) {
229   DnsRecordParser parser(kTestResponsesDifferentAnswers,
230                          sizeof(kTestResponsesDifferentAnswers),
231                          0);
232 
233   scoped_ptr<const RecordParsed> record1;
234   scoped_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(record1.Pass()));
241   EXPECT_EQ(MDnsCache::RecordChanged,
242             cache_.UpdateDnsRecord(record2.Pass()));
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,
249                          sizeof(kTestResponsesSameAnswers),
250                          0);
251 
252   scoped_ptr<const RecordParsed> record1;
253   scoped_ptr<const RecordParsed> record2;
254   std::vector<const RecordParsed*> results;
255 
256   record1 = RecordParsed::CreateFrom(&parser, default_time_);
257   record2 = RecordParsed::CreateFrom(&parser, default_time_ +
258                                      base::TimeDelta::FromSeconds(1));
259 
260   EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(record1.Pass()));
261   EXPECT_EQ(MDnsCache::NoChange, cache_.UpdateDnsRecord(record2.Pass()));
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),
269                          0);
270 
271   scoped_ptr<const RecordParsed> record1;
272   scoped_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::TimeDelta::FromSeconds(record1->ttl());
278   base::TimeDelta ttl2 = base::TimeDelta::FromSeconds(record2->ttl());
279 
280   EXPECT_EQ(base::Time(), cache_.next_expiration());
281   EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(record2.Pass()));
282   EXPECT_EQ(default_time_ + ttl2, cache_.next_expiration());
283   EXPECT_EQ(MDnsCache::NoChange, cache_.UpdateDnsRecord(record1.Pass()));
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),
293                          0);
294 
295   scoped_ptr<const RecordParsed> record_goodbye;
296   scoped_ptr<const RecordParsed> record_hello;
297   scoped_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),
304                            0);
305   record_goodbye2 = RecordParsed::CreateFrom(&parser, default_time_);
306 
307   base::TimeDelta ttl = base::TimeDelta::FromSeconds(record_hello->ttl());
308 
309   EXPECT_EQ(base::Time(), cache_.next_expiration());
310   EXPECT_EQ(MDnsCache::NoChange, cache_.UpdateDnsRecord(record_goodbye.Pass()));
311   EXPECT_EQ(base::Time(), cache_.next_expiration());
312   EXPECT_EQ(MDnsCache::RecordAdded,
313             cache_.UpdateDnsRecord(record_hello.Pass()));
314   EXPECT_EQ(default_time_ + ttl, cache_.next_expiration());
315   EXPECT_EQ(MDnsCache::NoChange,
316             cache_.UpdateDnsRecord(record_goodbye2.Pass()));
317   EXPECT_EQ(default_time_ + base::TimeDelta::FromSeconds(1),
318             cache_.next_expiration());
319 }
320 
TEST_F(MDnsCacheTest,AnyRRType)321 TEST_F(MDnsCacheTest, AnyRRType) {
322   DnsRecordParser parser(kTestResponseTwoRecords,
323                          sizeof(kTestResponseTwoRecords),
324                          0);
325 
326   scoped_ptr<const RecordParsed> record1;
327   scoped_ptr<const RecordParsed> record2;
328   std::vector<const RecordParsed*> results;
329 
330   record1 = RecordParsed::CreateFrom(&parser, default_time_);
331   record2 = RecordParsed::CreateFrom(&parser, default_time_);
332   EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(record1.Pass()));
333   EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(record2.Pass()));
334 
335   cache_.FindDnsRecords(0, "ghs.l.google.com", &results, default_time_);
336 
337   EXPECT_EQ(2u, results.size());
338   EXPECT_EQ(default_time_, results.front()->time_created());
339 
340   EXPECT_EQ("ghs.l.google.com", results[0]->name());
341   EXPECT_EQ("ghs.l.google.com", results[1]->name());
342   EXPECT_EQ(dns_protocol::kTypeA,
343             std::min(results[0]->type(), results[1]->type()));
344   EXPECT_EQ(dns_protocol::kTypeAAAA,
345             std::max(results[0]->type(), results[1]->type()));
346 }
347 
TEST_F(MDnsCacheTest,RemoveRecord)348 TEST_F(MDnsCacheTest, RemoveRecord) {
349   DnsRecordParser parser(kT1ResponseDatagram, sizeof(kT1ResponseDatagram),
350                          sizeof(dns_protocol::Header));
351   parser.SkipQuestion();
352 
353   scoped_ptr<const RecordParsed> record1;
354   std::vector<const RecordParsed*> results;
355 
356   record1 = RecordParsed::CreateFrom(&parser, default_time_);
357   EXPECT_EQ(MDnsCache::RecordAdded, cache_.UpdateDnsRecord(record1.Pass()));
358 
359   cache_.FindDnsRecords(dns_protocol::kTypeCNAME, "codereview.chromium.org",
360                         &results, default_time_);
361 
362   EXPECT_EQ(1u, results.size());
363 
364   scoped_ptr<const RecordParsed> record_out =
365       cache_.RemoveRecord(results.front());
366 
367   EXPECT_EQ(record_out.get(), results.front());
368 
369   cache_.FindDnsRecords(dns_protocol::kTypeCNAME, "codereview.chromium.org",
370                         &results, default_time_);
371 
372   EXPECT_EQ(0u, results.size());
373 }
374 
375 }  // namespace net
376