Refactor reading private DNS settings from Android.
This change adds two new fields to DnsConfig, dns_over_tls_active and
dns_over_tls_hostname, to store the state of Android private DNS. The
nameservers field in DnsConfig now holds the system resolver IPs
regardless of whether private DNS is active or not.
At this point, the Chrome async resolver will continue to be disabled
whenever Android private DNS is active. This will change in a future cl
when we attempt to upgrade to DoH when private DNS is active.
There are some small changes to the DoH upgrade metrics. Larger changes
will be made in a future cl once the actual upgrade logic is in place.
Bug: 985589
Change-Id: I5ecf9dc49cb480976583879cf2953282982c2dc8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1724566
Reviewed-by: Charlie Harrison <csharrison@chromium.org>
Reviewed-by: Eric Orth <ericorth@chromium.org>
Reviewed-by: Cathy Li <chili@chromium.org>
Commit-Queue: Katharine Daly <dalyk@google.com>
Cr-Commit-Position: refs/heads/master@{#687138}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchFeedFlowTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchFeedFlowTest.java
index c49a2d2..f4ec9645 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchFeedFlowTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchFeedFlowTest.java
@@ -176,7 +176,7 @@
}
@Override
public NetworkState getCurrentNetworkState() {
- return new NetworkState(true, ConnectivityManager.TYPE_WIFI, 0, null, false);
+ return new NetworkState(true, ConnectivityManager.TYPE_WIFI, 0, null, false, "");
}
}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchFlowTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchFlowTest.java
index fa0cdb4..f5ade34 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchFlowTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchFlowTest.java
@@ -77,7 +77,7 @@
}
@Override
public NetworkState getCurrentNetworkState() {
- return new NetworkState(true, ConnectivityManager.TYPE_WIFI, 0, null, false);
+ return new NetworkState(true, ConnectivityManager.TYPE_WIFI, 0, null, false, "");
}
}
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 975982b..97080e6 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -3286,6 +3286,7 @@
"android/java/src/org/chromium/net/AndroidKeyStore.java",
"android/java/src/org/chromium/net/AndroidNetworkLibrary.java",
"android/java/src/org/chromium/net/AndroidTrafficStats.java",
+ "android/java/src/org/chromium/net/DnsStatus.java",
"android/java/src/org/chromium/net/GURLUtils.java",
"android/java/src/org/chromium/net/HttpNegotiateAuthenticator.java",
"android/java/src/org/chromium/net/HttpUtil.java",
diff --git a/net/android/BUILD.gn b/net/android/BUILD.gn
index 34bd2b76..e40742a 100644
--- a/net/android/BUILD.gn
+++ b/net/android/BUILD.gn
@@ -13,6 +13,7 @@
"java/src/org/chromium/net/AndroidNetworkLibrary.java",
"java/src/org/chromium/net/AndroidTelephonyManagerBridge.java",
"java/src/org/chromium/net/AndroidTrafficStats.java",
+ "java/src/org/chromium/net/DnsStatus.java",
"java/src/org/chromium/net/GURLUtils.java",
"java/src/org/chromium/net/HttpNegotiateAuthenticator.java",
"java/src/org/chromium/net/HttpNegotiateConstants.java",
diff --git a/net/android/java/src/org/chromium/net/AndroidNetworkLibrary.java b/net/android/java/src/org/chromium/net/AndroidNetworkLibrary.java
index e5e48e4..ed09e7f 100644
--- a/net/android/java/src/org/chromium/net/AndroidNetworkLibrary.java
+++ b/net/android/java/src/org/chromium/net/AndroidNetworkLibrary.java
@@ -33,7 +33,6 @@
import org.chromium.base.compat.ApiHelperForM;
import org.chromium.base.compat.ApiHelperForN;
import org.chromium.base.compat.ApiHelperForP;
-import org.chromium.base.metrics.RecordHistogram;
import java.io.FileDescriptor;
import java.io.IOException;
@@ -48,15 +47,11 @@
import java.net.SocketException;
import java.net.SocketImpl;
import java.net.URLConnection;
-import java.net.UnknownHostException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.util.Enumeration;
-import java.util.HashSet;
import java.util.List;
-import java.util.Locale;
-import java.util.Set;
/**
* This class implements net utilities required by the net component.
@@ -70,45 +65,6 @@
// Cached value indicating if app has ACCESS_WIFI_STATE permission.
private static Boolean sHaveAccessWifiState;
- // Set of public DNS servers supporting DNS-over-HTTPS.
- private static final Set<InetAddress> sAutoDohServers = new HashSet<>();
- // Set of public DNS-over-TLS servers supporting DNS-over-HTTPS.
- private static final Set<String> sAutoDohDotServers = new HashSet<>();
-
- static {
- try {
- // Populate set of public DNS servers supporting DNS-over-HTTPS.
-
- // Google Public DNS
- sAutoDohServers.add(InetAddress.getByName("8.8.8.8"));
- sAutoDohServers.add(InetAddress.getByName("8.8.4.4"));
- sAutoDohServers.add(InetAddress.getByName("2001:4860:4860::8888"));
- sAutoDohServers.add(InetAddress.getByName("2001:4860:4860::8844"));
- // Cloudflare DNS
- sAutoDohServers.add(InetAddress.getByName("1.1.1.1"));
- sAutoDohServers.add(InetAddress.getByName("1.0.0.1"));
- sAutoDohServers.add(InetAddress.getByName("2606:4700:4700::1111"));
- sAutoDohServers.add(InetAddress.getByName("2606:4700:4700::1001"));
- // Quad9 DNS
- sAutoDohServers.add(InetAddress.getByName("9.9.9.9"));
- sAutoDohServers.add(InetAddress.getByName("149.112.112.112"));
- sAutoDohServers.add(InetAddress.getByName("2620:fe::fe"));
- sAutoDohServers.add(InetAddress.getByName("2620:fe::9"));
- } catch (UnknownHostException e) {
- throw new RuntimeException("Failed to parse IP addresses", e);
- }
-
- // Populate set of public DNS-over-TLS servers supporting DNS-over-HTTPS.
-
- // Google Public DNS
- sAutoDohDotServers.add("dns.google");
- // Cloudflare DNS
- sAutoDohDotServers.add("1dot1dot1dot1.cloudflare-dns.com");
- sAutoDohDotServers.add("cloudflare-dns.com");
- // Quad9 DNS
- sAutoDohDotServers.add("dns.quad9.net");
- }
-
/**
* @return the mime type (if any) that is associated with the file
* extension. Returns null if no corresponding mime type exists.
@@ -369,26 +325,6 @@
}
}
- /**
- * @returns result of linkProperties.isPrivateDnsActive().
- */
- static boolean isPrivateDnsActive(LinkProperties linkProperties) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && linkProperties != null) {
- return ApiHelperForP.isPrivateDnsActive(linkProperties);
- }
- return false;
- }
-
- /**
- * @returns result of linkProperties.getPrivateDnsServerName().
- */
- private static String getPrivateDnsServerName(LinkProperties linkProperties) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && linkProperties != null) {
- return ApiHelperForP.getPrivateDnsServerName(linkProperties);
- }
- return null;
- }
-
private static boolean haveAccessNetworkState() {
// This could be racy if called on multiple threads, but races will
// end in the same result so it's not a problem.
@@ -415,56 +351,38 @@
}
/**
- * Returns list of IP addresses of DNS servers.
- * If private DNS is active, then returns a 1x1 array.
+ * Returns object representing the DNS configuration for the provided
+ * network. If |network| is null, uses the active network.
*/
@TargetApi(Build.VERSION_CODES.M)
@CalledByNative
- private static byte[][] getDnsServers() {
+ public static DnsStatus getDnsStatus(Network network) {
if (!haveAccessNetworkState()) {
- return new byte[0][0];
+ return null;
}
ConnectivityManager connectivityManager =
(ConnectivityManager) ContextUtils.getApplicationContext().getSystemService(
Context.CONNECTIVITY_SERVICE);
if (connectivityManager == null) {
- return new byte[0][0];
+ return null;
}
- Network network = ApiHelperForM.getActiveNetwork(connectivityManager);
if (network == null) {
- return new byte[0][0];
+ network = ApiHelperForM.getActiveNetwork(connectivityManager);
+ }
+ if (network == null) {
+ return null;
}
LinkProperties linkProperties = connectivityManager.getLinkProperties(network);
if (linkProperties == null) {
- return new byte[0][0];
+ return null;
}
List<InetAddress> dnsServersList = linkProperties.getDnsServers();
- // Determine if any DNS servers could be auto-upgraded to DNS-over-HTTPS.
- boolean autoDoh = false;
- for (InetAddress dnsServer : dnsServersList) {
- if (sAutoDohServers.contains(dnsServer)) {
- autoDoh = true;
- break;
- }
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+ return new DnsStatus(dnsServersList, ApiHelperForP.isPrivateDnsActive(linkProperties),
+ ApiHelperForP.getPrivateDnsServerName(linkProperties));
+ } else {
+ return new DnsStatus(dnsServersList, false, "");
}
- if (isPrivateDnsActive(linkProperties)) {
- String privateDnsServerName = getPrivateDnsServerName(linkProperties);
- // If user explicitly selected a DNS-over-TLS server...
- if (privateDnsServerName != null) {
- // ...their DNS-over-HTTPS support depends on the DNS-over-TLS server name.
- autoDoh = sAutoDohDotServers.contains(privateDnsServerName.toLowerCase(Locale.US));
- }
- RecordHistogram.recordBooleanHistogram(
- "Net.DNS.Android.DotExplicit", privateDnsServerName != null);
- RecordHistogram.recordBooleanHistogram("Net.DNS.Android.AutoDohPrivate", autoDoh);
- return new byte[1][1];
- }
- RecordHistogram.recordBooleanHistogram("Net.DNS.Android.AutoDohPublic", autoDoh);
- byte[][] dnsServers = new byte[dnsServersList.size()][];
- for (int i = 0; i < dnsServersList.size(); i++) {
- dnsServers[i] = dnsServersList.get(i).getAddress();
- }
- return dnsServers;
}
/**
diff --git a/net/android/java/src/org/chromium/net/DnsStatus.java b/net/android/java/src/org/chromium/net/DnsStatus.java
new file mode 100644
index 0000000..b30ed91
--- /dev/null
+++ b/net/android/java/src/org/chromium/net/DnsStatus.java
@@ -0,0 +1,49 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.net;
+
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.annotations.JNINamespace;
+
+import java.net.InetAddress;
+import java.util.List;
+
+/**
+ * Class to access DNS server configuration.
+ */
+@JNINamespace("net::android")
+public class DnsStatus {
+ private final List<InetAddress> mDnsServers;
+
+ private final boolean mPrivateDnsActive;
+
+ private final String mPrivateDnsServerName;
+
+ public DnsStatus(
+ List<InetAddress> dnsServers, boolean privateDnsActive, String privateDnsServerName) {
+ mDnsServers = dnsServers;
+ mPrivateDnsActive = privateDnsActive;
+ mPrivateDnsServerName = privateDnsServerName;
+ }
+
+ @CalledByNative
+ public byte[][] getDnsServers() {
+ byte[][] dnsServers = new byte[mDnsServers.size()][];
+ for (int i = 0; i < mDnsServers.size(); i++) {
+ dnsServers[i] = mDnsServers.get(i).getAddress();
+ }
+ return dnsServers;
+ }
+
+ @CalledByNative
+ public boolean getPrivateDnsActive() {
+ return mPrivateDnsActive;
+ }
+
+ @CalledByNative
+ public String getPrivateDnsServerName() {
+ return mPrivateDnsServerName;
+ }
+}
diff --git a/net/android/java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.java b/net/android/java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.java
index 78606cdd..b717fe6a 100644
--- a/net/android/java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.java
+++ b/net/android/java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.java
@@ -65,14 +65,17 @@
private final String mNetworkIdentifier;
// Indicates if this network is using DNS-over-TLS.
private final boolean mIsPrivateDnsActive;
+ // Indicates the DNS-over-TLS server in use, if specified.
+ private final String mPrivateDnsServerName;
public NetworkState(boolean connected, int type, int subtype, String networkIdentifier,
- boolean isPrivateDnsActive) {
+ boolean isPrivateDnsActive, String privateDnsServerName) {
mConnected = connected;
mType = type;
mSubtype = subtype;
mNetworkIdentifier = networkIdentifier == null ? "" : networkIdentifier;
mIsPrivateDnsActive = isPrivateDnsActive;
+ mPrivateDnsServerName = privateDnsServerName == null ? "" : privateDnsServerName;
}
public boolean isConnected() {
@@ -164,6 +167,13 @@
public boolean isPrivateDnsActive() {
return mIsPrivateDnsActive;
}
+
+ /**
+ * Returns the DNS-over-TLS server in use, if specified.
+ */
+ public String getPrivateDnsServerName() {
+ return mPrivateDnsServerName;
+ }
}
/** Queries the ConnectivityManager for information about the current connection. */
@@ -232,14 +242,18 @@
}
networkInfo = processActiveNetworkInfo(networkInfo);
if (networkInfo == null) {
- return new NetworkState(false, -1, -1, null, false);
+ return new NetworkState(false, -1, -1, null, false, "");
}
if (network != null) {
- return new NetworkState(true, networkInfo.getType(), networkInfo.getSubtype(),
- String.valueOf(networkToNetId(network)),
- Build.VERSION.SDK_INT >= Build.VERSION_CODES.P
- && AndroidNetworkLibrary.isPrivateDnsActive(
- mConnectivityManager.getLinkProperties(network)));
+ DnsStatus dnsStatus = AndroidNetworkLibrary.getDnsStatus(network);
+ if (dnsStatus == null) {
+ return new NetworkState(true, networkInfo.getType(), networkInfo.getSubtype(),
+ String.valueOf(networkToNetId(network)), false, "");
+ } else {
+ return new NetworkState(true, networkInfo.getType(), networkInfo.getSubtype(),
+ String.valueOf(networkToNetId(network)),
+ dnsStatus.getPrivateDnsActive(), dnsStatus.getPrivateDnsServerName());
+ }
}
assert Build.VERSION.SDK_INT < Build.VERSION_CODES.M;
// If Wifi, then fetch SSID also
@@ -247,14 +261,14 @@
// Since Android 4.2 the SSID can be retrieved from NetworkInfo.getExtraInfo().
if (networkInfo.getExtraInfo() != null && !"".equals(networkInfo.getExtraInfo())) {
return new NetworkState(true, networkInfo.getType(), networkInfo.getSubtype(),
- networkInfo.getExtraInfo(), false);
+ networkInfo.getExtraInfo(), false, "");
}
// Fetch WiFi SSID directly from WifiManagerDelegate if not in NetworkInfo.
return new NetworkState(true, networkInfo.getType(), networkInfo.getSubtype(),
- wifiManagerDelegate.getWifiSsid(), false);
+ wifiManagerDelegate.getWifiSsid(), false, "");
}
return new NetworkState(
- true, networkInfo.getType(), networkInfo.getSubtype(), null, false);
+ true, networkInfo.getType(), networkInfo.getSubtype(), null, false, "");
}
// Fetches NetworkInfo and records UMA for NullPointerExceptions.
@@ -1128,7 +1142,9 @@
NetworkState networkState = getCurrentNetworkState();
if (networkState.getConnectionType() != mNetworkState.getConnectionType()
|| !networkState.getNetworkIdentifier().equals(mNetworkState.getNetworkIdentifier())
- || networkState.isPrivateDnsActive() != mNetworkState.isPrivateDnsActive()) {
+ || networkState.isPrivateDnsActive() != mNetworkState.isPrivateDnsActive()
+ || !networkState.getPrivateDnsServerName().equals(
+ mNetworkState.getPrivateDnsServerName())) {
mObserver.onConnectionTypeChanged(networkState.getConnectionType());
}
if (networkState.getConnectionType() != mNetworkState.getConnectionType()
diff --git a/net/android/javatests/src/org/chromium/net/NetworkChangeNotifierTest.java b/net/android/javatests/src/org/chromium/net/NetworkChangeNotifierTest.java
index 4d86bb1..811e566e 100644
--- a/net/android/javatests/src/org/chromium/net/NetworkChangeNotifierTest.java
+++ b/net/android/javatests/src/org/chromium/net/NetworkChangeNotifierTest.java
@@ -190,6 +190,7 @@
private int mNetworkType;
private int mNetworkSubtype;
private boolean mIsPrivateDnsActive;
+ private String mPrivateDnsServerName;
private NetworkCallback mLastRegisteredNetworkCallback;
private NetworkCallback mLastRegisteredDefaultNetworkCallback;
@@ -199,7 +200,7 @@
mNetworkType == ConnectivityManager.TYPE_WIFI
? wifiManagerDelegate.getWifiSsid()
: null,
- mIsPrivateDnsActive);
+ mIsPrivateDnsActive, mPrivateDnsServerName);
}
@Override
@@ -278,6 +279,10 @@
mIsPrivateDnsActive = isPrivateDnsActive;
}
+ public void setPrivateDnsServerName(String privateDnsServerName) {
+ mPrivateDnsServerName = privateDnsServerName;
+ }
+
public NetworkCallback getLastRegisteredNetworkCallback() {
return mLastRegisteredNetworkCallback;
}
@@ -656,15 +661,20 @@
// We should be notified if use of DNS-over-TLS changes.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
- // Verify notification for enabling.
+ // Verify notification for enabling private DNS.
mConnectivityDelegate.setIsPrivateDnsActive(true);
mConnectivityDelegate.getDefaultNetworkCallback().onLinkPropertiesChanged(null, null);
Assert.assertTrue(observer.hasReceivedNotification());
observer.resetHasReceivedNotification();
+ // Verify notification for specifying private DNS server.
+ mConnectivityDelegate.setPrivateDnsServerName("dotserver.com");
+ mConnectivityDelegate.getDefaultNetworkCallback().onLinkPropertiesChanged(null, null);
+ Assert.assertTrue(observer.hasReceivedNotification());
+ observer.resetHasReceivedNotification();
// Verify no notification for no change.
mConnectivityDelegate.getDefaultNetworkCallback().onLinkPropertiesChanged(null, null);
Assert.assertFalse(observer.hasReceivedNotification());
- // Verify notification for disbling.
+ // Verify notification for disabling.
mConnectivityDelegate.setIsPrivateDnsActive(false);
mConnectivityDelegate.getDefaultNetworkCallback().onLinkPropertiesChanged(null, null);
Assert.assertTrue(observer.hasReceivedNotification());
diff --git a/net/android/network_library.cc b/net/android/network_library.cc
index 6ed1e809..c7c7644 100644
--- a/net/android/network_library.cc
+++ b/net/android/network_library.cc
@@ -11,6 +11,7 @@
#include "base/logging.h"
#include "net/dns/public/dns_protocol.h"
#include "net/net_jni_headers/AndroidNetworkLibrary_jni.h"
+#include "net/net_jni_headers/DnsStatus_jni.h"
using base::android::AttachCurrentThread;
using base::android::ConvertJavaStringToUTF8;
@@ -136,15 +137,20 @@
}
internal::ConfigParsePosixResult GetDnsServers(
- std::vector<IPEndPoint>* dns_servers) {
+ std::vector<IPEndPoint>* dns_servers,
+ bool* dns_over_tls_active,
+ std::string* dns_over_tls_hostname) {
JNIEnv* env = AttachCurrentThread();
+ // Get the DNS status for the active network.
+ ScopedJavaLocalRef<jobject> result =
+ Java_AndroidNetworkLibrary_getDnsStatus(env, nullptr /* network */);
+ if (result.is_null())
+ return internal::CONFIG_PARSE_POSIX_NO_NAMESERVERS;
+
+ // Parse the DNS servers.
std::vector<std::string> dns_servers_strings;
base::android::JavaArrayOfByteArrayToStringVector(
- env, Java_AndroidNetworkLibrary_getDnsServers(env), &dns_servers_strings);
- if (dns_servers_strings.size() == 0)
- return internal::CONFIG_PARSE_POSIX_NO_NAMESERVERS;
- if (dns_servers_strings.size() == 1 && dns_servers_strings[0].size() == 1)
- return internal::CONFIG_PARSE_POSIX_PRIVATE_DNS_ACTIVE;
+ env, Java_DnsStatus_getDnsServers(env, result), &dns_servers_strings);
for (const std::string& dns_address_string : dns_servers_strings) {
IPAddress dns_address(
reinterpret_cast<const uint8_t*>(dns_address_string.c_str()),
@@ -152,7 +158,13 @@
IPEndPoint dns_server(dns_address, dns_protocol::kDefaultPort);
dns_servers->push_back(dns_server);
}
- return internal::CONFIG_PARSE_POSIX_OK;
+
+ *dns_over_tls_active = Java_DnsStatus_getPrivateDnsActive(env, result);
+ *dns_over_tls_hostname = base::android::ConvertJavaStringToUTF8(
+ Java_DnsStatus_getPrivateDnsServerName(env, result));
+
+ return dns_servers->size() ? internal::CONFIG_PARSE_POSIX_OK
+ : internal::CONFIG_PARSE_POSIX_NO_NAMESERVERS;
}
void TagSocket(SocketDescriptor socket, uid_t uid, int32_t tag) {
diff --git a/net/android/network_library.h b/net/android/network_library.h
index 5bce314..56572b2 100644
--- a/net/android/network_library.h
+++ b/net/android/network_library.h
@@ -91,13 +91,17 @@
// empty value is returned.
NET_EXPORT_PRIVATE base::Optional<int32_t> GetWifiSignalLevel();
-// Gets the DNS servers and puts them in |dns_servers|.
+// Gets the DNS servers and puts them in |dns_servers|. Sets
+// |dns_over_tls_active| and |dns_over_tls_hostname| based on the private DNS
+// settings. |dns_over_tls_hostname| will only be non-empty if
+// |dns_over_tls_active| is true.
// Only callable on Marshmallow and newer releases.
// Returns CONFIG_PARSE_POSIX_OK upon success,
-// CONFIG_PARSE_POSIX_NO_NAMESERVERS if no DNS servers found, or
-// CONFIG_PARSE_POSIX_PRIVATE_DNS_ACTIVE if private DNS active.
+// CONFIG_PARSE_POSIX_NO_NAMESERVERS if no DNS servers found.
NET_EXPORT_PRIVATE internal::ConfigParsePosixResult GetDnsServers(
- std::vector<IPEndPoint>* dns_servers);
+ std::vector<IPEndPoint>* dns_servers,
+ bool* dns_over_tls_active,
+ std::string* dns_over_tls_hostname);
// Apply TrafficStats tag |tag| and UID |uid| to |socket|. Future network
// traffic used by |socket| will be attributed to |uid| and |tag|.
diff --git a/net/dns/dns_config.cc b/net/dns/dns_config.cc
index 71e912f..5e2a769 100644
--- a/net/dns/dns_config.cc
+++ b/net/dns/dns_config.cc
@@ -20,6 +20,8 @@
DnsConfig::DnsConfig(std::vector<IPEndPoint> nameservers)
: nameservers(std::move(nameservers)),
+ dns_over_tls_active(false),
+ dns_over_tls_hostname(std::string()),
unhandled_options(false),
append_to_multi_label_name(true),
randomize_ports(false),
@@ -45,8 +47,10 @@
}
bool DnsConfig::EqualsIgnoreHosts(const DnsConfig& d) const {
- return (nameservers == d.nameservers) && (search == d.search) &&
- (unhandled_options == d.unhandled_options) &&
+ return (nameservers == d.nameservers) &&
+ (dns_over_tls_active == d.dns_over_tls_active) &&
+ (dns_over_tls_hostname == d.dns_over_tls_hostname) &&
+ (search == d.search) && (unhandled_options == d.unhandled_options) &&
(append_to_multi_label_name == d.append_to_multi_label_name) &&
(ndots == d.ndots) && (timeout == d.timeout) &&
(attempts == d.attempts) && (rotate == d.rotate) &&
@@ -57,6 +61,8 @@
void DnsConfig::CopyIgnoreHosts(const DnsConfig& d) {
nameservers = d.nameservers;
+ dns_over_tls_active = d.dns_over_tls_active;
+ dns_over_tls_hostname = d.dns_over_tls_hostname;
search = d.search;
unhandled_options = d.unhandled_options;
append_to_multi_label_name = d.append_to_multi_label_name;
@@ -77,6 +83,9 @@
list->AppendString(nameservers[i].ToString());
dict->Set("nameservers", std::move(list));
+ dict->SetBoolean("dns_over_tls_active", dns_over_tls_active);
+ dict->SetString("dns_over_tls_hostname", dns_over_tls_hostname);
+
list = std::make_unique<base::ListValue>();
for (size_t i = 0; i < search.size(); ++i)
list->AppendString(search[i]);
diff --git a/net/dns/dns_config.h b/net/dns/dns_config.h
index a8dbf81..c7125ae 100644
--- a/net/dns/dns_config.h
+++ b/net/dns/dns_config.h
@@ -71,6 +71,11 @@
// List of name server addresses.
std::vector<IPEndPoint> nameservers;
+
+ // Status of system DNS-over-TLS (DoT).
+ bool dns_over_tls_active;
+ std::string dns_over_tls_hostname;
+
// Suffix search list; used on first lookup when number of dots in given name
// is less than |ndots|.
std::vector<std::string> search;
diff --git a/net/dns/dns_config_service_posix.cc b/net/dns/dns_config_service_posix.cc
index ee2d572..2e0f06b 100644
--- a/net/dns/dns_config_service_posix.cc
+++ b/net/dns/dns_config_service_posix.cc
@@ -196,7 +196,9 @@
if (base::android::BuildInfo::GetInstance()->sdk_int() >=
base::android::SDK_VERSION_MARSHMALLOW) {
- return net::android::GetDnsServers(&dns_config->nameservers);
+ return net::android::GetDnsServers(&dns_config->nameservers,
+ &dns_config->dns_over_tls_active,
+ &dns_config->dns_over_tls_hostname);
}
if (IsVpnPresent()) {
diff --git a/net/dns/dns_config_service_posix.h b/net/dns/dns_config_service_posix.h
index 342b108d0..d2f8961 100644
--- a/net/dns/dns_config_service_posix.h
+++ b/net/dns/dns_config_service_posix.h
@@ -76,7 +76,6 @@
CONFIG_PARSE_POSIX_MISSING_OPTIONS,
CONFIG_PARSE_POSIX_UNHANDLED_OPTIONS,
CONFIG_PARSE_POSIX_NO_DNSINFO,
- CONFIG_PARSE_POSIX_PRIVATE_DNS_ACTIVE,
CONFIG_PARSE_POSIX_MAX // Bounding values for enumeration.
};
diff --git a/net/dns/host_resolver_manager.cc b/net/dns/host_resolver_manager.cc
index 7a55903..d3a2218 100644
--- a/net/dns/host_resolver_manager.cc
+++ b/net/dns/host_resolver_manager.cc
@@ -509,6 +509,28 @@
upgradable_servers->end();
}
+bool HasDoHUpgradeableServer(std::vector<IPEndPoint> nameservers) {
+ for (const auto& dns_server : nameservers) {
+ if (DnsServerSupportsDoh(dns_server.address()))
+ return true;
+ }
+ return false;
+}
+
+bool DotServerSupportsDoh(std::string dot_server) {
+ static const base::NoDestructor<std::unordered_set<std::string>>
+ upgradable_servers(std::initializer_list<std::string>({
+ // Google Public DNS
+ "dns.google",
+ // Cloudflare DNS
+ "1dot1dot1dot1.cloudflare-dns.com",
+ "cloudflare-dns.com",
+ // Quad9 DNS
+ "dns.quad9.net",
+ }));
+ return upgradable_servers->find(dot_server) != upgradable_servers->end();
+}
+
void NetLogHostCacheEntry(const NetLogWithSource& net_log,
NetLogEventType type,
NetLogEventPhase phase,
@@ -2945,6 +2967,10 @@
UMA_HISTOGRAM_MEDIUM_TIMES("Net.DNS.TotalTimeTyped.SystemPrivate",
duration);
break;
+ case MODE_FOR_HISTOGRAM_SYSTEM_PRIVATE_DNS_SUPPORTS_DOH:
+ UMA_HISTOGRAM_MEDIUM_TIMES(
+ "Net.DNS.TotalTimeTyped.SystemPrivateSupportsDoh", duration);
+ break;
case MODE_FOR_HISTOGRAM_ASYNC_DNS:
UMA_HISTOGRAM_MEDIUM_TIMES("Net.DNS.TotalTimeTyped.Async", duration);
break;
@@ -3015,15 +3041,25 @@
return !proc_params_.resolver_proc && HostResolverProc::GetDefault();
}
-void HostResolverManager::PushDnsTasks(
- bool proc_task_allowed,
- DnsConfig::SecureDnsMode secure_dns_mode,
- bool insecure_tasks_allowed,
- ResolveHostParameters::CacheUsage cache_usage,
- std::deque<TaskType>* out_tasks) {
+void HostResolverManager::PushCacheLookups(bool secure,
+ bool insecure,
+ std::deque<TaskType>* out_tasks) {
+ if (secure && insecure) {
+ out_tasks->push_back(TaskType::CACHE_LOOKUP);
+ } else if (secure) {
+ out_tasks->push_back(TaskType::SECURE_CACHE_LOOKUP);
+ } else if (insecure) {
+ out_tasks->push_back(TaskType::INSECURE_CACHE_LOOKUP);
+ } // else do nothing
+}
+
+void HostResolverManager::PushDnsTasks(bool proc_task_allowed,
+ DnsConfig::SecureDnsMode secure_dns_mode,
+ bool insecure_tasks_allowed,
+ bool allow_cache,
+ bool prioritize_local_lookups,
+ std::deque<TaskType>* out_tasks) {
DCHECK(HaveDnsConfig());
- bool allow_cache =
- cache_usage != ResolveHostParameters::CacheUsage::DISALLOWED;
// If a catch-all DNS block has been set for unit tests, we shouldn't send
// DnsTasks. It is still necessary to call this method, however, so that the
// correct cache tasks for the secure dns mode are added.
@@ -3032,45 +3068,40 @@
switch (secure_dns_mode) {
case DnsConfig::SecureDnsMode::SECURE:
DCHECK(dns_client_->GetConfig()->dns_over_https_servers.size() != 0);
- if (allow_cache)
- out_tasks->push_back(TaskType::SECURE_CACHE_LOOKUP);
+ PushCacheLookups(allow_cache /* secure */, false /* insecure */,
+ out_tasks);
if (dns_tasks_allowed)
out_tasks->push_back(TaskType::SECURE_DNS);
break;
case DnsConfig::SecureDnsMode::AUTOMATIC:
- // TODO(crbug.com/985589): For a DnsTask in AUTOMATIC mode, the async
- // resolver should only send insecure requests if it is enabled on this
- // platform.
if (!HasAvailableDohServer()) {
// Don't run a secure DnsTask if there are no available DoH servers.
- if (allow_cache)
- out_tasks->push_back(TaskType::CACHE_LOOKUP);
+ PushCacheLookups(allow_cache /* secure */, allow_cache /* insecure */,
+ out_tasks);
if (dns_tasks_allowed && insecure_tasks_allowed)
out_tasks->push_back(TaskType::DNS);
- } else if (cache_usage == HostResolver::ResolveHostParameters::
- CacheUsage::STALE_ALLOWED) {
- // If stale results are allowed, the cache should be checked for both
- // secure and insecure results prior to running a secure DnsTask.
- out_tasks->push_back(TaskType::CACHE_LOOKUP);
+ } else if (prioritize_local_lookups) {
+ PushCacheLookups(allow_cache /* secure */, allow_cache /* insecure */,
+ out_tasks);
if (dns_tasks_allowed) {
out_tasks->push_back(TaskType::SECURE_DNS);
if (insecure_tasks_allowed)
out_tasks->push_back(TaskType::DNS);
}
} else {
- if (allow_cache)
- out_tasks->push_back(TaskType::SECURE_CACHE_LOOKUP);
+ PushCacheLookups(allow_cache /* secure */, false /* insecure */,
+ out_tasks);
if (dns_tasks_allowed)
out_tasks->push_back(TaskType::SECURE_DNS);
- if (allow_cache)
- out_tasks->push_back(TaskType::INSECURE_CACHE_LOOKUP);
+ PushCacheLookups(false /* secure */, allow_cache /* insecure */,
+ out_tasks);
if (dns_tasks_allowed && insecure_tasks_allowed)
out_tasks->push_back(TaskType::DNS);
}
break;
case DnsConfig::SecureDnsMode::OFF:
- if (allow_cache)
- out_tasks->push_back(TaskType::CACHE_LOOKUP);
+ PushCacheLookups(allow_cache /* secure */, allow_cache /* insecure */,
+ out_tasks);
if (dns_tasks_allowed && insecure_tasks_allowed)
out_tasks->push_back(TaskType::DNS);
break;
@@ -3108,10 +3139,18 @@
// A cache lookup should generally be performed first. For jobs involving a
// DnsTask, this task will be removed before DnsTasks and other related tasks
// are added to the sequence.
- if (cache_usage != ResolveHostParameters::CacheUsage::DISALLOWED)
- out_tasks->push_front(TaskType::CACHE_LOOKUP);
+ bool allow_cache =
+ cache_usage != ResolveHostParameters::CacheUsage::DISALLOWED;
+ PushCacheLookups(allow_cache /* secure */, allow_cache /* insecure */,
+ out_tasks);
// Determine what type of task a future Job should start.
+ bool prioritize_local_lookups =
+ cache_usage ==
+ HostResolver::ResolveHostParameters::CacheUsage::STALE_ALLOWED;
+ bool insecure_dns_tasks_allowed =
+ insecure_dns_client_enabled_ && HaveDnsConfig() &&
+ !dns_client_->GetConfig()->dns_over_tls_active;
switch (source) {
case HostResolverSource::ANY:
// Force address queries with canonname to use ProcTask to counter poor
@@ -3133,8 +3172,8 @@
out_tasks->pop_front();
PushDnsTasks(
proc_task_allowed, *out_effective_secure_dns_mode,
- insecure_dns_client_enabled_ && !bypass_insecure_dns_client_,
- cache_usage, out_tasks);
+ insecure_dns_tasks_allowed && !bypass_insecure_dns_client_,
+ allow_cache, prioritize_local_lookups, out_tasks);
} else if (proc_task_allowed) {
out_tasks->push_back(TaskType::PROC);
}
@@ -3156,8 +3195,8 @@
if (!out_tasks->empty())
out_tasks->pop_front();
PushDnsTasks(false /* proc_task_allowed */,
- *out_effective_secure_dns_mode,
- insecure_dns_client_enabled_, cache_usage, out_tasks);
+ *out_effective_secure_dns_mode, insecure_dns_tasks_allowed,
+ allow_cache, prioritize_local_lookups, out_tasks);
}
break;
case HostResolverSource::MULTICAST_DNS:
@@ -3481,36 +3520,31 @@
#endif
}
-// TODO(crbug.com/985589): Update these metrics for DoH.
+// TODO(crbug.com/985589): Update these metrics when DoH upgrade starts
+// starts happening in practice.
void HostResolverManager::UpdateModeForHistogram(const DnsConfig& dns_config) {
- // Resolving with Async DNS resolver?
- if (HaveDnsConfig() && insecure_dns_client_enabled_) {
- mode_for_histogram_ = MODE_FOR_HISTOGRAM_ASYNC_DNS;
- for (const auto& dns_server : dns_client_->GetConfig()->nameservers) {
- if (DnsServerSupportsDoh(dns_server.address())) {
+ if (HaveDnsConfig()) {
+ const DnsConfig* config = dns_client_->GetConfig();
+ if (config->dns_over_tls_active) {
+ mode_for_histogram_ = MODE_FOR_HISTOGRAM_SYSTEM_PRIVATE_DNS;
+ if ((config->dns_over_tls_hostname.empty() &&
+ HasDoHUpgradeableServer(config->nameservers)) ||
+ DotServerSupportsDoh(config->dns_over_tls_hostname))
+ mode_for_histogram_ =
+ MODE_FOR_HISTOGRAM_SYSTEM_PRIVATE_DNS_SUPPORTS_DOH;
+ return;
+ }
+ if (insecure_dns_client_enabled_) {
+ mode_for_histogram_ = MODE_FOR_HISTOGRAM_ASYNC_DNS;
+ if (HasDoHUpgradeableServer(config->nameservers))
mode_for_histogram_ = MODE_FOR_HISTOGRAM_ASYNC_DNS_PRIVATE_SUPPORTS_DOH;
- break;
- }
+ return;
}
- } else {
- mode_for_histogram_ = MODE_FOR_HISTOGRAM_SYSTEM;
- for (const auto& dns_server : dns_config.nameservers) {
- if (DnsServerSupportsDoh(dns_server.address())) {
- mode_for_histogram_ = MODE_FOR_HISTOGRAM_SYSTEM_SUPPORTS_DOH;
- break;
- }
- }
-#if defined(OS_ANDROID)
- if (base::android::BuildInfo::GetInstance()->sdk_int() >=
- base::android::SDK_VERSION_P) {
- std::vector<IPEndPoint> dns_servers;
- if (net::android::GetDnsServers(&dns_servers) ==
- internal::CONFIG_PARSE_POSIX_PRIVATE_DNS_ACTIVE) {
- mode_for_histogram_ = MODE_FOR_HISTOGRAM_SYSTEM_PRIVATE_DNS;
- }
- }
-#endif // defined(OS_ANDROID)
}
+
+ mode_for_histogram_ = MODE_FOR_HISTOGRAM_SYSTEM;
+ if (HasDoHUpgradeableServer(dns_config.nameservers))
+ mode_for_histogram_ = MODE_FOR_HISTOGRAM_SYSTEM_SUPPORTS_DOH;
}
void HostResolverManager::InvalidateCaches() {
diff --git a/net/dns/host_resolver_manager.h b/net/dns/host_resolver_manager.h
index b83f4f8..9ecdd28b 100644
--- a/net/dns/host_resolver_manager.h
+++ b/net/dns/host_resolver_manager.h
@@ -233,6 +233,9 @@
// Using the system resolver, which is using DNS servers which offer
// DNS-over-HTTPS service.
MODE_FOR_HISTOGRAM_SYSTEM_SUPPORTS_DOH,
+ // Using private DNS via the system resolver, which is using DoT servers
+ // which offer DNS-over-HTTPS service.
+ MODE_FOR_HISTOGRAM_SYSTEM_PRIVATE_DNS_SUPPORTS_DOH,
// Using Chromium DNS resolver.
MODE_FOR_HISTOGRAM_ASYNC_DNS,
// Using Chromium DNS resolver which is using DNS servers which offer
@@ -350,12 +353,20 @@
// DnsTasks should be issued in this case.
bool HaveTestProcOverride();
+ // Pushes a cache lookup task depending on what sections of the cache can
+ // be checked at this time
+ void PushCacheLookups(bool secure,
+ bool insecure,
+ std::deque<TaskType>* out_tasks);
+
// Helper method to add DnsTasks and related tasks based on the SecureDnsMode
- // and fallback parameters.
+ // and fallback parameters. If |prioritize_local_lookups| is true, then we
+ // may push an insecure cache lookup ahead of a secure DnsTask.
void PushDnsTasks(bool proc_task_allowed,
SecureDnsMode secure_dns_mode,
bool insecure_tasks_allowed,
- ResolveHostParameters::CacheUsage cache_usage,
+ bool allow_cache,
+ bool prioritize_local_lookups,
std::deque<TaskType>* out_tasks);
// Initialized the sequence of tasks to run to resolve a request. The sequence
diff --git a/net/dns/host_resolver_manager_unittest.cc b/net/dns/host_resolver_manager_unittest.cc
index 860fca3..7756612 100644
--- a/net/dns/host_resolver_manager_unittest.cc
+++ b/net/dns/host_resolver_manager_unittest.cc
@@ -3624,6 +3624,23 @@
CreateExpected("127.0.0.1", 1212)));
}
+TEST_F(HostResolverManagerDnsTest, UseProcTaskWhenPrivateDnsActive) {
+ // Disable fallback to allow testing how requests are initially handled.
+ set_allow_fallback_to_proctask(false);
+ proc_->AddRuleForAllFamilies("nx_succeed", "192.168.2.47");
+ proc_->SignalMultiple(1u);
+
+ DnsConfig config = CreateValidDnsConfig();
+ config.dns_over_tls_active = true;
+ ChangeDnsConfig(config);
+ ResolveHostResponseHelper response_proc(resolver_->CreateRequest(
+ HostPortPair("nx_succeed", 1212), NetLogWithSource(), base::nullopt,
+ request_context_.get(), host_cache_.get()));
+ EXPECT_THAT(response_proc.result_error(), IsOk());
+ EXPECT_THAT(response_proc.request()->GetAddressResults().value().endpoints(),
+ testing::ElementsAre(CreateExpected("192.168.2.47", 1212)));
+}
+
// RFC 6761 localhost names should always resolve to loopback.
TEST_F(HostResolverManagerDnsTest, LocalhostLookup) {
// Add a rule resolving localhost names to a non-loopback IP and test
@@ -5027,6 +5044,67 @@
testing::ElementsAre(kExpectedInsecureIP));
}
+TEST_F(HostResolverManagerDnsTest, SecureDnsMode_Automatic_DotActive) {
+ proc_->AddRuleForAllFamilies("insecure_automatic", "192.168.1.100");
+ DnsConfig config = CreateValidDnsConfig();
+ config.dns_over_tls_active = true;
+ ChangeDnsConfig(config);
+ DnsConfigOverrides overrides;
+ overrides.secure_dns_mode = DnsConfig::SecureDnsMode::AUTOMATIC;
+ resolver_->SetDnsConfigOverrides(overrides);
+
+ const std::pair<const HostCache::Key, HostCache::Entry>* cache_result;
+
+ // The secure part of the dns client should be enabled.
+ ResolveHostResponseHelper response_secure(resolver_->CreateRequest(
+ HostPortPair("automatic", 80), NetLogWithSource(), base::nullopt,
+ request_context_.get(), host_cache_.get()));
+ ASSERT_THAT(response_secure.result_error(), IsOk());
+ EXPECT_THAT(
+ response_secure.request()->GetAddressResults().value().endpoints(),
+ testing::UnorderedElementsAre(CreateExpected("127.0.0.1", 80),
+ CreateExpected("::1", 80)));
+ HostCache::Key secure_key =
+ HostCache::Key("automatic", DnsQueryType::UNSPECIFIED,
+ 0 /* host_resolver_flags */, HostResolverSource::ANY);
+ secure_key.secure = true;
+ cache_result = GetCacheHit(secure_key);
+ EXPECT_TRUE(!!cache_result);
+
+ // Insecure async requests should be skipped since the system resolver
+ // requests will be secure.
+ ResolveHostResponseHelper response_insecure(resolver_->CreateRequest(
+ HostPortPair("insecure_automatic", 80), NetLogWithSource(), base::nullopt,
+ request_context_.get(), host_cache_.get()));
+ proc_->SignalMultiple(1u);
+ ASSERT_THAT(response_insecure.result_error(), IsOk());
+ EXPECT_THAT(
+ response_insecure.request()->GetAddressResults().value().endpoints(),
+ testing::ElementsAre(CreateExpected("192.168.1.100", 80)));
+ HostCache::Key insecure_key =
+ HostCache::Key("insecure_automatic", DnsQueryType::UNSPECIFIED,
+ 0 /* host_resolver_flags */, HostResolverSource::ANY);
+ cache_result = GetCacheHit(insecure_key);
+ EXPECT_TRUE(!!cache_result);
+
+ HostCache::Key cached_insecure_key =
+ HostCache::Key("insecure_automatic_cached", DnsQueryType::UNSPECIFIED,
+ 0 /* host_resolver_flags */, HostResolverSource::ANY);
+ IPEndPoint kExpectedInsecureIP = CreateExpected("192.168.1.101", 80);
+ PopulateCache(cached_insecure_key, kExpectedInsecureIP);
+
+ // The insecure cache should still be checked.
+ ResolveHostResponseHelper response_insecure_cached(resolver_->CreateRequest(
+ HostPortPair("insecure_automatic_cached", 80), NetLogWithSource(),
+ base::nullopt, request_context_.get(), host_cache_.get()));
+ EXPECT_THAT(response_insecure_cached.result_error(), IsOk());
+ EXPECT_THAT(response_insecure_cached.request()
+ ->GetAddressResults()
+ .value()
+ .endpoints(),
+ testing::ElementsAre(kExpectedInsecureIP));
+}
+
TEST_F(HostResolverManagerDnsTest, SecureDnsMode_Secure) {
proc_->AddRuleForAllFamilies("nx_succeed", "192.168.1.100");
set_allow_fallback_to_proctask(true);
@@ -6440,6 +6518,47 @@
EXPECT_EQ(resolver_->mode_for_histogram_,
HostResolverManager::MODE_FOR_HISTOGRAM_SYSTEM_SUPPORTS_DOH);
}
+
+ // Test private DNS is detected.
+ DnsConfig config = CreateValidDnsConfig();
+ config.dns_over_tls_active = true;
+ ChangeDnsConfig(config);
+ EXPECT_EQ(resolver_->mode_for_histogram_,
+ HostResolverManager::MODE_FOR_HISTOGRAM_SYSTEM_PRIVATE_DNS);
+
+ // Test upgradeability from IP addresses when private DNS is active.
+ for (const char* upgradable_server : upgradable_servers) {
+ IPAddress ip_address;
+ ASSERT_TRUE(ip_address.AssignFromIPLiteral(upgradable_server));
+ DnsConfig dns_config;
+ dns_config.dns_over_tls_active = true;
+ dns_config.nameservers.push_back(
+ IPEndPoint(ip_address, dns_protocol::kDefaultPort));
+ ChangeDnsConfig(dns_config);
+ EXPECT_EQ(resolver_->mode_for_histogram_,
+ HostResolverManager::
+ MODE_FOR_HISTOGRAM_SYSTEM_PRIVATE_DNS_SUPPORTS_DOH);
+ }
+
+ // Test upgradeability from private DNS hostname.
+ static const std::vector<const char*> upgradeable_private_servers(
+ {// Google Public DNS
+ "dns.google",
+ // Cloudflare DNS
+ "1dot1dot1dot1.cloudflare-dns.com", "cloudflare-dns.com",
+ // Quad9 DNS
+ "dns.quad9.net"});
+ for (const char* upgradeable_private_server : upgradeable_private_servers) {
+ DnsConfig dns_config;
+ dns_config.dns_over_tls_active = true;
+ dns_config.dns_over_tls_hostname = upgradeable_private_server;
+ dns_config.nameservers.push_back(
+ IPEndPoint(IPAddress(1, 2, 3, 4), dns_protocol::kDefaultPort));
+ ChangeDnsConfig(dns_config);
+ EXPECT_EQ(resolver_->mode_for_histogram_,
+ HostResolverManager::
+ MODE_FOR_HISTOGRAM_SYSTEM_PRIVATE_DNS_SUPPORTS_DOH);
+ }
}
TEST_F(HostResolverManagerDnsTest, TxtQuery) {
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 78fb7798..feb3818 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -72396,6 +72396,9 @@
<histogram name="Net.DNS.Android.AutoDohPrivate" enum="Boolean"
expires_after="M77">
+ <obsolete>
+ Deprecated 8/2019.
+ </obsolete>
<owner>pauljensen@chromium.org</owner>
<summary>
For devices using Android private DNS, are their DNS servers known to
@@ -72405,6 +72408,9 @@
<histogram name="Net.DNS.Android.AutoDohPublic" enum="Boolean"
expires_after="M77">
+ <obsolete>
+ Deprecated 8/2019.
+ </obsolete>
<owner>pauljensen@chromium.org</owner>
<summary>
For devices not using Android private DNS, are their DNS servers known to
@@ -72415,6 +72421,9 @@
<histogram name="Net.DNS.Android.DotExplicit" enum="Boolean"
expires_after="M77">
+ <obsolete>
+ Deprecated 8/2019.
+ </obsolete>
<owner>pauljensen@chromium.org</owner>
<summary>
For devices using Android private DNS, was their DNS-over-TLS server