Home | History | Annotate | Download | only in dns
      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:
    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.
    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.
    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.
    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.
    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.
    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.
    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 
    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 
    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