Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(213)

Side by Side Diff: net/dns/dns_config_service_win.cc

Issue 10543168: [net/dns] Instrument DnsConfigService to measure performance and failures. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix test expectations on win' Created 8 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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 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 { 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 // An extension for DnsHostsReader which also watches the HOSTS file,
395 // reads local name from GetComputerNameEx, local IP from GetAdaptersAddresses, 492 // reads local name from GetComputerNameEx, local IP from GetAdaptersAddresses,
396 // and observes changes to local IP address. 493 // and observes changes to local IP address.
mmenke 2012/06/19 14:49:15 Might as well fix this comment, too, while you're
397 class DnsConfigServiceWin::HostsReader : public SerialWorker { 494 class DnsConfigServiceWin::HostsReader : public SerialWorker {
398 public: 495 public:
399 explicit HostsReader(DnsConfigServiceWin* service) 496 explicit HostsReader(DnsConfigServiceWin* service)
400 : path_(GetHostsPath()), service_(service) { 497 : path_(GetHostsPath()), service_(service) {
401 } 498 }
402 499
403 private: 500 private:
501 virtual ~HostsReader() {}
502
404 virtual void DoWork() OVERRIDE { 503 virtual void DoWork() OVERRIDE {
405 success_ = ParseHostsFile(path_, &hosts_); 504 base::TimeTicks start_time = base::TimeTicks::Now();
406 505 HostsParseWinResult result = HOSTS_PARSE_WIN_UNREADABLE_HOSTS_FILE;
407 if (!success_) 506 if (ParseHostsFile(path_, &hosts_)) {
408 return; 507 result = AddLocalhostEntries(&hosts_);
409
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 } 508 }
437 StringToLowerASCII(&localname); 509 success_ = (result == HOSTS_PARSE_WIN_OK);
438 510 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.HostsParseWin",
439 bool have_ipv4 = 511 result, HOSTS_PARSE_WIN_MAX);
440 hosts_.count(DnsHostsKey(localname, ADDRESS_FAMILY_IPV4)) > 0; 512 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.HostParseResult", success_);
441 bool have_ipv6 = 513 UMA_HISTOGRAM_TIMES("AsyncDNS.HostsParseDuration",
442 hosts_.count(DnsHostsKey(localname, ADDRESS_FAMILY_IPV6)) > 0; 514 base::TimeTicks::Now() - start_time);
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 } 515 }
487 516
488 virtual void OnWorkFinished() OVERRIDE { 517 virtual void OnWorkFinished() OVERRIDE {
489 DCHECK(loop()->BelongsToCurrentThread()); 518 DCHECK(loop()->BelongsToCurrentThread());
490 if (success_) { 519 if (success_) {
491 service_->OnHostsRead(hosts_); 520 service_->OnHostsRead(hosts_);
492 } else { 521 } else {
493 LOG(WARNING) << "Failed to read DnsHosts."; 522 LOG(WARNING) << "Failed to read DnsHosts.";
494 } 523 }
495 } 524 }
496 525
497 const FilePath path_; 526 const FilePath path_;
498 DnsConfigServiceWin* service_; 527 DnsConfigServiceWin* service_;
499 // Written in DoWork, read in OnWorkFinished, no locking necessary. 528 // Written in DoWork, read in OnWorkFinished, no locking necessary.
500 DnsHosts hosts_; 529 DnsHosts hosts_;
501 bool success_; 530 bool success_;
502 531
503 DISALLOW_COPY_AND_ASSIGN(HostsReader); 532 DISALLOW_COPY_AND_ASSIGN(HostsReader);
504 }; 533 };
505 534
506 DnsConfigServiceWin::DnsConfigServiceWin() 535 DnsConfigServiceWin::DnsConfigServiceWin()
507 : config_reader_(new ConfigReader(this)), 536 : config_reader_(new ConfigReader(this)),
508 hosts_reader_(new HostsReader(this)) {} 537 hosts_reader_(new HostsReader(this)) {}
509 538
510 DnsConfigServiceWin::~DnsConfigServiceWin() { 539 DnsConfigServiceWin::~DnsConfigServiceWin() {
511 DCHECK(CalledOnValidThread());
512 config_reader_->Cancel(); 540 config_reader_->Cancel();
513 hosts_reader_->Cancel(); 541 hosts_reader_->Cancel();
514 NetworkChangeNotifier::RemoveIPAddressObserver(this); 542 NetworkChangeNotifier::RemoveIPAddressObserver(this);
515 } 543 }
516 544
517 void DnsConfigServiceWin::Watch(const CallbackType& callback) { 545 void DnsConfigServiceWin::Watch(const CallbackType& callback) {
518 DnsConfigService::Watch(callback); 546 DnsConfigService::Watch(callback);
519 // Also need to observe changes to local non-loopback IP for DnsHosts. 547 // Also need to observe changes to local non-loopback IP for DnsHosts.
520 NetworkChangeNotifier::AddIPAddressObserver(this); 548 NetworkChangeNotifier::AddIPAddressObserver(this);
521 } 549 }
(...skipping 27 matching lines...) Expand all
549 577
550 } // namespace internal 578 } // namespace internal
551 579
552 // static 580 // static
553 scoped_ptr<DnsConfigService> DnsConfigService::CreateSystemService() { 581 scoped_ptr<DnsConfigService> DnsConfigService::CreateSystemService() {
554 return scoped_ptr<DnsConfigService>(new internal::DnsConfigServiceWin()); 582 return scoped_ptr<DnsConfigService>(new internal::DnsConfigServiceWin());
555 } 583 }
556 584
557 } // namespace net 585 } // namespace net
558 586
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698