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 16using ::testing::Return; 17using ::testing::StrictMock; 18 19namespace net { 20 21static 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 45static 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 69static 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 100static 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 128class RecordRemovalMock { 129 public: 130 MOCK_METHOD1(OnRecordRemoved, void(const RecordParsed*)); 131}; 132 133class MDnsCacheTest : public ::testing::Test { 134 public: 135 MDnsCacheTest() 136 : default_time_(base::Time::FromDoubleT(1234.0)) {} 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. 146TEST_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. 178TEST_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. 228TEST_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. 247TEST_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. 266TEST_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. 290TEST_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 321TEST_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 348TEST_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