Chromium Code Reviews| 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; | |
| 161 (tries < 3) && (rv == ERROR_BUFFER_OVERFLOW); | |
| 162 tries++) { | |
| 163 out.reset( | |
| 164 reinterpret_cast<PIP_ADAPTER_ADDRESSES>(malloc(len))); | |
| 165 rv = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, | |
| 166 out.get(), &len); | |
| 167 } | |
| 168 if (rv != NO_ERROR) | |
| 169 out.reset(); | |
| 170 return out.Pass(); | |
| 171 } | |
| 172 | |
| 122 // Converts a string16 domain name to ASCII, possibly using punycode. | 173 // 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 | 174 // Returns true if the conversion succeeds and output is not empty. In case of |
| 124 // failure, |domain| might become dirty. | 175 // failure, |domain| might become dirty. |
| 125 bool ParseDomainASCII(const string16& widestr, std::string* domain) { | 176 bool ParseDomainASCII(const string16& widestr, std::string* domain) { |
| 126 DCHECK(domain); | 177 DCHECK(domain); |
| 127 if (widestr.empty()) | 178 if (widestr.empty()) |
| 128 return false; | 179 return false; |
| 129 | 180 |
| 130 // Check if already ASCII. | 181 // Check if already ASCII. |
| 131 if (IsStringASCII(widestr)) { | 182 if (IsStringASCII(widestr)) { |
| (...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 316 : service_(service), | 367 : service_(service), |
| 317 success_(false) {} | 368 success_(false) {} |
| 318 | 369 |
| 319 bool Watch() { | 370 bool Watch() { |
| 320 DCHECK(loop()->BelongsToCurrentThread()); | 371 DCHECK(loop()->BelongsToCurrentThread()); |
| 321 | 372 |
| 322 RegistryWatcher::CallbackType callback = | 373 RegistryWatcher::CallbackType callback = |
| 323 base::Bind(&ConfigReader::OnChange, base::Unretained(this)); | 374 base::Bind(&ConfigReader::OnChange, base::Unretained(this)); |
| 324 | 375 |
| 325 // The Tcpip key must be present. | 376 // The Tcpip key must be present. |
| 326 if (!tcpip_watcher_.Watch( | 377 if (!tcpip_watcher_.Watch(kTcpipPath, callback)) |
| 327 L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters", | |
| 328 callback)) | |
| 329 return false; | 378 return false; |
| 330 | 379 |
| 331 // Watch for IPv6 nameservers. | 380 // Watch for IPv6 nameservers. |
| 332 tcpip6_watcher_.Watch( | 381 tcpip6_watcher_.Watch(kTcpip6Path, callback); |
| 333 L"SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\Parameters", | |
| 334 callback); | |
| 335 | 382 |
| 336 // DNS suffix search list and devolution can be configured via group | 383 // 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 | 384 // 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. | 385 // does not apply, and the DNS client uses Tcpip and Dnscache settings. |
| 339 // If a policy is installed, DnsConfigService will need to be restarted. | 386 // If a policy is installed, DnsConfigService will need to be restarted. |
| 340 // BUG=99509 | 387 // BUG=99509 |
| 341 | 388 |
| 342 dnscache_watcher_.Watch( | 389 dnscache_watcher_.Watch(kDnscachePath, callback); |
| 343 L"SYSTEM\\CurrentControlSet\\Services\\Dnscache\\Parameters", | 390 policy_watcher_.Watch(kPolicyPath, callback); |
| 344 callback); | |
| 345 | |
| 346 policy_watcher_.Watch( | |
| 347 L"SOFTWARE\\Policies\\Microsoft\\Windows NT\\DNSClient", | |
| 348 callback); | |
| 349 | 391 |
| 350 WorkNow(); | 392 WorkNow(); |
| 351 return true; | 393 return true; |
| 352 } | 394 } |
| 353 | 395 |
| 354 void Cancel() { | 396 void Cancel() { |
| 355 DCHECK(loop()->BelongsToCurrentThread()); | 397 DCHECK(loop()->BelongsToCurrentThread()); |
| 356 SerialWorker::Cancel(); | 398 SerialWorker::Cancel(); |
| 357 policy_watcher_.Cancel(); | 399 policy_watcher_.Cancel(); |
| 358 dnscache_watcher_.Cancel(); | 400 dnscache_watcher_.Cancel(); |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 370 if (!IsCancelled()) | 412 if (!IsCancelled()) |
| 371 service_->InvalidateConfig(); | 413 service_->InvalidateConfig(); |
| 372 // We don't trust a config that we cannot watch in the future. | 414 // 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 | 415 // TODO(szym): re-start watcher if that makes sense. http://crbug.com/116139 |
| 374 if (succeeded) | 416 if (succeeded) |
| 375 WorkNow(); | 417 WorkNow(); |
| 376 else | 418 else |
| 377 LOG(ERROR) << "Failed to watch DNS config"; | 419 LOG(ERROR) << "Failed to watch DNS config"; |
| 378 } | 420 } |
| 379 | 421 |
| 380 bool ReadIpHelper(DnsSystemSettings* settings) { | 422 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) { | 423 DnsSystemSettings::DevolutionSetting& setting) { |
| 403 return watcher.ReadDword(L"UseDomainNameDevolution", &setting.enabled) && | 424 return reader.ReadDword(L"UseDomainNameDevolution", &setting.enabled) && |
| 404 watcher.ReadDword(L"DomainNameDevolutionLevel", &setting.level); | 425 reader.ReadDword(L"DomainNameDevolutionLevel", &setting.level); |
| 405 } | 426 } |
| 406 | 427 |
| 407 virtual void DoWork() OVERRIDE { | 428 virtual void DoWork() OVERRIDE { |
| 408 // Should be called on WorkerPool. | 429 // Should be called on WorkerPool. |
| 409 success_ = false; | 430 success_ = false; |
| 410 | 431 |
| 411 DnsSystemSettings settings; | 432 DnsSystemSettings settings; |
| 412 memset(&settings, 0, sizeof(settings)); | 433 memset(&settings, 0, sizeof(settings)); |
| 413 if (!ReadIpHelper(&settings)) | 434 settings.addresses = ReadIpHelper(GAA_FLAG_SKIP_ANYCAST | |
| 435 GAA_FLAG_SKIP_UNICAST | | |
| 436 GAA_FLAG_SKIP_MULTICAST | | |
| 437 GAA_FLAG_SKIP_FRIENDLY_NAME); | |
| 438 if (!settings.addresses.get()) | |
| 414 return; // no point reading the rest | 439 return; // no point reading the rest |
| 415 | 440 |
| 416 if (!policy_watcher_.ReadString(L"SearchList", | 441 RegistryReader tcpip_reader(kTcpipPath); |
| 417 &settings.policy_search_list)) | 442 RegistryReader tcpip6_reader(kTcpip6Path); |
| 443 RegistryReader dnscache_reader(kDnscachePath); | |
| 444 RegistryReader policy_reader(kPolicyPath); | |
| 445 | |
| 446 if (!policy_reader.ReadString(L"SearchList", | |
| 447 &settings.policy_search_list)) | |
| 418 return; | 448 return; |
| 419 | 449 |
| 420 if (!tcpip_watcher_.ReadString(L"SearchList", &settings.tcpip_search_list)) | 450 if (!tcpip_reader.ReadString(L"SearchList", &settings.tcpip_search_list)) |
| 421 return; | 451 return; |
| 422 | 452 |
| 423 if (!tcpip_watcher_.ReadString(L"Domain", &settings.tcpip_domain)) | 453 if (!tcpip_reader.ReadString(L"Domain", &settings.tcpip_domain)) |
| 424 return; | 454 return; |
| 425 | 455 |
| 426 if (!ReadDevolutionSetting(policy_watcher_, settings.policy_devolution)) | 456 if (!ReadDevolutionSetting(policy_reader, settings.policy_devolution)) |
| 427 return; | 457 return; |
| 428 | 458 |
| 429 if (!ReadDevolutionSetting(dnscache_watcher_, | 459 if (!ReadDevolutionSetting(dnscache_reader, |
| 430 settings.dnscache_devolution)) | 460 settings.dnscache_devolution)) |
| 431 return; | 461 return; |
| 432 | 462 |
| 433 if (!ReadDevolutionSetting(tcpip_watcher_, settings.tcpip_devolution)) | 463 if (!ReadDevolutionSetting(tcpip_reader, settings.tcpip_devolution)) |
| 434 return; | 464 return; |
| 435 | 465 |
| 436 if (!policy_watcher_.ReadDword(L"AppendToMultiLabelName", | 466 if (!policy_reader.ReadDword(L"AppendToMultiLabelName", |
| 437 &settings.append_to_multi_label_name)) | 467 &settings.append_to_multi_label_name)) |
| 438 return; | 468 return; |
| 439 | 469 |
| 440 success_ = ConvertSettingsToDnsConfig(settings, &dns_config_); | 470 success_ = ConvertSettingsToDnsConfig(settings, &dns_config_); |
| 441 } | 471 } |
| 442 | 472 |
| 443 virtual void OnWorkFinished() OVERRIDE { | 473 virtual void OnWorkFinished() OVERRIDE { |
| 444 DCHECK(loop()->BelongsToCurrentThread()); | 474 DCHECK(loop()->BelongsToCurrentThread()); |
| 445 DCHECK(!IsCancelled()); | 475 DCHECK(!IsCancelled()); |
| 446 if (success_) { | 476 if (success_) { |
| 447 service_->OnConfigRead(dns_config_); | 477 service_->OnConfigRead(dns_config_); |
| 448 } else { | 478 } else { |
| 449 LOG(WARNING) << "Failed to read config."; | 479 LOG(WARNING) << "Failed to read config."; |
| 450 } | 480 } |
| 451 } | 481 } |
| 452 | 482 |
| 453 DnsConfigServiceWin* service_; | 483 DnsConfigServiceWin* service_; |
| 454 // Written in DoRead(), read in OnReadFinished(). No locking required. | 484 // Written in DoRead(), read in OnReadFinished(). No locking required. |
| 455 DnsConfig dns_config_; | 485 DnsConfig dns_config_; |
| 456 bool success_; | 486 bool success_; |
| 457 | 487 |
| 458 RegistryWatcher tcpip_watcher_; | 488 RegistryWatcher tcpip_watcher_; |
| 459 RegistryWatcher tcpip6_watcher_; | 489 RegistryWatcher tcpip6_watcher_; |
| 460 RegistryWatcher dnscache_watcher_; | 490 RegistryWatcher dnscache_watcher_; |
| 461 RegistryWatcher policy_watcher_; | 491 RegistryWatcher policy_watcher_; |
| 462 }; | 492 }; |
| 463 | 493 |
| 494 FilePath GetHostsPath() { | |
| 495 TCHAR buffer[MAX_PATH]; | |
| 496 UINT rc = GetSystemDirectory(buffer, MAX_PATH); | |
| 497 DCHECK(0 < rc && rc < MAX_PATH); | |
| 498 return FilePath(buffer).Append(FILE_PATH_LITERAL("drivers\\etc\\hosts")); | |
| 499 } | |
| 500 | |
| 501 // An extension for DnsHostsReader which also reads local name from | |
| 502 // GetComputerNameEx and watches registry for changes to local name. | |
|
mmenke
2012/03/22 16:35:05
It also watches the HOSTs file, which DnsHostsRead
| |
| 503 class DnsConfigServiceWin::HostsReader | |
| 504 : public DnsHostsReader, | |
| 505 public NetworkChangeNotifier::IPAddressObserver { | |
| 506 public: | |
| 507 explicit HostsReader(DnsConfigServiceWin* service) | |
| 508 : DnsHostsReader(GetHostsPath()), service_(service) { | |
| 509 } | |
| 510 | |
| 511 bool Watch() { | |
| 512 DCHECK(loop()->BelongsToCurrentThread()); | |
| 513 | |
| 514 // In case the reader is restarted, remove it from the observer list. | |
| 515 NetworkChangeNotifier::RemoveIPAddressObserver(this); | |
|
mmenke
2012/03/22 16:35:05
Shouldn't we just call Cancel()?
Alternatively, h
szym
2012/03/22 18:42:45
SerialWorker::Cancel() cannot be undone. Making it
| |
| 516 | |
| 517 if (!hosts_watcher_.Watch(path(), | |
| 518 base::Bind(&HostsReader::OnHostsChanged, | |
| 519 base::Unretained(this)))) { | |
| 520 return false; | |
| 521 } | |
| 522 NetworkChangeNotifier::AddIPAddressObserver(this); | |
| 523 WorkNow(); | |
| 524 return true; | |
| 525 } | |
| 526 | |
| 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 // Default address of local computer name and "localhost" can be overridden | |
| 558 // by the HOSTS file, but if it's not there, then we need to fill it in. | |
| 559 | |
| 560 success_ = false; | |
| 561 | |
| 562 WCHAR buffer[MAX_PATH]; | |
| 563 DWORD size = MAX_PATH; | |
| 564 std::string localname; | |
| 565 if (!GetComputerNameExW(ComputerNameDnsHostname, buffer, &size) || | |
| 566 !ParseDomainASCII(buffer, &localname)) { | |
| 567 LOG(ERROR) << "Failed to read local computer name"; | |
| 568 return; | |
| 569 } | |
| 570 // TODO(szym): normalize |localname| to lowercase. http://crbug.com/118995 | |
| 571 | |
| 572 scoped_ptr_malloc<IP_ADAPTER_ADDRESSES> addresses = | |
| 573 ReadIpHelper(GAA_FLAG_SKIP_ANYCAST | | |
| 574 GAA_FLAG_SKIP_DNS_SERVER | | |
| 575 GAA_FLAG_SKIP_MULTICAST | | |
| 576 GAA_FLAG_SKIP_FRIENDLY_NAME); | |
| 577 if (!addresses.get()) | |
| 578 return; | |
| 579 | |
| 580 // The order of adapters is the network binding order, so stick to the | |
| 581 // first good adapter for each family. | |
| 582 IPAddressNumber& local_ipv4 = | |
| 583 dns_hosts_[DnsHostsKey(localname, ADDRESS_FAMILY_IPV4)]; | |
| 584 IPAddressNumber& local_ipv6 = | |
| 585 dns_hosts_[DnsHostsKey(localname, ADDRESS_FAMILY_IPV6)]; | |
|
mmenke
2012/03/22 16:35:05
This isn't safe. If we insert an entry into dns_h
mmenke
2012/03/22 16:35:05
Also, suggest you use pointers here instead of ref
szym
2012/03/22 18:42:45
The references (like iterators) in std::map are no
mmenke
2012/03/22 19:36:08
I had not realized that Very handy, though I agre
| |
| 586 for (const IP_ADAPTER_ADDRESSES* adapter = addresses.get(); | |
| 587 adapter != NULL && (local_ipv4.empty() || local_ipv6.empty()); | |
| 588 adapter = adapter->Next) { | |
| 589 if (adapter->OperStatus != IfOperStatusUp) | |
| 590 continue; | |
| 591 if (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK) | |
| 592 continue; | |
| 593 | |
| 594 for (const IP_ADAPTER_UNICAST_ADDRESS* address = | |
| 595 adapter->FirstUnicastAddress; | |
|
mmenke
2012/03/22 16:35:05
nit: 4-space indent
| |
| 596 address != NULL; | |
| 597 address = address->Next) { | |
| 598 IPEndPoint ipe; | |
| 599 if (ipe.FromSockAddr(address->Address.lpSockaddr, | |
| 600 address->Address.iSockaddrLength)) { | |
|
mmenke
2012/03/22 16:35:05
nit: Think this would be a little easier to read
| |
| 601 if (local_ipv4.empty() && (ipe.GetFamily() == AF_INET)) { | |
| 602 local_ipv4 = ipe.address(); | |
| 603 } else if (local_ipv6.empty() && (ipe.GetFamily() == AF_INET6)) { | |
| 604 local_ipv6 = ipe.address(); | |
| 605 } | |
| 606 } else { | |
| 607 return; | |
| 608 } | |
| 609 } | |
| 610 } | |
| 611 | |
| 612 if (local_ipv4.empty()) | |
| 613 dns_hosts_.erase(DnsHostsKey(localname, ADDRESS_FAMILY_IPV4)); | |
| 614 | |
| 615 if (local_ipv6.empty()) | |
| 616 dns_hosts_.erase(DnsHostsKey(localname, ADDRESS_FAMILY_IPV6)); | |
| 617 | |
| 618 IPAddressNumber& loop_ipv4 = | |
| 619 dns_hosts_[DnsHostsKey("localhost", ADDRESS_FAMILY_IPV4)]; | |
| 620 IPAddressNumber& loop_ipv6 = | |
| 621 dns_hosts_[DnsHostsKey("localhost", ADDRESS_FAMILY_IPV6)]; | |
|
mmenke
2012/03/22 16:35:05
Again, suggest you use pointers. Also think "loop
szym
2012/03/22 18:42:45
I re-discovered that std::map::insert will not ove
| |
| 622 if (loop_ipv4.empty()) { | |
| 623 const unsigned char kIPv4Localhost[] = { 127, 0, 0, 1 }; | |
| 624 loop_ipv4 = IPAddressNumber(kIPv4Localhost, | |
| 625 kIPv4Localhost + arraysize(kIPv4Localhost)); | |
| 626 } | |
| 627 | |
| 628 if (loop_ipv6.empty()) { | |
| 629 const unsigned char kIPv6Localhost[] = { 0, 0, 0, 0, 0, 0, 0, 0, | |
| 630 0, 0, 0, 0, 0, 0, 0, 1 }; | |
| 631 loop_ipv6 = IPAddressNumber(kIPv6Localhost, | |
| 632 kIPv6Localhost + arraysize(kIPv6Localhost)); | |
| 633 } | |
| 634 | |
| 635 success_ = true; | |
| 636 } | |
| 637 | |
| 638 virtual void OnWorkFinished() OVERRIDE { | |
| 639 DCHECK(loop()->BelongsToCurrentThread()); | |
| 640 if (!success_ || !hosts_watcher_.IsWatching()) | |
| 641 return; | |
| 642 service_->OnHostsRead(dns_hosts_); | |
| 643 } | |
| 644 | |
| 645 DnsConfigServiceWin* service_; | |
| 646 FilePathWatcherWrapper hosts_watcher_; | |
| 647 | |
| 648 DISALLOW_COPY_AND_ASSIGN(HostsReader); | |
| 649 }; | |
| 650 | |
| 651 | |
| 464 DnsConfigServiceWin::DnsConfigServiceWin() | 652 DnsConfigServiceWin::DnsConfigServiceWin() |
| 465 : config_reader_(new ConfigReader(this)), | 653 : config_reader_(new ConfigReader(this)), |
| 466 hosts_watcher_(new FilePathWatcherWrapper()) {} | 654 hosts_reader_(new HostsReader(this)) {} |
| 467 | 655 |
| 468 DnsConfigServiceWin::~DnsConfigServiceWin() { | 656 DnsConfigServiceWin::~DnsConfigServiceWin() { |
| 469 DCHECK(CalledOnValidThread()); | 657 DCHECK(CalledOnValidThread()); |
| 470 config_reader_->Cancel(); | 658 config_reader_->Cancel(); |
| 471 if (hosts_reader_) | 659 hosts_reader_->Cancel(); |
| 472 hosts_reader_->Cancel(); | |
| 473 } | 660 } |
| 474 | 661 |
| 475 void DnsConfigServiceWin::Watch(const CallbackType& callback) { | 662 void DnsConfigServiceWin::Watch(const CallbackType& callback) { |
| 476 DCHECK(CalledOnValidThread()); | 663 DCHECK(CalledOnValidThread()); |
| 477 DCHECK(!callback.is_null()); | 664 DCHECK(!callback.is_null()); |
| 478 set_callback(callback); | 665 set_callback(callback); |
| 479 | 666 |
| 480 // This is done only once per lifetime so open the keys and file watcher | 667 // This is done only once per lifetime so open the keys and file watcher |
| 481 // handles on this thread. | 668 // handles on this thread. |
| 482 // TODO(szym): Should/can this be avoided? http://crbug.com/114223 | 669 // TODO(szym): Should/can this be avoided? http://crbug.com/114223 |
| 483 base::ThreadRestrictions::ScopedAllowIO allow_io; | 670 base::ThreadRestrictions::ScopedAllowIO allow_io; |
| 484 | 671 |
| 485 if (!config_reader_->Watch()) { | 672 if (!config_reader_->Watch()) { |
| 486 LOG(ERROR) << "Failed to start watching DNS config"; | 673 LOG(ERROR) << "Failed to start watching DNS config"; |
| 487 InvalidateConfig(); | 674 InvalidateConfig(); |
| 488 } | 675 } |
| 489 | 676 |
| 490 TCHAR buffer[MAX_PATH]; | 677 if (!hosts_reader_->Watch()) { |
| 491 UINT rc = GetSystemDirectory(buffer, MAX_PATH); | 678 LOG(ERROR) << "Failed to start watching HOSTS"; |
| 492 DCHECK(0 < rc && rc < MAX_PATH); | 679 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 } | 680 } |
| 505 } | 681 } |
| 506 | 682 |
| 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 | 683 } // namespace internal |
| 516 | 684 |
| 517 // static | 685 // static |
| 518 scoped_ptr<DnsConfigService> DnsConfigService::CreateSystemService() { | 686 scoped_ptr<DnsConfigService> DnsConfigService::CreateSystemService() { |
| 519 return scoped_ptr<DnsConfigService>(new internal::DnsConfigServiceWin()); | 687 return scoped_ptr<DnsConfigService>(new internal::DnsConfigServiceWin()); |
| 520 } | 688 } |
| 521 | 689 |
| 522 } // namespace net | 690 } // namespace net |
| 523 | 691 |
| OLD | NEW |