| 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 HostsParseWinResult { |
| 45 HOSTS_PARSE_WIN_OK = 0, |
| 46 HOSTS_PARSE_WIN_UNREADABLE_HOSTS_FILE, |
| 47 HOSTS_PARSE_WIN_COMPUTER_NAME_FAILED, |
| 48 HOSTS_PARSE_WIN_IPHELPER_FAILED, |
| 49 HOSTS_PARSE_WIN_BAD_ADDRESS, |
| 50 HOSTS_PARSE_WIN_MAX // Bounding values for enumeration. |
| 51 }; |
| 52 |
| 42 // Convenience for reading values using RegKey. | 53 // Convenience for reading values using RegKey. |
| 43 class RegistryReader : public base::NonThreadSafe { | 54 class RegistryReader : public base::NonThreadSafe { |
| 44 public: | 55 public: |
| 45 explicit RegistryReader(const wchar_t* key) { | 56 explicit RegistryReader(const wchar_t* key) { |
| 46 // Ignoring the result. |key_.Valid()| will catch failures. | 57 // Ignoring the result. |key_.Valid()| will catch failures. |
| 47 key_.Open(HKEY_LOCAL_MACHINE, key, KEY_QUERY_VALUE); | 58 key_.Open(HKEY_LOCAL_MACHINE, key, KEY_QUERY_VALUE); |
| 48 } | 59 } |
| 49 | 60 |
| 50 bool ReadString(const wchar_t* name, | 61 bool ReadString(const wchar_t* name, |
| 51 DnsSystemSettings::RegString* out) const { | 62 DnsSystemSettings::RegString* out) const { |
| (...skipping 26 matching lines...) Expand all Loading... |
| 78 } | 89 } |
| 79 return (result == ERROR_FILE_NOT_FOUND); | 90 return (result == ERROR_FILE_NOT_FOUND); |
| 80 } | 91 } |
| 81 | 92 |
| 82 private: | 93 private: |
| 83 base::win::RegKey key_; | 94 base::win::RegKey key_; |
| 84 | 95 |
| 85 DISALLOW_COPY_AND_ASSIGN(RegistryReader); | 96 DISALLOW_COPY_AND_ASSIGN(RegistryReader); |
| 86 }; | 97 }; |
| 87 | 98 |
| 88 // Returns NULL if failed. | 99 // Wrapper for GetAdaptersAddresses. Returns NULL if failed. |
| 89 scoped_ptr_malloc<IP_ADAPTER_ADDRESSES> ReadIpHelper(ULONG flags) { | 100 scoped_ptr_malloc<IP_ADAPTER_ADDRESSES> ReadIpHelper(ULONG flags) { |
| 90 base::ThreadRestrictions::AssertIOAllowed(); | 101 base::ThreadRestrictions::AssertIOAllowed(); |
| 91 | 102 |
| 92 scoped_ptr_malloc<IP_ADAPTER_ADDRESSES> out; | 103 scoped_ptr_malloc<IP_ADAPTER_ADDRESSES> out; |
| 93 ULONG len = 15000; // As recommended by MSDN for GetAdaptersAddresses. | 104 ULONG len = 15000; // As recommended by MSDN for GetAdaptersAddresses. |
| 94 UINT rv = ERROR_BUFFER_OVERFLOW; | 105 UINT rv = ERROR_BUFFER_OVERFLOW; |
| 95 // Try up to three times. | 106 // Try up to three times. |
| 96 for (unsigned tries = 0; (tries < 3) && (rv == ERROR_BUFFER_OVERFLOW); | 107 for (unsigned tries = 0; (tries < 3) && (rv == ERROR_BUFFER_OVERFLOW); |
| 97 tries++) { | 108 tries++) { |
| 98 out.reset(reinterpret_cast<PIP_ADAPTER_ADDRESSES>(malloc(len))); | 109 out.reset(reinterpret_cast<PIP_ADAPTER_ADDRESSES>(malloc(len))); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 125 | 136 |
| 126 // |punycode_output| should now be ASCII; convert it to a std::string. | 137 // |punycode_output| should now be ASCII; convert it to a std::string. |
| 127 // (We could use UTF16ToASCII() instead, but that requires an extra string | 138 // (We could use UTF16ToASCII() instead, but that requires an extra string |
| 128 // copy. Since ASCII is a subset of UTF8 the following is equivalent). | 139 // copy. Since ASCII is a subset of UTF8 the following is equivalent). |
| 129 bool success = UTF16ToUTF8(punycode.data(), punycode.length(), domain); | 140 bool success = UTF16ToUTF8(punycode.data(), punycode.length(), domain); |
| 130 DCHECK(success); | 141 DCHECK(success); |
| 131 DCHECK(IsStringASCII(*domain)); | 142 DCHECK(IsStringASCII(*domain)); |
| 132 return success && !domain->empty(); | 143 return success && !domain->empty(); |
| 133 } | 144 } |
| 134 | 145 |
| 146 bool ReadDevolutionSetting(const RegistryReader& reader, |
| 147 DnsSystemSettings::DevolutionSetting* setting) { |
| 148 return reader.ReadDword(L"UseDomainNameDevolution", &setting->enabled) && |
| 149 reader.ReadDword(L"DomainNameDevolutionLevel", &setting->level); |
| 150 } |
| 151 |
| 152 // Reads DnsSystemSettings from IpHelper and registry. |
| 153 ConfigParseWinResult ReadSystemSettings(DnsSystemSettings* settings) { |
| 154 settings->addresses = ReadIpHelper(GAA_FLAG_SKIP_ANYCAST | |
| 155 GAA_FLAG_SKIP_UNICAST | |
| 156 GAA_FLAG_SKIP_MULTICAST | |
| 157 GAA_FLAG_SKIP_FRIENDLY_NAME); |
| 158 if (!settings->addresses.get()) |
| 159 return CONFIG_PARSE_WIN_READ_IPHELPER; |
| 160 |
| 161 RegistryReader tcpip_reader(kTcpipPath); |
| 162 RegistryReader tcpip6_reader(kTcpip6Path); |
| 163 RegistryReader dnscache_reader(kDnscachePath); |
| 164 RegistryReader policy_reader(kPolicyPath); |
| 165 RegistryReader primary_dns_suffix_reader(kPrimaryDnsSuffixPath); |
| 166 |
| 167 if (!policy_reader.ReadString(L"SearchList", |
| 168 &settings->policy_search_list)) { |
| 169 return CONFIG_PARSE_WIN_READ_POLICY_SEARCHLIST; |
| 170 } |
| 171 |
| 172 if (!tcpip_reader.ReadString(L"SearchList", &settings->tcpip_search_list)) |
| 173 return CONFIG_PARSE_WIN_READ_TCPIP_SEARCHLIST; |
| 174 |
| 175 if (!tcpip_reader.ReadString(L"Domain", &settings->tcpip_domain)) |
| 176 return CONFIG_PARSE_WIN_READ_DOMAIN; |
| 177 |
| 178 if (!ReadDevolutionSetting(policy_reader, &settings->policy_devolution)) |
| 179 return CONFIG_PARSE_WIN_READ_POLICY_DEVOLUTION; |
| 180 |
| 181 if (!ReadDevolutionSetting(dnscache_reader, &settings->dnscache_devolution)) |
| 182 return CONFIG_PARSE_WIN_READ_DNSCACHE_DEVOLUTION; |
| 183 |
| 184 if (!ReadDevolutionSetting(tcpip_reader, &settings->tcpip_devolution)) |
| 185 return CONFIG_PARSE_WIN_READ_TCPIP_DEVOLUTION; |
| 186 |
| 187 if (!policy_reader.ReadDword(L"AppendToMultiLabelName", |
| 188 &settings->append_to_multi_label_name)) { |
| 189 return CONFIG_PARSE_WIN_READ_APPEND_MULTILABEL; |
| 190 } |
| 191 |
| 192 if (!primary_dns_suffix_reader.ReadString(L"PrimaryDnsSuffix", |
| 193 &settings->primary_dns_suffix)) { |
| 194 return CONFIG_PARSE_WIN_READ_PRIMARY_SUFFIX; |
| 195 } |
| 196 return CONFIG_PARSE_WIN_OK; |
| 197 } |
| 198 |
| 199 // Default address of "localhost" and local computer name can be overridden |
| 200 // by the HOSTS file, but if it's not there, then we need to fill it in. |
| 201 HostsParseWinResult AddLocalhostEntries(DnsHosts* hosts) { |
| 202 const unsigned char kIPv4Localhost[] = { 127, 0, 0, 1 }; |
| 203 const unsigned char kIPv6Localhost[] = { 0, 0, 0, 0, 0, 0, 0, 0, |
| 204 0, 0, 0, 0, 0, 0, 0, 1 }; |
| 205 IPAddressNumber loopback_ipv4(kIPv4Localhost, |
| 206 kIPv4Localhost + arraysize(kIPv4Localhost)); |
| 207 IPAddressNumber loopback_ipv6(kIPv6Localhost, |
| 208 kIPv6Localhost + arraysize(kIPv6Localhost)); |
| 209 |
| 210 // This does not override any pre-existing entries from the HOSTS file. |
| 211 hosts->insert(std::make_pair(DnsHostsKey("localhost", ADDRESS_FAMILY_IPV4), |
| 212 loopback_ipv4)); |
| 213 hosts->insert(std::make_pair(DnsHostsKey("localhost", ADDRESS_FAMILY_IPV6), |
| 214 loopback_ipv6)); |
| 215 |
| 216 WCHAR buffer[MAX_PATH]; |
| 217 DWORD size = MAX_PATH; |
| 218 std::string localname; |
| 219 if (!GetComputerNameExW(ComputerNameDnsHostname, buffer, &size) || |
| 220 !ParseDomainASCII(buffer, &localname)) { |
| 221 return HOSTS_PARSE_WIN_COMPUTER_NAME_FAILED; |
| 222 } |
| 223 StringToLowerASCII(&localname); |
| 224 |
| 225 bool have_ipv4 = |
| 226 hosts->count(DnsHostsKey(localname, ADDRESS_FAMILY_IPV4)) > 0; |
| 227 bool have_ipv6 = |
| 228 hosts->count(DnsHostsKey(localname, ADDRESS_FAMILY_IPV6)) > 0; |
| 229 |
| 230 if (have_ipv4 && have_ipv6) |
| 231 return HOSTS_PARSE_WIN_OK; |
| 232 |
| 233 scoped_ptr_malloc<IP_ADAPTER_ADDRESSES> addresses = |
| 234 ReadIpHelper(GAA_FLAG_SKIP_ANYCAST | |
| 235 GAA_FLAG_SKIP_DNS_SERVER | |
| 236 GAA_FLAG_SKIP_MULTICAST | |
| 237 GAA_FLAG_SKIP_FRIENDLY_NAME); |
| 238 if (!addresses.get()) |
| 239 return HOSTS_PARSE_WIN_IPHELPER_FAILED; |
| 240 |
| 241 // The order of adapters is the network binding order, so stick to the |
| 242 // first good adapter for each family. |
| 243 for (const IP_ADAPTER_ADDRESSES* adapter = addresses.get(); |
| 244 adapter != NULL && (!have_ipv4 || !have_ipv6); |
| 245 adapter = adapter->Next) { |
| 246 if (adapter->OperStatus != IfOperStatusUp) |
| 247 continue; |
| 248 if (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK) |
| 249 continue; |
| 250 |
| 251 for (const IP_ADAPTER_UNICAST_ADDRESS* address = |
| 252 adapter->FirstUnicastAddress; |
| 253 address != NULL; |
| 254 address = address->Next) { |
| 255 IPEndPoint ipe; |
| 256 if (!ipe.FromSockAddr(address->Address.lpSockaddr, |
| 257 address->Address.iSockaddrLength)) { |
| 258 return HOSTS_PARSE_WIN_BAD_ADDRESS; |
| 259 } |
| 260 if (!have_ipv4 && (ipe.GetFamily() == AF_INET)) { |
| 261 have_ipv4 = true; |
| 262 (*hosts)[DnsHostsKey(localname, ADDRESS_FAMILY_IPV4)] = ipe.address(); |
| 263 } else if (!have_ipv6 && (ipe.GetFamily() == AF_INET6)) { |
| 264 have_ipv6 = true; |
| 265 (*hosts)[DnsHostsKey(localname, ADDRESS_FAMILY_IPV6)] = ipe.address(); |
| 266 } |
| 267 } |
| 268 } |
| 269 return HOSTS_PARSE_WIN_OK; |
| 270 } |
| 271 |
| 135 } // namespace | 272 } // namespace |
| 136 | 273 |
| 137 FilePath GetHostsPath() { | 274 FilePath GetHostsPath() { |
| 138 TCHAR buffer[MAX_PATH]; | 275 TCHAR buffer[MAX_PATH]; |
| 139 UINT rc = GetSystemDirectory(buffer, MAX_PATH); | 276 UINT rc = GetSystemDirectory(buffer, MAX_PATH); |
| 140 DCHECK(0 < rc && rc < MAX_PATH); | 277 DCHECK(0 < rc && rc < MAX_PATH); |
| 141 return FilePath(buffer).Append(FILE_PATH_LITERAL("drivers\\etc\\hosts")); | 278 return FilePath(buffer).Append(FILE_PATH_LITERAL("drivers\\etc\\hosts")); |
| 142 } | 279 } |
| 143 | 280 |
| 144 bool ParseSearchList(const string16& value, std::vector<std::string>* output) { | 281 bool ParseSearchList(const string16& value, std::vector<std::string>* output) { |
| (...skipping 14 matching lines...) Expand all Loading... |
| 159 // handle such suffixes. | 296 // handle such suffixes. |
| 160 const string16& t = woutput[i]; | 297 const string16& t = woutput[i]; |
| 161 std::string parsed; | 298 std::string parsed; |
| 162 if (!ParseDomainASCII(t, &parsed)) | 299 if (!ParseDomainASCII(t, &parsed)) |
| 163 break; | 300 break; |
| 164 output->push_back(parsed); | 301 output->push_back(parsed); |
| 165 } | 302 } |
| 166 return !output->empty(); | 303 return !output->empty(); |
| 167 } | 304 } |
| 168 | 305 |
| 169 bool ConvertSettingsToDnsConfig(const DnsSystemSettings& settings, | 306 ConfigParseWinResult ConvertSettingsToDnsConfig( |
| 170 DnsConfig* config) { | 307 const DnsSystemSettings& settings, |
| 308 DnsConfig* config) { |
| 171 *config = DnsConfig(); | 309 *config = DnsConfig(); |
| 172 | 310 |
| 173 // Use GetAdapterAddresses to get effective DNS server order and | 311 // Use GetAdapterAddresses to get effective DNS server order and |
| 174 // connection-specific DNS suffix. Ignore disconnected and loopback adapters. | 312 // connection-specific DNS suffix. Ignore disconnected and loopback adapters. |
| 175 // The order of adapters is the network binding order, so stick to the | 313 // The order of adapters is the network binding order, so stick to the |
| 176 // first good adapter. | 314 // first good adapter. |
| 177 for (const IP_ADAPTER_ADDRESSES* adapter = settings.addresses.get(); | 315 for (const IP_ADAPTER_ADDRESSES* adapter = settings.addresses.get(); |
| 178 adapter != NULL && config->nameservers.empty(); | 316 adapter != NULL && config->nameservers.empty(); |
| 179 adapter = adapter->Next) { | 317 adapter = adapter->Next) { |
| 180 if (adapter->OperStatus != IfOperStatusUp) | 318 if (adapter->OperStatus != IfOperStatusUp) |
| 181 continue; | 319 continue; |
| 182 if (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK) | 320 if (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK) |
| 183 continue; | 321 continue; |
| 184 | 322 |
| 185 for (const IP_ADAPTER_DNS_SERVER_ADDRESS* address = | 323 for (const IP_ADAPTER_DNS_SERVER_ADDRESS* address = |
| 186 adapter->FirstDnsServerAddress; | 324 adapter->FirstDnsServerAddress; |
| 187 address != NULL; | 325 address != NULL; |
| 188 address = address->Next) { | 326 address = address->Next) { |
| 189 IPEndPoint ipe; | 327 IPEndPoint ipe; |
| 190 if (ipe.FromSockAddr(address->Address.lpSockaddr, | 328 if (ipe.FromSockAddr(address->Address.lpSockaddr, |
| 191 address->Address.iSockaddrLength)) { | 329 address->Address.iSockaddrLength)) { |
| 192 // Override unset port. | 330 // Override unset port. |
| 193 if (!ipe.port()) | 331 if (!ipe.port()) |
| 194 ipe = IPEndPoint(ipe.address(), dns_protocol::kDefaultPort); | 332 ipe = IPEndPoint(ipe.address(), dns_protocol::kDefaultPort); |
| 195 config->nameservers.push_back(ipe); | 333 config->nameservers.push_back(ipe); |
| 196 } else { | 334 } else { |
| 197 return false; | 335 return CONFIG_PARSE_WIN_BAD_ADDRESS; |
| 198 } | 336 } |
| 199 } | 337 } |
| 200 | 338 |
| 201 // IP_ADAPTER_ADDRESSES in Vista+ has a search list at |FirstDnsSuffix|, | 339 // IP_ADAPTER_ADDRESSES in Vista+ has a search list at |FirstDnsSuffix|, |
| 202 // but it came up empty in all trials. | 340 // but it came up empty in all trials. |
| 203 // |DnsSuffix| stores the effective connection-specific suffix, which is | 341 // |DnsSuffix| stores the effective connection-specific suffix, which is |
| 204 // obtained via DHCP (regkey: Tcpip\Parameters\Interfaces\{XXX}\DhcpDomain) | 342 // obtained via DHCP (regkey: Tcpip\Parameters\Interfaces\{XXX}\DhcpDomain) |
| 205 // or specified by the user (regkey: Tcpip\Parameters\Domain). | 343 // or specified by the user (regkey: Tcpip\Parameters\Domain). |
| 206 std::string dns_suffix; | 344 std::string dns_suffix; |
| 207 if (ParseDomainASCII(adapter->DnsSuffix, &dns_suffix)) | 345 if (ParseDomainASCII(adapter->DnsSuffix, &dns_suffix)) |
| 208 config->search.push_back(dns_suffix); | 346 config->search.push_back(dns_suffix); |
| 209 } | 347 } |
| 210 | 348 |
| 211 if (config->nameservers.empty()) | 349 if (config->nameservers.empty()) |
| 212 return false; // No point continuing. | 350 return CONFIG_PARSE_WIN_NO_NAMESERVERS; // No point continuing. |
| 213 | 351 |
| 214 // Windows always tries a multi-label name "as is" before using suffixes. | 352 // Windows always tries a multi-label name "as is" before using suffixes. |
| 215 config->ndots = 1; | 353 config->ndots = 1; |
| 216 | 354 |
| 217 if (!settings.append_to_multi_label_name.set) { | 355 if (!settings.append_to_multi_label_name.set) { |
| 218 // The default setting is true for XP, false for Vista+. | 356 // The default setting is true for XP, false for Vista+. |
| 219 if (base::win::GetVersion() >= base::win::VERSION_VISTA) { | 357 if (base::win::GetVersion() >= base::win::VERSION_VISTA) { |
| 220 config->append_to_multi_label_name = false; | 358 config->append_to_multi_label_name = false; |
| 221 } else { | 359 } else { |
| 222 config->append_to_multi_label_name = true; | 360 config->append_to_multi_label_name = true; |
| 223 } | 361 } |
| 224 } else { | 362 } else { |
| 225 config->append_to_multi_label_name = | 363 config->append_to_multi_label_name = |
| 226 (settings.append_to_multi_label_name.value != 0); | 364 (settings.append_to_multi_label_name.value != 0); |
| 227 } | 365 } |
| 228 | 366 |
| 229 // SearchList takes precedence, so check it first. | 367 // SearchList takes precedence, so check it first. |
| 230 if (settings.policy_search_list.set) { | 368 if (settings.policy_search_list.set) { |
| 231 std::vector<std::string> search; | 369 std::vector<std::string> search; |
| 232 if (ParseSearchList(settings.policy_search_list.value, &search)) { | 370 if (ParseSearchList(settings.policy_search_list.value, &search)) { |
| 233 config->search.swap(search); | 371 config->search.swap(search); |
| 234 return true; | 372 return CONFIG_PARSE_WIN_OK; |
| 235 } | 373 } |
| 236 // Even if invalid, the policy disables the user-specified setting below. | 374 // Even if invalid, the policy disables the user-specified setting below. |
| 237 } else if (settings.tcpip_search_list.set) { | 375 } else if (settings.tcpip_search_list.set) { |
| 238 std::vector<std::string> search; | 376 std::vector<std::string> search; |
| 239 if (ParseSearchList(settings.tcpip_search_list.value, &search)) { | 377 if (ParseSearchList(settings.tcpip_search_list.value, &search)) { |
| 240 config->search.swap(search); | 378 config->search.swap(search); |
| 241 return true; | 379 return CONFIG_PARSE_WIN_OK; |
| 242 } | 380 } |
| 243 } | 381 } |
| 244 | 382 |
| 245 // In absence of explicit search list, suffix search is: | 383 // In absence of explicit search list, suffix search is: |
| 246 // [primary suffix, connection-specific suffix, devolution of primary suffix]. | 384 // [primary suffix, connection-specific suffix, devolution of primary suffix]. |
| 247 // Primary suffix can be set by policy (primary_dns_suffix) or | 385 // Primary suffix can be set by policy (primary_dns_suffix) or |
| 248 // user setting (tcpip_domain). | 386 // user setting (tcpip_domain). |
| 249 // | 387 // |
| 250 // The policy (primary_dns_suffix) can be edited via Group Policy Editor | 388 // The policy (primary_dns_suffix) can be edited via Group Policy Editor |
| 251 // (gpedit.msc) at Local Computer Policy => Computer Configuration | 389 // (gpedit.msc) at Local Computer Policy => Computer Configuration |
| 252 // => Administrative Template => Network => DNS Client => Primary DNS Suffix. | 390 // => Administrative Template => Network => DNS Client => Primary DNS Suffix. |
| 253 // | 391 // |
| 254 // The user setting (tcpip_domain) can be configurred at Computer Name in | 392 // The user setting (tcpip_domain) can be configurred at Computer Name in |
| 255 // System Settings | 393 // System Settings |
| 256 std::string primary_suffix; | 394 std::string primary_suffix; |
| 257 if ((settings.primary_dns_suffix.set && | 395 if ((settings.primary_dns_suffix.set && |
| 258 ParseDomainASCII(settings.primary_dns_suffix.value, &primary_suffix)) || | 396 ParseDomainASCII(settings.primary_dns_suffix.value, &primary_suffix)) || |
| 259 (settings.tcpip_domain.set && | 397 (settings.tcpip_domain.set && |
| 260 ParseDomainASCII(settings.tcpip_domain.value, &primary_suffix))) { | 398 ParseDomainASCII(settings.tcpip_domain.value, &primary_suffix))) { |
| 261 // Primary suffix goes in front. | 399 // Primary suffix goes in front. |
| 262 config->search.insert(config->search.begin(), primary_suffix); | 400 config->search.insert(config->search.begin(), primary_suffix); |
| 263 } else { | 401 } else { |
| 264 return true; // No primary suffix, hence no devolution. | 402 return CONFIG_PARSE_WIN_OK; // No primary suffix, hence no devolution. |
| 265 } | 403 } |
| 266 | 404 |
| 267 // Devolution is determined by precedence: policy > dnscache > tcpip. | 405 // Devolution is determined by precedence: policy > dnscache > tcpip. |
| 268 // |enabled|: UseDomainNameDevolution and |level|: DomainNameDevolutionLevel | 406 // |enabled|: UseDomainNameDevolution and |level|: DomainNameDevolutionLevel |
| 269 // are overridden independently. | 407 // are overridden independently. |
| 270 DnsSystemSettings::DevolutionSetting devolution = settings.policy_devolution; | 408 DnsSystemSettings::DevolutionSetting devolution = settings.policy_devolution; |
| 271 | 409 |
| 272 if (!devolution.enabled.set) | 410 if (!devolution.enabled.set) |
| 273 devolution.enabled = settings.dnscache_devolution.enabled; | 411 devolution.enabled = settings.dnscache_devolution.enabled; |
| 274 if (!devolution.enabled.set) | 412 if (!devolution.enabled.set) |
| 275 devolution.enabled = settings.tcpip_devolution.enabled; | 413 devolution.enabled = settings.tcpip_devolution.enabled; |
| 276 if (devolution.enabled.set && (devolution.enabled.value == 0)) | 414 if (devolution.enabled.set && (devolution.enabled.value == 0)) |
| 277 return true; // Devolution disabled. | 415 return CONFIG_PARSE_WIN_OK; // Devolution disabled. |
| 278 | 416 |
| 279 // By default devolution is enabled. | 417 // By default devolution is enabled. |
| 280 | 418 |
| 281 if (!devolution.level.set) | 419 if (!devolution.level.set) |
| 282 devolution.level = settings.dnscache_devolution.level; | 420 devolution.level = settings.dnscache_devolution.level; |
| 283 if (!devolution.level.set) | 421 if (!devolution.level.set) |
| 284 devolution.level = settings.tcpip_devolution.level; | 422 devolution.level = settings.tcpip_devolution.level; |
| 285 | 423 |
| 286 // After the recent update, Windows will try to determine a safe default | 424 // After the recent update, Windows will try to determine a safe default |
| 287 // value by comparing the forest root domain (FRD) to the primary suffix. | 425 // value by comparing the forest root domain (FRD) to the primary suffix. |
| 288 // See http://support.microsoft.com/kb/957579 for details. | 426 // See http://support.microsoft.com/kb/957579 for details. |
| 289 // For now, if the level is not set, we disable devolution, assuming that | 427 // For now, if the level is not set, we disable devolution, assuming that |
| 290 // we will fallback to the system getaddrinfo anyway. This might cause | 428 // we will fallback to the system getaddrinfo anyway. This might cause |
| 291 // performance loss for resolutions which depend on the system default | 429 // performance loss for resolutions which depend on the system default |
| 292 // devolution setting. | 430 // devolution setting. |
| 293 // | 431 // |
| 294 // If the level is explicitly set below 2, devolution is disabled. | 432 // If the level is explicitly set below 2, devolution is disabled. |
| 295 if (!devolution.level.set || devolution.level.value < 2) | 433 if (!devolution.level.set || devolution.level.value < 2) |
| 296 return true; // Devolution disabled. | 434 return CONFIG_PARSE_WIN_OK; // Devolution disabled. |
| 297 | 435 |
| 298 // Devolve the primary suffix. This naive logic matches the observed | 436 // Devolve the primary suffix. This naive logic matches the observed |
| 299 // behavior (see also ParseSearchList). If a suffix is not valid, it will be | 437 // 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. | 438 // discarded when the fully-qualified name is converted to DNS format. |
| 301 | 439 |
| 302 unsigned num_dots = std::count(primary_suffix.begin(), | 440 unsigned num_dots = std::count(primary_suffix.begin(), |
| 303 primary_suffix.end(), '.'); | 441 primary_suffix.end(), '.'); |
| 304 | 442 |
| 305 for (size_t offset = 0; num_dots >= devolution.level.value; --num_dots) { | 443 for (size_t offset = 0; num_dots >= devolution.level.value; --num_dots) { |
| 306 offset = primary_suffix.find('.', offset + 1); | 444 offset = primary_suffix.find('.', offset + 1); |
| 307 config->search.push_back(primary_suffix.substr(offset + 1)); | 445 config->search.push_back(primary_suffix.substr(offset + 1)); |
| 308 } | 446 } |
| 309 | 447 return CONFIG_PARSE_WIN_OK; |
| 310 return true; | |
| 311 } | 448 } |
| 312 | 449 |
| 313 // Watches registry for changes and reads config from registry and IP helper. | 450 // Reads config from registry and IpHelper. 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 { | 451 class DnsConfigServiceWin::ConfigReader : public SerialWorker { |
| 317 public: | 452 public: |
| 318 explicit ConfigReader(DnsConfigServiceWin* service) | 453 explicit ConfigReader(DnsConfigServiceWin* service) |
| 319 : service_(service), | 454 : service_(service), |
| 320 success_(false) {} | 455 success_(false) {} |
| 321 | 456 |
| 322 private: | 457 private: |
| 323 bool ReadDevolutionSetting(const RegistryReader& reader, | 458 virtual ~ConfigReader() {} |
| 324 DnsSystemSettings::DevolutionSetting& setting) { | |
| 325 return reader.ReadDword(L"UseDomainNameDevolution", &setting.enabled) && | |
| 326 reader.ReadDword(L"DomainNameDevolutionLevel", &setting.level); | |
| 327 } | |
| 328 | 459 |
| 329 virtual void DoWork() OVERRIDE { | 460 virtual void DoWork() OVERRIDE { |
| 330 // Should be called on WorkerPool. | 461 // Should be called on WorkerPool. |
| 331 success_ = false; | 462 base::TimeTicks start_time = base::TimeTicks::Now(); |
| 332 | |
| 333 DnsSystemSettings settings = {}; | 463 DnsSystemSettings settings = {}; |
| 334 settings.addresses = ReadIpHelper(GAA_FLAG_SKIP_ANYCAST | | 464 ConfigParseWinResult result = ReadSystemSettings(&settings); |
| 335 GAA_FLAG_SKIP_UNICAST | | 465 if (result == CONFIG_PARSE_WIN_OK) |
| 336 GAA_FLAG_SKIP_MULTICAST | | 466 result = ConvertSettingsToDnsConfig(settings, &dns_config_); |
| 337 GAA_FLAG_SKIP_FRIENDLY_NAME); | 467 success_ = (result == CONFIG_PARSE_WIN_OK); |
| 338 if (!settings.addresses.get()) | 468 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.ConfigParseWin", |
| 339 return; // no point reading the rest | 469 result, CONFIG_PARSE_WIN_MAX); |
| 340 | 470 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.ConfigParseResult", success_); |
| 341 RegistryReader tcpip_reader(kTcpipPath); | 471 UMA_HISTOGRAM_TIMES("AsyncDNS.ConfigParseDuration", |
| 342 RegistryReader tcpip6_reader(kTcpip6Path); | 472 base::TimeTicks::Now() - start_time); |
| 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 } | 473 } |
| 377 | 474 |
| 378 virtual void OnWorkFinished() OVERRIDE { | 475 virtual void OnWorkFinished() OVERRIDE { |
| 379 DCHECK(loop()->BelongsToCurrentThread()); | 476 DCHECK(loop()->BelongsToCurrentThread()); |
| 380 DCHECK(!IsCancelled()); | 477 DCHECK(!IsCancelled()); |
| 381 if (success_) { | 478 if (success_) { |
| 382 service_->OnConfigRead(dns_config_); | 479 service_->OnConfigRead(dns_config_); |
| 383 } else { | 480 } else { |
| 384 LOG(WARNING) << "Failed to read DnsConfig."; | 481 LOG(WARNING) << "Failed to read DnsConfig."; |
| 385 } | 482 } |
| 386 } | 483 } |
| 387 | 484 |
| 388 DnsConfigServiceWin* service_; | 485 DnsConfigServiceWin* service_; |
| 389 // Written in DoRead(), read in OnReadFinished(). No locking required. | 486 // Written in DoRead(), read in OnReadFinished(). No locking required. |
| 390 DnsConfig dns_config_; | 487 DnsConfig dns_config_; |
| 391 bool success_; | 488 bool success_; |
| 392 }; | 489 }; |
| 393 | 490 |
| 394 // An extension for DnsHostsReader which also watches the HOSTS file, | 491 // Reads hosts from HOSTS file and fills in localhost and local computer name if |
| 395 // reads local name from GetComputerNameEx, local IP from GetAdaptersAddresses, | 492 // necessary. All work performed on WorkerPool. |
| 396 // and observes changes to local IP address. | |
| 397 class DnsConfigServiceWin::HostsReader : public SerialWorker { | 493 class DnsConfigServiceWin::HostsReader : public SerialWorker { |
| 398 public: | 494 public: |
| 399 explicit HostsReader(DnsConfigServiceWin* service) | 495 explicit HostsReader(DnsConfigServiceWin* service) |
| 400 : path_(GetHostsPath()), service_(service) { | 496 : path_(GetHostsPath()), service_(service) { |
| 401 } | 497 } |
| 402 | 498 |
| 403 private: | 499 private: |
| 500 virtual ~HostsReader() {} |
| 501 |
| 404 virtual void DoWork() OVERRIDE { | 502 virtual void DoWork() OVERRIDE { |
| 405 success_ = ParseHostsFile(path_, &hosts_); | 503 base::TimeTicks start_time = base::TimeTicks::Now(); |
| 406 | 504 HostsParseWinResult result = HOSTS_PARSE_WIN_UNREADABLE_HOSTS_FILE; |
| 407 if (!success_) | 505 if (ParseHostsFile(path_, &hosts_)) |
| 408 return; | 506 result = AddLocalhostEntries(&hosts_); |
| 409 | 507 success_ = (result == HOSTS_PARSE_WIN_OK); |
| 410 success_ = false; | 508 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.HostsParseWin", |
| 411 | 509 result, HOSTS_PARSE_WIN_MAX); |
| 412 // Default address of "localhost" and local computer name can be overridden | 510 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.HostParseResult", success_); |
| 413 // by the HOSTS file, but if it's not there, then we need to fill it in. | 511 UMA_HISTOGRAM_TIMES("AsyncDNS.HostsParseDuration", |
| 414 | 512 base::TimeTicks::Now() - start_time); |
| 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 } | |
| 437 StringToLowerASCII(&localname); | |
| 438 | |
| 439 bool have_ipv4 = | |
| 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 } | 513 } |
| 487 | 514 |
| 488 virtual void OnWorkFinished() OVERRIDE { | 515 virtual void OnWorkFinished() OVERRIDE { |
| 489 DCHECK(loop()->BelongsToCurrentThread()); | 516 DCHECK(loop()->BelongsToCurrentThread()); |
| 490 if (success_) { | 517 if (success_) { |
| 491 service_->OnHostsRead(hosts_); | 518 service_->OnHostsRead(hosts_); |
| 492 } else { | 519 } else { |
| 493 LOG(WARNING) << "Failed to read DnsHosts."; | 520 LOG(WARNING) << "Failed to read DnsHosts."; |
| 494 } | 521 } |
| 495 } | 522 } |
| 496 | 523 |
| 497 const FilePath path_; | 524 const FilePath path_; |
| 498 DnsConfigServiceWin* service_; | 525 DnsConfigServiceWin* service_; |
| 499 // Written in DoWork, read in OnWorkFinished, no locking necessary. | 526 // Written in DoWork, read in OnWorkFinished, no locking necessary. |
| 500 DnsHosts hosts_; | 527 DnsHosts hosts_; |
| 501 bool success_; | 528 bool success_; |
| 502 | 529 |
| 503 DISALLOW_COPY_AND_ASSIGN(HostsReader); | 530 DISALLOW_COPY_AND_ASSIGN(HostsReader); |
| 504 }; | 531 }; |
| 505 | 532 |
| 506 DnsConfigServiceWin::DnsConfigServiceWin() | 533 DnsConfigServiceWin::DnsConfigServiceWin() |
| 507 : config_reader_(new ConfigReader(this)), | 534 : config_reader_(new ConfigReader(this)), |
| 508 hosts_reader_(new HostsReader(this)) {} | 535 hosts_reader_(new HostsReader(this)) {} |
| 509 | 536 |
| 510 DnsConfigServiceWin::~DnsConfigServiceWin() { | 537 DnsConfigServiceWin::~DnsConfigServiceWin() { |
| 511 DCHECK(CalledOnValidThread()); | |
| 512 config_reader_->Cancel(); | 538 config_reader_->Cancel(); |
| 513 hosts_reader_->Cancel(); | 539 hosts_reader_->Cancel(); |
| 514 NetworkChangeNotifier::RemoveIPAddressObserver(this); | 540 NetworkChangeNotifier::RemoveIPAddressObserver(this); |
| 515 } | 541 } |
| 516 | 542 |
| 517 void DnsConfigServiceWin::Watch(const CallbackType& callback) { | 543 void DnsConfigServiceWin::Watch(const CallbackType& callback) { |
| 518 DnsConfigService::Watch(callback); | 544 DnsConfigService::Watch(callback); |
| 519 // Also need to observe changes to local non-loopback IP for DnsHosts. | 545 // Also need to observe changes to local non-loopback IP for DnsHosts. |
| 520 NetworkChangeNotifier::AddIPAddressObserver(this); | 546 NetworkChangeNotifier::AddIPAddressObserver(this); |
| 521 } | 547 } |
| (...skipping 27 matching lines...) Expand all Loading... |
| 549 | 575 |
| 550 } // namespace internal | 576 } // namespace internal |
| 551 | 577 |
| 552 // static | 578 // static |
| 553 scoped_ptr<DnsConfigService> DnsConfigService::CreateSystemService() { | 579 scoped_ptr<DnsConfigService> DnsConfigService::CreateSystemService() { |
| 554 return scoped_ptr<DnsConfigService>(new internal::DnsConfigServiceWin()); | 580 return scoped_ptr<DnsConfigService>(new internal::DnsConfigServiceWin()); |
| 555 } | 581 } |
| 556 | 582 |
| 557 } // namespace net | 583 } // namespace net |
| 558 | 584 |
| OLD | NEW |