Merge "Add basic resolution of Private DNS hostname"
This commit is contained in:
@@ -131,6 +131,7 @@ import com.android.internal.util.XmlUtils;
|
|||||||
import com.android.server.am.BatteryStatsService;
|
import com.android.server.am.BatteryStatsService;
|
||||||
import com.android.server.connectivity.DataConnectionStats;
|
import com.android.server.connectivity.DataConnectionStats;
|
||||||
import com.android.server.connectivity.DnsManager;
|
import com.android.server.connectivity.DnsManager;
|
||||||
|
import com.android.server.connectivity.DnsManager.PrivateDnsConfig;
|
||||||
import com.android.server.connectivity.IpConnectivityMetrics;
|
import com.android.server.connectivity.IpConnectivityMetrics;
|
||||||
import com.android.server.connectivity.KeepaliveTracker;
|
import com.android.server.connectivity.KeepaliveTracker;
|
||||||
import com.android.server.connectivity.LingerMonitor;
|
import com.android.server.connectivity.LingerMonitor;
|
||||||
@@ -399,6 +400,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
*/
|
*/
|
||||||
private static final int EVENT_REVALIDATE_NETWORK = 36;
|
private static final int EVENT_REVALIDATE_NETWORK = 36;
|
||||||
|
|
||||||
|
// Handle changes in Private DNS settings.
|
||||||
|
private static final int EVENT_PRIVATE_DNS_SETTINGS_CHANGED = 37;
|
||||||
|
|
||||||
private static String eventName(int what) {
|
private static String eventName(int what) {
|
||||||
return sMagicDecoderRing.get(what, Integer.toString(what));
|
return sMagicDecoderRing.get(what, Integer.toString(what));
|
||||||
}
|
}
|
||||||
@@ -863,6 +867,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
mMultinetworkPolicyTracker.start();
|
mMultinetworkPolicyTracker.start();
|
||||||
|
|
||||||
mDnsManager = new DnsManager(mContext, mNetd, mSystemProperties);
|
mDnsManager = new DnsManager(mContext, mNetd, mSystemProperties);
|
||||||
|
registerPrivateDnsSettingsCallbacks();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Tethering makeTethering() {
|
private Tethering makeTethering() {
|
||||||
@@ -923,6 +928,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
EVENT_CONFIGURE_MOBILE_DATA_ALWAYS_ON);
|
EVENT_CONFIGURE_MOBILE_DATA_ALWAYS_ON);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void registerPrivateDnsSettingsCallbacks() {
|
||||||
|
for (Uri u : DnsManager.getPrivateDnsSettingsUris()) {
|
||||||
|
mSettingsObserver.observe(u, EVENT_PRIVATE_DNS_SETTINGS_CHANGED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private synchronized int nextNetworkRequestId() {
|
private synchronized int nextNetworkRequestId() {
|
||||||
return mNextNetworkRequestId++;
|
return mNextNetworkRequestId++;
|
||||||
}
|
}
|
||||||
@@ -2086,36 +2097,59 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
synchronized (mNetworkForNetId) {
|
synchronized (mNetworkForNetId) {
|
||||||
nai = mNetworkForNetId.get(msg.arg2);
|
nai = mNetworkForNetId.get(msg.arg2);
|
||||||
}
|
}
|
||||||
if (nai != null) {
|
if (nai == null) break;
|
||||||
final boolean valid =
|
|
||||||
(msg.arg1 == NetworkMonitor.NETWORK_TEST_RESULT_VALID);
|
final boolean valid = (msg.arg1 == NetworkMonitor.NETWORK_TEST_RESULT_VALID);
|
||||||
final boolean wasValidated = nai.lastValidated;
|
final boolean wasValidated = nai.lastValidated;
|
||||||
final boolean wasDefault = isDefaultNetwork(nai);
|
final boolean wasDefault = isDefaultNetwork(nai);
|
||||||
if (DBG) log(nai.name() + " validation " + (valid ? "passed" : "failed") +
|
|
||||||
(msg.obj == null ? "" : " with redirect to " + (String)msg.obj));
|
final PrivateDnsConfig privateDnsCfg = (msg.obj instanceof PrivateDnsConfig)
|
||||||
if (valid != nai.lastValidated) {
|
? (PrivateDnsConfig) msg.obj : null;
|
||||||
if (wasDefault) {
|
final String redirectUrl = (msg.obj instanceof String) ? (String) msg.obj : "";
|
||||||
metricsLogger().defaultNetworkMetrics().logDefaultNetworkValidity(
|
|
||||||
SystemClock.elapsedRealtime(), valid);
|
final boolean reevaluationRequired;
|
||||||
}
|
final String logMsg;
|
||||||
final int oldScore = nai.getCurrentScore();
|
if (valid) {
|
||||||
nai.lastValidated = valid;
|
reevaluationRequired = updatePrivateDns(nai, privateDnsCfg);
|
||||||
nai.everValidated |= valid;
|
logMsg = (DBG && (privateDnsCfg != null))
|
||||||
updateCapabilities(oldScore, nai, nai.networkCapabilities);
|
? " with " + privateDnsCfg.toString() : "";
|
||||||
// If score has changed, rebroadcast to NetworkFactories. b/17726566
|
} else {
|
||||||
if (oldScore != nai.getCurrentScore()) sendUpdatedScoreToFactories(nai);
|
reevaluationRequired = false;
|
||||||
|
logMsg = (DBG && !TextUtils.isEmpty(redirectUrl))
|
||||||
|
? " with redirect to " + redirectUrl : "";
|
||||||
|
}
|
||||||
|
if (DBG) {
|
||||||
|
log(nai.name() + " validation " + (valid ? "passed" : "failed") + logMsg);
|
||||||
|
}
|
||||||
|
// If there is a change in Private DNS configuration,
|
||||||
|
// trigger reevaluation of the network to test it.
|
||||||
|
if (reevaluationRequired) {
|
||||||
|
nai.networkMonitor.sendMessage(
|
||||||
|
NetworkMonitor.CMD_FORCE_REEVALUATION, Process.SYSTEM_UID);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (valid != nai.lastValidated) {
|
||||||
|
if (wasDefault) {
|
||||||
|
metricsLogger().defaultNetworkMetrics().logDefaultNetworkValidity(
|
||||||
|
SystemClock.elapsedRealtime(), valid);
|
||||||
}
|
}
|
||||||
updateInetCondition(nai);
|
final int oldScore = nai.getCurrentScore();
|
||||||
// Let the NetworkAgent know the state of its network
|
nai.lastValidated = valid;
|
||||||
Bundle redirectUrlBundle = new Bundle();
|
nai.everValidated |= valid;
|
||||||
redirectUrlBundle.putString(NetworkAgent.REDIRECT_URL_KEY, (String)msg.obj);
|
updateCapabilities(oldScore, nai, nai.networkCapabilities);
|
||||||
nai.asyncChannel.sendMessage(
|
// If score has changed, rebroadcast to NetworkFactories. b/17726566
|
||||||
NetworkAgent.CMD_REPORT_NETWORK_STATUS,
|
if (oldScore != nai.getCurrentScore()) sendUpdatedScoreToFactories(nai);
|
||||||
(valid ? NetworkAgent.VALID_NETWORK : NetworkAgent.INVALID_NETWORK),
|
}
|
||||||
0, redirectUrlBundle);
|
updateInetCondition(nai);
|
||||||
if (wasValidated && !nai.lastValidated) {
|
// Let the NetworkAgent know the state of its network
|
||||||
handleNetworkUnvalidated(nai);
|
Bundle redirectUrlBundle = new Bundle();
|
||||||
}
|
redirectUrlBundle.putString(NetworkAgent.REDIRECT_URL_KEY, redirectUrl);
|
||||||
|
nai.asyncChannel.sendMessage(
|
||||||
|
NetworkAgent.CMD_REPORT_NETWORK_STATUS,
|
||||||
|
(valid ? NetworkAgent.VALID_NETWORK : NetworkAgent.INVALID_NETWORK),
|
||||||
|
0, redirectUrlBundle);
|
||||||
|
if (wasValidated && !nai.lastValidated) {
|
||||||
|
handleNetworkUnvalidated(nai);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -2155,6 +2189,21 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case NetworkMonitor.EVENT_PRIVATE_DNS_CONFIG_RESOLVED: {
|
||||||
|
final NetworkAgentInfo nai;
|
||||||
|
synchronized (mNetworkForNetId) {
|
||||||
|
nai = mNetworkForNetId.get(msg.arg2);
|
||||||
|
}
|
||||||
|
if (nai == null) break;
|
||||||
|
|
||||||
|
final PrivateDnsConfig cfg = (PrivateDnsConfig) msg.obj;
|
||||||
|
final boolean reevaluationRequired = updatePrivateDns(nai, cfg);
|
||||||
|
if (nai.lastValidated && reevaluationRequired) {
|
||||||
|
nai.networkMonitor.sendMessage(
|
||||||
|
NetworkMonitor.CMD_FORCE_REEVALUATION, Process.SYSTEM_UID);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -2190,6 +2239,63 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handlePrivateDnsSettingsChanged() {
|
||||||
|
final PrivateDnsConfig cfg = mDnsManager.getPrivateDnsConfig();
|
||||||
|
|
||||||
|
for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
|
||||||
|
// Private DNS only ever applies to networks that might provide
|
||||||
|
// Internet access and therefore also require validation.
|
||||||
|
if (!NetworkMonitor.isValidationRequired(
|
||||||
|
mDefaultRequest.networkCapabilities, nai.networkCapabilities)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notify the NetworkMonitor thread in case it needs to cancel or
|
||||||
|
// schedule DNS resolutions. If a DNS resolution is required the
|
||||||
|
// result will be sent back to us.
|
||||||
|
nai.networkMonitor.notifyPrivateDnsSettingsChanged(cfg);
|
||||||
|
|
||||||
|
if (!cfg.inStrictMode()) {
|
||||||
|
// No strict mode hostname DNS resolution needed, so just update
|
||||||
|
// DNS settings directly. In opportunistic and "off" modes this
|
||||||
|
// just reprograms netd with the network-supplied DNS servers
|
||||||
|
// (and of course the boolean of whether or not to attempt TLS).
|
||||||
|
//
|
||||||
|
// TODO: Consider code flow parity with strict mode, i.e. having
|
||||||
|
// NetworkMonitor relay the PrivateDnsConfig back to us and then
|
||||||
|
// performing this call at that time.
|
||||||
|
updatePrivateDns(nai, cfg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean updatePrivateDns(NetworkAgentInfo nai, PrivateDnsConfig newCfg) {
|
||||||
|
final boolean reevaluationRequired = true;
|
||||||
|
final boolean dontReevaluate = false;
|
||||||
|
|
||||||
|
final PrivateDnsConfig oldCfg = mDnsManager.updatePrivateDns(nai.network, newCfg);
|
||||||
|
updateDnses(nai.linkProperties, null, nai.network.netId);
|
||||||
|
|
||||||
|
if (newCfg == null) {
|
||||||
|
if (oldCfg == null) return dontReevaluate;
|
||||||
|
return oldCfg.useTls ? reevaluationRequired : dontReevaluate;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oldCfg == null) {
|
||||||
|
return newCfg.useTls ? reevaluationRequired : dontReevaluate;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oldCfg.useTls != newCfg.useTls) {
|
||||||
|
return reevaluationRequired;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newCfg.inStrictMode() && !Objects.equals(oldCfg.hostname, newCfg.hostname)) {
|
||||||
|
return reevaluationRequired;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dontReevaluate;
|
||||||
|
}
|
||||||
|
|
||||||
private void updateLingerState(NetworkAgentInfo nai, long now) {
|
private void updateLingerState(NetworkAgentInfo nai, long now) {
|
||||||
// 1. Update the linger timer. If it's changed, reschedule or cancel the alarm.
|
// 1. Update the linger timer. If it's changed, reschedule or cancel the alarm.
|
||||||
// 2. If the network was lingering and there are now requests, unlinger it.
|
// 2. If the network was lingering and there are now requests, unlinger it.
|
||||||
@@ -2324,6 +2430,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
loge("Exception removing network: " + e);
|
loge("Exception removing network: " + e);
|
||||||
}
|
}
|
||||||
|
mDnsManager.removeNetwork(nai.network);
|
||||||
}
|
}
|
||||||
synchronized (mNetworkForNetId) {
|
synchronized (mNetworkForNetId) {
|
||||||
mNetIdInUse.delete(nai.network.netId);
|
mNetIdInUse.delete(nai.network.netId);
|
||||||
@@ -2870,6 +2977,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
handleReportNetworkConnectivity((Network) msg.obj, msg.arg1, toBool(msg.arg2));
|
handleReportNetworkConnectivity((Network) msg.obj, msg.arg1, toBool(msg.arg2));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case EVENT_PRIVATE_DNS_SETTINGS_CHANGED:
|
||||||
|
handlePrivateDnsSettingsChanged();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4559,11 +4669,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
final NetworkAgentInfo defaultNai = getDefaultNetwork();
|
final NetworkAgentInfo defaultNai = getDefaultNetwork();
|
||||||
final boolean isDefaultNetwork = (defaultNai != null && defaultNai.network.netId == netId);
|
final boolean isDefaultNetwork = (defaultNai != null && defaultNai.network.netId == netId);
|
||||||
|
|
||||||
Collection<InetAddress> dnses = newLp.getDnsServers();
|
if (DBG) {
|
||||||
if (DBG) log("Setting DNS servers for network " + netId + " to " + dnses);
|
final Collection<InetAddress> dnses = newLp.getDnsServers();
|
||||||
|
log("Setting DNS servers for network " + netId + " to " + dnses);
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
mDnsManager.setDnsConfigurationForNetwork(
|
mDnsManager.setDnsConfigurationForNetwork(netId, newLp, isDefaultNetwork);
|
||||||
netId, dnses, newLp.getDomains(), isDefaultNetwork);
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
loge("Exception in setDnsConfigurationForNetwork: " + e);
|
loge("Exception in setDnsConfigurationForNetwork: " + e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package com.android.server.connectivity;
|
package com.android.server.connectivity;
|
||||||
|
|
||||||
import static android.net.ConnectivityManager.PRIVATE_DNS_DEFAULT_MODE;
|
import static android.net.ConnectivityManager.PRIVATE_DNS_DEFAULT_MODE;
|
||||||
|
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF;
|
||||||
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
|
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
|
||||||
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
|
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
|
||||||
import static android.provider.Settings.Global.DNS_RESOLVER_MIN_SAMPLES;
|
import static android.provider.Settings.Global.DNS_RESOLVER_MIN_SAMPLES;
|
||||||
@@ -29,19 +30,32 @@ import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER;
|
|||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.net.LinkProperties;
|
||||||
|
import android.net.Network;
|
||||||
import android.net.NetworkUtils;
|
import android.net.NetworkUtils;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
import android.os.INetworkManagementService;
|
import android.os.INetworkManagementService;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
|
import android.system.GaiException;
|
||||||
|
import android.system.OsConstants;
|
||||||
|
import android.system.StructAddrinfo;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
|
|
||||||
import com.android.server.connectivity.MockableSystemProperties;
|
import com.android.server.connectivity.MockableSystemProperties;
|
||||||
|
|
||||||
|
import libcore.io.Libcore;
|
||||||
|
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.StringJoiner;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -61,10 +75,86 @@ public class DnsManager {
|
|||||||
private static final int DNS_RESOLVER_DEFAULT_MIN_SAMPLES = 8;
|
private static final int DNS_RESOLVER_DEFAULT_MIN_SAMPLES = 8;
|
||||||
private static final int DNS_RESOLVER_DEFAULT_MAX_SAMPLES = 64;
|
private static final int DNS_RESOLVER_DEFAULT_MAX_SAMPLES = 64;
|
||||||
|
|
||||||
|
public static class PrivateDnsConfig {
|
||||||
|
public final boolean useTls;
|
||||||
|
public final String hostname;
|
||||||
|
public final InetAddress[] ips;
|
||||||
|
|
||||||
|
public PrivateDnsConfig() {
|
||||||
|
this(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PrivateDnsConfig(boolean useTls) {
|
||||||
|
this.useTls = useTls;
|
||||||
|
this.hostname = "";
|
||||||
|
this.ips = new InetAddress[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public PrivateDnsConfig(String hostname, InetAddress[] ips) {
|
||||||
|
this.useTls = !TextUtils.isEmpty(hostname);
|
||||||
|
this.hostname = useTls ? hostname : "";
|
||||||
|
this.ips = (ips != null) ? ips : new InetAddress[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public PrivateDnsConfig(PrivateDnsConfig cfg) {
|
||||||
|
useTls = cfg.useTls;
|
||||||
|
hostname = cfg.hostname;
|
||||||
|
ips = cfg.ips;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean inStrictMode() {
|
||||||
|
return useTls && !TextUtils.isEmpty(hostname);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return PrivateDnsConfig.class.getSimpleName() +
|
||||||
|
"{" + useTls + ":" + hostname + "/" + Arrays.toString(ips) + "}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PrivateDnsConfig getPrivateDnsConfig(ContentResolver cr) {
|
||||||
|
final String mode = getPrivateDnsMode(cr);
|
||||||
|
|
||||||
|
final boolean useTls = !TextUtils.isEmpty(mode) && !PRIVATE_DNS_MODE_OFF.equals(mode);
|
||||||
|
|
||||||
|
if (PRIVATE_DNS_MODE_PROVIDER_HOSTNAME.equals(mode)) {
|
||||||
|
final String specifier = getStringSetting(cr, PRIVATE_DNS_SPECIFIER);
|
||||||
|
return new PrivateDnsConfig(specifier, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new PrivateDnsConfig(useTls);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PrivateDnsConfig tryBlockingResolveOf(Network network, String name) {
|
||||||
|
final StructAddrinfo hints = new StructAddrinfo();
|
||||||
|
// Unnecessary, but expressly no AI_ADDRCONFIG.
|
||||||
|
hints.ai_flags = 0;
|
||||||
|
// Fetch all IP addresses at once to minimize re-resolution.
|
||||||
|
hints.ai_family = OsConstants.AF_UNSPEC;
|
||||||
|
hints.ai_socktype = OsConstants.SOCK_DGRAM;
|
||||||
|
|
||||||
|
try {
|
||||||
|
final InetAddress[] ips = Libcore.os.android_getaddrinfo(name, hints, network.netId);
|
||||||
|
if (ips != null && ips.length > 0) {
|
||||||
|
return new PrivateDnsConfig(name, ips);
|
||||||
|
}
|
||||||
|
} catch (GaiException ignored) {}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Uri[] getPrivateDnsSettingsUris() {
|
||||||
|
final Uri[] uris = new Uri[2];
|
||||||
|
uris[0] = Settings.Global.getUriFor(PRIVATE_DNS_MODE);
|
||||||
|
uris[1] = Settings.Global.getUriFor(PRIVATE_DNS_SPECIFIER);
|
||||||
|
return uris;
|
||||||
|
}
|
||||||
|
|
||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
private final ContentResolver mContentResolver;
|
private final ContentResolver mContentResolver;
|
||||||
private final INetworkManagementService mNMS;
|
private final INetworkManagementService mNMS;
|
||||||
private final MockableSystemProperties mSystemProperties;
|
private final MockableSystemProperties mSystemProperties;
|
||||||
|
private final Map<Integer, PrivateDnsConfig> mPrivateDnsMap;
|
||||||
|
|
||||||
private int mNumDnsEntries;
|
private int mNumDnsEntries;
|
||||||
private int mSampleValidity;
|
private int mSampleValidity;
|
||||||
@@ -79,44 +169,55 @@ public class DnsManager {
|
|||||||
mContentResolver = mContext.getContentResolver();
|
mContentResolver = mContext.getContentResolver();
|
||||||
mNMS = nms;
|
mNMS = nms;
|
||||||
mSystemProperties = sp;
|
mSystemProperties = sp;
|
||||||
|
mPrivateDnsMap = new HashMap<>();
|
||||||
|
|
||||||
// TODO: Create and register ContentObservers to track every setting
|
// TODO: Create and register ContentObservers to track every setting
|
||||||
// used herein, posting messages to respond to changes.
|
// used herein, posting messages to respond to changes.
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isPrivateDnsInStrictMode() {
|
public PrivateDnsConfig getPrivateDnsConfig() {
|
||||||
return !TextUtils.isEmpty(mPrivateDnsMode) &&
|
return getPrivateDnsConfig(mContentResolver);
|
||||||
mPrivateDnsMode.startsWith(PRIVATE_DNS_MODE_PROVIDER_HOSTNAME) &&
|
}
|
||||||
!TextUtils.isEmpty(mPrivateDnsSpecifier);
|
|
||||||
|
public void removeNetwork(Network network) {
|
||||||
|
mPrivateDnsMap.remove(network.netId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PrivateDnsConfig updatePrivateDns(Network network, PrivateDnsConfig cfg) {
|
||||||
|
Slog.w(TAG, "updatePrivateDns(" + network + ", " + cfg + ")");
|
||||||
|
return (cfg != null)
|
||||||
|
? mPrivateDnsMap.put(network.netId, cfg)
|
||||||
|
: mPrivateDnsMap.remove(network);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDnsConfigurationForNetwork(
|
public void setDnsConfigurationForNetwork(
|
||||||
int netId, Collection<InetAddress> servers, String domains, boolean isDefaultNetwork) {
|
int netId, LinkProperties lp, boolean isDefaultNetwork) {
|
||||||
updateParametersSettings();
|
// We only use the PrivateDnsConfig data pushed to this class instance
|
||||||
updatePrivateDnsSettings();
|
// from ConnectivityService because it works in coordination with
|
||||||
|
// NetworkMonitor to decide which networks need validation and runs the
|
||||||
|
// blocking calls to resolve Private DNS strict mode hostnames.
|
||||||
|
//
|
||||||
|
// At this time we do attempt to enable Private DNS on non-Internet
|
||||||
|
// networks like IMS.
|
||||||
|
final PrivateDnsConfig privateDnsCfg = mPrivateDnsMap.get(netId);
|
||||||
|
|
||||||
final String[] serverStrs = NetworkUtils.makeStrings(servers);
|
final boolean useTls = (privateDnsCfg != null) && privateDnsCfg.useTls;
|
||||||
final String[] domainStrs = (domains == null) ? new String[0] : domains.split(" ");
|
final boolean strictMode = (privateDnsCfg != null) && privateDnsCfg.inStrictMode();
|
||||||
|
final String tlsHostname = strictMode ? privateDnsCfg.hostname : "";
|
||||||
|
|
||||||
|
final String[] serverStrs = NetworkUtils.makeStrings(
|
||||||
|
strictMode ? Arrays.stream(privateDnsCfg.ips)
|
||||||
|
.filter((ip) -> lp.isReachable(ip))
|
||||||
|
.collect(Collectors.toList())
|
||||||
|
: lp.getDnsServers());
|
||||||
|
final String[] domainStrs = getDomainStrings(lp.getDomains());
|
||||||
|
|
||||||
|
updateParametersSettings();
|
||||||
final int[] params = { mSampleValidity, mSuccessThreshold, mMinSamples, mMaxSamples };
|
final int[] params = { mSampleValidity, mSuccessThreshold, mMinSamples, mMaxSamples };
|
||||||
final boolean useTls = shouldUseTls(mPrivateDnsMode);
|
|
||||||
// TODO: Populate tlsHostname once it's decided how the hostname's IP
|
Slog.d(TAG, String.format("setDnsConfigurationForNetwork(%d, %s, %s, %s, %s, %s)",
|
||||||
// addresses will be resolved:
|
netId, Arrays.toString(serverStrs), Arrays.toString(domainStrs),
|
||||||
//
|
Arrays.toString(params), useTls, tlsHostname));
|
||||||
// [1] network-provided DNS servers are included here with the
|
|
||||||
// hostname and netd will use the network-provided servers to
|
|
||||||
// resolve the hostname and fix up its internal structures, or
|
|
||||||
//
|
|
||||||
// [2] network-provided DNS servers are included here without the
|
|
||||||
// hostname, the ConnectivityService layer resolves the given
|
|
||||||
// hostname, and then reconfigures netd with this information.
|
|
||||||
//
|
|
||||||
// In practice, there will always be a need for ConnectivityService or
|
|
||||||
// the captive portal app to use the network-provided services to make
|
|
||||||
// some queries. This argues in favor of [1], in concert with another
|
|
||||||
// mechanism, perhaps setting a high bit in the netid, to indicate
|
|
||||||
// via existing DNS APIs which set of servers (network-provided or
|
|
||||||
// non-network-provided private DNS) should be queried.
|
|
||||||
final String tlsHostname = "";
|
|
||||||
try {
|
try {
|
||||||
mNMS.setDnsConfigurationForNetwork(
|
mNMS.setDnsConfigurationForNetwork(
|
||||||
netId, serverStrs, domainStrs, params, useTls, tlsHostname);
|
netId, serverStrs, domainStrs, params, useTls, tlsHostname);
|
||||||
@@ -129,7 +230,7 @@ public class DnsManager {
|
|||||||
// default network, and we should just set net.dns1 to ::1, not least
|
// default network, and we should just set net.dns1 to ::1, not least
|
||||||
// because applications attempting to use net.dns resolvers will bypass
|
// because applications attempting to use net.dns resolvers will bypass
|
||||||
// the privacy protections of things like DNS-over-TLS.
|
// the privacy protections of things like DNS-over-TLS.
|
||||||
if (isDefaultNetwork) setDefaultDnsSystemProperties(servers);
|
if (isDefaultNetwork) setDefaultDnsSystemProperties(lp.getDnsServers());
|
||||||
flushVmDnsCache();
|
flushVmDnsCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,11 +264,6 @@ public class DnsManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updatePrivateDnsSettings() {
|
|
||||||
mPrivateDnsMode = getStringSetting(PRIVATE_DNS_MODE);
|
|
||||||
mPrivateDnsSpecifier = getStringSetting(PRIVATE_DNS_SPECIFIER);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateParametersSettings() {
|
private void updateParametersSettings() {
|
||||||
mSampleValidity = getIntSetting(
|
mSampleValidity = getIntSetting(
|
||||||
DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS,
|
DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS,
|
||||||
@@ -198,10 +294,6 @@ public class DnsManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getStringSetting(String which) {
|
|
||||||
return Settings.Global.getString(mContentResolver, which);
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getIntSetting(String which, int dflt) {
|
private int getIntSetting(String which, int dflt) {
|
||||||
return Settings.Global.getInt(mContentResolver, which, dflt);
|
return Settings.Global.getInt(mContentResolver, which, dflt);
|
||||||
}
|
}
|
||||||
@@ -216,11 +308,16 @@ public class DnsManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean shouldUseTls(String mode) {
|
private static String getPrivateDnsMode(ContentResolver cr) {
|
||||||
if (TextUtils.isEmpty(mode)) {
|
final String mode = getStringSetting(cr, PRIVATE_DNS_MODE);
|
||||||
mode = PRIVATE_DNS_DEFAULT_MODE;
|
return !TextUtils.isEmpty(mode) ? mode : PRIVATE_DNS_DEFAULT_MODE;
|
||||||
}
|
}
|
||||||
return mode.equals(PRIVATE_DNS_MODE_OPPORTUNISTIC) ||
|
|
||||||
mode.startsWith(PRIVATE_DNS_MODE_PROVIDER_HOSTNAME);
|
private static String getStringSetting(ContentResolver cr, String which) {
|
||||||
|
return Settings.Global.getString(cr, which);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String[] getDomainStrings(String domains) {
|
||||||
|
return (TextUtils.isEmpty(domains)) ? new String[0] : domains.split(" ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user