1// Copyright (c) 2012 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 "net/dns/dns_config_service.h"
6
7#include "base/basictypes.h"
8#include "base/bind.h"
9#include "base/cancelable_callback.h"
10#include "base/memory/scoped_ptr.h"
11#include "base/message_loop/message_loop.h"
12#include "base/strings/string_split.h"
13#include "base/test/test_timeouts.h"
14#include "net/base/net_util.h"
15#include "net/dns/dns_protocol.h"
16#include "testing/gtest/include/gtest/gtest.h"
17
18namespace net {
19
20namespace {
21
22const NameServerClassifier::NameServersType kNone =
23    NameServerClassifier::NAME_SERVERS_TYPE_NONE;
24const NameServerClassifier::NameServersType kGoogle =
25    NameServerClassifier::NAME_SERVERS_TYPE_GOOGLE_PUBLIC_DNS;
26const NameServerClassifier::NameServersType kPrivate =
27    NameServerClassifier::NAME_SERVERS_TYPE_PRIVATE;
28const NameServerClassifier::NameServersType kPublic =
29    NameServerClassifier::NAME_SERVERS_TYPE_PUBLIC;
30const NameServerClassifier::NameServersType kMixed =
31    NameServerClassifier::NAME_SERVERS_TYPE_MIXED;
32
33class NameServerClassifierTest : public testing::Test {
34 protected:
35  NameServerClassifier::NameServersType Classify(
36      const std::string& servers_string) {
37    std::vector<std::string> server_strings;
38    base::SplitString(servers_string, ' ', &server_strings);
39
40    std::vector<IPEndPoint> servers;
41    for (std::vector<std::string>::const_iterator it = server_strings.begin();
42         it != server_strings.end();
43         ++it) {
44      if (*it == "")
45        continue;
46
47      IPAddressNumber address;
48      bool parsed = ParseIPLiteralToNumber(*it, &address);
49      EXPECT_TRUE(parsed);
50      servers.push_back(IPEndPoint(address, dns_protocol::kDefaultPort));
51    }
52
53    return classifier_.GetNameServersType(servers);
54  }
55
56 private:
57  NameServerClassifier classifier_;
58};
59
60TEST_F(NameServerClassifierTest, None) {
61  EXPECT_EQ(kNone, Classify(""));
62}
63
64TEST_F(NameServerClassifierTest, Google) {
65  EXPECT_EQ(kGoogle, Classify("8.8.8.8"));
66  EXPECT_EQ(kGoogle, Classify("8.8.8.8 8.8.4.4"));
67  EXPECT_EQ(kGoogle, Classify("2001:4860:4860::8888"));
68  EXPECT_EQ(kGoogle, Classify("2001:4860:4860::8888 2001:4860:4860::8844"));
69  EXPECT_EQ(kGoogle, Classify("2001:4860:4860::8888 8.8.8.8"));
70
71  // Make sure nobody took any shortcuts on the IP matching:
72  EXPECT_EQ(kPublic, Classify("8.8.8.4"));
73  EXPECT_EQ(kPublic, Classify("8.8.4.8"));
74  EXPECT_EQ(kPublic, Classify("2001:4860:4860::8884"));
75  EXPECT_EQ(kPublic, Classify("2001:4860:4860::8848"));
76  EXPECT_EQ(kPublic, Classify("2001:4860:4860::1:8888"));
77  EXPECT_EQ(kPublic, Classify("2001:4860:4860:1::8888"));
78}
79
80TEST_F(NameServerClassifierTest, PrivateLocalhost) {
81  EXPECT_EQ(kPrivate, Classify("127.0.0.1"));
82  EXPECT_EQ(kPrivate, Classify("::1"));
83}
84
85TEST_F(NameServerClassifierTest, PrivateRfc1918) {
86  EXPECT_EQ(kPrivate, Classify("10.0.0.0 10.255.255.255"));
87  EXPECT_EQ(kPrivate, Classify("172.16.0.0 172.31.255.255"));
88  EXPECT_EQ(kPrivate, Classify("192.168.0.0 192.168.255.255"));
89  EXPECT_EQ(kPrivate, Classify("10.1.1.1 172.16.1.1 192.168.1.1"));
90}
91
92TEST_F(NameServerClassifierTest, PrivateIPv4LinkLocal) {
93  EXPECT_EQ(kPrivate, Classify("169.254.0.0 169.254.255.255"));
94}
95
96TEST_F(NameServerClassifierTest, PrivateIPv6LinkLocal) {
97  EXPECT_EQ(kPrivate,
98      Classify("fe80:: fe80:ffff:ffff:ffff:ffff:ffff:ffff:ffff"));
99}
100
101TEST_F(NameServerClassifierTest, Public) {
102  EXPECT_EQ(kPublic, Classify("4.2.2.1"));
103  EXPECT_EQ(kPublic, Classify("4.2.2.1 4.2.2.2"));
104}
105
106TEST_F(NameServerClassifierTest, Mixed) {
107  EXPECT_EQ(kMixed, Classify("8.8.8.8 192.168.1.1"));
108  EXPECT_EQ(kMixed, Classify("8.8.8.8 4.2.2.1"));
109  EXPECT_EQ(kMixed, Classify("192.168.1.1 4.2.2.1"));
110  EXPECT_EQ(kMixed, Classify("8.8.8.8 192.168.1.1 4.2.2.1"));
111}
112
113class DnsConfigServiceTest : public testing::Test {
114 public:
115  void OnConfigChanged(const DnsConfig& config) {
116    last_config_ = config;
117    if (quit_on_config_)
118      base::MessageLoop::current()->Quit();
119  }
120
121 protected:
122  class TestDnsConfigService : public DnsConfigService {
123   public:
124    virtual void ReadNow() OVERRIDE {}
125    virtual bool StartWatching() OVERRIDE { return true; }
126
127    // Expose the protected methods to this test suite.
128    void InvalidateConfig() {
129      DnsConfigService::InvalidateConfig();
130    }
131
132    void InvalidateHosts() {
133      DnsConfigService::InvalidateHosts();
134    }
135
136    void OnConfigRead(const DnsConfig& config) {
137      DnsConfigService::OnConfigRead(config);
138    }
139
140    void OnHostsRead(const DnsHosts& hosts) {
141      DnsConfigService::OnHostsRead(hosts);
142    }
143
144    void set_watch_failed(bool value) {
145      DnsConfigService::set_watch_failed(value);
146    }
147  };
148
149  void WaitForConfig(base::TimeDelta timeout) {
150    base::CancelableClosure closure(base::MessageLoop::QuitClosure());
151    base::MessageLoop::current()->PostDelayedTask(
152        FROM_HERE, closure.callback(), timeout);
153    quit_on_config_ = true;
154    base::MessageLoop::current()->Run();
155    quit_on_config_ = false;
156    closure.Cancel();
157  }
158
159  // Generate a config using the given seed..
160  DnsConfig MakeConfig(unsigned seed) {
161    DnsConfig config;
162    IPAddressNumber ip;
163    CHECK(ParseIPLiteralToNumber("1.2.3.4", &ip));
164    config.nameservers.push_back(IPEndPoint(ip, seed & 0xFFFF));
165    EXPECT_TRUE(config.IsValid());
166    return config;
167  }
168
169  // Generate hosts using the given seed.
170  DnsHosts MakeHosts(unsigned seed) {
171    DnsHosts hosts;
172    std::string hosts_content = "127.0.0.1 localhost";
173    hosts_content.append(seed, '1');
174    ParseHosts(hosts_content, &hosts);
175    EXPECT_FALSE(hosts.empty());
176    return hosts;
177  }
178
179  virtual void SetUp() OVERRIDE {
180    quit_on_config_ = false;
181
182    service_.reset(new TestDnsConfigService());
183    service_->WatchConfig(base::Bind(&DnsConfigServiceTest::OnConfigChanged,
184                                     base::Unretained(this)));
185    EXPECT_FALSE(last_config_.IsValid());
186  }
187
188  DnsConfig last_config_;
189  bool quit_on_config_;
190
191  // Service under test.
192  scoped_ptr<TestDnsConfigService> service_;
193};
194
195}  // namespace
196
197TEST_F(DnsConfigServiceTest, FirstConfig) {
198  DnsConfig config = MakeConfig(1);
199
200  service_->OnConfigRead(config);
201  // No hosts yet, so no config.
202  EXPECT_TRUE(last_config_.Equals(DnsConfig()));
203
204  service_->OnHostsRead(config.hosts);
205  EXPECT_TRUE(last_config_.Equals(config));
206}
207
208TEST_F(DnsConfigServiceTest, Timeout) {
209  DnsConfig config = MakeConfig(1);
210  config.hosts = MakeHosts(1);
211  ASSERT_TRUE(config.IsValid());
212
213  service_->OnConfigRead(config);
214  service_->OnHostsRead(config.hosts);
215  EXPECT_FALSE(last_config_.Equals(DnsConfig()));
216  EXPECT_TRUE(last_config_.Equals(config));
217
218  service_->InvalidateConfig();
219  WaitForConfig(TestTimeouts::action_timeout());
220  EXPECT_FALSE(last_config_.Equals(config));
221  EXPECT_TRUE(last_config_.Equals(DnsConfig()));
222
223  service_->OnConfigRead(config);
224  EXPECT_FALSE(last_config_.Equals(DnsConfig()));
225  EXPECT_TRUE(last_config_.Equals(config));
226
227  service_->InvalidateHosts();
228  WaitForConfig(TestTimeouts::action_timeout());
229  EXPECT_FALSE(last_config_.Equals(config));
230  EXPECT_TRUE(last_config_.Equals(DnsConfig()));
231
232  DnsConfig bad_config = last_config_ = MakeConfig(0xBAD);
233  service_->InvalidateConfig();
234  // We don't expect an update. This should time out.
235  WaitForConfig(base::TimeDelta::FromMilliseconds(100) +
236                TestTimeouts::tiny_timeout());
237  EXPECT_TRUE(last_config_.Equals(bad_config)) << "Unexpected change";
238
239  last_config_ = DnsConfig();
240  service_->OnConfigRead(config);
241  service_->OnHostsRead(config.hosts);
242  EXPECT_FALSE(last_config_.Equals(DnsConfig()));
243  EXPECT_TRUE(last_config_.Equals(config));
244}
245
246TEST_F(DnsConfigServiceTest, SameConfig) {
247  DnsConfig config = MakeConfig(1);
248  config.hosts = MakeHosts(1);
249
250  service_->OnConfigRead(config);
251  service_->OnHostsRead(config.hosts);
252  EXPECT_FALSE(last_config_.Equals(DnsConfig()));
253  EXPECT_TRUE(last_config_.Equals(config));
254
255  last_config_ = DnsConfig();
256  service_->OnConfigRead(config);
257  EXPECT_TRUE(last_config_.Equals(DnsConfig())) << "Unexpected change";
258
259  service_->OnHostsRead(config.hosts);
260  EXPECT_TRUE(last_config_.Equals(DnsConfig())) << "Unexpected change";
261}
262
263TEST_F(DnsConfigServiceTest, DifferentConfig) {
264  DnsConfig config1 = MakeConfig(1);
265  DnsConfig config2 = MakeConfig(2);
266  DnsConfig config3 = MakeConfig(1);
267  config1.hosts = MakeHosts(1);
268  config2.hosts = MakeHosts(1);
269  config3.hosts = MakeHosts(2);
270  ASSERT_TRUE(config1.EqualsIgnoreHosts(config3));
271  ASSERT_FALSE(config1.Equals(config2));
272  ASSERT_FALSE(config1.Equals(config3));
273  ASSERT_FALSE(config2.Equals(config3));
274
275  service_->OnConfigRead(config1);
276  service_->OnHostsRead(config1.hosts);
277  EXPECT_FALSE(last_config_.Equals(DnsConfig()));
278  EXPECT_TRUE(last_config_.Equals(config1));
279
280  // It doesn't matter for this tests, but increases coverage.
281  service_->InvalidateConfig();
282  service_->InvalidateHosts();
283
284  service_->OnConfigRead(config2);
285  EXPECT_TRUE(last_config_.Equals(config1)) << "Unexpected change";
286  service_->OnHostsRead(config2.hosts);  // Not an actual change.
287  EXPECT_FALSE(last_config_.Equals(config1));
288  EXPECT_TRUE(last_config_.Equals(config2));
289
290  service_->OnConfigRead(config3);
291  EXPECT_TRUE(last_config_.EqualsIgnoreHosts(config3));
292  service_->OnHostsRead(config3.hosts);
293  EXPECT_FALSE(last_config_.Equals(config2));
294  EXPECT_TRUE(last_config_.Equals(config3));
295}
296
297TEST_F(DnsConfigServiceTest, WatchFailure) {
298  DnsConfig config1 = MakeConfig(1);
299  DnsConfig config2 = MakeConfig(2);
300  config1.hosts = MakeHosts(1);
301  config2.hosts = MakeHosts(2);
302
303  service_->OnConfigRead(config1);
304  service_->OnHostsRead(config1.hosts);
305  EXPECT_FALSE(last_config_.Equals(DnsConfig()));
306  EXPECT_TRUE(last_config_.Equals(config1));
307
308  // Simulate watch failure.
309  service_->set_watch_failed(true);
310  service_->InvalidateConfig();
311  WaitForConfig(TestTimeouts::action_timeout());
312  EXPECT_FALSE(last_config_.Equals(config1));
313  EXPECT_TRUE(last_config_.Equals(DnsConfig()));
314
315  DnsConfig bad_config = last_config_ = MakeConfig(0xBAD);
316  // Actual change in config, so expect an update, but it should be empty.
317  service_->OnConfigRead(config1);
318  EXPECT_FALSE(last_config_.Equals(bad_config));
319  EXPECT_TRUE(last_config_.Equals(DnsConfig()));
320
321  last_config_ = bad_config;
322  // Actual change in config, so expect an update, but it should be empty.
323  service_->InvalidateConfig();
324  service_->OnConfigRead(config2);
325  EXPECT_FALSE(last_config_.Equals(bad_config));
326  EXPECT_TRUE(last_config_.Equals(DnsConfig()));
327
328  last_config_ = bad_config;
329  // No change, so no update.
330  service_->InvalidateConfig();
331  service_->OnConfigRead(config2);
332  EXPECT_TRUE(last_config_.Equals(bad_config));
333}
334
335#if (defined(OS_POSIX) && !defined(OS_ANDROID)) || defined(OS_WIN)
336// TODO(szym): This is really an integration test and can time out if HOSTS is
337// huge. http://crbug.com/107810
338TEST_F(DnsConfigServiceTest, DISABLED_GetSystemConfig) {
339  service_.reset();
340  scoped_ptr<DnsConfigService> service(DnsConfigService::CreateSystemService());
341
342  service->ReadConfig(base::Bind(&DnsConfigServiceTest::OnConfigChanged,
343                                 base::Unretained(this)));
344  base::TimeDelta kTimeout = TestTimeouts::action_max_timeout();
345  WaitForConfig(kTimeout);
346  ASSERT_TRUE(last_config_.IsValid()) << "Did not receive DnsConfig in " <<
347      kTimeout.InSecondsF() << "s";
348}
349#endif  // OS_POSIX || OS_WIN
350
351}  // namespace net
352
353