summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorszym@chromium.org <szym@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-09-17 12:24:52 +0000
committerszym@chromium.org <szym@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-09-17 12:24:52 +0000
commitc9fa8f31d868cce1592bca5c9989d4872ecfe6fb (patch)
treec301e727c758af2bc5d5bc77d1040873ea010b27 /net
parenta6751cc0130fc463583216c82c9555cd711b24a6 (diff)
downloadchromium_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.h10
-rw-r--r--net/dns/dns_config_service.cc8
-rw-r--r--net/dns/dns_config_service.h5
-rw-r--r--net/dns/dns_config_service_win.cc194
-rw-r--r--net/dns/dns_config_service_win.h18
-rw-r--r--net/dns/dns_config_service_win_unittest.cc39
-rw-r--r--net/dns/host_resolver_impl.cc9
-rw-r--r--net/dns/host_resolver_impl.h4
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_;