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/metrics/histogram.h" | |
| 16 #include "base/string_split.h" | 17 #include "base/string_split.h" |
| 17 #include "base/string_util.h" | 18 #include "base/string_util.h" |
| 18 #include "base/synchronization/lock.h" | 19 #include "base/synchronization/lock.h" |
| 19 #include "base/threading/non_thread_safe.h" | 20 #include "base/threading/non_thread_safe.h" |
| 20 #include "base/threading/thread_restrictions.h" | 21 #include "base/threading/thread_restrictions.h" |
| 22 #include "base/time.h" | |
| 21 #include "base/utf_string_conversions.h" | 23 #include "base/utf_string_conversions.h" |
| 22 #include "base/win/registry.h" | 24 #include "base/win/registry.h" |
| 23 #include "base/win/windows_version.h" | 25 #include "base/win/windows_version.h" |
| 24 #include "googleurl/src/url_canon.h" | 26 #include "googleurl/src/url_canon.h" |
| 25 #include "net/base/net_util.h" | 27 #include "net/base/net_util.h" |
| 26 #include "net/base/network_change_notifier.h" | 28 #include "net/base/network_change_notifier.h" |
| 27 #include "net/dns/dns_hosts.h" | 29 #include "net/dns/dns_hosts.h" |
| 28 #include "net/dns/dns_protocol.h" | 30 #include "net/dns/dns_protocol.h" |
| 29 #include "net/dns/serial_worker.h" | 31 #include "net/dns/serial_worker.h" |
| 30 | 32 |
| 31 #pragma comment(lib, "iphlpapi.lib") | 33 #pragma comment(lib, "iphlpapi.lib") |
| 32 | 34 |
| 33 namespace net { | 35 namespace net { |
| 34 | 36 |
| 35 namespace internal { | 37 namespace internal { |
| 36 | 38 |
| 37 namespace { | 39 namespace { |
| 38 | 40 |
| 39 const wchar_t* const kPrimaryDnsSuffixPath = | 41 const wchar_t* const kPrimaryDnsSuffixPath = |
| 40 L"SOFTWARE\\Policies\\Microsoft\\System\\DNSClient"; | 42 L"SOFTWARE\\Policies\\Microsoft\\System\\DNSClient"; |
| 41 | 43 |
| 44 enum ConfigParseWinResult { | |
| 45 CONFIG_PARSE_WIN_OK = 0, | |
| 46 CONFIG_PARSE_WIN_READ_IPHELPER, | |
| 47 CONFIG_PARSE_WIN_READ_POLICY_SEARCHLIST, | |
| 48 CONFIG_PARSE_WIN_READ_TCPIP_SEARCHLIST, | |
| 49 CONFIG_PARSE_WIN_READ_DOMAIN, | |
| 50 CONFIG_PARSE_WIN_READ_POLICY_DEVOLUTION, | |
| 51 CONFIG_PARSE_WIN_READ_DNSCACHE_DEVOLUTION, | |
| 52 CONFIG_PARSE_WIN_READ_TCPIP_DEVOLUTION, | |
| 53 CONFIG_PARSE_WIN_READ_APPEND_MULTILABEL, | |
| 54 CONFIG_PARSE_WIN_READ_PRIMARY_SUFFIX, | |
| 55 CONFIG_PARSE_WIN_BAD_ADDRESS, | |
| 56 CONFIG_PARSE_WIN_NO_NAMESERVERS, | |
|
mmenke
2012/06/18 17:19:50
You should name these consistently - Currently som
szym
2012/06/18 20:53:08
The naming scheme is meant to describe the problem
| |
| 57 CONFIG_PARSE_WIN_MAX // Bounding values for enumeration. | |
| 58 }; | |
| 59 | |
| 60 static void RecordConfigParseResult(ConfigParseWinResult result) { | |
| 61 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.ConfigParseWin", | |
| 62 result, CONFIG_PARSE_WIN_MAX); | |
| 63 } | |
| 64 | |
| 65 enum HostsParseWinResult { | |
| 66 HOSTS_PARSE_WIN_OK = 0, | |
| 67 HOSTS_PARSE_WIN_READ_HOSTS, | |
| 68 HOSTS_PARSE_WIN_READ_COMPUTER_NAME, | |
| 69 HOSTS_PARSE_WIN_READ_IPHELPER, | |
| 70 HOSTS_PARSE_WIN_BAD_ADDRESS, | |
|
mmenke
2012/06/18 17:19:50
See above comment.
| |
| 71 HOSTS_PARSE_WIN_MAX // Bounding values for enumeration. | |
| 72 }; | |
| 73 | |
| 74 static void RecordHostsParseResult(HostsParseWinResult result) { | |
| 75 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.HostsParseWin", | |
| 76 result, HOSTS_PARSE_WIN_MAX); | |
| 77 } | |
| 78 | |
| 42 // Convenience for reading values using RegKey. | 79 // Convenience for reading values using RegKey. |
| 43 class RegistryReader : public base::NonThreadSafe { | 80 class RegistryReader : public base::NonThreadSafe { |
| 44 public: | 81 public: |
| 45 explicit RegistryReader(const wchar_t* key) { | 82 explicit RegistryReader(const wchar_t* key) { |
| 46 // Ignoring the result. |key_.Valid()| will catch failures. | 83 // Ignoring the result. |key_.Valid()| will catch failures. |
| 47 key_.Open(HKEY_LOCAL_MACHINE, key, KEY_QUERY_VALUE); | 84 key_.Open(HKEY_LOCAL_MACHINE, key, KEY_QUERY_VALUE); |
| 48 } | 85 } |
| 49 | 86 |
| 50 bool ReadString(const wchar_t* name, | 87 bool ReadString(const wchar_t* name, |
| 51 DnsSystemSettings::RegString* out) const { | 88 DnsSystemSettings::RegString* out) const { |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 78 } | 115 } |
| 79 return (result == ERROR_FILE_NOT_FOUND); | 116 return (result == ERROR_FILE_NOT_FOUND); |
| 80 } | 117 } |
| 81 | 118 |
| 82 private: | 119 private: |
| 83 base::win::RegKey key_; | 120 base::win::RegKey key_; |
| 84 | 121 |
| 85 DISALLOW_COPY_AND_ASSIGN(RegistryReader); | 122 DISALLOW_COPY_AND_ASSIGN(RegistryReader); |
| 86 }; | 123 }; |
| 87 | 124 |
| 88 // Returns NULL if failed. | 125 // Wrapper for GetAdaptersAddresses. Returns NULL if failed. |
| 89 scoped_ptr_malloc<IP_ADAPTER_ADDRESSES> ReadIpHelper(ULONG flags) { | 126 scoped_ptr_malloc<IP_ADAPTER_ADDRESSES> ReadIpHelper(ULONG flags) { |
| 90 base::ThreadRestrictions::AssertIOAllowed(); | 127 base::ThreadRestrictions::AssertIOAllowed(); |
| 91 | 128 |
| 92 scoped_ptr_malloc<IP_ADAPTER_ADDRESSES> out; | 129 scoped_ptr_malloc<IP_ADAPTER_ADDRESSES> out; |
| 93 ULONG len = 15000; // As recommended by MSDN for GetAdaptersAddresses. | 130 ULONG len = 15000; // As recommended by MSDN for GetAdaptersAddresses. |
| 94 UINT rv = ERROR_BUFFER_OVERFLOW; | 131 UINT rv = ERROR_BUFFER_OVERFLOW; |
| 95 // Try up to three times. | 132 // Try up to three times. |
| 96 for (unsigned tries = 0; (tries < 3) && (rv == ERROR_BUFFER_OVERFLOW); | 133 for (unsigned tries = 0; (tries < 3) && (rv == ERROR_BUFFER_OVERFLOW); |
| 97 tries++) { | 134 tries++) { |
| 98 out.reset(reinterpret_cast<PIP_ADAPTER_ADDRESSES>(malloc(len))); | 135 out.reset(reinterpret_cast<PIP_ADAPTER_ADDRESSES>(malloc(len))); |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 125 | 162 |
| 126 // |punycode_output| should now be ASCII; convert it to a std::string. | 163 // |punycode_output| should now be ASCII; convert it to a std::string. |
| 127 // (We could use UTF16ToASCII() instead, but that requires an extra string | 164 // (We could use UTF16ToASCII() instead, but that requires an extra string |
| 128 // copy. Since ASCII is a subset of UTF8 the following is equivalent). | 165 // copy. Since ASCII is a subset of UTF8 the following is equivalent). |
| 129 bool success = UTF16ToUTF8(punycode.data(), punycode.length(), domain); | 166 bool success = UTF16ToUTF8(punycode.data(), punycode.length(), domain); |
| 130 DCHECK(success); | 167 DCHECK(success); |
| 131 DCHECK(IsStringASCII(*domain)); | 168 DCHECK(IsStringASCII(*domain)); |
| 132 return success && !domain->empty(); | 169 return success && !domain->empty(); |
| 133 } | 170 } |
| 134 | 171 |
| 172 bool ReadDevolutionSetting(const RegistryReader& reader, | |
| 173 DnsSystemSettings::DevolutionSetting* setting) { | |
| 174 return reader.ReadDword(L"UseDomainNameDevolution", &setting->enabled) && | |
| 175 reader.ReadDword(L"DomainNameDevolutionLevel", &setting->level); | |
| 176 } | |
| 177 | |
| 178 // Reads DnsSystemSettings from IpHelper and registry. | |
| 179 bool ReadSystemSettings(DnsSystemSettings* settings) { | |
|
mmenke
2012/06/18 17:19:50
Same suggestion as for the posix version - return
| |
| 180 settings->addresses = ReadIpHelper(GAA_FLAG_SKIP_ANYCAST | | |
| 181 GAA_FLAG_SKIP_UNICAST | | |
| 182 GAA_FLAG_SKIP_MULTICAST | | |
| 183 GAA_FLAG_SKIP_FRIENDLY_NAME); | |
| 184 if (!settings->addresses.get()) { | |
| 185 RecordConfigParseResult(CONFIG_PARSE_WIN_READ_IPHELPER); | |
| 186 return false; | |
| 187 } | |
| 188 | |
| 189 RegistryReader tcpip_reader(kTcpipPath); | |
| 190 RegistryReader tcpip6_reader(kTcpip6Path); | |
| 191 RegistryReader dnscache_reader(kDnscachePath); | |
| 192 RegistryReader policy_reader(kPolicyPath); | |
| 193 RegistryReader primary_dns_suffix_reader(kPrimaryDnsSuffixPath); | |
| 194 | |
| 195 if (!policy_reader.ReadString(L"SearchList", | |
| 196 &settings->policy_search_list)) { | |
| 197 RecordConfigParseResult(CONFIG_PARSE_WIN_READ_POLICY_SEARCHLIST); | |
| 198 return false; | |
| 199 } | |
| 200 | |
| 201 if (!tcpip_reader.ReadString(L"SearchList", &settings->tcpip_search_list)) { | |
| 202 RecordConfigParseResult(CONFIG_PARSE_WIN_READ_TCPIP_SEARCHLIST); | |
| 203 return false; | |
| 204 } | |
| 205 | |
| 206 if (!tcpip_reader.ReadString(L"Domain", &settings->tcpip_domain)) { | |
| 207 RecordConfigParseResult(CONFIG_PARSE_WIN_READ_DOMAIN); | |
| 208 return false; | |
| 209 } | |
| 210 | |
| 211 if (!ReadDevolutionSetting(policy_reader, &settings->policy_devolution)) { | |
| 212 RecordConfigParseResult(CONFIG_PARSE_WIN_READ_POLICY_DEVOLUTION); | |
| 213 return false; | |
| 214 } | |
| 215 | |
| 216 if (!ReadDevolutionSetting(dnscache_reader, | |
| 217 &settings->dnscache_devolution)) { | |
| 218 RecordConfigParseResult(CONFIG_PARSE_WIN_READ_DNSCACHE_DEVOLUTION); | |
| 219 return false; | |
| 220 } | |
| 221 | |
| 222 if (!ReadDevolutionSetting(tcpip_reader, &settings->tcpip_devolution)) { | |
| 223 RecordConfigParseResult(CONFIG_PARSE_WIN_READ_TCPIP_DEVOLUTION); | |
| 224 return false; | |
| 225 } | |
| 226 | |
| 227 if (!policy_reader.ReadDword(L"AppendToMultiLabelName", | |
| 228 &settings->append_to_multi_label_name)) { | |
| 229 RecordConfigParseResult(CONFIG_PARSE_WIN_READ_APPEND_MULTILABEL); | |
| 230 return false; | |
| 231 } | |
| 232 | |
| 233 if (!primary_dns_suffix_reader.ReadString(L"PrimaryDnsSuffix", | |
| 234 &settings->primary_dns_suffix)) { | |
| 235 RecordConfigParseResult(CONFIG_PARSE_WIN_READ_PRIMARY_SUFFIX); | |
| 236 return false; | |
| 237 } | |
| 238 return true; | |
| 239 } | |
| 240 | |
| 241 // Default address of "localhost" and local computer name can be overridden | |
| 242 // by the HOSTS file, but if it's not there, then we need to fill it in. | |
| 243 bool AddLocalhostEntries(DnsHosts* phosts) { | |
|
cbentzel
2012/06/16 18:03:41
Nit: We don't tend to use hungarian-style notation
mmenke
2012/06/18 17:19:50
Why not just make the function take in DnsHosts& h
mmenke
2012/06/18 17:19:50
Again, suggest having this return a HostsParseWinR
cbentzel
2012/06/18 18:37:17
Style-guide doesn't allow non-const references.
h
mmenke
2012/06/18 18:46:26
Ahh, right, good point. Doing a quick search thro
| |
| 244 DnsHosts& hosts = *phosts; | |
| 245 const unsigned char kIPv4Localhost[] = { 127, 0, 0, 1 }; | |
| 246 const unsigned char kIPv6Localhost[] = { 0, 0, 0, 0, 0, 0, 0, 0, | |
| 247 0, 0, 0, 0, 0, 0, 0, 1 }; | |
| 248 IPAddressNumber loopback_ipv4(kIPv4Localhost, | |
| 249 kIPv4Localhost + arraysize(kIPv4Localhost)); | |
| 250 IPAddressNumber loopback_ipv6(kIPv6Localhost, | |
| 251 kIPv6Localhost + arraysize(kIPv6Localhost)); | |
| 252 | |
| 253 // This does not override any pre-existing entries from the HOSTS file. | |
| 254 hosts.insert(std::make_pair(DnsHostsKey("localhost", ADDRESS_FAMILY_IPV4), | |
| 255 loopback_ipv4)); | |
| 256 hosts.insert(std::make_pair(DnsHostsKey("localhost", ADDRESS_FAMILY_IPV6), | |
| 257 loopback_ipv6)); | |
| 258 | |
| 259 WCHAR buffer[MAX_PATH]; | |
| 260 DWORD size = MAX_PATH; | |
| 261 std::string localname; | |
| 262 if (!GetComputerNameExW(ComputerNameDnsHostname, buffer, &size) || | |
| 263 !ParseDomainASCII(buffer, &localname)) { | |
| 264 LOG(ERROR) << "Failed to read local computer name"; | |
|
cbentzel
2012/06/16 18:03:41
Do you need the LOG(ERROR) now that we have the hi
| |
| 265 RecordHostsParseResult(HOSTS_PARSE_WIN_READ_COMPUTER_NAME); | |
| 266 return false; | |
| 267 } | |
| 268 StringToLowerASCII(&localname); | |
| 269 | |
| 270 bool have_ipv4 = | |
| 271 hosts.count(DnsHostsKey(localname, ADDRESS_FAMILY_IPV4)) > 0; | |
| 272 bool have_ipv6 = | |
| 273 hosts.count(DnsHostsKey(localname, ADDRESS_FAMILY_IPV6)) > 0; | |
| 274 | |
| 275 if (have_ipv4 && have_ipv6) | |
| 276 return true; | |
| 277 | |
| 278 scoped_ptr_malloc<IP_ADAPTER_ADDRESSES> addresses = | |
| 279 ReadIpHelper(GAA_FLAG_SKIP_ANYCAST | | |
| 280 GAA_FLAG_SKIP_DNS_SERVER | | |
| 281 GAA_FLAG_SKIP_MULTICAST | | |
| 282 GAA_FLAG_SKIP_FRIENDLY_NAME); | |
| 283 if (!addresses.get()) { | |
| 284 RecordHostsParseResult(HOSTS_PARSE_WIN_READ_IPHELPER); | |
| 285 return false; | |
| 286 } | |
| 287 | |
| 288 // The order of adapters is the network binding order, so stick to the | |
| 289 // first good adapter for each family. | |
| 290 for (const IP_ADAPTER_ADDRESSES* adapter = addresses.get(); | |
| 291 adapter != NULL && (!have_ipv4 || !have_ipv6); | |
| 292 adapter = adapter->Next) { | |
| 293 if (adapter->OperStatus != IfOperStatusUp) | |
| 294 continue; | |
| 295 if (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK) | |
| 296 continue; | |
| 297 | |
| 298 for (const IP_ADAPTER_UNICAST_ADDRESS* address = | |
| 299 adapter->FirstUnicastAddress; | |
| 300 address != NULL; | |
| 301 address = address->Next) { | |
| 302 IPEndPoint ipe; | |
| 303 if (!ipe.FromSockAddr(address->Address.lpSockaddr, | |
| 304 address->Address.iSockaddrLength)) { | |
| 305 RecordHostsParseResult(HOSTS_PARSE_WIN_BAD_ADDRESS); | |
| 306 return false; | |
| 307 } | |
| 308 if (!have_ipv4 && (ipe.GetFamily() == AF_INET)) { | |
| 309 have_ipv4 = true; | |
| 310 hosts[DnsHostsKey(localname, ADDRESS_FAMILY_IPV4)] = ipe.address(); | |
| 311 } else if (!have_ipv6 && (ipe.GetFamily() == AF_INET6)) { | |
| 312 have_ipv6 = true; | |
| 313 hosts[DnsHostsKey(localname, ADDRESS_FAMILY_IPV6)] = ipe.address(); | |
| 314 } | |
| 315 } | |
| 316 } | |
| 317 RecordHostsParseResult(HOSTS_PARSE_WIN_OK); | |
| 318 return true; | |
| 319 } | |
| 320 | |
| 135 } // namespace | 321 } // namespace |
| 136 | 322 |
| 137 FilePath GetHostsPath() { | 323 FilePath GetHostsPath() { |
| 138 TCHAR buffer[MAX_PATH]; | 324 TCHAR buffer[MAX_PATH]; |
| 139 UINT rc = GetSystemDirectory(buffer, MAX_PATH); | 325 UINT rc = GetSystemDirectory(buffer, MAX_PATH); |
| 140 DCHECK(0 < rc && rc < MAX_PATH); | 326 DCHECK(0 < rc && rc < MAX_PATH); |
| 141 return FilePath(buffer).Append(FILE_PATH_LITERAL("drivers\\etc\\hosts")); | 327 return FilePath(buffer).Append(FILE_PATH_LITERAL("drivers\\etc\\hosts")); |
| 142 } | 328 } |
| 143 | 329 |
| 144 bool ParseSearchList(const string16& value, std::vector<std::string>* output) { | 330 bool ParseSearchList(const string16& value, std::vector<std::string>* output) { |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 187 address != NULL; | 373 address != NULL; |
| 188 address = address->Next) { | 374 address = address->Next) { |
| 189 IPEndPoint ipe; | 375 IPEndPoint ipe; |
| 190 if (ipe.FromSockAddr(address->Address.lpSockaddr, | 376 if (ipe.FromSockAddr(address->Address.lpSockaddr, |
| 191 address->Address.iSockaddrLength)) { | 377 address->Address.iSockaddrLength)) { |
| 192 // Override unset port. | 378 // Override unset port. |
| 193 if (!ipe.port()) | 379 if (!ipe.port()) |
| 194 ipe = IPEndPoint(ipe.address(), dns_protocol::kDefaultPort); | 380 ipe = IPEndPoint(ipe.address(), dns_protocol::kDefaultPort); |
| 195 config->nameservers.push_back(ipe); | 381 config->nameservers.push_back(ipe); |
| 196 } else { | 382 } else { |
| 383 RecordConfigParseResult(CONFIG_PARSE_WIN_BAD_ADDRESS); | |
| 197 return false; | 384 return false; |
| 198 } | 385 } |
| 199 } | 386 } |
| 200 | 387 |
| 201 // IP_ADAPTER_ADDRESSES in Vista+ has a search list at |FirstDnsSuffix|, | 388 // IP_ADAPTER_ADDRESSES in Vista+ has a search list at |FirstDnsSuffix|, |
| 202 // but it came up empty in all trials. | 389 // but it came up empty in all trials. |
| 203 // |DnsSuffix| stores the effective connection-specific suffix, which is | 390 // |DnsSuffix| stores the effective connection-specific suffix, which is |
| 204 // obtained via DHCP (regkey: Tcpip\Parameters\Interfaces\{XXX}\DhcpDomain) | 391 // obtained via DHCP (regkey: Tcpip\Parameters\Interfaces\{XXX}\DhcpDomain) |
| 205 // or specified by the user (regkey: Tcpip\Parameters\Domain). | 392 // or specified by the user (regkey: Tcpip\Parameters\Domain). |
| 206 std::string dns_suffix; | 393 std::string dns_suffix; |
| 207 if (ParseDomainASCII(adapter->DnsSuffix, &dns_suffix)) | 394 if (ParseDomainASCII(adapter->DnsSuffix, &dns_suffix)) |
| 208 config->search.push_back(dns_suffix); | 395 config->search.push_back(dns_suffix); |
| 209 } | 396 } |
| 210 | 397 |
| 211 if (config->nameservers.empty()) | 398 if (config->nameservers.empty()) { |
| 399 RecordConfigParseResult(CONFIG_PARSE_WIN_NO_NAMESERVERS); | |
| 212 return false; // No point continuing. | 400 return false; // No point continuing. |
| 401 } | |
| 213 | 402 |
| 214 // Windows always tries a multi-label name "as is" before using suffixes. | 403 // Windows always tries a multi-label name "as is" before using suffixes. |
| 215 config->ndots = 1; | 404 config->ndots = 1; |
| 216 | 405 |
| 217 if (!settings.append_to_multi_label_name.set) { | 406 if (!settings.append_to_multi_label_name.set) { |
| 218 // The default setting is true for XP, false for Vista+. | 407 // The default setting is true for XP, false for Vista+. |
| 219 if (base::win::GetVersion() >= base::win::VERSION_VISTA) { | 408 if (base::win::GetVersion() >= base::win::VERSION_VISTA) { |
| 220 config->append_to_multi_label_name = false; | 409 config->append_to_multi_label_name = false; |
| 221 } else { | 410 } else { |
| 222 config->append_to_multi_label_name = true; | 411 config->append_to_multi_label_name = true; |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 299 // behavior (see also ParseSearchList). If a suffix is not valid, it will be | 488 // behavior (see also ParseSearchList). If a suffix is not valid, it will be |
| 300 // discarded when the fully-qualified name is converted to DNS format. | 489 // discarded when the fully-qualified name is converted to DNS format. |
| 301 | 490 |
| 302 unsigned num_dots = std::count(primary_suffix.begin(), | 491 unsigned num_dots = std::count(primary_suffix.begin(), |
| 303 primary_suffix.end(), '.'); | 492 primary_suffix.end(), '.'); |
| 304 | 493 |
| 305 for (size_t offset = 0; num_dots >= devolution.level.value; --num_dots) { | 494 for (size_t offset = 0; num_dots >= devolution.level.value; --num_dots) { |
| 306 offset = primary_suffix.find('.', offset + 1); | 495 offset = primary_suffix.find('.', offset + 1); |
| 307 config->search.push_back(primary_suffix.substr(offset + 1)); | 496 config->search.push_back(primary_suffix.substr(offset + 1)); |
| 308 } | 497 } |
| 309 | 498 RecordConfigParseResult(CONFIG_PARSE_WIN_OK); |
| 310 return true; | 499 return true; |
| 311 } | 500 } |
| 312 | 501 |
| 313 // Watches registry for changes and reads config from registry and IP helper. | 502 // Reads config from registry and IP helper. All work performed on WorkerPool. |
| 314 // Reading and opening of reg keys is always performed on WorkerPool. Setting | |
| 315 // up watches requires IO loop. | |
| 316 class DnsConfigServiceWin::ConfigReader : public SerialWorker { | 503 class DnsConfigServiceWin::ConfigReader : public SerialWorker { |
| 317 public: | 504 public: |
| 318 explicit ConfigReader(DnsConfigServiceWin* service) | 505 explicit ConfigReader(DnsConfigServiceWin* service) |
| 319 : service_(service), | 506 : service_(service), |
| 320 success_(false) {} | 507 success_(false) {} |
| 321 | 508 |
| 322 private: | 509 private: |
| 323 bool ReadDevolutionSetting(const RegistryReader& reader, | 510 virtual ~ConfigReader() {} |
| 324 DnsSystemSettings::DevolutionSetting& setting) { | |
| 325 return reader.ReadDword(L"UseDomainNameDevolution", &setting.enabled) && | |
| 326 reader.ReadDword(L"DomainNameDevolutionLevel", &setting.level); | |
| 327 } | |
| 328 | 511 |
| 329 virtual void DoWork() OVERRIDE { | 512 virtual void DoWork() OVERRIDE { |
| 330 // Should be called on WorkerPool. | 513 // Should be called on WorkerPool. |
| 331 success_ = false; | 514 base::TimeTicks start_time = base::TimeTicks::Now(); |
| 332 | |
| 333 DnsSystemSettings settings = {}; | 515 DnsSystemSettings settings = {}; |
| 334 settings.addresses = ReadIpHelper(GAA_FLAG_SKIP_ANYCAST | | 516 success_ = ReadSystemSettings(&settings); |
| 335 GAA_FLAG_SKIP_UNICAST | | 517 if (success_) |
| 336 GAA_FLAG_SKIP_MULTICAST | | 518 success_ = ConvertSettingsToDnsConfig(settings, &dns_config_); |
| 337 GAA_FLAG_SKIP_FRIENDLY_NAME); | 519 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.ConfigParseWinResult", success_); |
| 338 if (!settings.addresses.get()) | 520 UMA_HISTOGRAM_TIMES("AsyncDNS.ConfigParseDuration", |
| 339 return; // no point reading the rest | 521 base::TimeTicks::Now() - start_time); |
| 340 | |
| 341 RegistryReader tcpip_reader(kTcpipPath); | |
| 342 RegistryReader tcpip6_reader(kTcpip6Path); | |
| 343 RegistryReader dnscache_reader(kDnscachePath); | |
| 344 RegistryReader policy_reader(kPolicyPath); | |
| 345 RegistryReader primary_dns_suffix_reader(kPrimaryDnsSuffixPath); | |
| 346 | |
| 347 if (!policy_reader.ReadString(L"SearchList", | |
| 348 &settings.policy_search_list)) | |
| 349 return; | |
| 350 | |
| 351 if (!tcpip_reader.ReadString(L"SearchList", &settings.tcpip_search_list)) | |
| 352 return; | |
| 353 | |
| 354 if (!tcpip_reader.ReadString(L"Domain", &settings.tcpip_domain)) | |
| 355 return; | |
| 356 | |
| 357 if (!ReadDevolutionSetting(policy_reader, settings.policy_devolution)) | |
| 358 return; | |
| 359 | |
| 360 if (!ReadDevolutionSetting(dnscache_reader, | |
| 361 settings.dnscache_devolution)) | |
| 362 return; | |
| 363 | |
| 364 if (!ReadDevolutionSetting(tcpip_reader, settings.tcpip_devolution)) | |
| 365 return; | |
| 366 | |
| 367 if (!policy_reader.ReadDword(L"AppendToMultiLabelName", | |
| 368 &settings.append_to_multi_label_name)) | |
| 369 return; | |
| 370 | |
| 371 if (!primary_dns_suffix_reader.ReadString(L"PrimaryDnsSuffix", | |
| 372 &settings.primary_dns_suffix)) | |
| 373 return; | |
| 374 | |
| 375 success_ = ConvertSettingsToDnsConfig(settings, &dns_config_); | |
| 376 } | 522 } |
| 377 | 523 |
| 378 virtual void OnWorkFinished() OVERRIDE { | 524 virtual void OnWorkFinished() OVERRIDE { |
| 379 DCHECK(loop()->BelongsToCurrentThread()); | 525 DCHECK(loop()->BelongsToCurrentThread()); |
| 380 DCHECK(!IsCancelled()); | 526 DCHECK(!IsCancelled()); |
| 381 if (success_) { | 527 if (success_) { |
| 382 service_->OnConfigRead(dns_config_); | 528 service_->OnConfigRead(dns_config_); |
| 383 } else { | 529 } else { |
| 384 LOG(WARNING) << "Failed to read DnsConfig."; | 530 LOG(WARNING) << "Failed to read DnsConfig."; |
| 385 } | 531 } |
| 386 } | 532 } |
| 387 | 533 |
| 388 DnsConfigServiceWin* service_; | 534 DnsConfigServiceWin* service_; |
| 389 // Written in DoRead(), read in OnReadFinished(). No locking required. | 535 // Written in DoRead(), read in OnReadFinished(). No locking required. |
| 390 DnsConfig dns_config_; | 536 DnsConfig dns_config_; |
| 391 bool success_; | 537 bool success_; |
| 392 }; | 538 }; |
| 393 | 539 |
| 394 // An extension for DnsHostsReader which also watches the HOSTS file, | 540 // An extension for DnsHostsReader which also watches the HOSTS file, |
| 395 // reads local name from GetComputerNameEx, local IP from GetAdaptersAddresses, | 541 // reads local name from GetComputerNameEx, local IP from GetAdaptersAddresses, |
| 396 // and observes changes to local IP address. | 542 // and observes changes to local IP address. |
| 397 class DnsConfigServiceWin::HostsReader : public SerialWorker { | 543 class DnsConfigServiceWin::HostsReader : public SerialWorker { |
| 398 public: | 544 public: |
| 399 explicit HostsReader(DnsConfigServiceWin* service) | 545 explicit HostsReader(DnsConfigServiceWin* service) |
| 400 : path_(GetHostsPath()), service_(service) { | 546 : path_(GetHostsPath()), service_(service) { |
| 401 } | 547 } |
| 402 | 548 |
| 403 private: | 549 private: |
| 550 virtual ~HostsReader() {} | |
| 551 | |
| 404 virtual void DoWork() OVERRIDE { | 552 virtual void DoWork() OVERRIDE { |
| 553 base::TimeTicks start_time = base::TimeTicks::Now(); | |
| 405 success_ = ParseHostsFile(path_, &hosts_); | 554 success_ = ParseHostsFile(path_, &hosts_); |
| 406 | 555 if (success_) { |
| 407 if (!success_) | 556 success_ = AddLocalhostEntries(&hosts_); |
| 408 return; | 557 } else { |
| 409 | 558 RecordHostsParseResult(HOSTS_PARSE_WIN_READ_HOSTS); |
| 410 success_ = false; | |
| 411 | |
| 412 // Default address of "localhost" and local computer name can be overridden | |
| 413 // by the HOSTS file, but if it's not there, then we need to fill it in. | |
| 414 | |
| 415 const unsigned char kIPv4Localhost[] = { 127, 0, 0, 1 }; | |
| 416 const unsigned char kIPv6Localhost[] = { 0, 0, 0, 0, 0, 0, 0, 0, | |
| 417 0, 0, 0, 0, 0, 0, 0, 1 }; | |
| 418 IPAddressNumber loopback_ipv4(kIPv4Localhost, | |
| 419 kIPv4Localhost + arraysize(kIPv4Localhost)); | |
| 420 IPAddressNumber loopback_ipv6(kIPv6Localhost, | |
| 421 kIPv6Localhost + arraysize(kIPv6Localhost)); | |
| 422 | |
| 423 // This does not override any pre-existing entries from the HOSTS file. | |
| 424 hosts_.insert(std::make_pair(DnsHostsKey("localhost", ADDRESS_FAMILY_IPV4), | |
| 425 loopback_ipv4)); | |
| 426 hosts_.insert(std::make_pair(DnsHostsKey("localhost", ADDRESS_FAMILY_IPV6), | |
| 427 loopback_ipv6)); | |
| 428 | |
| 429 WCHAR buffer[MAX_PATH]; | |
| 430 DWORD size = MAX_PATH; | |
| 431 std::string localname; | |
| 432 if (!GetComputerNameExW(ComputerNameDnsHostname, buffer, &size) || | |
| 433 !ParseDomainASCII(buffer, &localname)) { | |
| 434 LOG(ERROR) << "Failed to read local computer name"; | |
| 435 return; | |
| 436 } | 559 } |
| 437 StringToLowerASCII(&localname); | 560 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.HostParseResult", success_); |
| 438 | 561 UMA_HISTOGRAM_TIMES("AsyncDNS.HostsParseDuration", |
| 439 bool have_ipv4 = | 562 base::TimeTicks::Now() - start_time); |
| 440 hosts_.count(DnsHostsKey(localname, ADDRESS_FAMILY_IPV4)) > 0; | |
| 441 bool have_ipv6 = | |
| 442 hosts_.count(DnsHostsKey(localname, ADDRESS_FAMILY_IPV6)) > 0; | |
| 443 | |
| 444 if (have_ipv4 && have_ipv6) { | |
| 445 success_ = true; | |
| 446 return; | |
| 447 } | |
| 448 | |
| 449 scoped_ptr_malloc<IP_ADAPTER_ADDRESSES> addresses = | |
| 450 ReadIpHelper(GAA_FLAG_SKIP_ANYCAST | | |
| 451 GAA_FLAG_SKIP_DNS_SERVER | | |
| 452 GAA_FLAG_SKIP_MULTICAST | | |
| 453 GAA_FLAG_SKIP_FRIENDLY_NAME); | |
| 454 if (!addresses.get()) | |
| 455 return; | |
| 456 | |
| 457 // The order of adapters is the network binding order, so stick to the | |
| 458 // first good adapter for each family. | |
| 459 for (const IP_ADAPTER_ADDRESSES* adapter = addresses.get(); | |
| 460 adapter != NULL && (!have_ipv4 || !have_ipv6); | |
| 461 adapter = adapter->Next) { | |
| 462 if (adapter->OperStatus != IfOperStatusUp) | |
| 463 continue; | |
| 464 if (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK) | |
| 465 continue; | |
| 466 | |
| 467 for (const IP_ADAPTER_UNICAST_ADDRESS* address = | |
| 468 adapter->FirstUnicastAddress; | |
| 469 address != NULL; | |
| 470 address = address->Next) { | |
| 471 IPEndPoint ipe; | |
| 472 if (!ipe.FromSockAddr(address->Address.lpSockaddr, | |
| 473 address->Address.iSockaddrLength)) { | |
| 474 return; | |
| 475 } | |
| 476 if (!have_ipv4 && (ipe.GetFamily() == AF_INET)) { | |
| 477 have_ipv4 = true; | |
| 478 hosts_[DnsHostsKey(localname, ADDRESS_FAMILY_IPV4)] = ipe.address(); | |
| 479 } else if (!have_ipv6 && (ipe.GetFamily() == AF_INET6)) { | |
| 480 have_ipv6 = true; | |
| 481 hosts_[DnsHostsKey(localname, ADDRESS_FAMILY_IPV6)] = ipe.address(); | |
| 482 } | |
| 483 } | |
| 484 } | |
| 485 success_ = true; | |
| 486 } | 563 } |
| 487 | 564 |
| 488 virtual void OnWorkFinished() OVERRIDE { | 565 virtual void OnWorkFinished() OVERRIDE { |
| 489 DCHECK(loop()->BelongsToCurrentThread()); | 566 DCHECK(loop()->BelongsToCurrentThread()); |
| 490 if (success_) { | 567 if (success_) { |
| 491 service_->OnHostsRead(hosts_); | 568 service_->OnHostsRead(hosts_); |
| 492 } else { | 569 } else { |
| 493 LOG(WARNING) << "Failed to read DnsHosts."; | 570 LOG(WARNING) << "Failed to read DnsHosts."; |
| 494 } | 571 } |
| 495 } | 572 } |
| 496 | 573 |
| 497 const FilePath path_; | 574 const FilePath path_; |
| 498 DnsConfigServiceWin* service_; | 575 DnsConfigServiceWin* service_; |
| 499 // Written in DoWork, read in OnWorkFinished, no locking necessary. | 576 // Written in DoWork, read in OnWorkFinished, no locking necessary. |
| 500 DnsHosts hosts_; | 577 DnsHosts hosts_; |
| 501 bool success_; | 578 bool success_; |
| 502 | 579 |
| 503 DISALLOW_COPY_AND_ASSIGN(HostsReader); | 580 DISALLOW_COPY_AND_ASSIGN(HostsReader); |
| 504 }; | 581 }; |
| 505 | 582 |
| 506 DnsConfigServiceWin::DnsConfigServiceWin() | 583 DnsConfigServiceWin::DnsConfigServiceWin() |
| 507 : config_reader_(new ConfigReader(this)), | 584 : config_reader_(new ConfigReader(this)), |
| 508 hosts_reader_(new HostsReader(this)) {} | 585 hosts_reader_(new HostsReader(this)) {} |
| 509 | 586 |
| 510 DnsConfigServiceWin::~DnsConfigServiceWin() { | 587 DnsConfigServiceWin::~DnsConfigServiceWin() { |
| 511 DCHECK(CalledOnValidThread()); | |
| 512 config_reader_->Cancel(); | 588 config_reader_->Cancel(); |
| 513 hosts_reader_->Cancel(); | 589 hosts_reader_->Cancel(); |
| 514 NetworkChangeNotifier::RemoveIPAddressObserver(this); | 590 NetworkChangeNotifier::RemoveIPAddressObserver(this); |
| 515 } | 591 } |
| 516 | 592 |
| 517 void DnsConfigServiceWin::Watch(const CallbackType& callback) { | 593 void DnsConfigServiceWin::Watch(const CallbackType& callback) { |
| 518 DnsConfigService::Watch(callback); | 594 DnsConfigService::Watch(callback); |
| 519 // Also need to observe changes to local non-loopback IP for DnsHosts. | 595 // Also need to observe changes to local non-loopback IP for DnsHosts. |
| 520 NetworkChangeNotifier::AddIPAddressObserver(this); | 596 NetworkChangeNotifier::AddIPAddressObserver(this); |
| 521 } | 597 } |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 549 | 625 |
| 550 } // namespace internal | 626 } // namespace internal |
| 551 | 627 |
| 552 // static | 628 // static |
| 553 scoped_ptr<DnsConfigService> DnsConfigService::CreateSystemService() { | 629 scoped_ptr<DnsConfigService> DnsConfigService::CreateSystemService() { |
| 554 return scoped_ptr<DnsConfigService>(new internal::DnsConfigServiceWin()); | 630 return scoped_ptr<DnsConfigService>(new internal::DnsConfigServiceWin()); |
| 555 } | 631 } |
| 556 | 632 |
| 557 } // namespace net | 633 } // namespace net |
| 558 | 634 |
| OLD | NEW |