summaryrefslogtreecommitdiff
path: root/chromium/net/dns
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2017-07-12 14:07:37 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2017-07-17 10:29:26 +0000
commitec02ee4181c49b61fce1c8fb99292dbb8139cc90 (patch)
tree25cde714b2b71eb639d1cd53f5a22e9ba76e14ef /chromium/net/dns
parentbb09965444b5bb20b096a291445170876225268d (diff)
downloadqtwebengine-chromium-ec02ee4181c49b61fce1c8fb99292dbb8139cc90.tar.gz
BASELINE: Update Chromium to 59.0.3071.134
Change-Id: Id02ef6fb2204c5fd21668a1c3e6911c83b17585a Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/net/dns')
-rw-r--r--chromium/net/dns/dns_protocol.h10
-rw-r--r--chromium/net/dns/dns_query.cc23
-rw-r--r--chromium/net/dns/dns_reloader.cc2
-rw-r--r--chromium/net/dns/dns_response.cc24
-rw-r--r--chromium/net/dns/dns_util.cc83
-rw-r--r--chromium/net/dns/dns_util.h20
-rw-r--r--chromium/net/dns/dns_util_unittest.cc48
-rw-r--r--chromium/net/dns/fuzzed_host_resolver.cc3
-rw-r--r--chromium/net/dns/fuzzed_host_resolver.h3
-rw-r--r--chromium/net/dns/host_cache.h6
-rw-r--r--chromium/net/dns/host_resolver.cc6
-rw-r--r--chromium/net/dns/host_resolver.h11
-rw-r--r--chromium/net/dns/host_resolver_impl.cc169
-rw-r--r--chromium/net/dns/host_resolver_impl.h16
-rw-r--r--chromium/net/dns/host_resolver_impl_unittest.cc180
-rw-r--r--chromium/net/dns/mapped_host_resolver.cc8
-rw-r--r--chromium/net/dns/mapped_host_resolver.h4
17 files changed, 355 insertions, 261 deletions
diff --git a/chromium/net/dns/dns_protocol.h b/chromium/net/dns/dns_protocol.h
index 416738a2bed..2c4478c4cad 100644
--- a/chromium/net/dns/dns_protocol.h
+++ b/chromium/net/dns/dns_protocol.h
@@ -135,12 +135,12 @@ static const uint8_t kRcodeNXDOMAIN = 3;
static const uint8_t kRcodeNOTIMP = 4;
static const uint8_t kRcodeREFUSED = 5;
-// DNS flags.
+// DNS header flags.
+//
+// https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-12
static const uint16_t kFlagResponse = 0x8000;
-static const uint16_t kFlagRA = 0x80;
-static const uint16_t kFlagRD = 0x100;
-static const uint16_t kFlagTC = 0x200;
-static const uint16_t kFlagAA = 0x400;
+static const uint16_t kFlagRD = 0x100; // Recursion Desired - query flag.
+static const uint16_t kFlagTC = 0x200; // Truncated - server flag.
} // namespace dns_protocol
diff --git a/chromium/net/dns/dns_query.cc b/chromium/net/dns/dns_query.cc
index aa9bc70454e..ac74ca47961 100644
--- a/chromium/net/dns/dns_query.cc
+++ b/chromium/net/dns/dns_query.cc
@@ -13,14 +13,19 @@
namespace net {
+namespace {
+
+const size_t kHeaderSize = sizeof(dns_protocol::Header);
+
+} // namespace
+
// DNS query consists of a 12-byte header followed by a question section.
// For details, see RFC 1035 section 4.1.1. This header template sets RD
// bit, which directs the name server to pursue query recursively, and sets
// the QDCOUNT to 1, meaning the question section has a single entry.
DnsQuery::DnsQuery(uint16_t id, const base::StringPiece& qname, uint16_t qtype)
: qname_size_(qname.size()),
- io_buffer_(
- new IOBufferWithSize(sizeof(dns_protocol::Header) + question_size())),
+ io_buffer_(new IOBufferWithSize(kHeaderSize + question_size())),
header_(reinterpret_cast<dns_protocol::Header*>(io_buffer_->data())) {
DCHECK(!DNSDomainToString(qname).empty());
*header_ = {};
@@ -29,8 +34,8 @@ DnsQuery::DnsQuery(uint16_t id, const base::StringPiece& qname, uint16_t qtype)
header_->qdcount = base::HostToNet16(1);
// Write question section after the header.
- base::BigEndianWriter writer(
- io_buffer_->data() + sizeof(dns_protocol::Header), question_size());
+ base::BigEndianWriter writer(io_buffer_->data() + kHeaderSize,
+ question_size());
writer.WriteBytes(qname.data(), qname.size());
writer.WriteU16(qtype);
writer.WriteU16(dns_protocol::kClassIN);
@@ -48,20 +53,18 @@ uint16_t DnsQuery::id() const {
}
base::StringPiece DnsQuery::qname() const {
- return base::StringPiece(io_buffer_->data() + sizeof(dns_protocol::Header),
- qname_size_);
+ return base::StringPiece(io_buffer_->data() + kHeaderSize, qname_size_);
}
uint16_t DnsQuery::qtype() const {
uint16_t type;
- base::ReadBigEndian<uint16_t>(
- io_buffer_->data() + sizeof(dns_protocol::Header) + qname_size_, &type);
+ base::ReadBigEndian<uint16_t>(io_buffer_->data() + kHeaderSize + qname_size_,
+ &type);
return type;
}
base::StringPiece DnsQuery::question() const {
- return base::StringPiece(io_buffer_->data() + sizeof(dns_protocol::Header),
- question_size());
+ return base::StringPiece(io_buffer_->data() + kHeaderSize, question_size());
}
void DnsQuery::set_flags(uint16_t flags) {
diff --git a/chromium/net/dns/dns_reloader.cc b/chromium/net/dns/dns_reloader.cc
index 74534e6b1ba..5e9165e2d15 100644
--- a/chromium/net/dns/dns_reloader.cc
+++ b/chromium/net/dns/dns_reloader.cc
@@ -92,7 +92,7 @@ class DnsReloader : public NetworkChangeNotifier::DNSObserver {
base::Lock lock_; // Protects resolver_generation_.
int resolver_generation_;
- friend struct base::DefaultLazyInstanceTraits<DnsReloader>;
+ friend struct base::LazyInstanceTraitsBase<DnsReloader>;
// We use thread local storage to identify which ReloadState to interact with.
static base::ThreadLocalStorage::StaticSlot tls_index_;
diff --git a/chromium/net/dns/dns_response.cc b/chromium/net/dns/dns_response.cc
index f168a255f39..5d234244a09 100644
--- a/chromium/net/dns/dns_response.cc
+++ b/chromium/net/dns/dns_response.cc
@@ -21,6 +21,8 @@ namespace net {
namespace {
+const size_t kHeaderSize = sizeof(dns_protocol::Header);
+
const uint8_t kRcodeMask = 0xf;
} // namespace
@@ -185,30 +187,25 @@ bool DnsResponse::InitParse(int nbytes, const DnsQuery& query) {
return false;
// Match the question section.
- const size_t hdr_size = sizeof(dns_protocol::Header);
const base::StringPiece question = query.question();
- if (question != base::StringPiece(io_buffer_->data() + hdr_size,
- question.size())) {
+ if (question !=
+ base::StringPiece(io_buffer_->data() + kHeaderSize, question.size())) {
return false;
}
// Construct the parser.
- parser_ = DnsRecordParser(io_buffer_->data(),
- nbytes,
- hdr_size + question.size());
+ parser_ = DnsRecordParser(io_buffer_->data(), nbytes,
+ kHeaderSize + question.size());
return true;
}
bool DnsResponse::InitParseWithoutQuery(int nbytes) {
DCHECK_GE(nbytes, 0);
- size_t hdr_size = sizeof(dns_protocol::Header);
-
- if (nbytes < static_cast<int>(hdr_size) || nbytes >= io_buffer_->size())
+ if (nbytes < static_cast<int>(kHeaderSize) || nbytes >= io_buffer_->size())
return false;
- parser_ = DnsRecordParser(
- io_buffer_->data(), nbytes, hdr_size);
+ parser_ = DnsRecordParser(io_buffer_->data(), nbytes, kHeaderSize);
unsigned qdcount = base::NetToHost16(header()->qdcount);
for (unsigned i = 0; i < qdcount; ++i) {
@@ -250,10 +247,9 @@ base::StringPiece DnsResponse::qname() const {
// The response is HEADER QNAME QTYPE QCLASS ANSWER.
// |parser_| is positioned at the beginning of ANSWER, so the end of QNAME is
// two uint16_ts before it.
- const size_t hdr_size = sizeof(dns_protocol::Header);
const size_t qname_size =
- parser_.GetOffset() - 2 * sizeof(uint16_t) - hdr_size;
- return base::StringPiece(io_buffer_->data() + hdr_size, qname_size);
+ parser_.GetOffset() - 2 * sizeof(uint16_t) - kHeaderSize;
+ return base::StringPiece(io_buffer_->data() + kHeaderSize, qname_size);
}
uint16_t DnsResponse::qtype() const {
diff --git a/chromium/net/dns/dns_util.cc b/chromium/net/dns/dns_util.cc
index 217aedc5001..8eff1c6425e 100644
--- a/chromium/net/dns/dns_util.cc
+++ b/chromium/net/dns/dns_util.cc
@@ -10,10 +10,21 @@
#include <cstring>
#include "base/metrics/field_trial.h"
+#include "base/metrics/histogram_macros.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "build/build_config.h"
#include "net/base/address_list.h"
+#include "net/dns/dns_protocol.h"
+
+namespace {
+
+// RFC 1035, section 2.3.4: labels 63 octets or less.
+// Section 3.1: Each label is represented as a one octet length field followed
+// by that number of octets.
+const int kMaxLabelLength = 63;
+
+} // namespace
#if defined(OS_POSIX)
#include <netinet/in.h>
@@ -34,12 +45,13 @@ namespace net {
// Based on DJB's public domain code.
bool DNSDomainFromDot(const base::StringPiece& dotted, std::string* out) {
const char* buf = dotted.data();
- unsigned n = dotted.size();
- char label[63];
+ size_t n = dotted.size();
+ char label[kMaxLabelLength];
size_t labellen = 0; /* <= sizeof label */
- char name[255];
+ char name[dns_protocol::kMaxNameLength];
size_t namelen = 0; /* <= sizeof name */
char ch;
+ bool valid_name = true;
for (;;) {
if (!n)
@@ -60,9 +72,16 @@ bool DNSDomainFromDot(const base::StringPiece& dotted, std::string* out) {
}
if (labellen >= sizeof label)
return false;
+ if (!IsValidHostLabelCharacter(ch, labellen == 0)) {
+ // TODO(palmer): In the future, when we can remove support for invalid
+ // names, return false here instead (and remove the UMA counter).
+ valid_name = false;
+ }
label[labellen++] = ch;
}
+ UMA_HISTOGRAM_BOOLEAN("Net.ValidDNSName", valid_name);
+
// Allow empty label at end of name to disable suffix search.
if (labellen) {
if (namelen + labellen + 1 > sizeof name)
@@ -88,6 +107,11 @@ bool IsValidDNSDomain(const base::StringPiece& dotted) {
return DNSDomainFromDot(dotted, &dns_formatted);
}
+bool IsValidHostLabelCharacter(char c, bool is_first_char) {
+ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
+ (c >= '0' && c <= '9') || (!is_first_char && c == '-') || c == '_';
+}
+
std::string DNSDomainToString(const base::StringPiece& domain) {
std::string ret;
@@ -96,7 +120,7 @@ std::string DNSDomainToString(const base::StringPiece& domain) {
if (domain[i] < 0)
return std::string();
#endif
- if (domain[i] > 63)
+ if (domain[i] > kMaxLabelLength)
return std::string();
if (i)
@@ -110,57 +134,6 @@ std::string DNSDomainToString(const base::StringPiece& domain) {
return ret;
}
-bool HaveOnlyLoopbackAddresses() {
-#if defined(OS_ANDROID)
- return android::HaveOnlyLoopbackAddresses();
-#elif defined(OS_NACL)
- NOTIMPLEMENTED();
- return false;
-#elif defined(OS_POSIX)
- struct ifaddrs* interface_addr = NULL;
- int rv = getifaddrs(&interface_addr);
- if (rv != 0) {
- DVLOG(1) << "getifaddrs() failed with errno = " << errno;
- return false;
- }
-
- bool result = true;
- for (struct ifaddrs* interface = interface_addr;
- interface != NULL;
- interface = interface->ifa_next) {
- if (!(IFF_UP & interface->ifa_flags))
- continue;
- if (IFF_LOOPBACK & interface->ifa_flags)
- continue;
- const struct sockaddr* addr = interface->ifa_addr;
- if (!addr)
- continue;
- if (addr->sa_family == AF_INET6) {
- // Safe cast since this is AF_INET6.
- const struct sockaddr_in6* addr_in6 =
- reinterpret_cast<const struct sockaddr_in6*>(addr);
- const struct in6_addr* sin6_addr = &addr_in6->sin6_addr;
- if (IN6_IS_ADDR_LOOPBACK(sin6_addr) || IN6_IS_ADDR_LINKLOCAL(sin6_addr))
- continue;
- }
- if (addr->sa_family != AF_INET6 && addr->sa_family != AF_INET)
- continue;
-
- result = false;
- break;
- }
- freeifaddrs(interface_addr);
- return result;
-#elif defined(OS_WIN)
- // TODO(wtc): implement with the GetAdaptersAddresses function.
- NOTIMPLEMENTED();
- return false;
-#else
- NOTIMPLEMENTED();
- return false;
-#endif // defined(various platforms)
-}
-
#if !defined(OS_NACL)
namespace {
diff --git a/chromium/net/dns/dns_util.h b/chromium/net/dns/dns_util.h
index c81ffde34ad..81eb1a28ba1 100644
--- a/chromium/net/dns/dns_util.h
+++ b/chromium/net/dns/dns_util.h
@@ -27,16 +27,26 @@ NET_EXPORT_PRIVATE bool DNSDomainFromDot(const base::StringPiece& dotted,
// Checks that a hostname is valid. Simple wrapper around DNSDomainFromDot.
NET_EXPORT_PRIVATE bool IsValidDNSDomain(const base::StringPiece& dotted);
+// Returns true if the character is valid in a DNS hostname label, whether in
+// the first position or later in the label.
+//
+// This function asserts a looser form of the restrictions in RFC 7719 (section
+// 2; https://tools.ietf.org/html/rfc7719#section-2): hostnames can include
+// characters a-z, A-Z, 0-9, -, and _, and any of those characters (except -)
+// are legal in the first position. The looser rules are necessary to support
+// service records (initial _), and non-compliant but attested hostnames that
+// include _. These looser rules also allow Punycode and hence IDN.
+//
+// TODO(palmer): In the future, when we can remove support for invalid names,
+// this can be a private implementation detail of |DNSDomainFromDot|, and need
+// not be NET_EXPORT_PRIVATE.
+NET_EXPORT_PRIVATE bool IsValidHostLabelCharacter(char c, bool is_first_char);
+
// DNSDomainToString converts a domain in DNS format to a dotted string.
// Excludes the dot at the end.
NET_EXPORT_PRIVATE std::string DNSDomainToString(
const base::StringPiece& domain);
-// Returns true if it can determine that only loopback addresses are configured.
-// i.e. if only 127.0.0.1 and ::1 are routable.
-// Also returns false if it cannot determine this.
-NET_EXPORT_PRIVATE bool HaveOnlyLoopbackAddresses();
-
#if !defined(OS_NACL)
NET_EXPORT_PRIVATE
base::TimeDelta GetTimeDeltaForConnectionTypeFromFieldTrialOrDefault(
diff --git a/chromium/net/dns/dns_util_unittest.cc b/chromium/net/dns/dns_util_unittest.cc
index 1d534716b6a..7b01d4263b9 100644
--- a/chromium/net/dns/dns_util_unittest.cc
+++ b/chromium/net/dns/dns_util_unittest.cc
@@ -6,6 +6,28 @@
#include "testing/gtest/include/gtest/gtest.h"
+namespace {
+
+bool IsValidDNSDomainName(const char* name) {
+ size_t length = strlen(name);
+ for (size_t i = 0; i < length; ++i) {
+ if (name[i] == '.') {
+ if (i == 0 || name[i - 1] == '.') {
+ return false;
+ }
+ continue;
+ }
+
+ if (!net::IsValidHostLabelCharacter(name[i],
+ i == 0 || name[i - 1] == '.')) {
+ return false;
+ }
+ }
+ return true;
+}
+
+} // namespace
+
namespace net {
class DNSUtilTest : public testing::Test {
@@ -69,4 +91,30 @@ TEST_F(DNSUtilTest, DNSDomainToString) {
EXPECT_EQ("", DNSDomainToString("\x06"));
}
+TEST_F(DNSUtilTest, IsValidDNSDomain) {
+ const char* const bad_hostnames[] = {
+ "%20%20noodles.blorg", "noo dles.blorg ", "noo dles.blorg. ",
+ "^noodles.blorg", "noodles^.blorg", "noo&dles.blorg",
+ "noodles.blorg`", "www.-noodles.blorg",
+ };
+
+ // TODO(palmer): In the future, when we can remove support for invalid names,
+ // change the calls to from |IsValidDNSDomainName| to |IsValidDNSDomain|, and
+ // remove |IsValidDNSDomainName| (defined above).
+
+ for (size_t i = 0; i < arraysize(bad_hostnames); ++i) {
+ EXPECT_FALSE(IsValidDNSDomainName(bad_hostnames[i]));
+ }
+
+ const char* const good_hostnames[] = {
+ "www.noodles.blorg", "1www.noodles.blorg", "www.2noodles.blorg",
+ "www.n--oodles.blorg", "www.noodl_es.blorg", "www.no-_odles.blorg",
+ "www_.noodles.blorg", "www.noodles.blorg.", "_privet._tcp.local",
+ };
+
+ for (size_t i = 0; i < arraysize(good_hostnames); ++i) {
+ EXPECT_TRUE(IsValidDNSDomainName(good_hostnames[i]));
+ }
+}
+
} // namespace net
diff --git a/chromium/net/dns/fuzzed_host_resolver.cc b/chromium/net/dns/fuzzed_host_resolver.cc
index d8e02325206..f44f3674ccf 100644
--- a/chromium/net/dns/fuzzed_host_resolver.cc
+++ b/chromium/net/dns/fuzzed_host_resolver.cc
@@ -223,7 +223,8 @@ void FuzzedHostResolver::SetDnsClientEnabled(bool enabled) {
SetDnsClient(std::move(dns_client));
}
-bool FuzzedHostResolver::IsIPv6Reachable(const NetLogWithSource& net_log) {
+bool FuzzedHostResolver::IsGloballyReachable(const IPAddress& dest,
+ const NetLogWithSource& net_log) {
return is_ipv6_reachable_;
}
diff --git a/chromium/net/dns/fuzzed_host_resolver.h b/chromium/net/dns/fuzzed_host_resolver.h
index cc14578be32..7cb1b516305 100644
--- a/chromium/net/dns/fuzzed_host_resolver.h
+++ b/chromium/net/dns/fuzzed_host_resolver.h
@@ -58,7 +58,8 @@ class FuzzedHostResolver : public HostResolverImpl {
private:
// HostResolverImpl implementation:
- bool IsIPv6Reachable(const NetLogWithSource& net_log) override;
+ bool IsGloballyReachable(const IPAddress& dest,
+ const NetLogWithSource& net_log) override;
void RunLoopbackProbeJob() override;
base::FuzzedDataProvider* data_provider_;
diff --git a/chromium/net/dns/host_cache.h b/chromium/net/dns/host_cache.h
index ccda0eb9a92..37cf204e3cc 100644
--- a/chromium/net/dns/host_cache.h
+++ b/chromium/net/dns/host_cache.h
@@ -79,6 +79,9 @@ class NET_EXPORT HostCache : NON_EXPORTED_BASE(public base::NonThreadSafe) {
base::TimeTicks expires() const { return expires_; }
+ // Public for the net-internals UI.
+ int network_changes() const { return network_changes_; }
+
private:
friend class HostCache;
@@ -87,7 +90,6 @@ class NET_EXPORT HostCache : NON_EXPORTED_BASE(public base::NonThreadSafe) {
base::TimeDelta ttl,
int network_changes);
- int network_changes() const { return network_changes_; }
int total_hits() const { return total_hits_; }
int stale_hits() const { return stale_hits_; }
@@ -158,7 +160,7 @@ class NET_EXPORT HostCache : NON_EXPORTED_BASE(public base::NonThreadSafe) {
// Following are used by net_internals UI.
size_t max_entries() const;
-
+ int network_changes() const { return network_changes_; }
const EntryMap& entries() const { return entries_; }
// Creates a default cache.
diff --git a/chromium/net/dns/host_resolver.cc b/chromium/net/dns/host_resolver.cc
index f0cd91b5787..1f6dcf9b65e 100644
--- a/chromium/net/dns/host_resolver.cc
+++ b/chromium/net/dns/host_resolver.cc
@@ -132,12 +132,12 @@ void HostResolver::InitializePersistence(
const PersistCallback& persist_callback,
std::unique_ptr<const base::Value> old_data) {}
-void HostResolver::SetDefaultAddressFamily(AddressFamily address_family) {
+void HostResolver::SetNoIPv6OnWifi(bool no_ipv6_on_wifi) {
NOTREACHED();
}
-AddressFamily HostResolver::GetDefaultAddressFamily() const {
- return ADDRESS_FAMILY_UNSPECIFIED;
+bool HostResolver::GetNoIPv6OnWifi() {
+ return false;
}
// static
diff --git a/chromium/net/dns/host_resolver.h b/chromium/net/dns/host_resolver.h
index 33cdd34e720..f909e7b004e 100644
--- a/chromium/net/dns/host_resolver.h
+++ b/chromium/net/dns/host_resolver.h
@@ -213,13 +213,10 @@ class NET_EXPORT HostResolver {
const PersistCallback& persist_callback,
std::unique_ptr<const base::Value> old_data);
- // Sets the default AddressFamily to use when requests have left it
- // unspecified. For example, this could be used to restrict resolution
- // results to AF_INET by passing in ADDRESS_FAMILY_IPV4, or to
- // AF_INET6 by passing in ADDRESS_FAMILY_IPV6. See http://crbug.com/696569 for
- // why this option is necessary.
- virtual void SetDefaultAddressFamily(AddressFamily address_family);
- virtual AddressFamily GetDefaultAddressFamily() const;
+ // Sets the HostResolver to assume that IPv6 is unreachable when on a wifi
+ // connection. See https://crbug.com/696569 for further context.
+ virtual void SetNoIPv6OnWifi(bool no_ipv6_on_wifi);
+ virtual bool GetNoIPv6OnWifi();
// Creates a HostResolver implementation that queries the underlying system.
// (Except if a unit-test has changed the global HostResolverProc using
diff --git a/chromium/net/dns/host_resolver_impl.cc b/chromium/net/dns/host_resolver_impl.cc
index 7596c776269..fd4c065b7d7 100644
--- a/chromium/net/dns/host_resolver_impl.cc
+++ b/chromium/net/dns/host_resolver_impl.cc
@@ -10,6 +10,16 @@
#include <netdb.h>
#endif
+#if defined(OS_POSIX)
+#include <netinet/in.h>
+#if !defined(OS_NACL)
+#include <net/if.h>
+#if !defined(OS_ANDROID)
+#include <ifaddrs.h>
+#endif // !defined(OS_ANDROID)
+#endif // !defined(OS_NACL)
+#endif // defined(OS_POSIX)
+
#include <cmath>
#include <memory>
#include <utility>
@@ -69,6 +79,10 @@
#include "net/base/winsock_init.h"
#endif
+#if defined(OS_ANDROID)
+#include "net/android/network_library.h"
+#endif
+
namespace net {
namespace {
@@ -217,39 +231,6 @@ bool ResemblesMulticastDNSName(const std::string& hostname) {
kSuffix, kSuffixLenTrimmed);
}
-// Attempts to connect a UDP socket to |dest|:53.
-bool IsGloballyReachable(const IPAddress& dest,
- const NetLogWithSource& net_log) {
- // TODO(eroman): Remove ScopedTracker below once crbug.com/455942 is fixed.
- tracked_objects::ScopedTracker tracking_profile_1(
- FROM_HERE_WITH_EXPLICIT_FUNCTION("455942 IsGloballyReachable"));
-
- std::unique_ptr<DatagramClientSocket> socket(
- ClientSocketFactory::GetDefaultFactory()->CreateDatagramClientSocket(
- DatagramSocket::DEFAULT_BIND, RandIntCallback(), net_log.net_log(),
- net_log.source()));
- int rv = socket->Connect(IPEndPoint(dest, 53));
- if (rv != OK)
- return false;
- IPEndPoint endpoint;
- rv = socket->GetLocalAddress(&endpoint);
- if (rv != OK)
- return false;
- DCHECK_EQ(ADDRESS_FAMILY_IPV6, endpoint.GetFamily());
- const IPAddress& address = endpoint.address();
-
- bool is_link_local =
- (address.bytes()[0] == 0xFE) && ((address.bytes()[1] & 0xC0) == 0x80);
- if (is_link_local)
- return false;
-
- const uint8_t kTeredoPrefix[] = {0x20, 0x01, 0, 0};
- if (IPAddressStartsWith(address, kTeredoPrefix))
- return false;
-
- return true;
-}
-
// Provide a common macro to simplify code and readability. We must use a
// macro as the underlying HISTOGRAM macro creates static variables.
#define DNS_HISTOGRAM(name, time) UMA_HISTOGRAM_CUSTOM_TIMES(name, time, \
@@ -337,6 +318,60 @@ bool IsAllIPv4Loopback(const AddressList& addresses) {
return true;
}
+// Returns true if it can determine that only loopback addresses are configured.
+// i.e. if only 127.0.0.1 and ::1 are routable.
+// Also returns false if it cannot determine this.
+bool HaveOnlyLoopbackAddresses() {
+#if defined(OS_ANDROID)
+ return android::HaveOnlyLoopbackAddresses();
+#elif defined(OS_NACL)
+ NOTIMPLEMENTED();
+ return false;
+#elif defined(OS_POSIX)
+ struct ifaddrs* interface_addr = NULL;
+ int rv = getifaddrs(&interface_addr);
+ if (rv != 0) {
+ DVLOG(1) << "getifaddrs() failed with errno = " << errno;
+ return false;
+ }
+
+ bool result = true;
+ for (struct ifaddrs* interface = interface_addr;
+ interface != NULL;
+ interface = interface->ifa_next) {
+ if (!(IFF_UP & interface->ifa_flags))
+ continue;
+ if (IFF_LOOPBACK & interface->ifa_flags)
+ continue;
+ const struct sockaddr* addr = interface->ifa_addr;
+ if (!addr)
+ continue;
+ if (addr->sa_family == AF_INET6) {
+ // Safe cast since this is AF_INET6.
+ const struct sockaddr_in6* addr_in6 =
+ reinterpret_cast<const struct sockaddr_in6*>(addr);
+ const struct in6_addr* sin6_addr = &addr_in6->sin6_addr;
+ if (IN6_IS_ADDR_LOOPBACK(sin6_addr) || IN6_IS_ADDR_LINKLOCAL(sin6_addr))
+ continue;
+ }
+ if (addr->sa_family != AF_INET6 && addr->sa_family != AF_INET)
+ continue;
+
+ result = false;
+ break;
+ }
+ freeifaddrs(interface_addr);
+ return result;
+#elif defined(OS_WIN)
+ // TODO(wtc): implement with the GetAdaptersAddresses function.
+ NOTIMPLEMENTED();
+ return false;
+#else
+ NOTIMPLEMENTED();
+ return false;
+#endif // defined(various platforms)
+}
+
// Creates NetLog parameters when the resolve failed.
std::unique_ptr<base::Value> NetLogProcTaskFailedCallback(
uint32_t attempt_number,
@@ -2011,7 +2046,7 @@ HostResolverImpl::HostResolverImpl(
net_log_(net_log),
received_dns_config_(false),
num_dns_failures_(0),
- default_address_family_(ADDRESS_FAMILY_UNSPECIFIED),
+ assume_ipv6_failure_on_wifi_(false),
use_local_ipv6_(false),
last_ipv6_probe_result_(true),
resolved_known_ipv6_hostname_(false),
@@ -2088,7 +2123,8 @@ int HostResolverImpl::ResolveHelper(const Key& key,
}
if (ServeFromCache(key, info, &net_error, addresses, allow_stale,
stale_info)) {
- source_net_log.AddEvent(NetLogEventType::HOST_RESOLVER_IMPL_CACHE_HIT);
+ source_net_log.AddEvent(NetLogEventType::HOST_RESOLVER_IMPL_CACHE_HIT,
+ addresses->CreateNetLogCallback());
// |ServeFromCache()| will set |*stale_info| as needed.
RunCacheHitCallbacks(key, info);
return net_error;
@@ -2096,7 +2132,8 @@ int HostResolverImpl::ResolveHelper(const Key& key,
// TODO(szym): Do not do this if nsswitch.conf instructs not to.
// http://crbug.com/117655
if (ServeFromHosts(key, info, addresses)) {
- source_net_log.AddEvent(NetLogEventType::HOST_RESOLVER_IMPL_HOSTS_HIT);
+ source_net_log.AddEvent(NetLogEventType::HOST_RESOLVER_IMPL_HOSTS_HIT,
+ addresses->CreateNetLogCallback());
MakeNotStale(stale_info);
return OK;
}
@@ -2185,13 +2222,13 @@ int HostResolverImpl::ResolveStaleFromCache(
return rv;
}
-void HostResolverImpl::SetDefaultAddressFamily(AddressFamily address_family) {
+void HostResolverImpl::SetNoIPv6OnWifi(bool no_ipv6_on_wifi) {
DCHECK(CalledOnValidThread());
- default_address_family_ = address_family;
+ assume_ipv6_failure_on_wifi_ = no_ipv6_on_wifi;
}
-AddressFamily HostResolverImpl::GetDefaultAddressFamily() const {
- return default_address_family_;
+bool HostResolverImpl::GetNoIPv6OnWifi() {
+ return assume_ipv6_failure_on_wifi_;
}
bool HostResolverImpl::ResolveAsIP(const Key& key,
@@ -2206,11 +2243,6 @@ bool HostResolverImpl::ResolveAsIP(const Key& key,
*net_error = OK;
AddressFamily family = GetAddressFamily(*ip_address);
- if (family == ADDRESS_FAMILY_IPV6 &&
- default_address_family_ == ADDRESS_FAMILY_IPV4) {
- // Don't return IPv6 addresses if default address family is set to IPv4.
- *net_error = ERR_NAME_NOT_RESOLVED;
- }
if (key.address_family != ADDRESS_FAMILY_UNSPECIFIED &&
key.address_family != family) {
// Don't return IPv6 addresses for IPv4 queries, and vice versa.
@@ -2353,9 +2385,6 @@ HostResolverImpl::Key HostResolverImpl::GetEffectiveKeyForRequest(
info.host_resolver_flags() | additional_resolver_flags_;
AddressFamily effective_address_family = info.address_family();
- if (info.address_family() == ADDRESS_FAMILY_UNSPECIFIED)
- effective_address_family = default_address_family_;
-
if (effective_address_family == ADDRESS_FAMILY_UNSPECIFIED &&
// When resolving IPv4 literals, there's no need to probe for IPv6.
// When resolving IPv6 literals, there's no benefit to artificially
@@ -2372,6 +2401,14 @@ HostResolverImpl::Key HostResolverImpl::GetEffectiveKeyForRequest(
}
bool HostResolverImpl::IsIPv6Reachable(const NetLogWithSource& net_log) {
+ // Don't bother checking if the device is on WiFi and IPv6 is assumed to not
+ // work on WiFi.
+ if (assume_ipv6_failure_on_wifi_ &&
+ NetworkChangeNotifier::GetConnectionType() ==
+ NetworkChangeNotifier::CONNECTION_WIFI) {
+ return false;
+ }
+
// Cache the result for kIPv6ProbePeriodMs (measured from after
// IsGloballyReachable() completes).
bool cached = true;
@@ -2388,6 +2425,38 @@ bool HostResolverImpl::IsIPv6Reachable(const NetLogWithSource& net_log) {
return last_ipv6_probe_result_;
}
+bool HostResolverImpl::IsGloballyReachable(const IPAddress& dest,
+ const NetLogWithSource& net_log) {
+ // TODO(eroman): Remove ScopedTracker below once crbug.com/455942 is fixed.
+ tracked_objects::ScopedTracker tracking_profile_1(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION("455942 IsGloballyReachable"));
+
+ std::unique_ptr<DatagramClientSocket> socket(
+ ClientSocketFactory::GetDefaultFactory()->CreateDatagramClientSocket(
+ DatagramSocket::DEFAULT_BIND, RandIntCallback(), net_log.net_log(),
+ net_log.source()));
+ int rv = socket->Connect(IPEndPoint(dest, 53));
+ if (rv != OK)
+ return false;
+ IPEndPoint endpoint;
+ rv = socket->GetLocalAddress(&endpoint);
+ if (rv != OK)
+ return false;
+ DCHECK_EQ(ADDRESS_FAMILY_IPV6, endpoint.GetFamily());
+ const IPAddress& address = endpoint.address();
+
+ bool is_link_local =
+ (address.bytes()[0] == 0xFE) && ((address.bytes()[1] & 0xC0) == 0x80);
+ if (is_link_local)
+ return false;
+
+ const uint8_t kTeredoPrefix[] = {0x20, 0x01, 0, 0};
+ if (IPAddressStartsWith(address, kTeredoPrefix))
+ return false;
+
+ return true;
+}
+
void HostResolverImpl::RunLoopbackProbeJob() {
new LoopbackProbeJob(weak_ptr_factory_.GetWeakPtr(),
worker_task_runner_.get());
@@ -2523,11 +2592,11 @@ void HostResolverImpl::UpdateDNSConfig(bool config_changed) {
if (config_changed) {
// If the DNS server has changed, existing cached info could be wrong so we
- // have to drop our internal cache :( Note that OS level DNS caches, such
+ // have to expire our internal cache :( Note that OS level DNS caches, such
// as NSCD's cache should be dropped automatically by the OS when
// resolv.conf changes so we don't need to do anything to clear that cache.
if (cache_.get()) {
- cache_->clear();
+ cache_->OnNetworkChange();
cache_hit_callbacks_.clear();
}
diff --git a/chromium/net/dns/host_resolver_impl.h b/chromium/net/dns/host_resolver_impl.h
index 24062d91ae0..f78d39ecaa0 100644
--- a/chromium/net/dns/host_resolver_impl.h
+++ b/chromium/net/dns/host_resolver_impl.h
@@ -158,8 +158,8 @@ class NET_EXPORT HostResolverImpl
const PersistCallback& persist_callback,
std::unique_ptr<const base::Value> old_data) override;
- void SetDefaultAddressFamily(AddressFamily address_family) override;
- AddressFamily GetDefaultAddressFamily() const override;
+ void SetNoIPv6OnWifi(bool no_ipv6_on_wifi) override;
+ bool GetNoIPv6OnWifi() override;
void set_proc_params_for_test(const ProcTaskParams& proc_params) {
proc_params_ = proc_params;
@@ -256,7 +256,11 @@ class NET_EXPORT HostResolverImpl
// Probes IPv6 support and returns true if IPv6 support is enabled.
// Results are cached, i.e. when called repeatedly this method returns result
// from the first probe for some time before probing again.
- virtual bool IsIPv6Reachable(const NetLogWithSource& net_log);
+ bool IsIPv6Reachable(const NetLogWithSource& net_log);
+
+ // Attempts to connect a UDP socket to |dest|:53. Virtual for testing.
+ virtual bool IsGloballyReachable(const IPAddress& dest,
+ const NetLogWithSource& net_log);
// Asynchronously checks if only loopback IPs are available.
virtual void RunLoopbackProbeJob();
@@ -349,9 +353,9 @@ class NET_EXPORT HostResolverImpl
// Number of consecutive failures of DnsTask, counted when fallback succeeds.
unsigned num_dns_failures_;
- // Address family to use when the request doesn't specify one. See
- // http://crbug.com/696569 for why the option is needed.
- AddressFamily default_address_family_;
+ // True if IPv6 should not be attempted when on a WiFi connection. See
+ // https://crbug.com/696569 for further context.
+ bool assume_ipv6_failure_on_wifi_;
// True if DnsConfigService detected that system configuration depends on
// local IPv6 connectivity. Disables probing.
diff --git a/chromium/net/dns/host_resolver_impl_unittest.cc b/chromium/net/dns/host_resolver_impl_unittest.cc
index ce5776a91b6..c33515e3ad3 100644
--- a/chromium/net/dns/host_resolver_impl_unittest.cc
+++ b/chromium/net/dns/host_resolver_impl_unittest.cc
@@ -28,6 +28,7 @@
#include "base/time/time.h"
#include "net/base/address_list.h"
#include "net/base/ip_address.h"
+#include "net/base/mock_network_change_notifier.h"
#include "net/base/net_errors.h"
#include "net/dns/dns_client.h"
#include "net/dns/dns_test_util.h"
@@ -462,7 +463,8 @@ class TestHostResolverImpl : public HostResolverImpl {
private:
const bool ipv6_reachable_;
- bool IsIPv6Reachable(const NetLogWithSource& net_log) override {
+ bool IsGloballyReachable(const IPAddress& dest,
+ const NetLogWithSource& net_log) override {
return ipv6_reachable_;
}
};
@@ -2405,6 +2407,88 @@ TEST_F(HostResolverImplDnsTest, ManuallyDisableDnsClientWithPendingRequests) {
EXPECT_TRUE(requests_[2]->HasOneAddress("192.168.0.3", 80));
}
+TEST_F(HostResolverImplDnsTest, NoIPv6OnWifi) {
+ test::ScopedMockNetworkChangeNotifier notifier;
+ CreateSerialResolver(); // To guarantee order of resolutions.
+ resolver_->SetNoIPv6OnWifi(true);
+
+ notifier.mock_network_change_notifier()->SetConnectionType(
+ NetworkChangeNotifier::CONNECTION_WIFI);
+ // Needed so IPv6 availability check isn't skipped.
+ ChangeDnsConfig(CreateValidDnsConfig());
+
+ proc_->AddRule("h1", ADDRESS_FAMILY_UNSPECIFIED, "::3");
+ proc_->AddRule("h1", ADDRESS_FAMILY_IPV4, "1.0.0.1");
+ proc_->AddRule("h1", ADDRESS_FAMILY_IPV6, "::2");
+
+ CreateRequest("h1", 80, MEDIUM, ADDRESS_FAMILY_UNSPECIFIED);
+ CreateRequest("h1", 80, MEDIUM, ADDRESS_FAMILY_IPV4);
+ CreateRequest("h1", 80, MEDIUM, ADDRESS_FAMILY_IPV6);
+
+ // Start all of the requests.
+ for (size_t i = 0u; i < requests_.size(); ++i) {
+ EXPECT_THAT(requests_[i]->Resolve(), IsError(ERR_IO_PENDING)) << i;
+ }
+
+ proc_->SignalMultiple(requests_.size());
+
+ // Wait for all the requests to complete.
+ for (size_t i = 0u; i < requests_.size(); ++i) {
+ EXPECT_THAT(requests_[i]->WaitForResult(), IsOk()) << i;
+ }
+
+ // Since the requests all had the same priority and we limited the thread
+ // count to 1, they should have completed in the same order as they were
+ // requested.
+ MockHostResolverProc::CaptureList capture_list = proc_->GetCaptureList();
+ ASSERT_EQ(3u, capture_list.size());
+
+ EXPECT_EQ("h1", capture_list[0].hostname);
+ EXPECT_EQ(ADDRESS_FAMILY_IPV4, capture_list[0].address_family);
+
+ EXPECT_EQ("h1", capture_list[1].hostname);
+ EXPECT_EQ(ADDRESS_FAMILY_IPV4, capture_list[1].address_family);
+
+ EXPECT_EQ("h1", capture_list[2].hostname);
+ EXPECT_EQ(ADDRESS_FAMILY_IPV6, capture_list[2].address_family);
+
+ // Now check that the correct resolved IP addresses were returned.
+ EXPECT_TRUE(requests_[0]->HasOneAddress("1.0.0.1", 80));
+ EXPECT_TRUE(requests_[1]->HasOneAddress("1.0.0.1", 80));
+ EXPECT_TRUE(requests_[2]->HasOneAddress("::2", 80));
+
+ // Now repeat the test on non-wifi to check that IPv6 is used as normal
+ // after the network changes.
+ notifier.mock_network_change_notifier()->SetConnectionType(
+ NetworkChangeNotifier::CONNECTION_4G);
+ base::RunLoop().RunUntilIdle(); // Wait for NetworkChangeNotifier.
+
+ CreateRequest("h1", 80, MEDIUM, ADDRESS_FAMILY_UNSPECIFIED);
+ CreateRequest("h1", 80, MEDIUM, ADDRESS_FAMILY_IPV4);
+ CreateRequest("h1", 80, MEDIUM, ADDRESS_FAMILY_IPV6);
+
+ // The IPv4 and IPv6 requests are in cache, but the UNSPECIFIED one isn't.
+ EXPECT_THAT(requests_[3]->Resolve(), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(requests_[4]->Resolve(), IsOk());
+ EXPECT_THAT(requests_[5]->Resolve(), IsOk());
+
+ proc_->SignalMultiple(1);
+
+ EXPECT_THAT(requests_[3]->WaitForResult(), IsOk());
+
+ // The MockHostResolverProc has only seen one new request.
+ capture_list = proc_->GetCaptureList();
+ ASSERT_EQ(4u, capture_list.size());
+
+ EXPECT_EQ("h1", capture_list[3].hostname);
+ EXPECT_EQ(ADDRESS_FAMILY_UNSPECIFIED, capture_list[3].address_family);
+
+ // Now check that the correct resolved IP addresses were returned.
+ EXPECT_TRUE(requests_[3]->HasOneAddress("::3", 80));
+ EXPECT_TRUE(requests_[4]->HasOneAddress("1.0.0.1", 80));
+ EXPECT_TRUE(requests_[5]->HasOneAddress("::2", 80));
+}
+
TEST_F(HostResolverImplTest, ResolveLocalHostname) {
AddressList addresses;
@@ -2522,98 +2606,4 @@ TEST_F(HostResolverImplTest, CacheHitCallback) {
EXPECT_EQ(1, count2);
}
-// Tests that after changing the default AddressFamily to IPV4, requests
-// with UNSPECIFIED address family map to IPV4.
-TEST_F(HostResolverImplTest, SetDefaultAddressFamily_IPv4) {
- CreateSerialResolver(); // To guarantee order of resolutions.
-
- proc_->AddRule("h1", ADDRESS_FAMILY_IPV4, "1.0.0.1");
- proc_->AddRule("h1", ADDRESS_FAMILY_IPV6, "::2");
-
- resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_IPV4);
-
- CreateRequest("h1", 80, MEDIUM, ADDRESS_FAMILY_UNSPECIFIED);
- CreateRequest("h1", 80, MEDIUM, ADDRESS_FAMILY_IPV4);
- CreateRequest("h1", 80, MEDIUM, ADDRESS_FAMILY_IPV6);
-
- // Start all of the requests.
- for (size_t i = 0; i < requests_.size(); ++i) {
- EXPECT_EQ(ERR_IO_PENDING, requests_[i]->Resolve()) << i;
- }
-
- proc_->SignalMultiple(requests_.size());
-
- // Wait for all the requests to complete.
- for (size_t i = 0u; i < requests_.size(); ++i) {
- EXPECT_EQ(OK, requests_[i]->WaitForResult()) << i;
- }
-
- // Since the requests all had the same priority and we limited the thread
- // count to 1, they should have completed in the same order as they were
- // requested. Moreover, request0 and request1 will have been serviced by
- // the same job.
-
- MockHostResolverProc::CaptureList capture_list = proc_->GetCaptureList();
- ASSERT_EQ(2u, capture_list.size());
-
- EXPECT_EQ("h1", capture_list[0].hostname);
- EXPECT_EQ(ADDRESS_FAMILY_IPV4, capture_list[0].address_family);
-
- EXPECT_EQ("h1", capture_list[1].hostname);
- EXPECT_EQ(ADDRESS_FAMILY_IPV6, capture_list[1].address_family);
-
- // Now check that the correct resolved IP addresses were returned.
- EXPECT_TRUE(requests_[0]->HasOneAddress("1.0.0.1", 80));
- EXPECT_TRUE(requests_[1]->HasOneAddress("1.0.0.1", 80));
- EXPECT_TRUE(requests_[2]->HasOneAddress("::2", 80));
-}
-
-// This is the exact same test as SetDefaultAddressFamily_IPv4, except the
-// default family is set to IPv6 and the family of requests is flipped where
-// specified.
-TEST_F(HostResolverImplTest, SetDefaultAddressFamily_IPv6) {
- CreateSerialResolver(); // To guarantee order of resolutions.
-
- // Don't use IPv6 replacements here since some systems don't support it.
- proc_->AddRule("h1", ADDRESS_FAMILY_IPV4, "1.0.0.1");
- proc_->AddRule("h1", ADDRESS_FAMILY_IPV6, "::2");
-
- resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_IPV6);
-
- CreateRequest("h1", 80, MEDIUM, ADDRESS_FAMILY_UNSPECIFIED);
- CreateRequest("h1", 80, MEDIUM, ADDRESS_FAMILY_IPV6);
- CreateRequest("h1", 80, MEDIUM, ADDRESS_FAMILY_IPV4);
-
- // Start all of the requests.
- for (size_t i = 0; i < requests_.size(); ++i) {
- EXPECT_EQ(ERR_IO_PENDING, requests_[i]->Resolve()) << i;
- }
-
- proc_->SignalMultiple(requests_.size());
-
- // Wait for all the requests to complete.
- for (size_t i = 0u; i < requests_.size(); ++i) {
- EXPECT_EQ(OK, requests_[i]->WaitForResult()) << i;
- }
-
- // Since the requests all had the same priority and we limited the thread
- // count to 1, they should have completed in the same order as they were
- // requested. Moreover, request0 and request1 will have been serviced by
- // the same job.
-
- MockHostResolverProc::CaptureList capture_list = proc_->GetCaptureList();
- ASSERT_EQ(2u, capture_list.size());
-
- EXPECT_EQ("h1", capture_list[0].hostname);
- EXPECT_EQ(ADDRESS_FAMILY_IPV6, capture_list[0].address_family);
-
- EXPECT_EQ("h1", capture_list[1].hostname);
- EXPECT_EQ(ADDRESS_FAMILY_IPV4, capture_list[1].address_family);
-
- // Now check that the correct resolved IP addresses were returned.
- EXPECT_TRUE(requests_[0]->HasOneAddress("::2", 80));
- EXPECT_TRUE(requests_[1]->HasOneAddress("::2", 80));
- EXPECT_TRUE(requests_[2]->HasOneAddress("1.0.0.1", 80));
-}
-
} // namespace net
diff --git a/chromium/net/dns/mapped_host_resolver.cc b/chromium/net/dns/mapped_host_resolver.cc
index 39c313c74b3..dc14b65025c 100644
--- a/chromium/net/dns/mapped_host_resolver.cc
+++ b/chromium/net/dns/mapped_host_resolver.cc
@@ -56,12 +56,12 @@ std::unique_ptr<base::Value> MappedHostResolver::GetDnsConfigAsValue() const {
return impl_->GetDnsConfigAsValue();
}
-void MappedHostResolver::SetDefaultAddressFamily(AddressFamily address_family) {
- impl_->SetDefaultAddressFamily(address_family);
+void MappedHostResolver::SetNoIPv6OnWifi(bool no_ipv6_on_wifi) {
+ impl_->SetNoIPv6OnWifi(no_ipv6_on_wifi);
}
-AddressFamily MappedHostResolver::GetDefaultAddressFamily() const {
- return impl_->GetDefaultAddressFamily();
+bool MappedHostResolver::GetNoIPv6OnWifi() {
+ return impl_->GetNoIPv6OnWifi();
}
int MappedHostResolver::ApplyRules(RequestInfo* info) const {
diff --git a/chromium/net/dns/mapped_host_resolver.h b/chromium/net/dns/mapped_host_resolver.h
index 54342e2d9c1..5ae459cbae5 100644
--- a/chromium/net/dns/mapped_host_resolver.h
+++ b/chromium/net/dns/mapped_host_resolver.h
@@ -57,8 +57,8 @@ class NET_EXPORT MappedHostResolver : public HostResolver {
void SetDnsClientEnabled(bool enabled) override;
HostCache* GetHostCache() override;
std::unique_ptr<base::Value> GetDnsConfigAsValue() const override;
- void SetDefaultAddressFamily(AddressFamily address_family) override;
- AddressFamily GetDefaultAddressFamily() const override;
+ void SetNoIPv6OnWifi(bool no_ipv6_on_wifi) override;
+ bool GetNoIPv6OnWifi() override;
private:
// Modify the request |info| according to |rules_|. Returns either OK or