blob: 749d2b129cab70ca4f2b78695a6795940a3835ae [file] [log] [blame]
[email protected]fea484e2012-02-07 23:21:571// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]d84316a2011-08-18 04:41:212// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]d84316a2011-08-18 04:41:215#include <resolv.h>
6
pauljensen101ed372015-04-17 00:11:427#include "base/cancelable_callback.h"
8#include "base/files/file_util.h"
[email protected]0e6f6192011-12-28 23:18:219#include "base/sys_byteorder.h"
pauljensen101ed372015-04-17 00:11:4210#include "base/test/test_timeouts.h"
11#include "base/threading/platform_thread.h"
martijna23c8962016-03-04 18:18:5112#include "net/base/ip_address.h"
[email protected]d84316a2011-08-18 04:41:2113#include "net/dns/dns_config_service_posix.h"
pauljensen101ed372015-04-17 00:11:4214#include "net/dns/dns_protocol.h"
[email protected]6998a662011-09-03 00:17:2915
[email protected]d84316a2011-08-18 04:41:2116#include "testing/gtest/include/gtest/gtest.h"
17
pauljensen101ed372015-04-17 00:11:4218#if defined(OS_ANDROID)
19#include "base/android/path_utils.h"
20#endif // defined(OS_ANDROID)
[email protected]f6679032014-01-21 20:31:1421
bcwhitee2452b1f2015-11-30 19:09:3322// Required for inet_pton()
23#if defined(OS_WIN)
24#include <winsock2.h>
25#else
26#include <arpa/inet.h>
27#endif
28
[email protected]d84316a2011-08-18 04:41:2129namespace net {
pauljensen101ed372015-04-17 00:11:4230
31#if !defined(OS_ANDROID)
32
[email protected]d84316a2011-08-18 04:41:2133namespace {
34
[email protected]7549cc22012-05-12 09:39:5535// MAXNS is normally 3, but let's test 4 if possible.
thestig9d3bb0c2015-01-24 00:49:5136const char* const kNameserversIPv4[] = {
[email protected]7549cc22012-05-12 09:39:5537 "8.8.8.8",
38 "192.168.1.1",
39 "63.1.2.4",
40 "1.0.0.1",
41};
[email protected]d84316a2011-08-18 04:41:2142
[email protected]629ddf852012-07-20 16:17:2943#if defined(OS_LINUX)
thestig9d3bb0c2015-01-24 00:49:5144const char* const kNameserversIPv6[] = {
[email protected]7549cc22012-05-12 09:39:5545 NULL,
46 "2001:DB8:0::42",
47 NULL,
48 "::FFFF:129.144.52.38",
49};
[email protected]629ddf852012-07-20 16:17:2950#endif
[email protected]d84316a2011-08-18 04:41:2151
maclellant912064d2015-11-20 23:21:4652void DummyConfigCallback(const DnsConfig& config) {
53 // Do nothing
54}
55
[email protected]7549cc22012-05-12 09:39:5556// Fills in |res| with sane configuration.
57void InitializeResState(res_state res) {
[email protected]d84316a2011-08-18 04:41:2158 memset(res, 0, sizeof(*res));
[email protected]539df6c2012-06-19 21:21:2959 res->options = RES_INIT | RES_RECURSE | RES_DEFNAMES | RES_DNSRCH |
60 RES_ROTATE;
[email protected]d84316a2011-08-18 04:41:2161 res->ndots = 2;
[email protected]7549cc22012-05-12 09:39:5562 res->retrans = 4;
[email protected]d84316a2011-08-18 04:41:2163 res->retry = 7;
64
65 const char kDnsrch[] = "chromium.org" "\0" "example.com";
66 memcpy(res->defdname, kDnsrch, sizeof(kDnsrch));
67 res->dnsrch[0] = res->defdname;
68 res->dnsrch[1] = res->defdname + sizeof("chromium.org");
69
[email protected]7549cc22012-05-12 09:39:5570 for (unsigned i = 0; i < arraysize(kNameserversIPv4) && i < MAXNS; ++i) {
[email protected]d84316a2011-08-18 04:41:2171 struct sockaddr_in sa;
72 sa.sin_family = AF_INET;
[email protected]7549cc22012-05-12 09:39:5573 sa.sin_port = base::HostToNet16(NS_DEFAULTPORT + i);
74 inet_pton(AF_INET, kNameserversIPv4[i], &sa.sin_addr);
[email protected]d84316a2011-08-18 04:41:2175 res->nsaddr_list[i] = sa;
[email protected]7549cc22012-05-12 09:39:5576 ++res->nscount;
[email protected]d84316a2011-08-18 04:41:2177 }
[email protected]d84316a2011-08-18 04:41:2178
[email protected]5c5b7382011-08-18 18:02:3379#if defined(OS_LINUX)
[email protected]7549cc22012-05-12 09:39:5580 // Install IPv6 addresses, replacing the corresponding IPv4 addresses.
81 unsigned nscount6 = 0;
82 for (unsigned i = 0; i < arraysize(kNameserversIPv6) && i < MAXNS; ++i) {
83 if (!kNameserversIPv6[i])
84 continue;
[email protected]d84316a2011-08-18 04:41:2185 // Must use malloc to mimick res_ninit.
86 struct sockaddr_in6 *sa6;
87 sa6 = (struct sockaddr_in6 *)malloc(sizeof(*sa6));
88 sa6->sin6_family = AF_INET6;
[email protected]9eb7b11b2012-03-28 20:19:3189 sa6->sin6_port = base::HostToNet16(NS_DEFAULTPORT - i);
[email protected]7549cc22012-05-12 09:39:5590 inet_pton(AF_INET6, kNameserversIPv6[i], &sa6->sin6_addr);
[email protected]d84316a2011-08-18 04:41:2191 res->_u._ext.nsaddrs[i] = sa6;
[email protected]7549cc22012-05-12 09:39:5592 memset(&res->nsaddr_list[i], 0, sizeof res->nsaddr_list[i]);
93 ++nscount6;
[email protected]d84316a2011-08-18 04:41:2194 }
[email protected]7549cc22012-05-12 09:39:5595 res->_u._ext.nscount6 = nscount6;
[email protected]d84316a2011-08-18 04:41:2196#endif
97}
98
99void CloseResState(res_state res) {
[email protected]5c5b7382011-08-18 18:02:33100#if defined(OS_LINUX)
[email protected]7549cc22012-05-12 09:39:55101 for (int i = 0; i < res->nscount; ++i) {
102 if (res->_u._ext.nsaddrs[i] != NULL)
103 free(res->_u._ext.nsaddrs[i]);
104 }
105#endif
106}
107
108void InitializeExpectedConfig(DnsConfig* config) {
109 config->ndots = 2;
110 config->timeout = base::TimeDelta::FromSeconds(4);
111 config->attempts = 7;
112 config->rotate = true;
113 config->edns0 = false;
114 config->append_to_multi_label_name = true;
115 config->search.clear();
116 config->search.push_back("chromium.org");
117 config->search.push_back("example.com");
118
119 config->nameservers.clear();
120 for (unsigned i = 0; i < arraysize(kNameserversIPv4) && i < MAXNS; ++i) {
martijna23c8962016-03-04 18:18:51121 IPAddress ip;
122 EXPECT_TRUE(ip.AssignFromIPLiteral(kNameserversIPv4[i]));
[email protected]7549cc22012-05-12 09:39:55123 config->nameservers.push_back(IPEndPoint(ip, NS_DEFAULTPORT + i));
124 }
125
126#if defined(OS_LINUX)
127 for (unsigned i = 0; i < arraysize(kNameserversIPv6) && i < MAXNS; ++i) {
128 if (!kNameserversIPv6[i])
129 continue;
martijna23c8962016-03-04 18:18:51130 IPAddress ip;
131 EXPECT_TRUE(ip.AssignFromIPLiteral(kNameserversIPv6[i]));
[email protected]7549cc22012-05-12 09:39:55132 config->nameservers[i] = IPEndPoint(ip, NS_DEFAULTPORT - i);
[email protected]d84316a2011-08-18 04:41:21133 }
134#endif
135}
136
[email protected]b3601bc22012-02-21 21:23:20137TEST(DnsConfigServicePosixTest, ConvertResStateToDnsConfig) {
[email protected]7549cc22012-05-12 09:39:55138 struct __res_state res;
139 DnsConfig config;
140 EXPECT_FALSE(config.IsValid());
141 InitializeResState(&res);
[email protected]539df6c2012-06-19 21:21:29142 ASSERT_EQ(internal::CONFIG_PARSE_POSIX_OK,
143 internal::ConvertResStateToDnsConfig(res, &config));
[email protected]7549cc22012-05-12 09:39:55144 CloseResState(&res);
145 EXPECT_TRUE(config.IsValid());
146
147 DnsConfig expected_config;
148 EXPECT_FALSE(expected_config.EqualsIgnoreHosts(config));
149 InitializeExpectedConfig(&expected_config);
150 EXPECT_TRUE(expected_config.EqualsIgnoreHosts(config));
[email protected]d84316a2011-08-18 04:41:21151}
152
[email protected]45d2f8472012-06-14 17:48:39153TEST(DnsConfigServicePosixTest, RejectEmptyNameserver) {
154 struct __res_state res = {};
[email protected]539df6c2012-06-19 21:21:29155 res.options = RES_INIT | RES_RECURSE | RES_DEFNAMES | RES_DNSRCH;
[email protected]45d2f8472012-06-14 17:48:39156 const char kDnsrch[] = "chromium.org";
157 memcpy(res.defdname, kDnsrch, sizeof(kDnsrch));
158 res.dnsrch[0] = res.defdname;
159
160 struct sockaddr_in sa = {};
161 sa.sin_family = AF_INET;
162 sa.sin_port = base::HostToNet16(NS_DEFAULTPORT);
163 sa.sin_addr.s_addr = INADDR_ANY;
164 res.nsaddr_list[0] = sa;
165 sa.sin_addr.s_addr = 0xCAFE1337;
166 res.nsaddr_list[1] = sa;
167 res.nscount = 2;
168
169 DnsConfig config;
[email protected]539df6c2012-06-19 21:21:29170 EXPECT_EQ(internal::CONFIG_PARSE_POSIX_NULL_ADDRESS,
171 internal::ConvertResStateToDnsConfig(res, &config));
[email protected]45d2f8472012-06-14 17:48:39172
173 sa.sin_addr.s_addr = 0xDEADBEEF;
174 res.nsaddr_list[0] = sa;
[email protected]539df6c2012-06-19 21:21:29175 EXPECT_EQ(internal::CONFIG_PARSE_POSIX_OK,
176 internal::ConvertResStateToDnsConfig(res, &config));
[email protected]45d2f8472012-06-14 17:48:39177}
178
maclellant912064d2015-11-20 23:21:46179TEST(DnsConfigServicePosixTest, DestroyWhileJobsWorking) {
180 // Regression test to verify crash does not occur if DnsConfigServicePosix
181 // instance is destroyed while SerialWorker jobs have posted to worker pool.
danakj22f90e72016-04-16 01:55:40182 std::unique_ptr<internal::DnsConfigServicePosix> service(
maclellant912064d2015-11-20 23:21:46183 new internal::DnsConfigServicePosix());
184 service->ReadConfig(base::Bind(&DummyConfigCallback));
185 service.reset();
186 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1000));
187}
188
[email protected]b4481b222012-03-16 17:13:11189} // namespace
[email protected]f6679032014-01-21 20:31:14190
pauljensen101ed372015-04-17 00:11:42191#else // OS_ANDROID
192
193namespace internal {
194
195const char kTempHosts1[] = "127.0.0.1 localhost";
196const char kTempHosts2[] = "127.0.0.2 localhost";
197
198class DnsConfigServicePosixTest : public testing::Test {
199 public:
200 DnsConfigServicePosixTest() : seen_config_(false) {}
201 ~DnsConfigServicePosixTest() override {}
202
203 void OnConfigChanged(const DnsConfig& config) {
204 EXPECT_TRUE(config.IsValid());
205 seen_config_ = true;
ki.stfu375812e2015-10-09 20:23:17206 base::MessageLoop::current()->QuitWhenIdle();
pauljensen101ed372015-04-17 00:11:42207 }
208
209 void WriteMockHostsFile(const char* hosts_string) {
210 ASSERT_EQ(base::WriteFile(temp_file_, hosts_string, strlen(hosts_string)),
211 static_cast<int>(strlen(hosts_string)));
212 }
213
214 void MockDNSConfig(const char* dns_server) {
martijna23c8962016-03-04 18:18:51215 IPAddress dns_address;
216 ASSERT_TRUE(dns_address.AssignFromIPLiteral(dns_server));
pauljensen101ed372015-04-17 00:11:42217 test_config_.nameservers.clear();
218 test_config_.nameservers.push_back(
martijna23c8962016-03-04 18:18:51219 IPEndPoint(dns_address, dns_protocol::kDefaultPort));
pauljensen101ed372015-04-17 00:11:42220 service_->SetDnsConfigForTesting(&test_config_);
221 }
222
maclellant912064d2015-11-20 23:21:46223 void MockHostsFilePath(const char* file_path) {
224 service_->SetHostsFilePathForTesting(file_path);
225 }
226
pauljensen101ed372015-04-17 00:11:42227 void SetUp() override {
228 // TODO(pauljensen): Get rid of GetExternalStorageDirectory() when
229 // crbug.com/475568 is fixed. For now creating a temp file in the
230 // default temp directory (/data/data/...) will cause FilePathWatcher
231 // to fail, so create the temp file in /sdcard.
232 base::FilePath parent_dir;
233 ASSERT_TRUE(base::android::GetExternalStorageDirectory(&parent_dir));
234 ASSERT_TRUE(base::CreateTemporaryFileInDir(parent_dir, &temp_file_));
235 WriteMockHostsFile(kTempHosts1);
236 // Set the time on the hosts file back so it appears older than the
237 // 1s safety offset in DnsConfigServicePosix::SeenChangeSince().
238 // TODO(pauljensen): Switch from Sleep() to TouchFile() when
239 // crbug.com/475568 is fixed. For now TouchFile() will fail in /sdcard.
240 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1100));
241 // // Copy real hosts file's last modified time to mock hosts file.
242 // base::File hosts(base::FilePath(DnsConfigServicePosix::kFilePathHosts),
243 // base::File::FLAG_OPEN | base::File::FLAG_READ);
244 // base::File::Info hosts_info;
245 // ASSERT_TRUE(hosts.GetInfo(&hosts_info));
246 // ASSERT_TRUE(base::TouchFile(temp_file_, hosts_info.last_modified,
247 // hosts_info.last_accessed));
248 }
249
250 void TearDown() override { ASSERT_TRUE(base::DeleteFile(temp_file_, false)); }
251
252 void StartWatching() {
253 creation_time_ = base::Time::Now();
254 service_.reset(new DnsConfigServicePosix());
maclellant912064d2015-11-20 23:21:46255 MockHostsFilePath(temp_file_.value().c_str());
pauljensen101ed372015-04-17 00:11:42256 MockDNSConfig("8.8.8.8");
257 seen_config_ = false;
258 service_->WatchConfig(base::Bind(
259 &DnsConfigServicePosixTest::OnConfigChanged, base::Unretained(this)));
260 ExpectChange();
261 }
262
263 void ExpectChange() {
264 EXPECT_FALSE(seen_config_);
265 base::MessageLoop::current()->Run();
266 EXPECT_TRUE(seen_config_);
267 seen_config_ = false;
268 }
269
270 bool seen_config_;
271 base::Time creation_time_;
272 base::FilePath temp_file_;
danakj22f90e72016-04-16 01:55:40273 std::unique_ptr<DnsConfigServicePosix> service_;
pauljensen101ed372015-04-17 00:11:42274 DnsConfig test_config_;
275};
276
277TEST_F(DnsConfigServicePosixTest, SeenChangeSince) {
278 // Verify SeenChangeSince() returns false if no changes
279 StartWatching();
280 EXPECT_FALSE(service_->SeenChangeSince(creation_time_));
281 // Verify SeenChangeSince() returns true if network change
282 MockDNSConfig("8.8.4.4");
283 service_->OnNetworkChanged(NetworkChangeNotifier::CONNECTION_WIFI);
284 EXPECT_TRUE(service_->SeenChangeSince(creation_time_));
285 ExpectChange();
286 // Verify SeenChangeSince() returns true if hosts file changes
287 StartWatching();
288 EXPECT_FALSE(service_->SeenChangeSince(creation_time_));
289 WriteMockHostsFile(kTempHosts2);
290 EXPECT_TRUE(service_->SeenChangeSince(creation_time_));
291 ExpectChange();
292}
293
294} // namespace internal
295
296#endif // OS_ANDROID
297
298} // namespace net