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_win.h" 6 7 #include <algorithm> 8 #include <string> 9 10 #include "base/bind.h" 11 #include "base/callback.h" 12 #include "base/compiler_specific.h" 13 #include "base/files/file_path.h" 14 #include "base/files/file_path_watcher.h" 15 #include "base/logging.h" 16 #include "base/memory/scoped_ptr.h" 17 #include "base/metrics/histogram.h" 18 #include "base/strings/string_split.h" 19 #include "base/strings/string_util.h" 20 #include "base/strings/utf_string_conversions.h" 21 #include "base/synchronization/lock.h" 22 #include "base/threading/non_thread_safe.h" 23 #include "base/threading/thread_restrictions.h" 24 #include "base/time/time.h" 25 #include "base/win/object_watcher.h" 26 #include "base/win/registry.h" 27 #include "base/win/windows_version.h" 28 #include "net/base/net_util.h" 29 #include "net/base/network_change_notifier.h" 30 #include "net/dns/dns_hosts.h" 31 #include "net/dns/dns_protocol.h" 32 #include "net/dns/serial_worker.h" 33 #include "url/url_canon.h" 34 35 #pragma comment(lib, "iphlpapi.lib") 36 37 namespace net { 38 39 namespace internal { 40 41 namespace { 42 43 // Interval between retries to parse config. Used only until parsing succeeds. 44 const int kRetryIntervalSeconds = 5; 45 46 const wchar_t* const kPrimaryDnsSuffixPath = 47 L"SOFTWARE\\Policies\\Microsoft\\System\\DNSClient"; 48 49 enum HostsParseWinResult { 50 HOSTS_PARSE_WIN_OK = 0, 51 HOSTS_PARSE_WIN_UNREADABLE_HOSTS_FILE, 52 HOSTS_PARSE_WIN_COMPUTER_NAME_FAILED, 53 HOSTS_PARSE_WIN_IPHELPER_FAILED, 54 HOSTS_PARSE_WIN_BAD_ADDRESS, 55 HOSTS_PARSE_WIN_MAX // Bounding values for enumeration. 56 }; 57 58 // Convenience for reading values using RegKey. 59 class RegistryReader : public base::NonThreadSafe { 60 public: 61 explicit RegistryReader(const wchar_t* key) { 62 // Ignoring the result. |key_.Valid()| will catch failures. 63 key_.Open(HKEY_LOCAL_MACHINE, key, KEY_QUERY_VALUE); 64 } 65 66 bool ReadString(const wchar_t* name, 67 DnsSystemSettings::RegString* out) const { 68 DCHECK(CalledOnValidThread()); 69 out->set = false; 70 if (!key_.Valid()) { 71 // Assume that if the |key_| is invalid then the key is missing. 72 return true; 73 } 74 LONG result = key_.ReadValue(name, &out->value); 75 if (result == ERROR_SUCCESS) { 76 out->set = true; 77 return true; 78 } 79 return (result == ERROR_FILE_NOT_FOUND); 80 } 81 82 bool ReadDword(const wchar_t* name, 83 DnsSystemSettings::RegDword* out) const { 84 DCHECK(CalledOnValidThread()); 85 out->set = false; 86 if (!key_.Valid()) { 87 // Assume that if the |key_| is invalid then the key is missing. 88 return true; 89 } 90 LONG result = key_.ReadValueDW(name, &out->value); 91 if (result == ERROR_SUCCESS) { 92 out->set = true; 93 return true; 94 } 95 return (result == ERROR_FILE_NOT_FOUND); 96 } 97 98 private: 99 base::win::RegKey key_; 100 101 DISALLOW_COPY_AND_ASSIGN(RegistryReader); 102 }; 103 104 // Wrapper for GetAdaptersAddresses. Returns NULL if failed. 105 scoped_ptr_malloc<IP_ADAPTER_ADDRESSES> ReadIpHelper(ULONG flags) { 106 base::ThreadRestrictions::AssertIOAllowed(); 107 108 scoped_ptr_malloc<IP_ADAPTER_ADDRESSES> out; 109 ULONG len = 15000; // As recommended by MSDN for GetAdaptersAddresses. 110 UINT rv = ERROR_BUFFER_OVERFLOW; 111 // Try up to three times. 112 for (unsigned tries = 0; (tries < 3) && (rv == ERROR_BUFFER_OVERFLOW); 113 tries++) { 114 out.reset(reinterpret_cast<PIP_ADAPTER_ADDRESSES>(malloc(len))); 115 rv = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, out.get(), &len); 116 } 117 if (rv != NO_ERROR) 118 out.reset(); 119 return out.Pass(); 120 } 121 122 // Converts a base::string16 domain name to ASCII, possibly using punycode. 123 // Returns true if the conversion succeeds and output is not empty. In case of 124 // failure, |domain| might become dirty. 125 bool ParseDomainASCII(const base::string16& widestr, std::string* domain) { 126 DCHECK(domain); 127 if (widestr.empty()) 128 return false; 129 130 // Check if already ASCII. 131 if (IsStringASCII(widestr)) { 132 *domain = UTF16ToASCII(widestr); 133 return true; 134 } 135 136 // Otherwise try to convert it from IDN to punycode. 137 const int kInitialBufferSize = 256; 138 url_canon::RawCanonOutputT<char16, kInitialBufferSize> punycode; 139 if (!url_canon::IDNToASCII(widestr.data(), widestr.length(), &punycode)) 140 return false; 141 142 // |punycode_output| should now be ASCII; convert it to a std::string. 143 // (We could use UTF16ToASCII() instead, but that requires an extra string 144 // copy. Since ASCII is a subset of UTF8 the following is equivalent). 145 bool success = UTF16ToUTF8(punycode.data(), punycode.length(), domain); 146 DCHECK(success); 147 DCHECK(IsStringASCII(*domain)); 148 return success && !domain->empty(); 149 } 150 151 bool ReadDevolutionSetting(const RegistryReader& reader, 152 DnsSystemSettings::DevolutionSetting* setting) { 153 return reader.ReadDword(L"UseDomainNameDevolution", &setting->enabled) && 154 reader.ReadDword(L"DomainNameDevolutionLevel", &setting->level); 155 } 156 157 // Reads DnsSystemSettings from IpHelper and registry. 158 ConfigParseWinResult ReadSystemSettings(DnsSystemSettings* settings) { 159 settings->addresses = ReadIpHelper(GAA_FLAG_SKIP_ANYCAST | 160 GAA_FLAG_SKIP_UNICAST | 161 GAA_FLAG_SKIP_MULTICAST | 162 GAA_FLAG_SKIP_FRIENDLY_NAME); 163 if (!settings->addresses.get()) 164 return CONFIG_PARSE_WIN_READ_IPHELPER; 165 166 RegistryReader tcpip_reader(kTcpipPath); 167 RegistryReader tcpip6_reader(kTcpip6Path); 168 RegistryReader dnscache_reader(kDnscachePath); 169 RegistryReader policy_reader(kPolicyPath); 170 RegistryReader primary_dns_suffix_reader(kPrimaryDnsSuffixPath); 171 172 if (!policy_reader.ReadString(L"SearchList", 173 &settings->policy_search_list)) { 174 return CONFIG_PARSE_WIN_READ_POLICY_SEARCHLIST; 175 } 176 177 if (!tcpip_reader.ReadString(L"SearchList", &settings->tcpip_search_list)) 178 return CONFIG_PARSE_WIN_READ_TCPIP_SEARCHLIST; 179 180 if (!tcpip_reader.ReadString(L"Domain", &settings->tcpip_domain)) 181 return CONFIG_PARSE_WIN_READ_DOMAIN; 182 183 if (!ReadDevolutionSetting(policy_reader, &settings->policy_devolution)) 184 return CONFIG_PARSE_WIN_READ_POLICY_DEVOLUTION; 185 186 if (!ReadDevolutionSetting(dnscache_reader, &settings->dnscache_devolution)) 187 return CONFIG_PARSE_WIN_READ_DNSCACHE_DEVOLUTION; 188 189 if (!ReadDevolutionSetting(tcpip_reader, &settings->tcpip_devolution)) 190 return CONFIG_PARSE_WIN_READ_TCPIP_DEVOLUTION; 191 192 if (!policy_reader.ReadDword(L"AppendToMultiLabelName", 193 &settings->append_to_multi_label_name)) { 194 return CONFIG_PARSE_WIN_READ_APPEND_MULTILABEL; 195 } 196 197 if (!primary_dns_suffix_reader.ReadString(L"PrimaryDnsSuffix", 198 &settings->primary_dns_suffix)) { 199 return CONFIG_PARSE_WIN_READ_PRIMARY_SUFFIX; 200 } 201 return CONFIG_PARSE_WIN_OK; 202 } 203 204 // Default address of "localhost" and local computer name can be overridden 205 // by the HOSTS file, but if it's not there, then we need to fill it in. 206 HostsParseWinResult AddLocalhostEntries(DnsHosts* hosts) { 207 const unsigned char kIPv4Localhost[] = { 127, 0, 0, 1 }; 208 const unsigned char kIPv6Localhost[] = { 0, 0, 0, 0, 0, 0, 0, 0, 209 0, 0, 0, 0, 0, 0, 0, 1 }; 210 IPAddressNumber loopback_ipv4(kIPv4Localhost, 211 kIPv4Localhost + arraysize(kIPv4Localhost)); 212 IPAddressNumber loopback_ipv6(kIPv6Localhost, 213 kIPv6Localhost + arraysize(kIPv6Localhost)); 214 215 // This does not override any pre-existing entries from the HOSTS file. 216 hosts->insert(std::make_pair(DnsHostsKey("localhost", ADDRESS_FAMILY_IPV4), 217 loopback_ipv4)); 218 hosts->insert(std::make_pair(DnsHostsKey("localhost", ADDRESS_FAMILY_IPV6), 219 loopback_ipv6)); 220 221 WCHAR buffer[MAX_PATH]; 222 DWORD size = MAX_PATH; 223 std::string localname; 224 if (!GetComputerNameExW(ComputerNameDnsHostname, buffer, &size) || 225 !ParseDomainASCII(buffer, &localname)) { 226 return HOSTS_PARSE_WIN_COMPUTER_NAME_FAILED; 227 } 228 StringToLowerASCII(&localname); 229 230 bool have_ipv4 = 231 hosts->count(DnsHostsKey(localname, ADDRESS_FAMILY_IPV4)) > 0; 232 bool have_ipv6 = 233 hosts->count(DnsHostsKey(localname, ADDRESS_FAMILY_IPV6)) > 0; 234 235 if (have_ipv4 && have_ipv6) 236 return HOSTS_PARSE_WIN_OK; 237 238 scoped_ptr_malloc<IP_ADAPTER_ADDRESSES> addresses = 239 ReadIpHelper(GAA_FLAG_SKIP_ANYCAST | 240 GAA_FLAG_SKIP_DNS_SERVER | 241 GAA_FLAG_SKIP_MULTICAST | 242 GAA_FLAG_SKIP_FRIENDLY_NAME); 243 if (!addresses.get()) 244 return HOSTS_PARSE_WIN_IPHELPER_FAILED; 245 246 // The order of adapters is the network binding order, so stick to the 247 // first good adapter for each family. 248 for (const IP_ADAPTER_ADDRESSES* adapter = addresses.get(); 249 adapter != NULL && (!have_ipv4 || !have_ipv6); 250 adapter = adapter->Next) { 251 if (adapter->OperStatus != IfOperStatusUp) 252 continue; 253 if (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK) 254 continue; 255 256 for (const IP_ADAPTER_UNICAST_ADDRESS* address = 257 adapter->FirstUnicastAddress; 258 address != NULL; 259 address = address->Next) { 260 IPEndPoint ipe; 261 if (!ipe.FromSockAddr(address->Address.lpSockaddr, 262 address->Address.iSockaddrLength)) { 263 return HOSTS_PARSE_WIN_BAD_ADDRESS; 264 } 265 if (!have_ipv4 && (ipe.GetFamily() == ADDRESS_FAMILY_IPV4)) { 266 have_ipv4 = true; 267 (*hosts)[DnsHostsKey(localname, ADDRESS_FAMILY_IPV4)] = ipe.address(); 268 } else if (!have_ipv6 && (ipe.GetFamily() == ADDRESS_FAMILY_IPV6)) { 269 have_ipv6 = true; 270 (*hosts)[DnsHostsKey(localname, ADDRESS_FAMILY_IPV6)] = ipe.address(); 271 } 272 } 273 } 274 return HOSTS_PARSE_WIN_OK; 275 } 276 277 // Watches a single registry key for changes. 278 class RegistryWatcher : public base::win::ObjectWatcher::Delegate, 279 public base::NonThreadSafe { 280 public: 281 typedef base::Callback<void(bool succeeded)> CallbackType; 282 RegistryWatcher() {} 283 284 bool Watch(const wchar_t* key, const CallbackType& callback) { 285 DCHECK(CalledOnValidThread()); 286 DCHECK(!callback.is_null()); 287 DCHECK(callback_.is_null()); 288 callback_ = callback; 289 if (key_.Open(HKEY_LOCAL_MACHINE, key, KEY_NOTIFY) != ERROR_SUCCESS) 290 return false; 291 if (key_.StartWatching() != ERROR_SUCCESS) 292 return false; 293 if (!watcher_.StartWatching(key_.watch_event(), this)) 294 return false; 295 return true; 296 } 297 298 virtual void OnObjectSignaled(HANDLE object) OVERRIDE { 299 DCHECK(CalledOnValidThread()); 300 bool succeeded = (key_.StartWatching() == ERROR_SUCCESS) && 301 watcher_.StartWatching(key_.watch_event(), this); 302 if (!succeeded && key_.Valid()) { 303 watcher_.StopWatching(); 304 key_.StopWatching(); 305 key_.Close(); 306 } 307 if (!callback_.is_null()) 308 callback_.Run(succeeded); 309 } 310 311 private: 312 CallbackType callback_; 313 base::win::RegKey key_; 314 base::win::ObjectWatcher watcher_; 315 316 DISALLOW_COPY_AND_ASSIGN(RegistryWatcher); 317 }; 318 319 // Returns true iff |address| is DNS address from IPv6 stateless discovery, 320 // i.e., matches fec0:0:0:ffff::{1,2,3}. 321 // http://tools.ietf.org/html/draft-ietf-ipngwg-dns-discovery 322 bool IsStatelessDiscoveryAddress(const IPAddressNumber& address) { 323 if (address.size() != kIPv6AddressSize) 324 return false; 325 const uint8 kPrefix[] = { 326 0xfe, 0xc0, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 327 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 328 }; 329 return std::equal(kPrefix, kPrefix + arraysize(kPrefix), 330 address.begin()) && (address.back() < 4); 331 } 332 333 } // namespace 334 335 base::FilePath GetHostsPath() { 336 TCHAR buffer[MAX_PATH]; 337 UINT rc = GetSystemDirectory(buffer, MAX_PATH); 338 DCHECK(0 < rc && rc < MAX_PATH); 339 return base::FilePath(buffer).Append( 340 FILE_PATH_LITERAL("drivers\\etc\\hosts")); 341 } 342 343 bool ParseSearchList(const base::string16& value, 344 std::vector<std::string>* output) { 345 DCHECK(output); 346 if (value.empty()) 347 return false; 348 349 output->clear(); 350 351 // If the list includes an empty hostname (",," or ", ,"), it is terminated. 352 // Although nslookup and network connection property tab ignore such 353 // fragments ("a,b,,c" becomes ["a", "b", "c"]), our reference is getaddrinfo 354 // (which sees ["a", "b"]). WMI queries also return a matching search list. 355 std::vector<base::string16> woutput; 356 base::SplitString(value, ',', &woutput); 357 for (size_t i = 0; i < woutput.size(); ++i) { 358 // Convert non-ASCII to punycode, although getaddrinfo does not properly 359 // handle such suffixes. 360 const base::string16& t = woutput[i]; 361 std::string parsed; 362 if (!ParseDomainASCII(t, &parsed)) 363 break; 364 output->push_back(parsed); 365 } 366 return !output->empty(); 367 } 368 369 ConfigParseWinResult ConvertSettingsToDnsConfig( 370 const DnsSystemSettings& settings, 371 DnsConfig* config) { 372 *config = DnsConfig(); 373 374 // Use GetAdapterAddresses to get effective DNS server order and 375 // connection-specific DNS suffix. Ignore disconnected and loopback adapters. 376 // The order of adapters is the network binding order, so stick to the 377 // first good adapter. 378 for (const IP_ADAPTER_ADDRESSES* adapter = settings.addresses.get(); 379 adapter != NULL && config->nameservers.empty(); 380 adapter = adapter->Next) { 381 if (adapter->OperStatus != IfOperStatusUp) 382 continue; 383 if (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK) 384 continue; 385 386 for (const IP_ADAPTER_DNS_SERVER_ADDRESS* address = 387 adapter->FirstDnsServerAddress; 388 address != NULL; 389 address = address->Next) { 390 IPEndPoint ipe; 391 if (ipe.FromSockAddr(address->Address.lpSockaddr, 392 address->Address.iSockaddrLength)) { 393 if (IsStatelessDiscoveryAddress(ipe.address())) 394 continue; 395 // Override unset port. 396 if (!ipe.port()) 397 ipe = IPEndPoint(ipe.address(), dns_protocol::kDefaultPort); 398 config->nameservers.push_back(ipe); 399 } else { 400 return CONFIG_PARSE_WIN_BAD_ADDRESS; 401 } 402 } 403 404 // IP_ADAPTER_ADDRESSES in Vista+ has a search list at |FirstDnsSuffix|, 405 // but it came up empty in all trials. 406 // |DnsSuffix| stores the effective connection-specific suffix, which is 407 // obtained via DHCP (regkey: Tcpip\Parameters\Interfaces\{XXX}\DhcpDomain) 408 // or specified by the user (regkey: Tcpip\Parameters\Domain). 409 std::string dns_suffix; 410 if (ParseDomainASCII(adapter->DnsSuffix, &dns_suffix)) 411 config->search.push_back(dns_suffix); 412 } 413 414 if (config->nameservers.empty()) 415 return CONFIG_PARSE_WIN_NO_NAMESERVERS; // No point continuing. 416 417 // Windows always tries a multi-label name "as is" before using suffixes. 418 config->ndots = 1; 419 420 if (!settings.append_to_multi_label_name.set) { 421 // The default setting is true for XP, false for Vista+. 422 if (base::win::GetVersion() >= base::win::VERSION_VISTA) { 423 config->append_to_multi_label_name = false; 424 } else { 425 config->append_to_multi_label_name = true; 426 } 427 } else { 428 config->append_to_multi_label_name = 429 (settings.append_to_multi_label_name.value != 0); 430 } 431 432 // SearchList takes precedence, so check it first. 433 if (settings.policy_search_list.set) { 434 std::vector<std::string> search; 435 if (ParseSearchList(settings.policy_search_list.value, &search)) { 436 config->search.swap(search); 437 return CONFIG_PARSE_WIN_OK; 438 } 439 // Even if invalid, the policy disables the user-specified setting below. 440 } else if (settings.tcpip_search_list.set) { 441 std::vector<std::string> search; 442 if (ParseSearchList(settings.tcpip_search_list.value, &search)) { 443 config->search.swap(search); 444 return CONFIG_PARSE_WIN_OK; 445 } 446 } 447 448 // In absence of explicit search list, suffix search is: 449 // [primary suffix, connection-specific suffix, devolution of primary suffix]. 450 // Primary suffix can be set by policy (primary_dns_suffix) or 451 // user setting (tcpip_domain). 452 // 453 // The policy (primary_dns_suffix) can be edited via Group Policy Editor 454 // (gpedit.msc) at Local Computer Policy => Computer Configuration 455 // => Administrative Template => Network => DNS Client => Primary DNS Suffix. 456 // 457 // The user setting (tcpip_domain) can be configurred at Computer Name in 458 // System Settings 459 std::string primary_suffix; 460 if ((settings.primary_dns_suffix.set && 461 ParseDomainASCII(settings.primary_dns_suffix.value, &primary_suffix)) || 462 (settings.tcpip_domain.set && 463 ParseDomainASCII(settings.tcpip_domain.value, &primary_suffix))) { 464 // Primary suffix goes in front. 465 config->search.insert(config->search.begin(), primary_suffix); 466 } else { 467 return CONFIG_PARSE_WIN_OK; // No primary suffix, hence no devolution. 468 } 469 470 // Devolution is determined by precedence: policy > dnscache > tcpip. 471 // |enabled|: UseDomainNameDevolution and |level|: DomainNameDevolutionLevel 472 // are overridden independently. 473 DnsSystemSettings::DevolutionSetting devolution = settings.policy_devolution; 474 475 if (!devolution.enabled.set) 476 devolution.enabled = settings.dnscache_devolution.enabled; 477 if (!devolution.enabled.set) 478 devolution.enabled = settings.tcpip_devolution.enabled; 479 if (devolution.enabled.set && (devolution.enabled.value == 0)) 480 return CONFIG_PARSE_WIN_OK; // Devolution disabled. 481 482 // By default devolution is enabled. 483 484 if (!devolution.level.set) 485 devolution.level = settings.dnscache_devolution.level; 486 if (!devolution.level.set) 487 devolution.level = settings.tcpip_devolution.level; 488 489 // After the recent update, Windows will try to determine a safe default 490 // value by comparing the forest root domain (FRD) to the primary suffix. 491 // See http://support.microsoft.com/kb/957579 for details. 492 // For now, if the level is not set, we disable devolution, assuming that 493 // we will fallback to the system getaddrinfo anyway. This might cause 494 // performance loss for resolutions which depend on the system default 495 // devolution setting. 496 // 497 // If the level is explicitly set below 2, devolution is disabled. 498 if (!devolution.level.set || devolution.level.value < 2) 499 return CONFIG_PARSE_WIN_OK; // Devolution disabled. 500 501 // Devolve the primary suffix. This naive logic matches the observed 502 // behavior (see also ParseSearchList). If a suffix is not valid, it will be 503 // discarded when the fully-qualified name is converted to DNS format. 504 505 unsigned num_dots = std::count(primary_suffix.begin(), 506 primary_suffix.end(), '.'); 507 508 for (size_t offset = 0; num_dots >= devolution.level.value; --num_dots) { 509 offset = primary_suffix.find('.', offset + 1); 510 config->search.push_back(primary_suffix.substr(offset + 1)); 511 } 512 return CONFIG_PARSE_WIN_OK; 513 } 514 515 // Watches registry and HOSTS file for changes. Must live on a thread which 516 // allows IO. 517 class DnsConfigServiceWin::Watcher 518 : public NetworkChangeNotifier::IPAddressObserver { 519 public: 520 explicit Watcher(DnsConfigServiceWin* service) : service_(service) {} 521 ~Watcher() { 522 NetworkChangeNotifier::RemoveIPAddressObserver(this); 523 } 524 525 bool Watch() { 526 RegistryWatcher::CallbackType callback = 527 base::Bind(&DnsConfigServiceWin::OnConfigChanged, 528 base::Unretained(service_)); 529 530 bool success = true; 531 532 // The Tcpip key must be present. 533 if (!tcpip_watcher_.Watch(kTcpipPath, callback)) { 534 LOG(ERROR) << "DNS registry watch failed to start."; 535 success = false; 536 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.WatchStatus", 537 DNS_CONFIG_WATCH_FAILED_TO_START_CONFIG, 538 DNS_CONFIG_WATCH_MAX); 539 } 540 541 // Watch for IPv6 nameservers. 542 tcpip6_watcher_.Watch(kTcpip6Path, callback); 543 544 // DNS suffix search list and devolution can be configured via group 545 // policy which sets this registry key. If the key is missing, the policy 546 // does not apply, and the DNS client uses Tcpip and Dnscache settings. 547 // If a policy is installed, DnsConfigService will need to be restarted. 548 // BUG=99509 549 550 dnscache_watcher_.Watch(kDnscachePath, callback); 551 policy_watcher_.Watch(kPolicyPath, callback); 552 553 if (!hosts_watcher_.Watch(GetHostsPath(), false, 554 base::Bind(&Watcher::OnHostsChanged, 555 base::Unretained(this)))) { 556 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.WatchStatus", 557 DNS_CONFIG_WATCH_FAILED_TO_START_HOSTS, 558 DNS_CONFIG_WATCH_MAX); 559 LOG(ERROR) << "DNS hosts watch failed to start."; 560 success = false; 561 } else { 562 // Also need to observe changes to local non-loopback IP for DnsHosts. 563 NetworkChangeNotifier::AddIPAddressObserver(this); 564 } 565 return success; 566 } 567 568 private: 569 void OnHostsChanged(const base::FilePath& path, bool error) { 570 if (error) 571 NetworkChangeNotifier::RemoveIPAddressObserver(this); 572 service_->OnHostsChanged(!error); 573 } 574 575 // NetworkChangeNotifier::IPAddressObserver: 576 virtual void OnIPAddressChanged() OVERRIDE { 577 // Need to update non-loopback IP of local host. 578 service_->OnHostsChanged(true); 579 } 580 581 DnsConfigServiceWin* service_; 582 583 RegistryWatcher tcpip_watcher_; 584 RegistryWatcher tcpip6_watcher_; 585 RegistryWatcher dnscache_watcher_; 586 RegistryWatcher policy_watcher_; 587 base::FilePathWatcher hosts_watcher_; 588 589 DISALLOW_COPY_AND_ASSIGN(Watcher); 590 }; 591 592 // Reads config from registry and IpHelper. All work performed on WorkerPool. 593 class DnsConfigServiceWin::ConfigReader : public SerialWorker { 594 public: 595 explicit ConfigReader(DnsConfigServiceWin* service) 596 : service_(service), 597 success_(false) {} 598 599 private: 600 virtual ~ConfigReader() {} 601 602 virtual void DoWork() OVERRIDE { 603 // Should be called on WorkerPool. 604 base::TimeTicks start_time = base::TimeTicks::Now(); 605 DnsSystemSettings settings = {}; 606 ConfigParseWinResult result = ReadSystemSettings(&settings); 607 if (result == CONFIG_PARSE_WIN_OK) 608 result = ConvertSettingsToDnsConfig(settings, &dns_config_); 609 success_ = (result == CONFIG_PARSE_WIN_OK); 610 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.ConfigParseWin", 611 result, CONFIG_PARSE_WIN_MAX); 612 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.ConfigParseResult", success_); 613 UMA_HISTOGRAM_TIMES("AsyncDNS.ConfigParseDuration", 614 base::TimeTicks::Now() - start_time); 615 } 616 617 virtual void OnWorkFinished() OVERRIDE { 618 DCHECK(loop()->BelongsToCurrentThread()); 619 DCHECK(!IsCancelled()); 620 if (success_) { 621 service_->OnConfigRead(dns_config_); 622 } else { 623 LOG(WARNING) << "Failed to read DnsConfig."; 624 // Try again in a while in case DnsConfigWatcher missed the signal. 625 base::MessageLoop::current()->PostDelayedTask( 626 FROM_HERE, 627 base::Bind(&ConfigReader::WorkNow, this), 628 base::TimeDelta::FromSeconds(kRetryIntervalSeconds)); 629 } 630 } 631 632 DnsConfigServiceWin* service_; 633 // Written in DoWork(), read in OnWorkFinished(). No locking required. 634 DnsConfig dns_config_; 635 bool success_; 636 }; 637 638 // Reads hosts from HOSTS file and fills in localhost and local computer name if 639 // necessary. All work performed on WorkerPool. 640 class DnsConfigServiceWin::HostsReader : public SerialWorker { 641 public: 642 explicit HostsReader(DnsConfigServiceWin* service) 643 : path_(GetHostsPath()), 644 service_(service), 645 success_(false) { 646 } 647 648 private: 649 virtual ~HostsReader() {} 650 651 virtual void DoWork() OVERRIDE { 652 base::TimeTicks start_time = base::TimeTicks::Now(); 653 HostsParseWinResult result = HOSTS_PARSE_WIN_UNREADABLE_HOSTS_FILE; 654 if (ParseHostsFile(path_, &hosts_)) 655 result = AddLocalhostEntries(&hosts_); 656 success_ = (result == HOSTS_PARSE_WIN_OK); 657 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.HostsParseWin", 658 result, HOSTS_PARSE_WIN_MAX); 659 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.HostParseResult", success_); 660 UMA_HISTOGRAM_TIMES("AsyncDNS.HostsParseDuration", 661 base::TimeTicks::Now() - start_time); 662 } 663 664 virtual void OnWorkFinished() OVERRIDE { 665 DCHECK(loop()->BelongsToCurrentThread()); 666 if (success_) { 667 service_->OnHostsRead(hosts_); 668 } else { 669 LOG(WARNING) << "Failed to read DnsHosts."; 670 } 671 } 672 673 const base::FilePath path_; 674 DnsConfigServiceWin* service_; 675 // Written in DoWork, read in OnWorkFinished, no locking necessary. 676 DnsHosts hosts_; 677 bool success_; 678 679 DISALLOW_COPY_AND_ASSIGN(HostsReader); 680 }; 681 682 DnsConfigServiceWin::DnsConfigServiceWin() 683 : config_reader_(new ConfigReader(this)), 684 hosts_reader_(new HostsReader(this)) {} 685 686 DnsConfigServiceWin::~DnsConfigServiceWin() { 687 config_reader_->Cancel(); 688 hosts_reader_->Cancel(); 689 } 690 691 void DnsConfigServiceWin::ReadNow() { 692 config_reader_->WorkNow(); 693 hosts_reader_->WorkNow(); 694 } 695 696 bool DnsConfigServiceWin::StartWatching() { 697 // TODO(szym): re-start watcher if that makes sense. http://crbug.com/116139 698 watcher_.reset(new Watcher(this)); 699 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.WatchStatus", DNS_CONFIG_WATCH_STARTED, 700 DNS_CONFIG_WATCH_MAX); 701 return watcher_->Watch(); 702 } 703 704 void DnsConfigServiceWin::OnConfigChanged(bool succeeded) { 705 InvalidateConfig(); 706 if (succeeded) { 707 config_reader_->WorkNow(); 708 } else { 709 LOG(ERROR) << "DNS config watch failed."; 710 set_watch_failed(true); 711 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.WatchStatus", 712 DNS_CONFIG_WATCH_FAILED_CONFIG, 713 DNS_CONFIG_WATCH_MAX); 714 } 715 } 716 717 void DnsConfigServiceWin::OnHostsChanged(bool succeeded) { 718 InvalidateHosts(); 719 if (succeeded) { 720 hosts_reader_->WorkNow(); 721 } else { 722 LOG(ERROR) << "DNS hosts watch failed."; 723 set_watch_failed(true); 724 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.WatchStatus", 725 DNS_CONFIG_WATCH_FAILED_HOSTS, 726 DNS_CONFIG_WATCH_MAX); 727 } 728 } 729 730 } // namespace internal 731 732 // static 733 scoped_ptr<DnsConfigService> DnsConfigService::CreateSystemService() { 734 return scoped_ptr<DnsConfigService>(new internal::DnsConfigServiceWin()); 735 } 736 737 } // namespace net 738