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/files/file_path_watcher.h" | |
| 13 #include "base/file_path.h" | 14 #include "base/file_path.h" |
| 14 #include "base/logging.h" | 15 #include "base/logging.h" |
| 15 #include "base/memory/scoped_ptr.h" | 16 #include "base/memory/scoped_ptr.h" |
| 16 #include "base/metrics/histogram.h" | 17 #include "base/metrics/histogram.h" |
| 17 #include "base/string_split.h" | 18 #include "base/string_split.h" |
| 18 #include "base/string_util.h" | 19 #include "base/string_util.h" |
| 19 #include "base/synchronization/lock.h" | 20 #include "base/synchronization/lock.h" |
| 20 #include "base/threading/non_thread_safe.h" | 21 #include "base/threading/non_thread_safe.h" |
| 21 #include "base/threading/thread_restrictions.h" | 22 #include "base/threading/thread_restrictions.h" |
| 22 #include "base/time.h" | 23 #include "base/time.h" |
| 23 #include "base/utf_string_conversions.h" | 24 #include "base/utf_string_conversions.h" |
| 25 #include "base/win/object_watcher.h" | |
| 24 #include "base/win/registry.h" | 26 #include "base/win/registry.h" |
| 25 #include "base/win/windows_version.h" | 27 #include "base/win/windows_version.h" |
| 26 #include "googleurl/src/url_canon.h" | 28 #include "googleurl/src/url_canon.h" |
| 27 #include "net/base/net_util.h" | 29 #include "net/base/net_util.h" |
| 28 #include "net/base/network_change_notifier.h" | |
| 29 #include "net/dns/dns_hosts.h" | 30 #include "net/dns/dns_hosts.h" |
| 30 #include "net/dns/dns_protocol.h" | 31 #include "net/dns/dns_protocol.h" |
| 31 #include "net/dns/serial_worker.h" | 32 #include "net/dns/serial_worker.h" |
| 32 | 33 |
| 33 #pragma comment(lib, "iphlpapi.lib") | 34 #pragma comment(lib, "iphlpapi.lib") |
| 34 | 35 |
| 35 namespace net { | 36 namespace net { |
| 36 | 37 |
| 37 namespace internal { | 38 namespace internal { |
| 38 | 39 |
| (...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 265 (*hosts)[DnsHostsKey(localname, ADDRESS_FAMILY_IPV4)] = ipe.address(); | 266 (*hosts)[DnsHostsKey(localname, ADDRESS_FAMILY_IPV4)] = ipe.address(); |
| 266 } else if (!have_ipv6 && (ipe.GetFamily() == AF_INET6)) { | 267 } else if (!have_ipv6 && (ipe.GetFamily() == AF_INET6)) { |
| 267 have_ipv6 = true; | 268 have_ipv6 = true; |
| 268 (*hosts)[DnsHostsKey(localname, ADDRESS_FAMILY_IPV6)] = ipe.address(); | 269 (*hosts)[DnsHostsKey(localname, ADDRESS_FAMILY_IPV6)] = ipe.address(); |
| 269 } | 270 } |
| 270 } | 271 } |
| 271 } | 272 } |
| 272 return HOSTS_PARSE_WIN_OK; | 273 return HOSTS_PARSE_WIN_OK; |
| 273 } | 274 } |
| 274 | 275 |
| 276 // Watches a single registry key for changes. | |
| 277 class RegistryWatcher : public base::win::ObjectWatcher::Delegate, | |
| 278 public base::NonThreadSafe { | |
| 279 public: | |
| 280 typedef base::Callback<void(bool succeeded)> CallbackType; | |
| 281 RegistryWatcher() {} | |
| 282 | |
| 283 bool Watch(const wchar_t* key, const CallbackType& callback) { | |
| 284 DCHECK(CalledOnValidThread()); | |
| 285 DCHECK(!callback.is_null()); | |
| 286 DCHECK(callback_.is_null()); | |
| 287 callback_ = callback; | |
| 288 if (key_.Open(HKEY_LOCAL_MACHINE, key, KEY_NOTIFY) != ERROR_SUCCESS) | |
| 289 return false; | |
| 290 if (key_.StartWatching() != ERROR_SUCCESS) | |
| 291 return false; | |
| 292 if (!watcher_.StartWatching(key_.watch_event(), this)) | |
| 293 return false; | |
| 294 return true; | |
| 295 } | |
| 296 | |
| 297 virtual void OnObjectSignaled(HANDLE object) OVERRIDE { | |
| 298 DCHECK(CalledOnValidThread()); | |
| 299 bool succeeded = (key_.StartWatching() == ERROR_SUCCESS) && | |
| 300 watcher_.StartWatching(key_.watch_event(), this); | |
| 301 if (!succeeded && key_.Valid()) { | |
| 302 watcher_.StopWatching(); | |
| 303 key_.StopWatching(); | |
| 304 key_.Close(); | |
| 305 } | |
| 306 if (!callback_.is_null()) | |
| 307 callback_.Run(succeeded); | |
| 308 } | |
| 309 | |
| 310 private: | |
| 311 CallbackType callback_; | |
| 312 base::win::RegKey key_; | |
| 313 base::win::ObjectWatcher watcher_; | |
| 314 | |
| 315 DISALLOW_COPY_AND_ASSIGN(RegistryWatcher); | |
| 316 }; | |
| 317 | |
| 275 } // namespace | 318 } // namespace |
| 276 | 319 |
| 277 FilePath GetHostsPath() { | 320 FilePath GetHostsPath() { |
| 278 TCHAR buffer[MAX_PATH]; | 321 TCHAR buffer[MAX_PATH]; |
| 279 UINT rc = GetSystemDirectory(buffer, MAX_PATH); | 322 UINT rc = GetSystemDirectory(buffer, MAX_PATH); |
| 280 DCHECK(0 < rc && rc < MAX_PATH); | 323 DCHECK(0 < rc && rc < MAX_PATH); |
| 281 return FilePath(buffer).Append(FILE_PATH_LITERAL("drivers\\etc\\hosts")); | 324 return FilePath(buffer).Append(FILE_PATH_LITERAL("drivers\\etc\\hosts")); |
| 282 } | 325 } |
| 283 | 326 |
| 284 bool ParseSearchList(const string16& value, std::vector<std::string>* output) { | 327 bool ParseSearchList(const string16& value, std::vector<std::string>* output) { |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 443 unsigned num_dots = std::count(primary_suffix.begin(), | 486 unsigned num_dots = std::count(primary_suffix.begin(), |
| 444 primary_suffix.end(), '.'); | 487 primary_suffix.end(), '.'); |
| 445 | 488 |
| 446 for (size_t offset = 0; num_dots >= devolution.level.value; --num_dots) { | 489 for (size_t offset = 0; num_dots >= devolution.level.value; --num_dots) { |
| 447 offset = primary_suffix.find('.', offset + 1); | 490 offset = primary_suffix.find('.', offset + 1); |
| 448 config->search.push_back(primary_suffix.substr(offset + 1)); | 491 config->search.push_back(primary_suffix.substr(offset + 1)); |
| 449 } | 492 } |
| 450 return CONFIG_PARSE_WIN_OK; | 493 return CONFIG_PARSE_WIN_OK; |
| 451 } | 494 } |
| 452 | 495 |
| 496 // Watches registry and HOSTS file for changes. Setting up watches requires | |
| 497 // IO loop. | |
| 498 class DnsConfigServiceWin::Watcher { | |
|
pauljensen
2012/08/27 21:44:10
Why is DnsConfigServiceWin::Watcher a separate cla
szym
2012/08/27 21:49:20
The primary reason is that this is a direct copy f
| |
| 499 public: | |
| 500 explicit Watcher(DnsConfigServiceWin* service) : service_(service) {} | |
| 501 ~Watcher() {} | |
| 502 | |
| 503 bool Watch() { | |
| 504 RegistryWatcher::CallbackType callback = | |
| 505 base::Bind(&DnsConfigServiceWin::OnConfigChanged, | |
| 506 base::Unretained(service_)); | |
| 507 | |
| 508 bool success = true; | |
| 509 | |
| 510 // The Tcpip key must be present. | |
| 511 if (!tcpip_watcher_.Watch(kTcpipPath, callback)) { | |
| 512 LOG(ERROR) << "DNS registry watch failed to start."; | |
| 513 success = false; | |
| 514 } | |
| 515 | |
| 516 // Watch for IPv6 nameservers. | |
| 517 tcpip6_watcher_.Watch(kTcpip6Path, callback); | |
| 518 | |
| 519 // DNS suffix search list and devolution can be configured via group | |
| 520 // policy which sets this registry key. If the key is missing, the policy | |
| 521 // does not apply, and the DNS client uses Tcpip and Dnscache settings. | |
| 522 // If a policy is installed, DnsConfigService will need to be restarted. | |
| 523 // BUG=99509 | |
| 524 | |
| 525 dnscache_watcher_.Watch(kDnscachePath, callback); | |
| 526 policy_watcher_.Watch(kPolicyPath, callback); | |
| 527 | |
| 528 if (!hosts_watcher_.Watch(GetHostsPath(), | |
| 529 base::Bind(&Watcher::OnHostsChanged, | |
| 530 base::Unretained(this)))) { | |
| 531 LOG(ERROR) << "DNS hosts watch failed to start."; | |
| 532 success = false; | |
| 533 } | |
| 534 return success; | |
| 535 } | |
| 536 | |
| 537 private: | |
| 538 void OnHostsChanged(const FilePath& path, bool error) { | |
| 539 service_->OnHostsChanged(!error); | |
| 540 } | |
| 541 | |
| 542 DnsConfigServiceWin* service_; | |
| 543 | |
| 544 RegistryWatcher tcpip_watcher_; | |
| 545 RegistryWatcher tcpip6_watcher_; | |
| 546 RegistryWatcher dnscache_watcher_; | |
| 547 RegistryWatcher policy_watcher_; | |
| 548 base::files::FilePathWatcher hosts_watcher_; | |
| 549 | |
| 550 DISALLOW_COPY_AND_ASSIGN(Watcher); | |
| 551 }; | |
| 552 | |
| 453 // Reads config from registry and IpHelper. All work performed on WorkerPool. | 553 // Reads config from registry and IpHelper. All work performed on WorkerPool. |
| 454 class DnsConfigServiceWin::ConfigReader : public SerialWorker { | 554 class DnsConfigServiceWin::ConfigReader : public SerialWorker { |
| 455 public: | 555 public: |
| 456 explicit ConfigReader(DnsConfigServiceWin* service) | 556 explicit ConfigReader(DnsConfigServiceWin* service) |
| 457 : service_(service), | 557 : service_(service), |
| 458 success_(false) {} | 558 success_(false) {} |
| 459 | 559 |
| 460 private: | 560 private: |
| 461 virtual ~ConfigReader() {} | 561 virtual ~ConfigReader() {} |
| 462 | 562 |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 534 const FilePath path_; | 634 const FilePath path_; |
| 535 DnsConfigServiceWin* service_; | 635 DnsConfigServiceWin* service_; |
| 536 // Written in DoWork, read in OnWorkFinished, no locking necessary. | 636 // Written in DoWork, read in OnWorkFinished, no locking necessary. |
| 537 DnsHosts hosts_; | 637 DnsHosts hosts_; |
| 538 bool success_; | 638 bool success_; |
| 539 | 639 |
| 540 DISALLOW_COPY_AND_ASSIGN(HostsReader); | 640 DISALLOW_COPY_AND_ASSIGN(HostsReader); |
| 541 }; | 641 }; |
| 542 | 642 |
| 543 DnsConfigServiceWin::DnsConfigServiceWin() | 643 DnsConfigServiceWin::DnsConfigServiceWin() |
| 544 : config_reader_(new ConfigReader(this)), | 644 : watcher_(new Watcher(this)), |
| 645 config_reader_(new ConfigReader(this)), | |
| 545 hosts_reader_(new HostsReader(this)) {} | 646 hosts_reader_(new HostsReader(this)) {} |
| 546 | 647 |
| 547 DnsConfigServiceWin::~DnsConfigServiceWin() { | 648 DnsConfigServiceWin::~DnsConfigServiceWin() { |
| 548 config_reader_->Cancel(); | 649 config_reader_->Cancel(); |
| 549 hosts_reader_->Cancel(); | 650 hosts_reader_->Cancel(); |
| 550 NetworkChangeNotifier::RemoveIPAddressObserver(this); | 651 NetworkChangeNotifier::RemoveIPAddressObserver(this); |
| 551 } | 652 } |
| 552 | 653 |
| 553 void DnsConfigServiceWin::Watch(const CallbackType& callback) { | 654 void DnsConfigServiceWin::ReadNow() { |
| 554 DnsConfigService::Watch(callback); | 655 config_reader_->WorkNow(); |
| 656 hosts_reader_->WorkNow(); | |
| 657 } | |
| 658 | |
| 659 bool DnsConfigServiceWin::StartWatching() { | |
| 555 // Also need to observe changes to local non-loopback IP for DnsHosts. | 660 // Also need to observe changes to local non-loopback IP for DnsHosts. |
| 556 NetworkChangeNotifier::AddIPAddressObserver(this); | 661 NetworkChangeNotifier::AddIPAddressObserver(this); |
| 557 } | 662 // TODO(szym): re-start watcher if that makes sense. http://crbug.com/116139 |
| 558 | 663 return watcher_->Watch(); |
| 559 void DnsConfigServiceWin::OnDNSChanged(unsigned detail) { | |
| 560 if (detail & NetworkChangeNotifier::CHANGE_DNS_WATCH_FAILED) { | |
| 561 InvalidateConfig(); | |
| 562 InvalidateHosts(); | |
| 563 // We don't trust a config that we cannot watch in the future. | |
| 564 config_reader_->Cancel(); | |
| 565 hosts_reader_->Cancel(); | |
| 566 return; | |
| 567 } | |
| 568 if (detail & NetworkChangeNotifier::CHANGE_DNS_WATCH_STARTED) | |
| 569 detail = ~0; // Assume everything changed. | |
| 570 if (detail & NetworkChangeNotifier::CHANGE_DNS_SETTINGS) { | |
| 571 InvalidateConfig(); | |
| 572 config_reader_->WorkNow(); | |
| 573 } | |
| 574 if (detail & NetworkChangeNotifier::CHANGE_DNS_HOSTS) { | |
| 575 InvalidateHosts(); | |
| 576 hosts_reader_->WorkNow(); | |
| 577 } | |
| 578 } | 664 } |
| 579 | 665 |
| 580 void DnsConfigServiceWin::OnIPAddressChanged() { | 666 void DnsConfigServiceWin::OnIPAddressChanged() { |
| 581 // Need to update non-loopback IP of local host. | 667 // Need to update non-loopback IP of local host. |
| 582 if (NetworkChangeNotifier::IsWatchingDNS()) | 668 OnHostsChanged(true); |
| 583 OnDNSChanged(NetworkChangeNotifier::CHANGE_DNS_HOSTS); | 669 } |
| 670 | |
| 671 void DnsConfigServiceWin::OnConfigChanged(bool succeeded) { | |
| 672 InvalidateConfig(); | |
| 673 if (succeeded) { | |
| 674 config_reader_->WorkNow(); | |
| 675 } else { | |
| 676 LOG(ERROR) << "DNS config watch failed."; | |
| 677 // Don't trust the result if the watcher failed. | |
| 678 // Note: The SerialWorker will need to be re-constructed to accept new jobs. | |
| 679 config_reader_->Cancel(); | |
| 680 } | |
| 681 } | |
| 682 | |
| 683 void DnsConfigServiceWin::OnHostsChanged(bool succeeded) { | |
| 684 InvalidateHosts(); | |
| 685 if (succeeded) { | |
| 686 hosts_reader_->WorkNow(); | |
| 687 } else { | |
| 688 LOG(ERROR) << "DNS hosts watch failed."; | |
| 689 // Don't trust the result if the watcher failed. | |
| 690 // Note: The SerialWorker will need to be re-constructed to accept new jobs. | |
| 691 hosts_reader_->Cancel(); | |
| 692 NetworkChangeNotifier::RemoveIPAddressObserver(this); | |
| 693 } | |
| 584 } | 694 } |
| 585 | 695 |
| 586 } // namespace internal | 696 } // namespace internal |
| 587 | 697 |
| 588 // static | 698 // static |
| 589 scoped_ptr<DnsConfigService> DnsConfigService::CreateSystemService() { | 699 scoped_ptr<DnsConfigService> DnsConfigService::CreateSystemService() { |
| 590 return scoped_ptr<DnsConfigService>(new internal::DnsConfigServiceWin()); | 700 return scoped_ptr<DnsConfigService>(new internal::DnsConfigServiceWin()); |
| 591 } | 701 } |
| 592 | 702 |
| 593 } // namespace net | 703 } // namespace net |
| 594 | 704 |
| OLD | NEW |