| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/dns/dns_config_service_win.h" | 5 #include "net/dns/dns_config_service_win.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <string> | 8 #include <string> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| 11 #include "base/callback.h" | 11 #include "base/callback.h" |
| 12 #include "base/compiler_specific.h" | 12 #include "base/compiler_specific.h" |
| 13 #include "base/file_path.h" | 13 #include "base/file_path.h" |
| 14 #include "base/logging.h" | 14 #include "base/logging.h" |
| 15 #include "base/memory/scoped_ptr.h" | 15 #include "base/memory/scoped_ptr.h" |
| 16 #include "base/string_split.h" | 16 #include "base/string_split.h" |
| 17 #include "base/string_util.h" | 17 #include "base/string_util.h" |
| 18 #include "base/synchronization/lock.h" | 18 #include "base/synchronization/lock.h" |
| 19 #include "base/threading/non_thread_safe.h" |
| 19 #include "base/threading/thread_restrictions.h" | 20 #include "base/threading/thread_restrictions.h" |
| 20 #include "base/utf_string_conversions.h" | 21 #include "base/utf_string_conversions.h" |
| 21 #include "base/win/object_watcher.h" | 22 #include "base/win/object_watcher.h" |
| 22 #include "base/win/registry.h" | 23 #include "base/win/registry.h" |
| 23 #include "base/win/windows_version.h" | 24 #include "base/win/windows_version.h" |
| 24 #include "googleurl/src/url_canon.h" | 25 #include "googleurl/src/url_canon.h" |
| 25 #include "net/base/net_util.h" | 26 #include "net/base/net_util.h" |
| 27 #include "net/base/network_change_notifier.h" |
| 26 #include "net/dns/dns_protocol.h" | 28 #include "net/dns/dns_protocol.h" |
| 27 #include "net/dns/file_path_watcher_wrapper.h" | 29 #include "net/dns/file_path_watcher_wrapper.h" |
| 28 #include "net/dns/serial_worker.h" | 30 #include "net/dns/serial_worker.h" |
| 29 | 31 |
| 30 #pragma comment(lib, "iphlpapi.lib") | 32 #pragma comment(lib, "iphlpapi.lib") |
| 31 | 33 |
| 32 namespace net { | 34 namespace net { |
| 33 | 35 |
| 34 namespace internal { | 36 namespace internal { |
| 35 | 37 |
| 36 namespace { | 38 namespace { |
| 37 | 39 |
| 38 // Watches a single registry key for changes. Thread-safe. | 40 // Registry key paths. |
| 39 class RegistryWatcher : public base::win::ObjectWatcher::Delegate { | 41 const wchar_t* const kTcpipPath = |
| 42 L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"; |
| 43 const wchar_t* const kTcpip6Path = |
| 44 L"SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\Parameters"; |
| 45 const wchar_t* const kDnscachePath = |
| 46 L"SYSTEM\\CurrentControlSet\\Services\\Dnscache\\Parameters"; |
| 47 const wchar_t* const kPolicyPath = |
| 48 L"SOFTWARE\\Policies\\Microsoft\\Windows NT\\DNSClient"; |
| 49 |
| 50 // Convenience for reading values using RegKey. |
| 51 class RegistryReader : public base::NonThreadSafe { |
| 40 public: | 52 public: |
| 41 typedef base::Callback<void(bool succeeded)> CallbackType; | 53 explicit RegistryReader(const wchar_t* key) { |
| 42 RegistryWatcher() {} | 54 // Ignoring the result. |key_.Valid()| will catch failures. |
| 43 | 55 key_.Open(HKEY_LOCAL_MACHINE, key, KEY_QUERY_VALUE); |
| 44 bool Watch(const wchar_t* key, const CallbackType& callback) { | |
| 45 base::AutoLock lock(lock_); | |
| 46 DCHECK(!callback.is_null()); | |
| 47 CancelLocked(); | |
| 48 if (key_.Open(HKEY_LOCAL_MACHINE, key, | |
| 49 KEY_NOTIFY | KEY_QUERY_VALUE) != ERROR_SUCCESS) | |
| 50 return false; | |
| 51 if (key_.StartWatching() != ERROR_SUCCESS) | |
| 52 return false; | |
| 53 if (!watcher_.StartWatching(key_.watch_event(), this)) | |
| 54 return false; | |
| 55 callback_ = callback; | |
| 56 return true; | |
| 57 } | |
| 58 | |
| 59 void Cancel() { | |
| 60 base::AutoLock lock(lock_); | |
| 61 CancelLocked(); | |
| 62 } | |
| 63 | |
| 64 virtual void OnObjectSignaled(HANDLE object) OVERRIDE { | |
| 65 base::AutoLock lock(lock_); | |
| 66 bool succeeded = (key_.StartWatching() == ERROR_SUCCESS) && | |
| 67 watcher_.StartWatching(key_.watch_event(), this); | |
| 68 if (!callback_.is_null()) | |
| 69 callback_.Run(succeeded); | |
| 70 } | 56 } |
| 71 | 57 |
| 72 bool ReadString(const wchar_t* name, | 58 bool ReadString(const wchar_t* name, |
| 73 DnsSystemSettings::RegString* out) const { | 59 DnsSystemSettings::RegString* out) const { |
| 74 base::AutoLock lock(lock_); | 60 DCHECK(CalledOnValidThread()); |
| 75 out->set = false; | 61 out->set = false; |
| 76 if (!key_.Valid()) { | 62 if (!key_.Valid()) { |
| 77 // Assume that if the |key_| is invalid then the key is missing. | 63 // Assume that if the |key_| is invalid then the key is missing. |
| 78 return true; | 64 return true; |
| 79 } | 65 } |
| 80 LONG result = key_.ReadValue(name, &out->value); | 66 LONG result = key_.ReadValue(name, &out->value); |
| 81 if (result == ERROR_SUCCESS) { | 67 if (result == ERROR_SUCCESS) { |
| 82 out->set = true; | 68 out->set = true; |
| 83 return true; | 69 return true; |
| 84 } | 70 } |
| 85 return (result == ERROR_FILE_NOT_FOUND); | 71 return (result == ERROR_FILE_NOT_FOUND); |
| 86 } | 72 } |
| 87 | 73 |
| 88 bool ReadDword(const wchar_t* name, | 74 bool ReadDword(const wchar_t* name, |
| 89 DnsSystemSettings::RegDword* out) const { | 75 DnsSystemSettings::RegDword* out) const { |
| 90 base::AutoLock lock(lock_); | 76 DCHECK(CalledOnValidThread()); |
| 91 out->set = false; | 77 out->set = false; |
| 92 if (!key_.Valid()) { | 78 if (!key_.Valid()) { |
| 93 // Assume that if the |key_| is invalid then the key is missing. | 79 // Assume that if the |key_| is invalid then the key is missing. |
| 94 return true; | 80 return true; |
| 95 } | 81 } |
| 96 LONG result = key_.ReadValueDW(name, &out->value); | 82 LONG result = key_.ReadValueDW(name, &out->value); |
| 97 if (result == ERROR_SUCCESS) { | 83 if (result == ERROR_SUCCESS) { |
| 98 out->set = true; | 84 out->set = true; |
| 99 return true; | 85 return true; |
| 100 } | 86 } |
| 101 return (result == ERROR_FILE_NOT_FOUND); | 87 return (result == ERROR_FILE_NOT_FOUND); |
| 102 } | 88 } |
| 103 | 89 |
| 104 private: | 90 private: |
| 105 void CancelLocked() { | 91 base::win::RegKey key_; |
| 106 lock_.AssertAcquired(); | 92 |
| 93 DISALLOW_COPY_AND_ASSIGN(RegistryReader); |
| 94 }; |
| 95 |
| 96 |
| 97 // Watches a single registry key for changes. |
| 98 class RegistryWatcher : public base::win::ObjectWatcher::Delegate, |
| 99 public base::NonThreadSafe { |
| 100 public: |
| 101 typedef base::Callback<void(bool succeeded)> CallbackType; |
| 102 RegistryWatcher() {} |
| 103 |
| 104 bool Watch(const wchar_t* key, const CallbackType& callback) { |
| 105 DCHECK(CalledOnValidThread()); |
| 106 DCHECK(!callback.is_null()); |
| 107 Cancel(); |
| 108 if (key_.Open(HKEY_LOCAL_MACHINE, key, KEY_NOTIFY) != ERROR_SUCCESS) |
| 109 return false; |
| 110 if (key_.StartWatching() != ERROR_SUCCESS) |
| 111 return false; |
| 112 if (!watcher_.StartWatching(key_.watch_event(), this)) |
| 113 return false; |
| 114 callback_ = callback; |
| 115 return true; |
| 116 } |
| 117 |
| 118 bool IsWatching() const { |
| 119 DCHECK(CalledOnValidThread()); |
| 120 return !callback_.is_null(); |
| 121 } |
| 122 |
| 123 void Cancel() { |
| 124 DCHECK(CalledOnValidThread()); |
| 107 callback_.Reset(); | 125 callback_.Reset(); |
| 108 if (key_.Valid()) { | 126 if (key_.Valid()) { |
| 109 watcher_.StopWatching(); | 127 watcher_.StopWatching(); |
| 110 key_.StopWatching(); | 128 key_.StopWatching(); |
| 129 key_.Close(); |
| 111 } | 130 } |
| 112 } | 131 } |
| 113 | 132 |
| 114 mutable base::Lock lock_; | 133 virtual void OnObjectSignaled(HANDLE object) OVERRIDE { |
| 134 DCHECK(CalledOnValidThread()); |
| 135 bool succeeded = (key_.StartWatching() == ERROR_SUCCESS) && |
| 136 watcher_.StartWatching(key_.watch_event(), this); |
| 137 CallbackType callback = callback_; |
| 138 if (!succeeded) |
| 139 Cancel(); |
| 140 if (!callback.is_null()) |
| 141 callback.Run(succeeded); |
| 142 } |
| 143 |
| 144 private: |
| 115 CallbackType callback_; | 145 CallbackType callback_; |
| 116 base::win::RegKey key_; | 146 base::win::RegKey key_; |
| 117 base::win::ObjectWatcher watcher_; | 147 base::win::ObjectWatcher watcher_; |
| 118 | 148 |
| 119 DISALLOW_COPY_AND_ASSIGN(RegistryWatcher); | 149 DISALLOW_COPY_AND_ASSIGN(RegistryWatcher); |
| 120 }; | 150 }; |
| 121 | 151 |
| 152 // Returns NULL if failed. |
| 153 scoped_ptr_malloc<IP_ADAPTER_ADDRESSES> ReadIpHelper(ULONG flags) { |
| 154 base::ThreadRestrictions::AssertIOAllowed(); |
| 155 |
| 156 scoped_ptr_malloc<IP_ADAPTER_ADDRESSES> out; |
| 157 ULONG len = 15000; // As recommended by MSDN for GetAdaptersAddresses. |
| 158 UINT rv = ERROR_BUFFER_OVERFLOW; |
| 159 // Try up to three times. |
| 160 for (unsigned tries = 0; (tries < 3) && (rv == ERROR_BUFFER_OVERFLOW); |
| 161 tries++) { |
| 162 out.reset(reinterpret_cast<PIP_ADAPTER_ADDRESSES>(malloc(len))); |
| 163 rv = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, out.get(), &len); |
| 164 } |
| 165 if (rv != NO_ERROR) |
| 166 out.reset(); |
| 167 return out.Pass(); |
| 168 } |
| 169 |
| 122 // Converts a string16 domain name to ASCII, possibly using punycode. | 170 // Converts a string16 domain name to ASCII, possibly using punycode. |
| 123 // Returns true if the conversion succeeds and output is not empty. In case of | 171 // Returns true if the conversion succeeds and output is not empty. In case of |
| 124 // failure, |domain| might become dirty. | 172 // failure, |domain| might become dirty. |
| 125 bool ParseDomainASCII(const string16& widestr, std::string* domain) { | 173 bool ParseDomainASCII(const string16& widestr, std::string* domain) { |
| 126 DCHECK(domain); | 174 DCHECK(domain); |
| 127 if (widestr.empty()) | 175 if (widestr.empty()) |
| 128 return false; | 176 return false; |
| 129 | 177 |
| 130 // Check if already ASCII. | 178 // Check if already ASCII. |
| 131 if (IsStringASCII(widestr)) { | 179 if (IsStringASCII(widestr)) { |
| (...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 316 : service_(service), | 364 : service_(service), |
| 317 success_(false) {} | 365 success_(false) {} |
| 318 | 366 |
| 319 bool Watch() { | 367 bool Watch() { |
| 320 DCHECK(loop()->BelongsToCurrentThread()); | 368 DCHECK(loop()->BelongsToCurrentThread()); |
| 321 | 369 |
| 322 RegistryWatcher::CallbackType callback = | 370 RegistryWatcher::CallbackType callback = |
| 323 base::Bind(&ConfigReader::OnChange, base::Unretained(this)); | 371 base::Bind(&ConfigReader::OnChange, base::Unretained(this)); |
| 324 | 372 |
| 325 // The Tcpip key must be present. | 373 // The Tcpip key must be present. |
| 326 if (!tcpip_watcher_.Watch( | 374 if (!tcpip_watcher_.Watch(kTcpipPath, callback)) |
| 327 L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters", | |
| 328 callback)) | |
| 329 return false; | 375 return false; |
| 330 | 376 |
| 331 // Watch for IPv6 nameservers. | 377 // Watch for IPv6 nameservers. |
| 332 tcpip6_watcher_.Watch( | 378 tcpip6_watcher_.Watch(kTcpip6Path, callback); |
| 333 L"SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\Parameters", | |
| 334 callback); | |
| 335 | 379 |
| 336 // DNS suffix search list and devolution can be configured via group | 380 // DNS suffix search list and devolution can be configured via group |
| 337 // policy which sets this registry key. If the key is missing, the policy | 381 // policy which sets this registry key. If the key is missing, the policy |
| 338 // does not apply, and the DNS client uses Tcpip and Dnscache settings. | 382 // does not apply, and the DNS client uses Tcpip and Dnscache settings. |
| 339 // If a policy is installed, DnsConfigService will need to be restarted. | 383 // If a policy is installed, DnsConfigService will need to be restarted. |
| 340 // BUG=99509 | 384 // BUG=99509 |
| 341 | 385 |
| 342 dnscache_watcher_.Watch( | 386 dnscache_watcher_.Watch(kDnscachePath, callback); |
| 343 L"SYSTEM\\CurrentControlSet\\Services\\Dnscache\\Parameters", | 387 policy_watcher_.Watch(kPolicyPath, callback); |
| 344 callback); | |
| 345 | |
| 346 policy_watcher_.Watch( | |
| 347 L"SOFTWARE\\Policies\\Microsoft\\Windows NT\\DNSClient", | |
| 348 callback); | |
| 349 | 388 |
| 350 WorkNow(); | 389 WorkNow(); |
| 351 return true; | 390 return true; |
| 352 } | 391 } |
| 353 | 392 |
| 354 void Cancel() { | 393 void Cancel() { |
| 355 DCHECK(loop()->BelongsToCurrentThread()); | 394 DCHECK(loop()->BelongsToCurrentThread()); |
| 356 SerialWorker::Cancel(); | 395 SerialWorker::Cancel(); |
| 357 policy_watcher_.Cancel(); | 396 policy_watcher_.Cancel(); |
| 358 dnscache_watcher_.Cancel(); | 397 dnscache_watcher_.Cancel(); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 370 if (!IsCancelled()) | 409 if (!IsCancelled()) |
| 371 service_->InvalidateConfig(); | 410 service_->InvalidateConfig(); |
| 372 // We don't trust a config that we cannot watch in the future. | 411 // We don't trust a config that we cannot watch in the future. |
| 373 // TODO(szym): re-start watcher if that makes sense. http://crbug.com/116139 | 412 // TODO(szym): re-start watcher if that makes sense. http://crbug.com/116139 |
| 374 if (succeeded) | 413 if (succeeded) |
| 375 WorkNow(); | 414 WorkNow(); |
| 376 else | 415 else |
| 377 LOG(ERROR) << "Failed to watch DNS config"; | 416 LOG(ERROR) << "Failed to watch DNS config"; |
| 378 } | 417 } |
| 379 | 418 |
| 380 bool ReadIpHelper(DnsSystemSettings* settings) { | 419 bool ReadDevolutionSetting(const RegistryReader& reader, |
| 381 base::ThreadRestrictions::AssertIOAllowed(); | |
| 382 | |
| 383 ULONG flags = GAA_FLAG_SKIP_ANYCAST | | |
| 384 GAA_FLAG_SKIP_UNICAST | | |
| 385 GAA_FLAG_SKIP_MULTICAST | | |
| 386 GAA_FLAG_SKIP_FRIENDLY_NAME; | |
| 387 ULONG len = 15000; // As recommended by MSDN for GetAdaptersAddresses. | |
| 388 UINT rv = ERROR_BUFFER_OVERFLOW; | |
| 389 // Try up to three times. | |
| 390 for (unsigned tries = 0; | |
| 391 (tries < 3) && (rv == ERROR_BUFFER_OVERFLOW); | |
| 392 tries++) { | |
| 393 settings->addresses.reset( | |
| 394 reinterpret_cast<PIP_ADAPTER_ADDRESSES>(malloc(len))); | |
| 395 rv = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, | |
| 396 settings->addresses.get(), &len); | |
| 397 } | |
| 398 return (rv == NO_ERROR); | |
| 399 } | |
| 400 | |
| 401 bool ReadDevolutionSetting(const RegistryWatcher& watcher, | |
| 402 DnsSystemSettings::DevolutionSetting& setting) { | 420 DnsSystemSettings::DevolutionSetting& setting) { |
| 403 return watcher.ReadDword(L"UseDomainNameDevolution", &setting.enabled) && | 421 return reader.ReadDword(L"UseDomainNameDevolution", &setting.enabled) && |
| 404 watcher.ReadDword(L"DomainNameDevolutionLevel", &setting.level); | 422 reader.ReadDword(L"DomainNameDevolutionLevel", &setting.level); |
| 405 } | 423 } |
| 406 | 424 |
| 407 virtual void DoWork() OVERRIDE { | 425 virtual void DoWork() OVERRIDE { |
| 408 // Should be called on WorkerPool. | 426 // Should be called on WorkerPool. |
| 409 success_ = false; | 427 success_ = false; |
| 410 | 428 |
| 411 DnsSystemSettings settings; | 429 DnsSystemSettings settings; |
| 412 memset(&settings, 0, sizeof(settings)); | 430 memset(&settings, 0, sizeof(settings)); |
| 413 if (!ReadIpHelper(&settings)) | 431 settings.addresses = ReadIpHelper(GAA_FLAG_SKIP_ANYCAST | |
| 432 GAA_FLAG_SKIP_UNICAST | |
| 433 GAA_FLAG_SKIP_MULTICAST | |
| 434 GAA_FLAG_SKIP_FRIENDLY_NAME); |
| 435 if (!settings.addresses.get()) |
| 414 return; // no point reading the rest | 436 return; // no point reading the rest |
| 415 | 437 |
| 416 if (!policy_watcher_.ReadString(L"SearchList", | 438 RegistryReader tcpip_reader(kTcpipPath); |
| 417 &settings.policy_search_list)) | 439 RegistryReader tcpip6_reader(kTcpip6Path); |
| 440 RegistryReader dnscache_reader(kDnscachePath); |
| 441 RegistryReader policy_reader(kPolicyPath); |
| 442 |
| 443 if (!policy_reader.ReadString(L"SearchList", |
| 444 &settings.policy_search_list)) |
| 418 return; | 445 return; |
| 419 | 446 |
| 420 if (!tcpip_watcher_.ReadString(L"SearchList", &settings.tcpip_search_list)) | 447 if (!tcpip_reader.ReadString(L"SearchList", &settings.tcpip_search_list)) |
| 421 return; | 448 return; |
| 422 | 449 |
| 423 if (!tcpip_watcher_.ReadString(L"Domain", &settings.tcpip_domain)) | 450 if (!tcpip_reader.ReadString(L"Domain", &settings.tcpip_domain)) |
| 424 return; | 451 return; |
| 425 | 452 |
| 426 if (!ReadDevolutionSetting(policy_watcher_, settings.policy_devolution)) | 453 if (!ReadDevolutionSetting(policy_reader, settings.policy_devolution)) |
| 427 return; | 454 return; |
| 428 | 455 |
| 429 if (!ReadDevolutionSetting(dnscache_watcher_, | 456 if (!ReadDevolutionSetting(dnscache_reader, |
| 430 settings.dnscache_devolution)) | 457 settings.dnscache_devolution)) |
| 431 return; | 458 return; |
| 432 | 459 |
| 433 if (!ReadDevolutionSetting(tcpip_watcher_, settings.tcpip_devolution)) | 460 if (!ReadDevolutionSetting(tcpip_reader, settings.tcpip_devolution)) |
| 434 return; | 461 return; |
| 435 | 462 |
| 436 if (!policy_watcher_.ReadDword(L"AppendToMultiLabelName", | 463 if (!policy_reader.ReadDword(L"AppendToMultiLabelName", |
| 437 &settings.append_to_multi_label_name)) | 464 &settings.append_to_multi_label_name)) |
| 438 return; | 465 return; |
| 439 | 466 |
| 440 success_ = ConvertSettingsToDnsConfig(settings, &dns_config_); | 467 success_ = ConvertSettingsToDnsConfig(settings, &dns_config_); |
| 441 } | 468 } |
| 442 | 469 |
| 443 virtual void OnWorkFinished() OVERRIDE { | 470 virtual void OnWorkFinished() OVERRIDE { |
| 444 DCHECK(loop()->BelongsToCurrentThread()); | 471 DCHECK(loop()->BelongsToCurrentThread()); |
| 445 DCHECK(!IsCancelled()); | 472 DCHECK(!IsCancelled()); |
| 446 if (success_) { | 473 if (success_) { |
| 447 service_->OnConfigRead(dns_config_); | 474 service_->OnConfigRead(dns_config_); |
| 448 } else { | 475 } else { |
| 449 LOG(WARNING) << "Failed to read config."; | 476 LOG(WARNING) << "Failed to read config."; |
| 450 } | 477 } |
| 451 } | 478 } |
| 452 | 479 |
| 453 DnsConfigServiceWin* service_; | 480 DnsConfigServiceWin* service_; |
| 454 // Written in DoRead(), read in OnReadFinished(). No locking required. | 481 // Written in DoRead(), read in OnReadFinished(). No locking required. |
| 455 DnsConfig dns_config_; | 482 DnsConfig dns_config_; |
| 456 bool success_; | 483 bool success_; |
| 457 | 484 |
| 458 RegistryWatcher tcpip_watcher_; | 485 RegistryWatcher tcpip_watcher_; |
| 459 RegistryWatcher tcpip6_watcher_; | 486 RegistryWatcher tcpip6_watcher_; |
| 460 RegistryWatcher dnscache_watcher_; | 487 RegistryWatcher dnscache_watcher_; |
| 461 RegistryWatcher policy_watcher_; | 488 RegistryWatcher policy_watcher_; |
| 462 }; | 489 }; |
| 463 | 490 |
| 491 FilePath GetHostsPath() { |
| 492 TCHAR buffer[MAX_PATH]; |
| 493 UINT rc = GetSystemDirectory(buffer, MAX_PATH); |
| 494 DCHECK(0 < rc && rc < MAX_PATH); |
| 495 return FilePath(buffer).Append(FILE_PATH_LITERAL("drivers\\etc\\hosts")); |
| 496 } |
| 497 |
| 498 // An extension for DnsHostsReader which also watches the HOSTS file, |
| 499 // reads local name from GetComputerNameEx, local IP from GetAdaptersAddresses, |
| 500 // and observes changes to local IP address. |
| 501 class DnsConfigServiceWin::HostsReader |
| 502 : public DnsHostsReader, |
| 503 public NetworkChangeNotifier::IPAddressObserver { |
| 504 public: |
| 505 explicit HostsReader(DnsConfigServiceWin* service) |
| 506 : DnsHostsReader(GetHostsPath()), service_(service) { |
| 507 } |
| 508 |
| 509 bool Watch() { |
| 510 DCHECK(loop()->BelongsToCurrentThread()); |
| 511 DCHECK(!IsCancelled()); |
| 512 |
| 513 // In case the reader is restarted, remove it from the observer list. |
| 514 NetworkChangeNotifier::RemoveIPAddressObserver(this); |
| 515 |
| 516 if (!hosts_watcher_.Watch(path(), |
| 517 base::Bind(&HostsReader::OnHostsChanged, |
| 518 base::Unretained(this)))) { |
| 519 return false; |
| 520 } |
| 521 NetworkChangeNotifier::AddIPAddressObserver(this); |
| 522 WorkNow(); |
| 523 return true; |
| 524 } |
| 525 |
| 526 // Cancels the underlying SerialWorker. Cannot be undone. |
| 527 void Cancel() { |
| 528 DnsHostsReader::Cancel(); |
| 529 hosts_watcher_.Cancel(); |
| 530 NetworkChangeNotifier::RemoveIPAddressObserver(this); |
| 531 } |
| 532 |
| 533 private: |
| 534 virtual void OnIPAddressChanged() OVERRIDE { |
| 535 DCHECK(loop()->BelongsToCurrentThread()); |
| 536 service_->InvalidateHosts(); |
| 537 if (!hosts_watcher_.IsWatching()) |
| 538 return; |
| 539 WorkNow(); |
| 540 } |
| 541 |
| 542 void OnHostsChanged(bool succeeded) { |
| 543 DCHECK(loop()->BelongsToCurrentThread()); |
| 544 service_->InvalidateHosts(); |
| 545 if (succeeded) |
| 546 WorkNow(); |
| 547 else |
| 548 LOG(ERROR) << "Failed to watch DNS hosts"; |
| 549 } |
| 550 |
| 551 virtual void DoWork() OVERRIDE { |
| 552 DnsHostsReader::DoWork(); |
| 553 |
| 554 if (!success_) |
| 555 return; |
| 556 |
| 557 success_ = false; |
| 558 |
| 559 // Default address of "localhost" and local computer name can be overridden |
| 560 // by the HOSTS file, but if it's not there, then we need to fill it in. |
| 561 |
| 562 const unsigned char kIPv4Localhost[] = { 127, 0, 0, 1 }; |
| 563 const unsigned char kIPv6Localhost[] = { 0, 0, 0, 0, 0, 0, 0, 0, |
| 564 0, 0, 0, 0, 0, 0, 0, 1 }; |
| 565 IPAddressNumber loopback_ipv4(kIPv4Localhost, |
| 566 kIPv4Localhost + arraysize(kIPv4Localhost)); |
| 567 IPAddressNumber loopback_ipv6(kIPv6Localhost, |
| 568 kIPv6Localhost + arraysize(kIPv6Localhost)); |
| 569 |
| 570 // This does not override any pre-existing entries from the HOSTS file. |
| 571 dns_hosts_.insert( |
| 572 std::make_pair(DnsHostsKey("localhost", ADDRESS_FAMILY_IPV4), |
| 573 loopback_ipv4)); |
| 574 dns_hosts_.insert( |
| 575 std::make_pair(DnsHostsKey("localhost", ADDRESS_FAMILY_IPV6), |
| 576 loopback_ipv6)); |
| 577 |
| 578 WCHAR buffer[MAX_PATH]; |
| 579 DWORD size = MAX_PATH; |
| 580 std::string localname; |
| 581 if (!GetComputerNameExW(ComputerNameDnsHostname, buffer, &size) || |
| 582 !ParseDomainASCII(buffer, &localname)) { |
| 583 LOG(ERROR) << "Failed to read local computer name"; |
| 584 return; |
| 585 } |
| 586 StringToLowerASCII(&localname); |
| 587 |
| 588 bool have_ipv4 = |
| 589 dns_hosts_.count(DnsHostsKey(localname, ADDRESS_FAMILY_IPV4)) > 0; |
| 590 bool have_ipv6 = |
| 591 dns_hosts_.count(DnsHostsKey(localname, ADDRESS_FAMILY_IPV6)) > 0; |
| 592 |
| 593 if (have_ipv4 && have_ipv6) { |
| 594 success_ = true; |
| 595 return; |
| 596 } |
| 597 |
| 598 scoped_ptr_malloc<IP_ADAPTER_ADDRESSES> addresses = |
| 599 ReadIpHelper(GAA_FLAG_SKIP_ANYCAST | |
| 600 GAA_FLAG_SKIP_DNS_SERVER | |
| 601 GAA_FLAG_SKIP_MULTICAST | |
| 602 GAA_FLAG_SKIP_FRIENDLY_NAME); |
| 603 if (!addresses.get()) |
| 604 return; |
| 605 |
| 606 // The order of adapters is the network binding order, so stick to the |
| 607 // first good adapter for each family. |
| 608 for (const IP_ADAPTER_ADDRESSES* adapter = addresses.get(); |
| 609 adapter != NULL && (!have_ipv4 || !have_ipv6); |
| 610 adapter = adapter->Next) { |
| 611 if (adapter->OperStatus != IfOperStatusUp) |
| 612 continue; |
| 613 if (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK) |
| 614 continue; |
| 615 |
| 616 for (const IP_ADAPTER_UNICAST_ADDRESS* address = |
| 617 adapter->FirstUnicastAddress; |
| 618 address != NULL; |
| 619 address = address->Next) { |
| 620 IPEndPoint ipe; |
| 621 if (!ipe.FromSockAddr(address->Address.lpSockaddr, |
| 622 address->Address.iSockaddrLength)) { |
| 623 return; |
| 624 } |
| 625 if (!have_ipv4 && (ipe.GetFamily() == AF_INET)) { |
| 626 have_ipv4 = true; |
| 627 dns_hosts_[DnsHostsKey(localname, ADDRESS_FAMILY_IPV4)] = |
| 628 ipe.address(); |
| 629 } else if (!have_ipv6 && (ipe.GetFamily() == AF_INET6)) { |
| 630 have_ipv6 = true; |
| 631 dns_hosts_[DnsHostsKey(localname, ADDRESS_FAMILY_IPV6)] = |
| 632 ipe.address(); |
| 633 } |
| 634 } |
| 635 } |
| 636 |
| 637 success_ = true; |
| 638 } |
| 639 |
| 640 virtual void OnWorkFinished() OVERRIDE { |
| 641 DCHECK(loop()->BelongsToCurrentThread()); |
| 642 if (!success_ || !hosts_watcher_.IsWatching()) |
| 643 return; |
| 644 service_->OnHostsRead(dns_hosts_); |
| 645 } |
| 646 |
| 647 DnsConfigServiceWin* service_; |
| 648 FilePathWatcherWrapper hosts_watcher_; |
| 649 |
| 650 DISALLOW_COPY_AND_ASSIGN(HostsReader); |
| 651 }; |
| 652 |
| 653 |
| 464 DnsConfigServiceWin::DnsConfigServiceWin() | 654 DnsConfigServiceWin::DnsConfigServiceWin() |
| 465 : config_reader_(new ConfigReader(this)), | 655 : config_reader_(new ConfigReader(this)), |
| 466 hosts_watcher_(new FilePathWatcherWrapper()) {} | 656 hosts_reader_(new HostsReader(this)) {} |
| 467 | 657 |
| 468 DnsConfigServiceWin::~DnsConfigServiceWin() { | 658 DnsConfigServiceWin::~DnsConfigServiceWin() { |
| 469 DCHECK(CalledOnValidThread()); | 659 DCHECK(CalledOnValidThread()); |
| 470 config_reader_->Cancel(); | 660 config_reader_->Cancel(); |
| 471 if (hosts_reader_) | 661 hosts_reader_->Cancel(); |
| 472 hosts_reader_->Cancel(); | |
| 473 } | 662 } |
| 474 | 663 |
| 475 void DnsConfigServiceWin::Watch(const CallbackType& callback) { | 664 void DnsConfigServiceWin::Watch(const CallbackType& callback) { |
| 476 DCHECK(CalledOnValidThread()); | 665 DCHECK(CalledOnValidThread()); |
| 477 DCHECK(!callback.is_null()); | 666 DCHECK(!callback.is_null()); |
| 478 set_callback(callback); | 667 set_callback(callback); |
| 479 | 668 |
| 480 // This is done only once per lifetime so open the keys and file watcher | 669 // This is done only once per lifetime so open the keys and file watcher |
| 481 // handles on this thread. | 670 // handles on this thread. |
| 482 // TODO(szym): Should/can this be avoided? http://crbug.com/114223 | 671 // TODO(szym): Should/can this be avoided? http://crbug.com/114223 |
| 483 base::ThreadRestrictions::ScopedAllowIO allow_io; | 672 base::ThreadRestrictions::ScopedAllowIO allow_io; |
| 484 | 673 |
| 485 if (!config_reader_->Watch()) { | 674 if (!config_reader_->Watch()) { |
| 486 LOG(ERROR) << "Failed to start watching DNS config"; | 675 LOG(ERROR) << "Failed to start watching DNS config"; |
| 487 InvalidateConfig(); | 676 InvalidateConfig(); |
| 488 } | 677 } |
| 489 | 678 |
| 490 TCHAR buffer[MAX_PATH]; | 679 if (!hosts_reader_->Watch()) { |
| 491 UINT rc = GetSystemDirectory(buffer, MAX_PATH); | 680 LOG(ERROR) << "Failed to start watching HOSTS"; |
| 492 DCHECK(0 < rc && rc < MAX_PATH); | 681 InvalidateHosts(); |
| 493 FilePath hosts_path = FilePath(buffer). | |
| 494 Append(FILE_PATH_LITERAL("drivers\\etc\\hosts")); | |
| 495 hosts_reader_ = new DnsHostsReader( | |
| 496 hosts_path, | |
| 497 base::Bind(&DnsConfigServiceWin::OnHostsRead, base::Unretained(this))); | |
| 498 if (hosts_watcher_->Watch(hosts_path, | |
| 499 base::Bind(&DnsConfigServiceWin::OnHostsChanged, | |
| 500 base::Unretained(this)))) { | |
| 501 OnHostsChanged(true); | |
| 502 } else { | |
| 503 OnHostsChanged(false); | |
| 504 } | 682 } |
| 505 } | 683 } |
| 506 | 684 |
| 507 void DnsConfigServiceWin::OnHostsChanged(bool succeeded) { | |
| 508 InvalidateHosts(); | |
| 509 if (succeeded) | |
| 510 hosts_reader_->WorkNow(); | |
| 511 else | |
| 512 LOG(ERROR) << "Failed to watch DNS hosts"; | |
| 513 } | |
| 514 | |
| 515 } // namespace internal | 685 } // namespace internal |
| 516 | 686 |
| 517 // static | 687 // static |
| 518 scoped_ptr<DnsConfigService> DnsConfigService::CreateSystemService() { | 688 scoped_ptr<DnsConfigService> DnsConfigService::CreateSystemService() { |
| 519 return scoped_ptr<DnsConfigService>(new internal::DnsConfigServiceWin()); | 689 return scoped_ptr<DnsConfigService>(new internal::DnsConfigServiceWin()); |
| 520 } | 690 } |
| 521 | 691 |
| 522 } // namespace net | 692 } // namespace net |
| 523 | 693 |
| OLD | NEW |