Loading services/core/java/com/android/server/ConnectivityService.java +144 −33 Original line number Diff line number Diff line Loading @@ -131,6 +131,7 @@ import com.android.internal.util.XmlUtils; import com.android.server.am.BatteryStatsService; import com.android.server.connectivity.DataConnectionStats; import com.android.server.connectivity.DnsManager; import com.android.server.connectivity.DnsManager.PrivateDnsConfig; import com.android.server.connectivity.IpConnectivityMetrics; import com.android.server.connectivity.KeepaliveTracker; import com.android.server.connectivity.LingerMonitor; Loading Loading @@ -399,6 +400,9 @@ public class ConnectivityService extends IConnectivityManager.Stub */ 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) { return sMagicDecoderRing.get(what, Integer.toString(what)); } Loading Loading @@ -863,6 +867,7 @@ public class ConnectivityService extends IConnectivityManager.Stub mMultinetworkPolicyTracker.start(); mDnsManager = new DnsManager(mContext, mNetd, mSystemProperties); registerPrivateDnsSettingsCallbacks(); } private Tethering makeTethering() { Loading Loading @@ -923,6 +928,12 @@ public class ConnectivityService extends IConnectivityManager.Stub 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() { return mNextNetworkRequestId++; } Loading Loading @@ -2086,13 +2097,37 @@ public class ConnectivityService extends IConnectivityManager.Stub synchronized (mNetworkForNetId) { nai = mNetworkForNetId.get(msg.arg2); } if (nai != null) { final boolean valid = (msg.arg1 == NetworkMonitor.NETWORK_TEST_RESULT_VALID); if (nai == null) break; final boolean valid = (msg.arg1 == NetworkMonitor.NETWORK_TEST_RESULT_VALID); final boolean wasValidated = nai.lastValidated; 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) ? (PrivateDnsConfig) msg.obj : null; final String redirectUrl = (msg.obj instanceof String) ? (String) msg.obj : ""; final boolean reevaluationRequired; final String logMsg; if (valid) { reevaluationRequired = updatePrivateDns(nai, privateDnsCfg); logMsg = (DBG && (privateDnsCfg != null)) ? " with " + privateDnsCfg.toString() : ""; } else { 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( Loading @@ -2108,7 +2143,7 @@ public class ConnectivityService extends IConnectivityManager.Stub updateInetCondition(nai); // Let the NetworkAgent know the state of its network Bundle redirectUrlBundle = new Bundle(); redirectUrlBundle.putString(NetworkAgent.REDIRECT_URL_KEY, (String)msg.obj); redirectUrlBundle.putString(NetworkAgent.REDIRECT_URL_KEY, redirectUrl); nai.asyncChannel.sendMessage( NetworkAgent.CMD_REPORT_NETWORK_STATUS, (valid ? NetworkAgent.VALID_NETWORK : NetworkAgent.INVALID_NETWORK), Loading @@ -2116,7 +2151,6 @@ public class ConnectivityService extends IConnectivityManager.Stub if (wasValidated && !nai.lastValidated) { handleNetworkUnvalidated(nai); } } break; } case NetworkMonitor.EVENT_PROVISIONING_NOTIFICATION: { Loading Loading @@ -2155,6 +2189,21 @@ public class ConnectivityService extends IConnectivityManager.Stub } 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; } Loading Loading @@ -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) { // 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. Loading Loading @@ -2324,6 +2430,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } catch (Exception e) { loge("Exception removing network: " + e); } mDnsManager.removeNetwork(nai.network); } synchronized (mNetworkForNetId) { mNetIdInUse.delete(nai.network.netId); Loading Loading @@ -2870,6 +2977,9 @@ public class ConnectivityService extends IConnectivityManager.Stub handleReportNetworkConnectivity((Network) msg.obj, msg.arg1, toBool(msg.arg2)); break; } case EVENT_PRIVATE_DNS_SETTINGS_CHANGED: handlePrivateDnsSettingsChanged(); break; } } } Loading Loading @@ -4559,11 +4669,12 @@ public class ConnectivityService extends IConnectivityManager.Stub final NetworkAgentInfo defaultNai = getDefaultNetwork(); final boolean isDefaultNetwork = (defaultNai != null && defaultNai.network.netId == netId); Collection<InetAddress> dnses = newLp.getDnsServers(); if (DBG) log("Setting DNS servers for network " + netId + " to " + dnses); if (DBG) { final Collection<InetAddress> dnses = newLp.getDnsServers(); log("Setting DNS servers for network " + netId + " to " + dnses); } try { mDnsManager.setDnsConfigurationForNetwork( netId, dnses, newLp.getDomains(), isDefaultNetwork); mDnsManager.setDnsConfigurationForNetwork(netId, newLp, isDefaultNetwork); } catch (Exception e) { loge("Exception in setDnsConfigurationForNetwork: " + e); } Loading services/core/java/com/android/server/NetworkManagementService.java +0 −12 Original line number Diff line number Diff line Loading @@ -21,9 +21,6 @@ import static android.Manifest.permission.DUMP; import static android.Manifest.permission.NETWORK_SETTINGS; import static android.Manifest.permission.NETWORK_STACK; import static android.Manifest.permission.SHUTDOWN; import static android.net.ConnectivityManager.PRIVATE_DNS_DEFAULT_MODE; import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC; import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME; import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_DOZABLE; import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_DOZABLE; import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_NONE; Loading Loading @@ -1957,15 +1954,6 @@ public class NetworkManagementService extends INetworkManagementService.Stub } } private static boolean shouldUseTls(ContentResolver cr) { String privateDns = Settings.Global.getString(cr, Settings.Global.PRIVATE_DNS_MODE); if (TextUtils.isEmpty(privateDns)) { privateDns = PRIVATE_DNS_DEFAULT_MODE; } return privateDns.equals(PRIVATE_DNS_MODE_OPPORTUNISTIC) || privateDns.startsWith(PRIVATE_DNS_MODE_PROVIDER_HOSTNAME); } @Override public void addVpnUidRanges(int netId, UidRange[] ranges) { mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); Loading services/core/java/com/android/server/connectivity/DnsManager.java +141 −44 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.server.connectivity; 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_PROVIDER_HOSTNAME; import static android.provider.Settings.Global.DNS_RESOLVER_MIN_SAMPLES; Loading @@ -29,19 +30,32 @@ import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkUtils; import android.net.Uri; import android.os.Binder; import android.os.INetworkManagementService; import android.os.Handler; import android.os.UserHandle; import android.provider.Settings; import android.system.GaiException; import android.system.OsConstants; import android.system.StructAddrinfo; import android.text.TextUtils; import android.util.Slog; import com.android.server.connectivity.MockableSystemProperties; import libcore.io.Libcore; import java.net.InetAddress; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.stream.Collectors; import java.util.StringJoiner; /** Loading @@ -61,10 +75,86 @@ public class DnsManager { private static final int DNS_RESOLVER_DEFAULT_MIN_SAMPLES = 8; 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 ContentResolver mContentResolver; private final INetworkManagementService mNMS; private final MockableSystemProperties mSystemProperties; private final Map<Integer, PrivateDnsConfig> mPrivateDnsMap; private int mNumDnsEntries; private int mSampleValidity; Loading @@ -79,44 +169,55 @@ public class DnsManager { mContentResolver = mContext.getContentResolver(); mNMS = nms; mSystemProperties = sp; mPrivateDnsMap = new HashMap<>(); // TODO: Create and register ContentObservers to track every setting // used herein, posting messages to respond to changes. } public boolean isPrivateDnsInStrictMode() { return !TextUtils.isEmpty(mPrivateDnsMode) && mPrivateDnsMode.startsWith(PRIVATE_DNS_MODE_PROVIDER_HOSTNAME) && !TextUtils.isEmpty(mPrivateDnsSpecifier); public PrivateDnsConfig getPrivateDnsConfig() { return getPrivateDnsConfig(mContentResolver); } 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( int netId, Collection<InetAddress> servers, String domains, boolean isDefaultNetwork) { updateParametersSettings(); updatePrivateDnsSettings(); int netId, LinkProperties lp, boolean isDefaultNetwork) { // We only use the PrivateDnsConfig data pushed to this class instance // 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 boolean useTls = (privateDnsCfg != null) && privateDnsCfg.useTls; 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()); final String[] serverStrs = NetworkUtils.makeStrings(servers); final String[] domainStrs = (domains == null) ? new String[0] : domains.split(" "); updateParametersSettings(); final int[] params = { mSampleValidity, mSuccessThreshold, mMinSamples, mMaxSamples }; final boolean useTls = shouldUseTls(mPrivateDnsMode); // TODO: Populate tlsHostname once it's decided how the hostname's IP // addresses will be resolved: // // [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 = ""; Slog.d(TAG, String.format("setDnsConfigurationForNetwork(%d, %s, %s, %s, %s, %s)", netId, Arrays.toString(serverStrs), Arrays.toString(domainStrs), Arrays.toString(params), useTls, tlsHostname)); try { mNMS.setDnsConfigurationForNetwork( netId, serverStrs, domainStrs, params, useTls, tlsHostname); Loading @@ -129,7 +230,7 @@ public class DnsManager { // default network, and we should just set net.dns1 to ::1, not least // because applications attempting to use net.dns resolvers will bypass // the privacy protections of things like DNS-over-TLS. if (isDefaultNetwork) setDefaultDnsSystemProperties(servers); if (isDefaultNetwork) setDefaultDnsSystemProperties(lp.getDnsServers()); flushVmDnsCache(); } Loading Loading @@ -163,11 +264,6 @@ public class DnsManager { } } private void updatePrivateDnsSettings() { mPrivateDnsMode = getStringSetting(PRIVATE_DNS_MODE); mPrivateDnsSpecifier = getStringSetting(PRIVATE_DNS_SPECIFIER); } private void updateParametersSettings() { mSampleValidity = getIntSetting( DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS, Loading Loading @@ -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) { return Settings.Global.getInt(mContentResolver, which, dflt); } Loading @@ -216,11 +308,16 @@ public class DnsManager { } } private static boolean shouldUseTls(String mode) { if (TextUtils.isEmpty(mode)) { mode = PRIVATE_DNS_DEFAULT_MODE; private static String getPrivateDnsMode(ContentResolver cr) { final String mode = getStringSetting(cr, PRIVATE_DNS_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(" "); } } services/core/java/com/android/server/connectivity/NetworkMonitor.java +77 −3 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
services/core/java/com/android/server/ConnectivityService.java +144 −33 Original line number Diff line number Diff line Loading @@ -131,6 +131,7 @@ import com.android.internal.util.XmlUtils; import com.android.server.am.BatteryStatsService; import com.android.server.connectivity.DataConnectionStats; import com.android.server.connectivity.DnsManager; import com.android.server.connectivity.DnsManager.PrivateDnsConfig; import com.android.server.connectivity.IpConnectivityMetrics; import com.android.server.connectivity.KeepaliveTracker; import com.android.server.connectivity.LingerMonitor; Loading Loading @@ -399,6 +400,9 @@ public class ConnectivityService extends IConnectivityManager.Stub */ 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) { return sMagicDecoderRing.get(what, Integer.toString(what)); } Loading Loading @@ -863,6 +867,7 @@ public class ConnectivityService extends IConnectivityManager.Stub mMultinetworkPolicyTracker.start(); mDnsManager = new DnsManager(mContext, mNetd, mSystemProperties); registerPrivateDnsSettingsCallbacks(); } private Tethering makeTethering() { Loading Loading @@ -923,6 +928,12 @@ public class ConnectivityService extends IConnectivityManager.Stub 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() { return mNextNetworkRequestId++; } Loading Loading @@ -2086,13 +2097,37 @@ public class ConnectivityService extends IConnectivityManager.Stub synchronized (mNetworkForNetId) { nai = mNetworkForNetId.get(msg.arg2); } if (nai != null) { final boolean valid = (msg.arg1 == NetworkMonitor.NETWORK_TEST_RESULT_VALID); if (nai == null) break; final boolean valid = (msg.arg1 == NetworkMonitor.NETWORK_TEST_RESULT_VALID); final boolean wasValidated = nai.lastValidated; 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) ? (PrivateDnsConfig) msg.obj : null; final String redirectUrl = (msg.obj instanceof String) ? (String) msg.obj : ""; final boolean reevaluationRequired; final String logMsg; if (valid) { reevaluationRequired = updatePrivateDns(nai, privateDnsCfg); logMsg = (DBG && (privateDnsCfg != null)) ? " with " + privateDnsCfg.toString() : ""; } else { 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( Loading @@ -2108,7 +2143,7 @@ public class ConnectivityService extends IConnectivityManager.Stub updateInetCondition(nai); // Let the NetworkAgent know the state of its network Bundle redirectUrlBundle = new Bundle(); redirectUrlBundle.putString(NetworkAgent.REDIRECT_URL_KEY, (String)msg.obj); redirectUrlBundle.putString(NetworkAgent.REDIRECT_URL_KEY, redirectUrl); nai.asyncChannel.sendMessage( NetworkAgent.CMD_REPORT_NETWORK_STATUS, (valid ? NetworkAgent.VALID_NETWORK : NetworkAgent.INVALID_NETWORK), Loading @@ -2116,7 +2151,6 @@ public class ConnectivityService extends IConnectivityManager.Stub if (wasValidated && !nai.lastValidated) { handleNetworkUnvalidated(nai); } } break; } case NetworkMonitor.EVENT_PROVISIONING_NOTIFICATION: { Loading Loading @@ -2155,6 +2189,21 @@ public class ConnectivityService extends IConnectivityManager.Stub } 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; } Loading Loading @@ -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) { // 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. Loading Loading @@ -2324,6 +2430,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } catch (Exception e) { loge("Exception removing network: " + e); } mDnsManager.removeNetwork(nai.network); } synchronized (mNetworkForNetId) { mNetIdInUse.delete(nai.network.netId); Loading Loading @@ -2870,6 +2977,9 @@ public class ConnectivityService extends IConnectivityManager.Stub handleReportNetworkConnectivity((Network) msg.obj, msg.arg1, toBool(msg.arg2)); break; } case EVENT_PRIVATE_DNS_SETTINGS_CHANGED: handlePrivateDnsSettingsChanged(); break; } } } Loading Loading @@ -4559,11 +4669,12 @@ public class ConnectivityService extends IConnectivityManager.Stub final NetworkAgentInfo defaultNai = getDefaultNetwork(); final boolean isDefaultNetwork = (defaultNai != null && defaultNai.network.netId == netId); Collection<InetAddress> dnses = newLp.getDnsServers(); if (DBG) log("Setting DNS servers for network " + netId + " to " + dnses); if (DBG) { final Collection<InetAddress> dnses = newLp.getDnsServers(); log("Setting DNS servers for network " + netId + " to " + dnses); } try { mDnsManager.setDnsConfigurationForNetwork( netId, dnses, newLp.getDomains(), isDefaultNetwork); mDnsManager.setDnsConfigurationForNetwork(netId, newLp, isDefaultNetwork); } catch (Exception e) { loge("Exception in setDnsConfigurationForNetwork: " + e); } Loading
services/core/java/com/android/server/NetworkManagementService.java +0 −12 Original line number Diff line number Diff line Loading @@ -21,9 +21,6 @@ import static android.Manifest.permission.DUMP; import static android.Manifest.permission.NETWORK_SETTINGS; import static android.Manifest.permission.NETWORK_STACK; import static android.Manifest.permission.SHUTDOWN; import static android.net.ConnectivityManager.PRIVATE_DNS_DEFAULT_MODE; import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC; import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME; import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_DOZABLE; import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_DOZABLE; import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_NONE; Loading Loading @@ -1957,15 +1954,6 @@ public class NetworkManagementService extends INetworkManagementService.Stub } } private static boolean shouldUseTls(ContentResolver cr) { String privateDns = Settings.Global.getString(cr, Settings.Global.PRIVATE_DNS_MODE); if (TextUtils.isEmpty(privateDns)) { privateDns = PRIVATE_DNS_DEFAULT_MODE; } return privateDns.equals(PRIVATE_DNS_MODE_OPPORTUNISTIC) || privateDns.startsWith(PRIVATE_DNS_MODE_PROVIDER_HOSTNAME); } @Override public void addVpnUidRanges(int netId, UidRange[] ranges) { mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); Loading
services/core/java/com/android/server/connectivity/DnsManager.java +141 −44 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.server.connectivity; 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_PROVIDER_HOSTNAME; import static android.provider.Settings.Global.DNS_RESOLVER_MIN_SAMPLES; Loading @@ -29,19 +30,32 @@ import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkUtils; import android.net.Uri; import android.os.Binder; import android.os.INetworkManagementService; import android.os.Handler; import android.os.UserHandle; import android.provider.Settings; import android.system.GaiException; import android.system.OsConstants; import android.system.StructAddrinfo; import android.text.TextUtils; import android.util.Slog; import com.android.server.connectivity.MockableSystemProperties; import libcore.io.Libcore; import java.net.InetAddress; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.stream.Collectors; import java.util.StringJoiner; /** Loading @@ -61,10 +75,86 @@ public class DnsManager { private static final int DNS_RESOLVER_DEFAULT_MIN_SAMPLES = 8; 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 ContentResolver mContentResolver; private final INetworkManagementService mNMS; private final MockableSystemProperties mSystemProperties; private final Map<Integer, PrivateDnsConfig> mPrivateDnsMap; private int mNumDnsEntries; private int mSampleValidity; Loading @@ -79,44 +169,55 @@ public class DnsManager { mContentResolver = mContext.getContentResolver(); mNMS = nms; mSystemProperties = sp; mPrivateDnsMap = new HashMap<>(); // TODO: Create and register ContentObservers to track every setting // used herein, posting messages to respond to changes. } public boolean isPrivateDnsInStrictMode() { return !TextUtils.isEmpty(mPrivateDnsMode) && mPrivateDnsMode.startsWith(PRIVATE_DNS_MODE_PROVIDER_HOSTNAME) && !TextUtils.isEmpty(mPrivateDnsSpecifier); public PrivateDnsConfig getPrivateDnsConfig() { return getPrivateDnsConfig(mContentResolver); } 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( int netId, Collection<InetAddress> servers, String domains, boolean isDefaultNetwork) { updateParametersSettings(); updatePrivateDnsSettings(); int netId, LinkProperties lp, boolean isDefaultNetwork) { // We only use the PrivateDnsConfig data pushed to this class instance // 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 boolean useTls = (privateDnsCfg != null) && privateDnsCfg.useTls; 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()); final String[] serverStrs = NetworkUtils.makeStrings(servers); final String[] domainStrs = (domains == null) ? new String[0] : domains.split(" "); updateParametersSettings(); final int[] params = { mSampleValidity, mSuccessThreshold, mMinSamples, mMaxSamples }; final boolean useTls = shouldUseTls(mPrivateDnsMode); // TODO: Populate tlsHostname once it's decided how the hostname's IP // addresses will be resolved: // // [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 = ""; Slog.d(TAG, String.format("setDnsConfigurationForNetwork(%d, %s, %s, %s, %s, %s)", netId, Arrays.toString(serverStrs), Arrays.toString(domainStrs), Arrays.toString(params), useTls, tlsHostname)); try { mNMS.setDnsConfigurationForNetwork( netId, serverStrs, domainStrs, params, useTls, tlsHostname); Loading @@ -129,7 +230,7 @@ public class DnsManager { // default network, and we should just set net.dns1 to ::1, not least // because applications attempting to use net.dns resolvers will bypass // the privacy protections of things like DNS-over-TLS. if (isDefaultNetwork) setDefaultDnsSystemProperties(servers); if (isDefaultNetwork) setDefaultDnsSystemProperties(lp.getDnsServers()); flushVmDnsCache(); } Loading Loading @@ -163,11 +264,6 @@ public class DnsManager { } } private void updatePrivateDnsSettings() { mPrivateDnsMode = getStringSetting(PRIVATE_DNS_MODE); mPrivateDnsSpecifier = getStringSetting(PRIVATE_DNS_SPECIFIER); } private void updateParametersSettings() { mSampleValidity = getIntSetting( DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS, Loading Loading @@ -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) { return Settings.Global.getInt(mContentResolver, which, dflt); } Loading @@ -216,11 +308,16 @@ public class DnsManager { } } private static boolean shouldUseTls(String mode) { if (TextUtils.isEmpty(mode)) { mode = PRIVATE_DNS_DEFAULT_MODE; private static String getPrivateDnsMode(ContentResolver cr) { final String mode = getStringSetting(cr, PRIVATE_DNS_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(" "); } }
services/core/java/com/android/server/connectivity/NetworkMonitor.java +77 −3 File changed.Preview size limit exceeded, changes collapsed. Show changes