diff options
author | szym@chromium.org <szym@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-09-17 12:24:52 +0000 |
---|---|---|
committer | szym@chromium.org <szym@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-09-17 12:24:52 +0000 |
commit | c9fa8f31d868cce1592bca5c9989d4872ecfe6fb (patch) | |
tree | c301e727c758af2bc5d5bc77d1040873ea010b27 /net | |
parent | a6751cc0130fc463583216c82c9555cd711b24a6 (diff) | |
download | chromium_src-c9fa8f31d868cce1592bca5c9989d4872ecfe6fb.zip chromium_src-c9fa8f31d868cce1592bca5c9989d4872ecfe6fb.tar.gz chromium_src-c9fa8f31d868cce1592bca5c9989d4872ecfe6fb.tar.bz2 |
[net/dns] Treat Name Resolution Policy Table as unhandled option.
Also, conservatively assume that non-empty NRPT or unknown DnsConfig could mean
DirectAccess is used, and disable IPv6 probing in that case.
BUG=259792
Review URL: https://chromiumcodereview.appspot.com/23522036
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@223595 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r-- | net/base/net_log_event_type_list.h | 10 | ||||
-rw-r--r-- | net/dns/dns_config_service.cc | 8 | ||||
-rw-r--r-- | net/dns/dns_config_service.h | 5 | ||||
-rw-r--r-- | net/dns/dns_config_service_win.cc | 194 | ||||
-rw-r--r-- | net/dns/dns_config_service_win.h | 18 | ||||
-rw-r--r-- | net/dns/dns_config_service_win_unittest.cc | 39 | ||||
-rw-r--r-- | net/dns/host_resolver_impl.cc | 9 | ||||
-rw-r--r-- | net/dns/host_resolver_impl.h | 4 |
8 files changed, 178 insertions, 109 deletions
diff --git a/net/base/net_log_event_type_list.h b/net/base/net_log_event_type_list.h index 4c4371c..83d6bb7 100644 --- a/net/base/net_log_event_type_list.h +++ b/net/base/net_log_event_type_list.h @@ -1632,14 +1632,8 @@ EVENT_TYPE(NETWORK_CHANGED) // { // "nameservers": <List of name server IPs>, // "search": <List of domain suffixes>, -// "unhandled_options": <See DnsConfig>, -// "append_to_multi_label_name": <See DnsConfig>, -// "ndots": <See DnsConfig>, -// "timeout": <See DnsConfig>, -// "attempts": <See DnsConfig>, -// "rotate": <See DnsConfig>, -// "edns0": <See DnsConfig>, -// "num_hosts": <Number of entries in the HOSTS file> +// "num_hosts": <Number of entries in the HOSTS file>, +// <other>: <See DnsConfig> // } EVENT_TYPE(DNS_CONFIG_CHANGED) diff --git a/net/dns/dns_config_service.cc b/net/dns/dns_config_service.cc index d7af988..6613182 100644 --- a/net/dns/dns_config_service.cc +++ b/net/dns/dns_config_service.cc @@ -21,7 +21,8 @@ DnsConfig::DnsConfig() timeout(base::TimeDelta::FromSeconds(kDnsTimeoutSeconds)), attempts(2), rotate(false), - edns0(false) {} + edns0(false), + use_local_ipv6(false) {} DnsConfig::~DnsConfig() {} @@ -38,7 +39,8 @@ bool DnsConfig::EqualsIgnoreHosts(const DnsConfig& d) const { (timeout == d.timeout) && (attempts == d.attempts) && (rotate == d.rotate) && - (edns0 == d.edns0); + (edns0 == d.edns0) && + (use_local_ipv6 == d.use_local_ipv6); } void DnsConfig::CopyIgnoreHosts(const DnsConfig& d) { @@ -51,6 +53,7 @@ void DnsConfig::CopyIgnoreHosts(const DnsConfig& d) { attempts = d.attempts; rotate = d.rotate; edns0 = d.edns0; + use_local_ipv6 = d.use_local_ipv6; } base::Value* DnsConfig::ToValue() const { @@ -73,6 +76,7 @@ base::Value* DnsConfig::ToValue() const { dict->SetInteger("attempts", attempts); dict->SetBoolean("rotate", rotate); dict->SetBoolean("edns0", edns0); + dict->SetBoolean("use_local_ipv6", use_local_ipv6); dict->SetInteger("num_hosts", hosts.size()); return dict; diff --git a/net/dns/dns_config_service.h b/net/dns/dns_config_service.h index d14a2cd..7386e60 100644 --- a/net/dns/dns_config_service.h +++ b/net/dns/dns_config_service.h @@ -83,6 +83,11 @@ struct NET_EXPORT_PRIVATE DnsConfig { bool rotate; // Enable EDNS0 extensions. bool edns0; + + // Indicates system configuration uses local IPv6 connectivity, e.g., + // DirectAccess. This is exposed for HostResolver to skip IPv6 probes, + // as it may cause them to return incorrect results. + bool use_local_ipv6; }; diff --git a/net/dns/dns_config_service_win.cc b/net/dns/dns_config_service_win.cc index 6d12155..fe97b74 100644 --- a/net/dns/dns_config_service_win.cc +++ b/net/dns/dns_config_service_win.cc @@ -43,8 +43,19 @@ namespace { // Interval between retries to parse config. Used only until parsing succeeds. const int kRetryIntervalSeconds = 5; +// Registry key paths. +const wchar_t* const kTcpipPath = + L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"; +const wchar_t* const kTcpip6Path = + L"SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\Parameters"; +const wchar_t* const kDnscachePath = + L"SYSTEM\\CurrentControlSet\\Services\\Dnscache\\Parameters"; +const wchar_t* const kPolicyPath = + L"SOFTWARE\\Policies\\Microsoft\\Windows NT\\DNSClient"; const wchar_t* const kPrimaryDnsSuffixPath = L"SOFTWARE\\Policies\\Microsoft\\System\\DNSClient"; +const wchar_t* const kNRPTPath = + L"SOFTWARE\\Policies\\Microsoft\\Windows NT\\DNSClient\\DnsPolicyConfig"; enum HostsParseWinResult { HOSTS_PARSE_WIN_OK = 0, @@ -198,6 +209,10 @@ ConfigParseWinResult ReadSystemSettings(DnsSystemSettings* settings) { &settings->primary_dns_suffix)) { return CONFIG_PARSE_WIN_READ_PRIMARY_SUFFIX; } + + base::win::RegistryKeyIterator nrpt_rules(HKEY_LOCAL_MACHINE, kNRPTPath); + settings->have_name_resolution_policy = (nrpt_rules.SubkeyCount() > 0); + return CONFIG_PARSE_WIN_OK; } @@ -330,8 +345,7 @@ bool IsStatelessDiscoveryAddress(const IPAddressNumber& address) { address.begin()) && (address.back() < 4); } -} // namespace - +// Returns the path to the HOSTS file. base::FilePath GetHostsPath() { TCHAR buffer[MAX_PATH]; UINT rc = GetSystemDirectory(buffer, MAX_PATH); @@ -340,6 +354,92 @@ base::FilePath GetHostsPath() { FILE_PATH_LITERAL("drivers\\etc\\hosts")); } +void ConfigureSuffixSearch(const DnsSystemSettings& settings, + DnsConfig* config) { + // SearchList takes precedence, so check it first. + if (settings.policy_search_list.set) { + std::vector<std::string> search; + if (ParseSearchList(settings.policy_search_list.value, &search)) { + config->search.swap(search); + return; + } + // Even if invalid, the policy disables the user-specified setting below. + } else if (settings.tcpip_search_list.set) { + std::vector<std::string> search; + if (ParseSearchList(settings.tcpip_search_list.value, &search)) { + config->search.swap(search); + return; + } + } + + // In absence of explicit search list, suffix search is: + // [primary suffix, connection-specific suffix, devolution of primary suffix]. + // Primary suffix can be set by policy (primary_dns_suffix) or + // user setting (tcpip_domain). + // + // The policy (primary_dns_suffix) can be edited via Group Policy Editor + // (gpedit.msc) at Local Computer Policy => Computer Configuration + // => Administrative Template => Network => DNS Client => Primary DNS Suffix. + // + // The user setting (tcpip_domain) can be configurred at Computer Name in + // System Settings + std::string primary_suffix; + if ((settings.primary_dns_suffix.set && + ParseDomainASCII(settings.primary_dns_suffix.value, &primary_suffix)) || + (settings.tcpip_domain.set && + ParseDomainASCII(settings.tcpip_domain.value, &primary_suffix))) { + // Primary suffix goes in front. + config->search.insert(config->search.begin(), primary_suffix); + } else { + return; // No primary suffix, hence no devolution. + } + + // Devolution is determined by precedence: policy > dnscache > tcpip. + // |enabled|: UseDomainNameDevolution and |level|: DomainNameDevolutionLevel + // are overridden independently. + DnsSystemSettings::DevolutionSetting devolution = settings.policy_devolution; + + if (!devolution.enabled.set) + devolution.enabled = settings.dnscache_devolution.enabled; + if (!devolution.enabled.set) + devolution.enabled = settings.tcpip_devolution.enabled; + if (devolution.enabled.set && (devolution.enabled.value == 0)) + return; // Devolution disabled. + + // By default devolution is enabled. + + if (!devolution.level.set) + devolution.level = settings.dnscache_devolution.level; + if (!devolution.level.set) + devolution.level = settings.tcpip_devolution.level; + + // After the recent update, Windows will try to determine a safe default + // value by comparing the forest root domain (FRD) to the primary suffix. + // See http://support.microsoft.com/kb/957579 for details. + // For now, if the level is not set, we disable devolution, assuming that + // we will fallback to the system getaddrinfo anyway. This might cause + // performance loss for resolutions which depend on the system default + // devolution setting. + // + // If the level is explicitly set below 2, devolution is disabled. + if (!devolution.level.set || devolution.level.value < 2) + return; // Devolution disabled. + + // Devolve the primary suffix. This naive logic matches the observed + // behavior (see also ParseSearchList). If a suffix is not valid, it will be + // discarded when the fully-qualified name is converted to DNS format. + + unsigned num_dots = std::count(primary_suffix.begin(), + primary_suffix.end(), '.'); + + for (size_t offset = 0; num_dots >= devolution.level.value; --num_dots) { + offset = primary_suffix.find('.', offset + 1); + config->search.push_back(primary_suffix.substr(offset + 1)); + } +} + +} // namespace + bool ParseSearchList(const base::string16& value, std::vector<std::string>* output) { DCHECK(output); @@ -429,87 +529,16 @@ ConfigParseWinResult ConvertSettingsToDnsConfig( (settings.append_to_multi_label_name.value != 0); } - // SearchList takes precedence, so check it first. - if (settings.policy_search_list.set) { - std::vector<std::string> search; - if (ParseSearchList(settings.policy_search_list.value, &search)) { - config->search.swap(search); - return CONFIG_PARSE_WIN_OK; - } - // Even if invalid, the policy disables the user-specified setting below. - } else if (settings.tcpip_search_list.set) { - std::vector<std::string> search; - if (ParseSearchList(settings.tcpip_search_list.value, &search)) { - config->search.swap(search); - return CONFIG_PARSE_WIN_OK; - } + ConfigParseWinResult result = CONFIG_PARSE_WIN_OK; + if (settings.have_name_resolution_policy) { + config->unhandled_options = true; + // TODO(szym): only set this to true if NRPT has DirectAccess rules. + config->use_local_ipv6 = true; + result = CONFIG_PARSE_WIN_UNHANDLED_OPTIONS; } - // In absence of explicit search list, suffix search is: - // [primary suffix, connection-specific suffix, devolution of primary suffix]. - // Primary suffix can be set by policy (primary_dns_suffix) or - // user setting (tcpip_domain). - // - // The policy (primary_dns_suffix) can be edited via Group Policy Editor - // (gpedit.msc) at Local Computer Policy => Computer Configuration - // => Administrative Template => Network => DNS Client => Primary DNS Suffix. - // - // The user setting (tcpip_domain) can be configurred at Computer Name in - // System Settings - std::string primary_suffix; - if ((settings.primary_dns_suffix.set && - ParseDomainASCII(settings.primary_dns_suffix.value, &primary_suffix)) || - (settings.tcpip_domain.set && - ParseDomainASCII(settings.tcpip_domain.value, &primary_suffix))) { - // Primary suffix goes in front. - config->search.insert(config->search.begin(), primary_suffix); - } else { - return CONFIG_PARSE_WIN_OK; // No primary suffix, hence no devolution. - } - - // Devolution is determined by precedence: policy > dnscache > tcpip. - // |enabled|: UseDomainNameDevolution and |level|: DomainNameDevolutionLevel - // are overridden independently. - DnsSystemSettings::DevolutionSetting devolution = settings.policy_devolution; - - if (!devolution.enabled.set) - devolution.enabled = settings.dnscache_devolution.enabled; - if (!devolution.enabled.set) - devolution.enabled = settings.tcpip_devolution.enabled; - if (devolution.enabled.set && (devolution.enabled.value == 0)) - return CONFIG_PARSE_WIN_OK; // Devolution disabled. - - // By default devolution is enabled. - - if (!devolution.level.set) - devolution.level = settings.dnscache_devolution.level; - if (!devolution.level.set) - devolution.level = settings.tcpip_devolution.level; - - // After the recent update, Windows will try to determine a safe default - // value by comparing the forest root domain (FRD) to the primary suffix. - // See http://support.microsoft.com/kb/957579 for details. - // For now, if the level is not set, we disable devolution, assuming that - // we will fallback to the system getaddrinfo anyway. This might cause - // performance loss for resolutions which depend on the system default - // devolution setting. - // - // If the level is explicitly set below 2, devolution is disabled. - if (!devolution.level.set || devolution.level.value < 2) - return CONFIG_PARSE_WIN_OK; // Devolution disabled. - - // Devolve the primary suffix. This naive logic matches the observed - // behavior (see also ParseSearchList). If a suffix is not valid, it will be - // discarded when the fully-qualified name is converted to DNS format. - - unsigned num_dots = std::count(primary_suffix.begin(), - primary_suffix.end(), '.'); - - for (size_t offset = 0; num_dots >= devolution.level.value; --num_dots) { - offset = primary_suffix.find('.', offset + 1); - config->search.push_back(primary_suffix.substr(offset + 1)); - } - return CONFIG_PARSE_WIN_OK; + ConfigureSuffixSearch(settings, config); + return result; } // Watches registry and HOSTS file for changes. Must live on a thread which @@ -606,7 +635,8 @@ class DnsConfigServiceWin::ConfigReader : public SerialWorker { ConfigParseWinResult result = ReadSystemSettings(&settings); if (result == CONFIG_PARSE_WIN_OK) result = ConvertSettingsToDnsConfig(settings, &dns_config_); - success_ = (result == CONFIG_PARSE_WIN_OK); + success_ = (result == CONFIG_PARSE_WIN_OK || + result == CONFIG_PARSE_WIN_UNHANDLED_OPTIONS); UMA_HISTOGRAM_ENUMERATION("AsyncDNS.ConfigParseWin", result, CONFIG_PARSE_WIN_MAX); UMA_HISTOGRAM_BOOLEAN("AsyncDNS.ConfigParseResult", success_); diff --git a/net/dns/dns_config_service_win.h b/net/dns/dns_config_service_win.h index 06fc0d9..9503dc8 100644 --- a/net/dns/dns_config_service_win.h +++ b/net/dns/dns_config_service_win.h @@ -34,19 +34,6 @@ namespace net { namespace internal { -// Registry key paths. -const wchar_t* const kTcpipPath = - L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"; -const wchar_t* const kTcpip6Path = - L"SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\Parameters"; -const wchar_t* const kDnscachePath = - L"SYSTEM\\CurrentControlSet\\Services\\Dnscache\\Parameters"; -const wchar_t* const kPolicyPath = - L"SOFTWARE\\Policies\\Microsoft\\Windows NT\\DNSClient"; - -// Returns the path to the HOSTS file. -base::FilePath GetHostsPath(); - // Parses |value| as search list (comma-delimited list of domain names) from // a registry key and stores it in |out|. Returns true on success. Empty // entries (e.g., "chromium.org,,org") terminate the list. Non-ascii hostnames @@ -98,6 +85,10 @@ struct NET_EXPORT_PRIVATE DnsSystemSettings { // SOFTWARE\Policies\Microsoft\Windows NT\DNSClient\AppendToMultiLabelName RegDword append_to_multi_label_name; + + // True when the Name Resolution Policy Table (NRPT) has at least one rule: + // SOFTWARE\Policies\Microsoft\Windows NT\DNSClient\DnsPolicyConfig\Rule* + bool have_name_resolution_policy; }; enum ConfigParseWinResult { @@ -113,6 +104,7 @@ enum ConfigParseWinResult { CONFIG_PARSE_WIN_READ_PRIMARY_SUFFIX, CONFIG_PARSE_WIN_BAD_ADDRESS, CONFIG_PARSE_WIN_NO_NAMESERVERS, + CONFIG_PARSE_WIN_UNHANDLED_OPTIONS, CONFIG_PARSE_WIN_MAX // Bounding values for enumeration. }; diff --git a/net/dns/dns_config_service_win_unittest.cc b/net/dns/dns_config_service_win_unittest.cc index b28b8e9..3f3e4ed 100644 --- a/net/dns/dns_config_service_win_unittest.cc +++ b/net/dns/dns_config_service_win_unittest.cc @@ -4,6 +4,7 @@ #include "net/dns/dns_config_service_win.h" +#include "base/basictypes.h" #include "base/logging.h" #include "base/win/windows_version.h" #include "net/dns/dns_protocol.h" @@ -420,10 +421,46 @@ TEST(DnsConfigServiceWinTest, AppendToMultiLabelName) { DnsConfig config; EXPECT_EQ(internal::CONFIG_PARSE_WIN_OK, internal::ConvertSettingsToDnsConfig(settings, &config)); - EXPECT_EQ(config.append_to_multi_label_name, t.expected_output); + EXPECT_EQ(t.expected_output, config.append_to_multi_label_name); } } +// Setting have_name_resolution_policy_table should set unhandled_options. +TEST(DnsConfigServiceWinTest, HaveNRPT) { + AdapterInfo infos[2] = { + { IF_TYPE_USB, IfOperStatusUp, L"connection.suffix", { "1.0.0.1" } }, + { 0 }, + }; + + const struct TestCase { + bool have_nrpt; + bool unhandled_options; + internal::ConfigParseWinResult result; + } cases[] = { + { false, false, internal::CONFIG_PARSE_WIN_OK }, + { true, true, internal::CONFIG_PARSE_WIN_UNHANDLED_OPTIONS }, + }; + + for (size_t i = 0; i < arraysize(cases); ++i) { + const TestCase& t = cases[i]; + internal::DnsSystemSettings settings = { + CreateAdapterAddresses(infos), + { false }, { false }, { false }, { false }, + { { false }, { false } }, + { { false }, { false } }, + { { false }, { false } }, + { false }, + t.have_nrpt, + }; + DnsConfig config; + EXPECT_EQ(t.result, + internal::ConvertSettingsToDnsConfig(settings, &config)); + EXPECT_EQ(t.unhandled_options, config.unhandled_options); + EXPECT_EQ(t.have_nrpt, config.use_local_ipv6); + } +} + + } // namespace } // namespace net diff --git a/net/dns/host_resolver_impl.cc b/net/dns/host_resolver_impl.cc index 52c6f93..90b7d36 100644 --- a/net/dns/host_resolver_impl.cc +++ b/net/dns/host_resolver_impl.cc @@ -1799,6 +1799,7 @@ HostResolverImpl::HostResolverImpl( received_dns_config_(false), num_dns_failures_(0), probe_ipv6_support_(true), + use_local_ipv6_(false), resolved_known_ipv6_hostname_(false), additional_resolver_flags_(0), fallback_to_proctask_(true) { @@ -1824,12 +1825,12 @@ HostResolverImpl::HostResolverImpl( EnsureDnsReloaderInit(); #endif - // TODO(szym): Remove when received_dns_config_ is removed, once - // http://crbug.com/137914 is resolved. { DnsConfig dns_config; NetworkChangeNotifier::GetDnsConfig(&dns_config); received_dns_config_ = dns_config.IsValid(); + // Conservatively assume local IPv6 is needed when DnsConfig is not valid. + use_local_ipv6_ = !dns_config.IsValid() || dns_config.use_local_ipv6; } fallback_to_proctask_ = !ConfigureAsyncDnsNoFallbackFieldTrial(); @@ -2142,7 +2143,7 @@ HostResolverImpl::Key HostResolverImpl::GetEffectiveKeyForRequest( AddressFamily effective_address_family = info.address_family(); if (info.address_family() == ADDRESS_FAMILY_UNSPECIFIED) { - if (probe_ipv6_support_) { + if (probe_ipv6_support_ && !use_local_ipv6_) { base::TimeTicks start_time = base::TimeTicks::Now(); // Google DNS address. const uint8 kIPv6Address[] = @@ -2266,6 +2267,8 @@ void HostResolverImpl::OnDNSChanged() { // TODO(szym): Remove once http://crbug.com/137914 is resolved. received_dns_config_ = dns_config.IsValid(); + // Conservatively assume local IPv6 is needed when DnsConfig is not valid. + use_local_ipv6_ = !dns_config.IsValid() || dns_config.use_local_ipv6; num_dns_failures_ = 0; diff --git a/net/dns/host_resolver_impl.h b/net/dns/host_resolver_impl.h index 2d93258..e7f5f65 100644 --- a/net/dns/host_resolver_impl.h +++ b/net/dns/host_resolver_impl.h @@ -279,6 +279,10 @@ class NET_EXPORT HostResolverImpl // explicit setting in |default_address_family_| is used. bool probe_ipv6_support_; + // True if DnsConfigService detected that system configuration depends on + // local IPv6 connectivity. Disables probing. + bool use_local_ipv6_; + // True iff ProcTask has successfully resolved a hostname known to have IPv6 // addresses using ADDRESS_FAMILY_UNSPECIFIED. Reset on IP address change. bool resolved_known_ipv6_hostname_; |