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

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

Issue 23522036: [net/dns] Treat Name Resolution Policy Table as unhandled option. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: responded to review Created 7 years, 3 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
« no previous file with comments | « net/dns/dns_config_service_win.h ('k') | net/dns/dns_config_service_win_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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"
(...skipping 25 matching lines...) Expand all
36 36
37 namespace net { 37 namespace net {
38 38
39 namespace internal { 39 namespace internal {
40 40
41 namespace { 41 namespace {
42 42
43 // Interval between retries to parse config. Used only until parsing succeeds. 43 // Interval between retries to parse config. Used only until parsing succeeds.
44 const int kRetryIntervalSeconds = 5; 44 const int kRetryIntervalSeconds = 5;
45 45
46 // Registry key paths.
47 const wchar_t* const kTcpipPath =
48 L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters";
49 const wchar_t* const kTcpip6Path =
50 L"SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\Parameters";
51 const wchar_t* const kDnscachePath =
52 L"SYSTEM\\CurrentControlSet\\Services\\Dnscache\\Parameters";
53 const wchar_t* const kPolicyPath =
54 L"SOFTWARE\\Policies\\Microsoft\\Windows NT\\DNSClient";
46 const wchar_t* const kPrimaryDnsSuffixPath = 55 const wchar_t* const kPrimaryDnsSuffixPath =
47 L"SOFTWARE\\Policies\\Microsoft\\System\\DNSClient"; 56 L"SOFTWARE\\Policies\\Microsoft\\System\\DNSClient";
57 const wchar_t* const kNRPTPath =
58 L"SOFTWARE\\Policies\\Microsoft\\Windows NT\\DNSClient\\DnsPolicyConfig";
48 59
49 enum HostsParseWinResult { 60 enum HostsParseWinResult {
50 HOSTS_PARSE_WIN_OK = 0, 61 HOSTS_PARSE_WIN_OK = 0,
51 HOSTS_PARSE_WIN_UNREADABLE_HOSTS_FILE, 62 HOSTS_PARSE_WIN_UNREADABLE_HOSTS_FILE,
52 HOSTS_PARSE_WIN_COMPUTER_NAME_FAILED, 63 HOSTS_PARSE_WIN_COMPUTER_NAME_FAILED,
53 HOSTS_PARSE_WIN_IPHELPER_FAILED, 64 HOSTS_PARSE_WIN_IPHELPER_FAILED,
54 HOSTS_PARSE_WIN_BAD_ADDRESS, 65 HOSTS_PARSE_WIN_BAD_ADDRESS,
55 HOSTS_PARSE_WIN_MAX // Bounding values for enumeration. 66 HOSTS_PARSE_WIN_MAX // Bounding values for enumeration.
56 }; 67 };
57 68
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after
191 202
192 if (!policy_reader.ReadDword(L"AppendToMultiLabelName", 203 if (!policy_reader.ReadDword(L"AppendToMultiLabelName",
193 &settings->append_to_multi_label_name)) { 204 &settings->append_to_multi_label_name)) {
194 return CONFIG_PARSE_WIN_READ_APPEND_MULTILABEL; 205 return CONFIG_PARSE_WIN_READ_APPEND_MULTILABEL;
195 } 206 }
196 207
197 if (!primary_dns_suffix_reader.ReadString(L"PrimaryDnsSuffix", 208 if (!primary_dns_suffix_reader.ReadString(L"PrimaryDnsSuffix",
198 &settings->primary_dns_suffix)) { 209 &settings->primary_dns_suffix)) {
199 return CONFIG_PARSE_WIN_READ_PRIMARY_SUFFIX; 210 return CONFIG_PARSE_WIN_READ_PRIMARY_SUFFIX;
200 } 211 }
212
213 base::win::RegistryKeyIterator nrpt_rules(HKEY_LOCAL_MACHINE, kNRPTPath);
214 settings->have_name_resolution_policy = (nrpt_rules.SubkeyCount() > 0);
215
201 return CONFIG_PARSE_WIN_OK; 216 return CONFIG_PARSE_WIN_OK;
202 } 217 }
203 218
204 // Default address of "localhost" and local computer name can be overridden 219 // Default address of "localhost" and local computer name can be overridden
205 // by the HOSTS file, but if it's not there, then we need to fill it in. 220 // by the HOSTS file, but if it's not there, then we need to fill it in.
206 HostsParseWinResult AddLocalhostEntries(DnsHosts* hosts) { 221 HostsParseWinResult AddLocalhostEntries(DnsHosts* hosts) {
207 const unsigned char kIPv4Localhost[] = { 127, 0, 0, 1 }; 222 const unsigned char kIPv4Localhost[] = { 127, 0, 0, 1 };
208 const unsigned char kIPv6Localhost[] = { 0, 0, 0, 0, 0, 0, 0, 0, 223 const unsigned char kIPv6Localhost[] = { 0, 0, 0, 0, 0, 0, 0, 0,
209 0, 0, 0, 0, 0, 0, 0, 1 }; 224 0, 0, 0, 0, 0, 0, 0, 1 };
210 IPAddressNumber loopback_ipv4(kIPv4Localhost, 225 IPAddressNumber loopback_ipv4(kIPv4Localhost,
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
323 if (address.size() != kIPv6AddressSize) 338 if (address.size() != kIPv6AddressSize)
324 return false; 339 return false;
325 const uint8 kPrefix[] = { 340 const uint8 kPrefix[] = {
326 0xfe, 0xc0, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 341 0xfe, 0xc0, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
327 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 342 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
328 }; 343 };
329 return std::equal(kPrefix, kPrefix + arraysize(kPrefix), 344 return std::equal(kPrefix, kPrefix + arraysize(kPrefix),
330 address.begin()) && (address.back() < 4); 345 address.begin()) && (address.back() < 4);
331 } 346 }
332 347
333 } // namespace 348 // Returns the path to the HOSTS file.
334
335 base::FilePath GetHostsPath() { 349 base::FilePath GetHostsPath() {
336 TCHAR buffer[MAX_PATH]; 350 TCHAR buffer[MAX_PATH];
337 UINT rc = GetSystemDirectory(buffer, MAX_PATH); 351 UINT rc = GetSystemDirectory(buffer, MAX_PATH);
338 DCHECK(0 < rc && rc < MAX_PATH); 352 DCHECK(0 < rc && rc < MAX_PATH);
339 return base::FilePath(buffer).Append( 353 return base::FilePath(buffer).Append(
340 FILE_PATH_LITERAL("drivers\\etc\\hosts")); 354 FILE_PATH_LITERAL("drivers\\etc\\hosts"));
341 } 355 }
342 356
357 void ConfigureSuffixSearch(const DnsSystemSettings& settings,
358 DnsConfig* config) {
359 // SearchList takes precedence, so check it first.
360 if (settings.policy_search_list.set) {
361 std::vector<std::string> search;
362 if (ParseSearchList(settings.policy_search_list.value, &search)) {
363 config->search.swap(search);
364 return;
365 }
366 // Even if invalid, the policy disables the user-specified setting below.
367 } else if (settings.tcpip_search_list.set) {
368 std::vector<std::string> search;
369 if (ParseSearchList(settings.tcpip_search_list.value, &search)) {
370 config->search.swap(search);
371 return;
372 }
373 }
374
375 // In absence of explicit search list, suffix search is:
376 // [primary suffix, connection-specific suffix, devolution of primary suffix].
377 // Primary suffix can be set by policy (primary_dns_suffix) or
378 // user setting (tcpip_domain).
379 //
380 // The policy (primary_dns_suffix) can be edited via Group Policy Editor
381 // (gpedit.msc) at Local Computer Policy => Computer Configuration
382 // => Administrative Template => Network => DNS Client => Primary DNS Suffix.
383 //
384 // The user setting (tcpip_domain) can be configurred at Computer Name in
385 // System Settings
386 std::string primary_suffix;
387 if ((settings.primary_dns_suffix.set &&
388 ParseDomainASCII(settings.primary_dns_suffix.value, &primary_suffix)) ||
389 (settings.tcpip_domain.set &&
390 ParseDomainASCII(settings.tcpip_domain.value, &primary_suffix))) {
391 // Primary suffix goes in front.
392 config->search.insert(config->search.begin(), primary_suffix);
393 } else {
394 return; // No primary suffix, hence no devolution.
395 }
396
397 // Devolution is determined by precedence: policy > dnscache > tcpip.
398 // |enabled|: UseDomainNameDevolution and |level|: DomainNameDevolutionLevel
399 // are overridden independently.
400 DnsSystemSettings::DevolutionSetting devolution = settings.policy_devolution;
401
402 if (!devolution.enabled.set)
403 devolution.enabled = settings.dnscache_devolution.enabled;
404 if (!devolution.enabled.set)
405 devolution.enabled = settings.tcpip_devolution.enabled;
406 if (devolution.enabled.set && (devolution.enabled.value == 0))
407 return; // Devolution disabled.
408
409 // By default devolution is enabled.
410
411 if (!devolution.level.set)
412 devolution.level = settings.dnscache_devolution.level;
413 if (!devolution.level.set)
414 devolution.level = settings.tcpip_devolution.level;
415
416 // After the recent update, Windows will try to determine a safe default
417 // value by comparing the forest root domain (FRD) to the primary suffix.
418 // See http://support.microsoft.com/kb/957579 for details.
419 // For now, if the level is not set, we disable devolution, assuming that
420 // we will fallback to the system getaddrinfo anyway. This might cause
421 // performance loss for resolutions which depend on the system default
422 // devolution setting.
423 //
424 // If the level is explicitly set below 2, devolution is disabled.
425 if (!devolution.level.set || devolution.level.value < 2)
426 return; // Devolution disabled.
427
428 // Devolve the primary suffix. This naive logic matches the observed
429 // behavior (see also ParseSearchList). If a suffix is not valid, it will be
430 // discarded when the fully-qualified name is converted to DNS format.
431
432 unsigned num_dots = std::count(primary_suffix.begin(),
433 primary_suffix.end(), '.');
434
435 for (size_t offset = 0; num_dots >= devolution.level.value; --num_dots) {
436 offset = primary_suffix.find('.', offset + 1);
437 config->search.push_back(primary_suffix.substr(offset + 1));
438 }
439 }
440
441 } // namespace
442
343 bool ParseSearchList(const base::string16& value, 443 bool ParseSearchList(const base::string16& value,
344 std::vector<std::string>* output) { 444 std::vector<std::string>* output) {
345 DCHECK(output); 445 DCHECK(output);
346 if (value.empty()) 446 if (value.empty())
347 return false; 447 return false;
348 448
349 output->clear(); 449 output->clear();
350 450
351 // If the list includes an empty hostname (",," or ", ,"), it is terminated. 451 // If the list includes an empty hostname (",," or ", ,"), it is terminated.
352 // Although nslookup and network connection property tab ignore such 452 // Although nslookup and network connection property tab ignore such
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
422 if (base::win::GetVersion() >= base::win::VERSION_VISTA) { 522 if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
423 config->append_to_multi_label_name = false; 523 config->append_to_multi_label_name = false;
424 } else { 524 } else {
425 config->append_to_multi_label_name = true; 525 config->append_to_multi_label_name = true;
426 } 526 }
427 } else { 527 } else {
428 config->append_to_multi_label_name = 528 config->append_to_multi_label_name =
429 (settings.append_to_multi_label_name.value != 0); 529 (settings.append_to_multi_label_name.value != 0);
430 } 530 }
431 531
432 // SearchList takes precedence, so check it first. 532 ConfigParseWinResult result = CONFIG_PARSE_WIN_OK;
433 if (settings.policy_search_list.set) { 533 if (settings.have_name_resolution_policy) {
434 std::vector<std::string> search; 534 config->unhandled_options = true;
435 if (ParseSearchList(settings.policy_search_list.value, &search)) { 535 // TODO(szym): only set this to true if NRPT has DirectAccess rules.
436 config->search.swap(search); 536 config->use_local_ipv6 = true;
437 return CONFIG_PARSE_WIN_OK; 537 result = CONFIG_PARSE_WIN_UNHANDLED_OPTIONS;
438 }
439 // Even if invalid, the policy disables the user-specified setting below.
440 } else if (settings.tcpip_search_list.set) {
441 std::vector<std::string> search;
442 if (ParseSearchList(settings.tcpip_search_list.value, &search)) {
443 config->search.swap(search);
444 return CONFIG_PARSE_WIN_OK;
445 }
446 } 538 }
447 539
448 // In absence of explicit search list, suffix search is: 540 ConfigureSuffixSearch(settings, config);
449 // [primary suffix, connection-specific suffix, devolution of primary suffix]. 541 return result;
450 // Primary suffix can be set by policy (primary_dns_suffix) or
451 // user setting (tcpip_domain).
452 //
453 // The policy (primary_dns_suffix) can be edited via Group Policy Editor
454 // (gpedit.msc) at Local Computer Policy => Computer Configuration
455 // => Administrative Template => Network => DNS Client => Primary DNS Suffix.
456 //
457 // The user setting (tcpip_domain) can be configurred at Computer Name in
458 // System Settings
459 std::string primary_suffix;
460 if ((settings.primary_dns_suffix.set &&
461 ParseDomainASCII(settings.primary_dns_suffix.value, &primary_suffix)) ||
462 (settings.tcpip_domain.set &&
463 ParseDomainASCII(settings.tcpip_domain.value, &primary_suffix))) {
464 // Primary suffix goes in front.
465 config->search.insert(config->search.begin(), primary_suffix);
466 } else {
467 return CONFIG_PARSE_WIN_OK; // No primary suffix, hence no devolution.
468 }
469
470 // Devolution is determined by precedence: policy > dnscache > tcpip.
471 // |enabled|: UseDomainNameDevolution and |level|: DomainNameDevolutionLevel
472 // are overridden independently.
473 DnsSystemSettings::DevolutionSetting devolution = settings.policy_devolution;
474
475 if (!devolution.enabled.set)
476 devolution.enabled = settings.dnscache_devolution.enabled;
477 if (!devolution.enabled.set)
478 devolution.enabled = settings.tcpip_devolution.enabled;
479 if (devolution.enabled.set && (devolution.enabled.value == 0))
480 return CONFIG_PARSE_WIN_OK; // Devolution disabled.
481
482 // By default devolution is enabled.
483
484 if (!devolution.level.set)
485 devolution.level = settings.dnscache_devolution.level;
486 if (!devolution.level.set)
487 devolution.level = settings.tcpip_devolution.level;
488
489 // After the recent update, Windows will try to determine a safe default
490 // value by comparing the forest root domain (FRD) to the primary suffix.
491 // See http://support.microsoft.com/kb/957579 for details.
492 // For now, if the level is not set, we disable devolution, assuming that
493 // we will fallback to the system getaddrinfo anyway. This might cause
494 // performance loss for resolutions which depend on the system default
495 // devolution setting.
496 //
497 // If the level is explicitly set below 2, devolution is disabled.
498 if (!devolution.level.set || devolution.level.value < 2)
499 return CONFIG_PARSE_WIN_OK; // Devolution disabled.
500
501 // Devolve the primary suffix. This naive logic matches the observed
502 // behavior (see also ParseSearchList). If a suffix is not valid, it will be
503 // discarded when the fully-qualified name is converted to DNS format.
504
505 unsigned num_dots = std::count(primary_suffix.begin(),
506 primary_suffix.end(), '.');
507
508 for (size_t offset = 0; num_dots >= devolution.level.value; --num_dots) {
509 offset = primary_suffix.find('.', offset + 1);
510 config->search.push_back(primary_suffix.substr(offset + 1));
511 }
512 return CONFIG_PARSE_WIN_OK;
513 } 542 }
514 543
515 // Watches registry and HOSTS file for changes. Must live on a thread which 544 // Watches registry and HOSTS file for changes. Must live on a thread which
516 // allows IO. 545 // allows IO.
517 class DnsConfigServiceWin::Watcher 546 class DnsConfigServiceWin::Watcher
518 : public NetworkChangeNotifier::IPAddressObserver { 547 : public NetworkChangeNotifier::IPAddressObserver {
519 public: 548 public:
520 explicit Watcher(DnsConfigServiceWin* service) : service_(service) {} 549 explicit Watcher(DnsConfigServiceWin* service) : service_(service) {}
521 ~Watcher() { 550 ~Watcher() {
522 NetworkChangeNotifier::RemoveIPAddressObserver(this); 551 NetworkChangeNotifier::RemoveIPAddressObserver(this);
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
599 private: 628 private:
600 virtual ~ConfigReader() {} 629 virtual ~ConfigReader() {}
601 630
602 virtual void DoWork() OVERRIDE { 631 virtual void DoWork() OVERRIDE {
603 // Should be called on WorkerPool. 632 // Should be called on WorkerPool.
604 base::TimeTicks start_time = base::TimeTicks::Now(); 633 base::TimeTicks start_time = base::TimeTicks::Now();
605 DnsSystemSettings settings = {}; 634 DnsSystemSettings settings = {};
606 ConfigParseWinResult result = ReadSystemSettings(&settings); 635 ConfigParseWinResult result = ReadSystemSettings(&settings);
607 if (result == CONFIG_PARSE_WIN_OK) 636 if (result == CONFIG_PARSE_WIN_OK)
608 result = ConvertSettingsToDnsConfig(settings, &dns_config_); 637 result = ConvertSettingsToDnsConfig(settings, &dns_config_);
609 success_ = (result == CONFIG_PARSE_WIN_OK); 638 success_ = (result == CONFIG_PARSE_WIN_OK ||
639 result == CONFIG_PARSE_WIN_UNHANDLED_OPTIONS);
610 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.ConfigParseWin", 640 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.ConfigParseWin",
611 result, CONFIG_PARSE_WIN_MAX); 641 result, CONFIG_PARSE_WIN_MAX);
612 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.ConfigParseResult", success_); 642 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.ConfigParseResult", success_);
613 UMA_HISTOGRAM_TIMES("AsyncDNS.ConfigParseDuration", 643 UMA_HISTOGRAM_TIMES("AsyncDNS.ConfigParseDuration",
614 base::TimeTicks::Now() - start_time); 644 base::TimeTicks::Now() - start_time);
615 } 645 }
616 646
617 virtual void OnWorkFinished() OVERRIDE { 647 virtual void OnWorkFinished() OVERRIDE {
618 DCHECK(loop()->BelongsToCurrentThread()); 648 DCHECK(loop()->BelongsToCurrentThread());
619 DCHECK(!IsCancelled()); 649 DCHECK(!IsCancelled());
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after
728 } 758 }
729 759
730 } // namespace internal 760 } // namespace internal
731 761
732 // static 762 // static
733 scoped_ptr<DnsConfigService> DnsConfigService::CreateSystemService() { 763 scoped_ptr<DnsConfigService> DnsConfigService::CreateSystemService() {
734 return scoped_ptr<DnsConfigService>(new internal::DnsConfigServiceWin()); 764 return scoped_ptr<DnsConfigService>(new internal::DnsConfigServiceWin());
735 } 765 }
736 766
737 } // namespace net 767 } // namespace net
OLDNEW
« no previous file with comments | « net/dns/dns_config_service_win.h ('k') | net/dns/dns_config_service_win_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698