Loading services/core/java/com/android/server/ConnectivityService.java +65 −0 Original line number Original line Diff line number Diff line Loading @@ -52,6 +52,8 @@ import android.database.ContentObserver; import android.net.ConnectivityManager; import android.net.ConnectivityManager; import android.net.ConnectivityManager.PacketKeepalive; import android.net.ConnectivityManager.PacketKeepalive; import android.net.IConnectivityManager; import android.net.IConnectivityManager; import android.net.IIpConnectivityMetrics; import android.net.INetdEventCallback; import android.net.INetworkManagementEventObserver; import android.net.INetworkManagementEventObserver; import android.net.INetworkPolicyListener; import android.net.INetworkPolicyListener; import android.net.INetworkPolicyManager; import android.net.INetworkPolicyManager; Loading Loading @@ -140,6 +142,7 @@ 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.DnsManager.PrivateDnsConfig; import com.android.server.connectivity.DnsManager.PrivateDnsValidationUpdate; 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; Loading @@ -155,6 +158,7 @@ import com.android.server.connectivity.PermissionMonitor; import com.android.server.connectivity.Tethering; import com.android.server.connectivity.Tethering; import com.android.server.connectivity.Vpn; import com.android.server.connectivity.Vpn; import com.android.server.connectivity.tethering.TetheringDependencies; import com.android.server.connectivity.tethering.TetheringDependencies; import com.android.server.net.BaseNetdEventCallback; import com.android.server.net.BaseNetworkObserver; import com.android.server.net.BaseNetworkObserver; import com.android.server.net.LockdownVpnTracker; import com.android.server.net.LockdownVpnTracker; import com.android.server.net.NetworkPolicyManagerInternal; import com.android.server.net.NetworkPolicyManagerInternal; Loading Loading @@ -256,6 +260,7 @@ public class ConnectivityService extends IConnectivityManager.Stub private INetworkStatsService mStatsService; private INetworkStatsService mStatsService; private INetworkPolicyManager mPolicyManager; private INetworkPolicyManager mPolicyManager; private NetworkPolicyManagerInternal mPolicyManagerInternal; private NetworkPolicyManagerInternal mPolicyManagerInternal; private IIpConnectivityMetrics mIpConnectivityMetrics; private String mCurrentTcpBufferSizes; private String mCurrentTcpBufferSizes; Loading Loading @@ -414,6 +419,9 @@ public class ConnectivityService extends IConnectivityManager.Stub // Handle changes in Private DNS settings. // Handle changes in Private DNS settings. private static final int EVENT_PRIVATE_DNS_SETTINGS_CHANGED = 37; private static final int EVENT_PRIVATE_DNS_SETTINGS_CHANGED = 37; // Handle private DNS validation status updates. private static final int EVENT_PRIVATE_DNS_VALIDATION_UPDATE = 38; 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)); } } Loading Loading @@ -1553,6 +1561,41 @@ public class ConnectivityService extends IConnectivityManager.Stub return true; return true; } } @VisibleForTesting protected final INetdEventCallback mNetdEventCallback = new BaseNetdEventCallback() { @Override public void onPrivateDnsValidationEvent(int netId, String ipAddress, String hostname, boolean validated) { try { mHandler.sendMessage(mHandler.obtainMessage( EVENT_PRIVATE_DNS_VALIDATION_UPDATE, new PrivateDnsValidationUpdate(netId, InetAddress.parseNumericAddress(ipAddress), hostname, validated))); } catch (IllegalArgumentException e) { loge("Error parsing ip address in validation event"); } } }; @VisibleForTesting protected void registerNetdEventCallback() { mIpConnectivityMetrics = (IIpConnectivityMetrics) IIpConnectivityMetrics.Stub.asInterface( ServiceManager.getService(IpConnectivityLog.SERVICE_NAME)); if (mIpConnectivityMetrics == null) { Slog.wtf(TAG, "Missing IIpConnectivityMetrics"); } try { mIpConnectivityMetrics.addNetdEventCallback( INetdEventCallback.CALLBACK_CALLER_CONNECTIVITY_SERVICE, mNetdEventCallback); } catch (Exception e) { loge("Error registering netd callback: " + e); } } private final INetworkPolicyListener mPolicyListener = new NetworkPolicyManager.Listener() { private final INetworkPolicyListener mPolicyListener = new NetworkPolicyManager.Listener() { @Override @Override public void onUidRulesChanged(int uid, int uidRules) { public void onUidRulesChanged(int uid, int uidRules) { Loading Loading @@ -1738,6 +1781,7 @@ public class ConnectivityService extends IConnectivityManager.Stub void systemReady() { void systemReady() { loadGlobalProxy(); loadGlobalProxy(); registerNetdEventCallback(); synchronized (this) { synchronized (this) { mSystemReady = true; mSystemReady = true; Loading Loading @@ -2288,6 +2332,9 @@ public class ConnectivityService extends IConnectivityManager.Stub for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) { for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) { handlePerNetworkPrivateDnsConfig(nai, cfg); handlePerNetworkPrivateDnsConfig(nai, cfg); if (networkRequiresValidation(nai)) { handleUpdateLinkProperties(nai, new LinkProperties(nai.linkProperties)); } } } } } Loading @@ -2312,6 +2359,15 @@ public class ConnectivityService extends IConnectivityManager.Stub updateDnses(nai.linkProperties, null, nai.network.netId); updateDnses(nai.linkProperties, null, nai.network.netId); } } private void handlePrivateDnsValidationUpdate(PrivateDnsValidationUpdate update) { NetworkAgentInfo nai = getNetworkAgentInfoForNetId(update.netId); if (nai == null) { return; } mDnsManager.updatePrivateDnsValidation(update); handleUpdateLinkProperties(nai, new LinkProperties(nai.linkProperties)); } 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. Loading Loading @@ -3002,6 +3058,10 @@ public class ConnectivityService extends IConnectivityManager.Stub case EVENT_PRIVATE_DNS_SETTINGS_CHANGED: case EVENT_PRIVATE_DNS_SETTINGS_CHANGED: handlePrivateDnsSettingsChanged(); handlePrivateDnsSettingsChanged(); break; break; case EVENT_PRIVATE_DNS_VALIDATION_UPDATE: handlePrivateDnsValidationUpdate( (PrivateDnsValidationUpdate) msg.obj); break; } } } } } } Loading Loading @@ -4575,6 +4635,11 @@ public class ConnectivityService extends IConnectivityManager.Stub updateRoutes(newLp, oldLp, netId); updateRoutes(newLp, oldLp, netId); updateDnses(newLp, oldLp, netId); updateDnses(newLp, oldLp, netId); // Make sure LinkProperties represents the latest private DNS status. // This does not need to be done before updateDnses because the // LinkProperties are not the source of the private DNS configuration. // updateDnses will fetch the private DNS configuration from DnsManager. mDnsManager.updatePrivateDnsStatus(netId, newLp); // Start or stop clat accordingly to network state. // Start or stop clat accordingly to network state. networkAgent.updateClat(mNetd); networkAgent.updateClat(mNetd); Loading services/core/java/com/android/server/connectivity/DnsManager.java +135 −4 Original line number Original line Diff line number Diff line Loading @@ -37,10 +37,10 @@ import android.net.Uri; import android.net.dns.ResolvUtil; import android.net.dns.ResolvUtil; import android.os.Binder; import android.os.Binder; import android.os.INetworkManagementService; import android.os.INetworkManagementService; import android.os.Handler; import android.os.UserHandle; import android.os.UserHandle; import android.provider.Settings; import android.provider.Settings; import android.text.TextUtils; import android.text.TextUtils; import android.util.Pair; import android.util.Slog; import android.util.Slog; import com.android.server.connectivity.MockableSystemProperties; import com.android.server.connectivity.MockableSystemProperties; Loading @@ -50,8 +50,12 @@ import java.net.UnknownHostException; import java.util.Arrays; import java.util.Arrays; import java.util.Collection; import java.util.Collection; import java.util.HashMap; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; import java.util.stream.Collectors; import java.util.Set; import java.util.StringJoiner; import java.util.StringJoiner; Loading Loading @@ -110,6 +114,7 @@ import java.util.StringJoiner; */ */ public class DnsManager { public class DnsManager { private static final String TAG = DnsManager.class.getSimpleName(); private static final String TAG = DnsManager.class.getSimpleName(); private static final PrivateDnsConfig PRIVATE_DNS_OFF = new PrivateDnsConfig(); /* Defaults for resolver parameters. */ /* Defaults for resolver parameters. */ private static final int DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS = 1800; private static final int DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS = 1800; Loading Loading @@ -183,11 +188,89 @@ public class DnsManager { }; }; } } public static class PrivateDnsValidationUpdate { final public int netId; final public InetAddress ipAddress; final public String hostname; final public boolean validated; public PrivateDnsValidationUpdate(int netId, InetAddress ipAddress, String hostname, boolean validated) { this.netId = netId; this.ipAddress = ipAddress; this.hostname = hostname; this.validated = validated; } } private static class PrivateDnsValidationStatuses { enum ValidationStatus { IN_PROGRESS, FAILED, SUCCEEDED } // Validation statuses of <hostname, ipAddress> pairs for a single netId private Map<Pair<String, InetAddress>, ValidationStatus> mValidationMap; private PrivateDnsValidationStatuses() { mValidationMap = new HashMap<>(); } private boolean hasValidatedServer() { for (ValidationStatus status : mValidationMap.values()) { if (status == ValidationStatus.SUCCEEDED) { return true; } } return false; } private void updateTrackedDnses(String[] ipAddresses, String hostname) { Set<Pair<String, InetAddress>> latestDnses = new HashSet<>(); for (String ipAddress : ipAddresses) { try { latestDnses.add(new Pair(hostname, InetAddress.parseNumericAddress(ipAddress))); } catch (IllegalArgumentException e) {} } // Remove <hostname, ipAddress> pairs that should not be tracked. for (Iterator<Map.Entry<Pair<String, InetAddress>, ValidationStatus>> it = mValidationMap.entrySet().iterator(); it.hasNext(); ) { Map.Entry<Pair<String, InetAddress>, ValidationStatus> entry = it.next(); if (!latestDnses.contains(entry.getKey())) { it.remove(); } } // Add new <hostname, ipAddress> pairs that should be tracked. for (Pair<String, InetAddress> p : latestDnses) { if (!mValidationMap.containsKey(p)) { mValidationMap.put(p, ValidationStatus.IN_PROGRESS); } } } private void updateStatus(PrivateDnsValidationUpdate update) { Pair<String, InetAddress> p = new Pair(update.hostname, update.ipAddress); if (!mValidationMap.containsKey(p)) { return; } if (update.validated) { mValidationMap.put(p, ValidationStatus.SUCCEEDED); } else { mValidationMap.put(p, ValidationStatus.FAILED); } } } 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; // TODO: Replace these Maps with SparseArrays. private final Map<Integer, PrivateDnsConfig> mPrivateDnsMap; private final Map<Integer, PrivateDnsConfig> mPrivateDnsMap; private final Map<Integer, PrivateDnsValidationStatuses> mPrivateDnsValidationMap; private int mNumDnsEntries; private int mNumDnsEntries; private int mSampleValidity; private int mSampleValidity; Loading @@ -203,6 +286,7 @@ public class DnsManager { mNMS = nms; mNMS = nms; mSystemProperties = sp; mSystemProperties = sp; mPrivateDnsMap = new HashMap<>(); mPrivateDnsMap = new HashMap<>(); mPrivateDnsValidationMap = 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. Loading @@ -214,6 +298,7 @@ public class DnsManager { public void removeNetwork(Network network) { public void removeNetwork(Network network) { mPrivateDnsMap.remove(network.netId); mPrivateDnsMap.remove(network.netId); mPrivateDnsValidationMap.remove(network.netId); } } public PrivateDnsConfig updatePrivateDns(Network network, PrivateDnsConfig cfg) { public PrivateDnsConfig updatePrivateDns(Network network, PrivateDnsConfig cfg) { Loading @@ -223,6 +308,40 @@ public class DnsManager { : mPrivateDnsMap.remove(network.netId); : mPrivateDnsMap.remove(network.netId); } } public void updatePrivateDnsStatus(int netId, LinkProperties lp) { // Use the PrivateDnsConfig data pushed to this class instance // from ConnectivityService. final PrivateDnsConfig privateDnsCfg = mPrivateDnsMap.getOrDefault(netId, PRIVATE_DNS_OFF); final boolean useTls = privateDnsCfg.useTls; final boolean strictMode = privateDnsCfg.inStrictMode(); final String tlsHostname = strictMode ? privateDnsCfg.hostname : ""; if (strictMode) { lp.setUsePrivateDns(true); lp.setPrivateDnsServerName(tlsHostname); } else if (useTls) { // We are in opportunistic mode. Private DNS should be used if there // is a known DNS-over-TLS validated server. boolean validated = mPrivateDnsValidationMap.containsKey(netId) && mPrivateDnsValidationMap.get(netId).hasValidatedServer(); lp.setUsePrivateDns(validated); lp.setPrivateDnsServerName(null); } else { // Private DNS is disabled. lp.setUsePrivateDns(false); lp.setPrivateDnsServerName(null); } } public void updatePrivateDnsValidation(PrivateDnsValidationUpdate update) { final PrivateDnsValidationStatuses statuses = mPrivateDnsValidationMap.get(update.netId); if (statuses == null) return; statuses.updateStatus(update); } public void setDnsConfigurationForNetwork( public void setDnsConfigurationForNetwork( int netId, LinkProperties lp, boolean isDefaultNetwork) { int netId, LinkProperties lp, boolean isDefaultNetwork) { final String[] assignedServers = NetworkUtils.makeStrings(lp.getDnsServers()); final String[] assignedServers = NetworkUtils.makeStrings(lp.getDnsServers()); Loading @@ -238,10 +357,11 @@ public class DnsManager { // // // At this time we do not attempt to enable Private DNS on non-Internet // At this time we do not attempt to enable Private DNS on non-Internet // networks like IMS. // networks like IMS. final PrivateDnsConfig privateDnsCfg = mPrivateDnsMap.get(netId); final PrivateDnsConfig privateDnsCfg = mPrivateDnsMap.getOrDefault(netId, PRIVATE_DNS_OFF); final boolean useTls = (privateDnsCfg != null) && privateDnsCfg.useTls; final boolean useTls = privateDnsCfg.useTls; final boolean strictMode = (privateDnsCfg != null) && privateDnsCfg.inStrictMode(); final boolean strictMode = privateDnsCfg.inStrictMode(); final String tlsHostname = strictMode ? privateDnsCfg.hostname : ""; final String tlsHostname = strictMode ? privateDnsCfg.hostname : ""; final String[] tlsServers = final String[] tlsServers = strictMode ? NetworkUtils.makeStrings( strictMode ? NetworkUtils.makeStrings( Loading @@ -251,6 +371,17 @@ public class DnsManager { : useTls ? assignedServers // Opportunistic : useTls ? assignedServers // Opportunistic : new String[0]; // Off : new String[0]; // Off // Prepare to track the validation status of the DNS servers in the // resolver config when private DNS is in opportunistic or strict mode. if (useTls) { if (!mPrivateDnsValidationMap.containsKey(netId)) { mPrivateDnsValidationMap.put(netId, new PrivateDnsValidationStatuses()); } mPrivateDnsValidationMap.get(netId).updateTrackedDnses(tlsServers, tlsHostname); } else { mPrivateDnsValidationMap.remove(netId); } Slog.d(TAG, String.format("setDnsConfigurationForNetwork(%d, %s, %s, %s, %s, %s)", Slog.d(TAG, String.format("setDnsConfigurationForNetwork(%d, %s, %s, %s, %s, %s)", netId, Arrays.toString(assignedServers), Arrays.toString(domainStrs), netId, Arrays.toString(assignedServers), Arrays.toString(domainStrs), Arrays.toString(params), tlsHostname, Arrays.toString(tlsServers))); Arrays.toString(params), tlsHostname, Arrays.toString(tlsServers))); Loading tests/net/java/com/android/server/ConnectivityServiceTest.java +131 −1 Original line number Original line Diff line number Diff line Loading @@ -161,6 +161,7 @@ import java.net.InetAddress; import java.util.ArrayList; import java.util.ArrayList; import java.util.Arrays; import java.util.Arrays; import java.util.Collection; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.List; import java.util.Objects; import java.util.Objects; import java.util.Set; import java.util.Set; Loading Loading @@ -879,6 +880,10 @@ public class ConnectivityServiceTest { return mMetricsService; return mMetricsService; } } @Override protected void registerNetdEventCallback() { } public WrappedNetworkMonitor getLastCreatedWrappedNetworkMonitor() { public WrappedNetworkMonitor getLastCreatedWrappedNetworkMonitor() { return mLastCreatedNetworkMonitor; return mLastCreatedNetworkMonitor; } } Loading Loading @@ -3777,6 +3782,11 @@ public class ConnectivityServiceTest { // The default on Android is opportunistic mode ("Automatic"). // The default on Android is opportunistic mode ("Automatic"). setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com"); setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com"); final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback(); final NetworkRequest cellRequest = new NetworkRequest.Builder() .addTransportType(TRANSPORT_CELLULAR).build(); mCm.requestNetwork(cellRequest, cellNetworkCallback); mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); waitForIdle(); waitForIdle(); // CS tells netd about the empty DNS config for this network. // CS tells netd about the empty DNS config for this network. Loading Loading @@ -3812,6 +3822,14 @@ public class ConnectivityServiceTest { assertTrue(ArrayUtils.containsAll(tlsServers.getValue(), assertTrue(ArrayUtils.containsAll(tlsServers.getValue(), new String[]{"2001:db8::1", "192.0.2.1"})); new String[]{"2001:db8::1", "192.0.2.1"})); reset(mNetworkManagementService); reset(mNetworkManagementService); cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent); cellNetworkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, mCellNetworkAgent); CallbackInfo cbi = cellNetworkCallback.expectCallback( CallbackState.LINK_PROPERTIES, mCellNetworkAgent); cellNetworkCallback.assertNoCallback(); assertFalse(((LinkProperties)cbi.arg).isPrivateDnsActive()); assertNull(((LinkProperties)cbi.arg).getPrivateDnsServerName()); setPrivateDnsSettings(PRIVATE_DNS_MODE_OFF, "ignored.example.com"); setPrivateDnsSettings(PRIVATE_DNS_MODE_OFF, "ignored.example.com"); verify(mNetworkManagementService, times(1)).setDnsConfigurationForNetwork( verify(mNetworkManagementService, times(1)).setDnsConfigurationForNetwork( Loading @@ -3821,6 +3839,7 @@ public class ConnectivityServiceTest { assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(), assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(), new String[]{"2001:db8::1", "192.0.2.1"})); new String[]{"2001:db8::1", "192.0.2.1"})); reset(mNetworkManagementService); reset(mNetworkManagementService); cellNetworkCallback.assertNoCallback(); setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com"); setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com"); verify(mNetworkManagementService, atLeastOnce()).setDnsConfigurationForNetwork( verify(mNetworkManagementService, atLeastOnce()).setDnsConfigurationForNetwork( Loading @@ -3833,8 +3852,112 @@ public class ConnectivityServiceTest { assertTrue(ArrayUtils.containsAll(tlsServers.getValue(), assertTrue(ArrayUtils.containsAll(tlsServers.getValue(), new String[]{"2001:db8::1", "192.0.2.1"})); new String[]{"2001:db8::1", "192.0.2.1"})); reset(mNetworkManagementService); reset(mNetworkManagementService); cellNetworkCallback.assertNoCallback(); // Can't test strict mode without properly mocking out the DNS lookups. setPrivateDnsSettings(PRIVATE_DNS_MODE_PROVIDER_HOSTNAME, "strict.example.com"); // Can't test dns configuration for strict mode without properly mocking // out the DNS lookups, but can test that LinkProperties is updated. cbi = cellNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent); cellNetworkCallback.assertNoCallback(); assertTrue(((LinkProperties)cbi.arg).isPrivateDnsActive()); assertEquals("strict.example.com", ((LinkProperties)cbi.arg).getPrivateDnsServerName()); } @Test public void testLinkPropertiesWithPrivateDnsValidationEvents() throws Exception { // The default on Android is opportunistic mode ("Automatic"). setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com"); final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback(); final NetworkRequest cellRequest = new NetworkRequest.Builder() .addTransportType(TRANSPORT_CELLULAR).build(); mCm.requestNetwork(cellRequest, cellNetworkCallback); mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); waitForIdle(); LinkProperties lp = new LinkProperties(); mCellNetworkAgent.sendLinkProperties(lp); mCellNetworkAgent.connect(false); waitForIdle(); cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent); cellNetworkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, mCellNetworkAgent); CallbackInfo cbi = cellNetworkCallback.expectCallback( CallbackState.LINK_PROPERTIES, mCellNetworkAgent); cellNetworkCallback.assertNoCallback(); assertFalse(((LinkProperties)cbi.arg).isPrivateDnsActive()); assertNull(((LinkProperties)cbi.arg).getPrivateDnsServerName()); Set<InetAddress> dnsServers = new HashSet<>(); checkDnsServers(cbi.arg, dnsServers); // Send a validation event for a server that is not part of the current // resolver config. The validation event should be ignored. mService.mNetdEventCallback.onPrivateDnsValidationEvent( mCellNetworkAgent.getNetwork().netId, "", "145.100.185.18", true); cellNetworkCallback.assertNoCallback(); // Add a dns server to the LinkProperties. LinkProperties lp2 = new LinkProperties(lp); lp2.addDnsServer(InetAddress.getByName("145.100.185.16")); mCellNetworkAgent.sendLinkProperties(lp2); cbi = cellNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent); cellNetworkCallback.assertNoCallback(); assertFalse(((LinkProperties)cbi.arg).isPrivateDnsActive()); assertNull(((LinkProperties)cbi.arg).getPrivateDnsServerName()); dnsServers.add(InetAddress.getByName("145.100.185.16")); checkDnsServers(cbi.arg, dnsServers); // Send a validation event containing a hostname that is not part of // the current resolver config. The validation event should be ignored. mService.mNetdEventCallback.onPrivateDnsValidationEvent( mCellNetworkAgent.getNetwork().netId, "145.100.185.16", "hostname", true); cellNetworkCallback.assertNoCallback(); // Send a validation event where validation failed. mService.mNetdEventCallback.onPrivateDnsValidationEvent( mCellNetworkAgent.getNetwork().netId, "145.100.185.16", "", false); cellNetworkCallback.assertNoCallback(); // Send a validation event where validation succeeded for a server in // the current resolver config. A LinkProperties callback with updated // private dns fields should be sent. mService.mNetdEventCallback.onPrivateDnsValidationEvent( mCellNetworkAgent.getNetwork().netId, "145.100.185.16", "", true); cbi = cellNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent); cellNetworkCallback.assertNoCallback(); assertTrue(((LinkProperties)cbi.arg).isPrivateDnsActive()); assertNull(((LinkProperties)cbi.arg).getPrivateDnsServerName()); checkDnsServers(cbi.arg, dnsServers); // The private dns fields in LinkProperties should be preserved when // the network agent sends unrelated changes. LinkProperties lp3 = new LinkProperties(lp2); lp3.setMtu(1300); mCellNetworkAgent.sendLinkProperties(lp3); cbi = cellNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent); cellNetworkCallback.assertNoCallback(); assertTrue(((LinkProperties)cbi.arg).isPrivateDnsActive()); assertNull(((LinkProperties)cbi.arg).getPrivateDnsServerName()); checkDnsServers(cbi.arg, dnsServers); assertEquals(1300, ((LinkProperties)cbi.arg).getMtu()); // Removing the only validated server should affect the private dns // fields in LinkProperties. LinkProperties lp4 = new LinkProperties(lp3); lp4.removeDnsServer(InetAddress.getByName("145.100.185.16")); mCellNetworkAgent.sendLinkProperties(lp4); cbi = cellNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent); cellNetworkCallback.assertNoCallback(); assertFalse(((LinkProperties)cbi.arg).isPrivateDnsActive()); assertNull(((LinkProperties)cbi.arg).getPrivateDnsServerName()); dnsServers.remove(InetAddress.getByName("145.100.185.16")); checkDnsServers(cbi.arg, dnsServers); assertEquals(1300, ((LinkProperties)cbi.arg).getMtu()); } } private void checkDirectlyConnectedRoutes(Object callbackObj, private void checkDirectlyConnectedRoutes(Object callbackObj, Loading @@ -3854,6 +3977,13 @@ public class ConnectivityServiceTest { assertTrue(observedRoutes.containsAll(expectedRoutes)); assertTrue(observedRoutes.containsAll(expectedRoutes)); } } private static void checkDnsServers(Object callbackObj, Set<InetAddress> dnsServers) { assertTrue(callbackObj instanceof LinkProperties); LinkProperties lp = (LinkProperties) callbackObj; assertEquals(dnsServers.size(), lp.getDnsServers().size()); assertTrue(lp.getDnsServers().containsAll(dnsServers)); } private static <T> void assertEmpty(T[] ts) { private static <T> void assertEmpty(T[] ts) { int length = ts.length; int length = ts.length; assertEquals("expected empty array, but length was " + length, 0, length); assertEquals("expected empty array, but length was " + length, 0, length); Loading tests/net/java/com/android/server/connectivity/DnsManagerTest.java 0 → 100644 +201 −0 File added.Preview size limit exceeded, changes collapsed. Show changes Loading
services/core/java/com/android/server/ConnectivityService.java +65 −0 Original line number Original line Diff line number Diff line Loading @@ -52,6 +52,8 @@ import android.database.ContentObserver; import android.net.ConnectivityManager; import android.net.ConnectivityManager; import android.net.ConnectivityManager.PacketKeepalive; import android.net.ConnectivityManager.PacketKeepalive; import android.net.IConnectivityManager; import android.net.IConnectivityManager; import android.net.IIpConnectivityMetrics; import android.net.INetdEventCallback; import android.net.INetworkManagementEventObserver; import android.net.INetworkManagementEventObserver; import android.net.INetworkPolicyListener; import android.net.INetworkPolicyListener; import android.net.INetworkPolicyManager; import android.net.INetworkPolicyManager; Loading Loading @@ -140,6 +142,7 @@ 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.DnsManager.PrivateDnsConfig; import com.android.server.connectivity.DnsManager.PrivateDnsValidationUpdate; 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; Loading @@ -155,6 +158,7 @@ import com.android.server.connectivity.PermissionMonitor; import com.android.server.connectivity.Tethering; import com.android.server.connectivity.Tethering; import com.android.server.connectivity.Vpn; import com.android.server.connectivity.Vpn; import com.android.server.connectivity.tethering.TetheringDependencies; import com.android.server.connectivity.tethering.TetheringDependencies; import com.android.server.net.BaseNetdEventCallback; import com.android.server.net.BaseNetworkObserver; import com.android.server.net.BaseNetworkObserver; import com.android.server.net.LockdownVpnTracker; import com.android.server.net.LockdownVpnTracker; import com.android.server.net.NetworkPolicyManagerInternal; import com.android.server.net.NetworkPolicyManagerInternal; Loading Loading @@ -256,6 +260,7 @@ public class ConnectivityService extends IConnectivityManager.Stub private INetworkStatsService mStatsService; private INetworkStatsService mStatsService; private INetworkPolicyManager mPolicyManager; private INetworkPolicyManager mPolicyManager; private NetworkPolicyManagerInternal mPolicyManagerInternal; private NetworkPolicyManagerInternal mPolicyManagerInternal; private IIpConnectivityMetrics mIpConnectivityMetrics; private String mCurrentTcpBufferSizes; private String mCurrentTcpBufferSizes; Loading Loading @@ -414,6 +419,9 @@ public class ConnectivityService extends IConnectivityManager.Stub // Handle changes in Private DNS settings. // Handle changes in Private DNS settings. private static final int EVENT_PRIVATE_DNS_SETTINGS_CHANGED = 37; private static final int EVENT_PRIVATE_DNS_SETTINGS_CHANGED = 37; // Handle private DNS validation status updates. private static final int EVENT_PRIVATE_DNS_VALIDATION_UPDATE = 38; 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)); } } Loading Loading @@ -1553,6 +1561,41 @@ public class ConnectivityService extends IConnectivityManager.Stub return true; return true; } } @VisibleForTesting protected final INetdEventCallback mNetdEventCallback = new BaseNetdEventCallback() { @Override public void onPrivateDnsValidationEvent(int netId, String ipAddress, String hostname, boolean validated) { try { mHandler.sendMessage(mHandler.obtainMessage( EVENT_PRIVATE_DNS_VALIDATION_UPDATE, new PrivateDnsValidationUpdate(netId, InetAddress.parseNumericAddress(ipAddress), hostname, validated))); } catch (IllegalArgumentException e) { loge("Error parsing ip address in validation event"); } } }; @VisibleForTesting protected void registerNetdEventCallback() { mIpConnectivityMetrics = (IIpConnectivityMetrics) IIpConnectivityMetrics.Stub.asInterface( ServiceManager.getService(IpConnectivityLog.SERVICE_NAME)); if (mIpConnectivityMetrics == null) { Slog.wtf(TAG, "Missing IIpConnectivityMetrics"); } try { mIpConnectivityMetrics.addNetdEventCallback( INetdEventCallback.CALLBACK_CALLER_CONNECTIVITY_SERVICE, mNetdEventCallback); } catch (Exception e) { loge("Error registering netd callback: " + e); } } private final INetworkPolicyListener mPolicyListener = new NetworkPolicyManager.Listener() { private final INetworkPolicyListener mPolicyListener = new NetworkPolicyManager.Listener() { @Override @Override public void onUidRulesChanged(int uid, int uidRules) { public void onUidRulesChanged(int uid, int uidRules) { Loading Loading @@ -1738,6 +1781,7 @@ public class ConnectivityService extends IConnectivityManager.Stub void systemReady() { void systemReady() { loadGlobalProxy(); loadGlobalProxy(); registerNetdEventCallback(); synchronized (this) { synchronized (this) { mSystemReady = true; mSystemReady = true; Loading Loading @@ -2288,6 +2332,9 @@ public class ConnectivityService extends IConnectivityManager.Stub for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) { for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) { handlePerNetworkPrivateDnsConfig(nai, cfg); handlePerNetworkPrivateDnsConfig(nai, cfg); if (networkRequiresValidation(nai)) { handleUpdateLinkProperties(nai, new LinkProperties(nai.linkProperties)); } } } } } Loading @@ -2312,6 +2359,15 @@ public class ConnectivityService extends IConnectivityManager.Stub updateDnses(nai.linkProperties, null, nai.network.netId); updateDnses(nai.linkProperties, null, nai.network.netId); } } private void handlePrivateDnsValidationUpdate(PrivateDnsValidationUpdate update) { NetworkAgentInfo nai = getNetworkAgentInfoForNetId(update.netId); if (nai == null) { return; } mDnsManager.updatePrivateDnsValidation(update); handleUpdateLinkProperties(nai, new LinkProperties(nai.linkProperties)); } 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. Loading Loading @@ -3002,6 +3058,10 @@ public class ConnectivityService extends IConnectivityManager.Stub case EVENT_PRIVATE_DNS_SETTINGS_CHANGED: case EVENT_PRIVATE_DNS_SETTINGS_CHANGED: handlePrivateDnsSettingsChanged(); handlePrivateDnsSettingsChanged(); break; break; case EVENT_PRIVATE_DNS_VALIDATION_UPDATE: handlePrivateDnsValidationUpdate( (PrivateDnsValidationUpdate) msg.obj); break; } } } } } } Loading Loading @@ -4575,6 +4635,11 @@ public class ConnectivityService extends IConnectivityManager.Stub updateRoutes(newLp, oldLp, netId); updateRoutes(newLp, oldLp, netId); updateDnses(newLp, oldLp, netId); updateDnses(newLp, oldLp, netId); // Make sure LinkProperties represents the latest private DNS status. // This does not need to be done before updateDnses because the // LinkProperties are not the source of the private DNS configuration. // updateDnses will fetch the private DNS configuration from DnsManager. mDnsManager.updatePrivateDnsStatus(netId, newLp); // Start or stop clat accordingly to network state. // Start or stop clat accordingly to network state. networkAgent.updateClat(mNetd); networkAgent.updateClat(mNetd); Loading
services/core/java/com/android/server/connectivity/DnsManager.java +135 −4 Original line number Original line Diff line number Diff line Loading @@ -37,10 +37,10 @@ import android.net.Uri; import android.net.dns.ResolvUtil; import android.net.dns.ResolvUtil; import android.os.Binder; import android.os.Binder; import android.os.INetworkManagementService; import android.os.INetworkManagementService; import android.os.Handler; import android.os.UserHandle; import android.os.UserHandle; import android.provider.Settings; import android.provider.Settings; import android.text.TextUtils; import android.text.TextUtils; import android.util.Pair; import android.util.Slog; import android.util.Slog; import com.android.server.connectivity.MockableSystemProperties; import com.android.server.connectivity.MockableSystemProperties; Loading @@ -50,8 +50,12 @@ import java.net.UnknownHostException; import java.util.Arrays; import java.util.Arrays; import java.util.Collection; import java.util.Collection; import java.util.HashMap; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; import java.util.stream.Collectors; import java.util.Set; import java.util.StringJoiner; import java.util.StringJoiner; Loading Loading @@ -110,6 +114,7 @@ import java.util.StringJoiner; */ */ public class DnsManager { public class DnsManager { private static final String TAG = DnsManager.class.getSimpleName(); private static final String TAG = DnsManager.class.getSimpleName(); private static final PrivateDnsConfig PRIVATE_DNS_OFF = new PrivateDnsConfig(); /* Defaults for resolver parameters. */ /* Defaults for resolver parameters. */ private static final int DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS = 1800; private static final int DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS = 1800; Loading Loading @@ -183,11 +188,89 @@ public class DnsManager { }; }; } } public static class PrivateDnsValidationUpdate { final public int netId; final public InetAddress ipAddress; final public String hostname; final public boolean validated; public PrivateDnsValidationUpdate(int netId, InetAddress ipAddress, String hostname, boolean validated) { this.netId = netId; this.ipAddress = ipAddress; this.hostname = hostname; this.validated = validated; } } private static class PrivateDnsValidationStatuses { enum ValidationStatus { IN_PROGRESS, FAILED, SUCCEEDED } // Validation statuses of <hostname, ipAddress> pairs for a single netId private Map<Pair<String, InetAddress>, ValidationStatus> mValidationMap; private PrivateDnsValidationStatuses() { mValidationMap = new HashMap<>(); } private boolean hasValidatedServer() { for (ValidationStatus status : mValidationMap.values()) { if (status == ValidationStatus.SUCCEEDED) { return true; } } return false; } private void updateTrackedDnses(String[] ipAddresses, String hostname) { Set<Pair<String, InetAddress>> latestDnses = new HashSet<>(); for (String ipAddress : ipAddresses) { try { latestDnses.add(new Pair(hostname, InetAddress.parseNumericAddress(ipAddress))); } catch (IllegalArgumentException e) {} } // Remove <hostname, ipAddress> pairs that should not be tracked. for (Iterator<Map.Entry<Pair<String, InetAddress>, ValidationStatus>> it = mValidationMap.entrySet().iterator(); it.hasNext(); ) { Map.Entry<Pair<String, InetAddress>, ValidationStatus> entry = it.next(); if (!latestDnses.contains(entry.getKey())) { it.remove(); } } // Add new <hostname, ipAddress> pairs that should be tracked. for (Pair<String, InetAddress> p : latestDnses) { if (!mValidationMap.containsKey(p)) { mValidationMap.put(p, ValidationStatus.IN_PROGRESS); } } } private void updateStatus(PrivateDnsValidationUpdate update) { Pair<String, InetAddress> p = new Pair(update.hostname, update.ipAddress); if (!mValidationMap.containsKey(p)) { return; } if (update.validated) { mValidationMap.put(p, ValidationStatus.SUCCEEDED); } else { mValidationMap.put(p, ValidationStatus.FAILED); } } } 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; // TODO: Replace these Maps with SparseArrays. private final Map<Integer, PrivateDnsConfig> mPrivateDnsMap; private final Map<Integer, PrivateDnsConfig> mPrivateDnsMap; private final Map<Integer, PrivateDnsValidationStatuses> mPrivateDnsValidationMap; private int mNumDnsEntries; private int mNumDnsEntries; private int mSampleValidity; private int mSampleValidity; Loading @@ -203,6 +286,7 @@ public class DnsManager { mNMS = nms; mNMS = nms; mSystemProperties = sp; mSystemProperties = sp; mPrivateDnsMap = new HashMap<>(); mPrivateDnsMap = new HashMap<>(); mPrivateDnsValidationMap = 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. Loading @@ -214,6 +298,7 @@ public class DnsManager { public void removeNetwork(Network network) { public void removeNetwork(Network network) { mPrivateDnsMap.remove(network.netId); mPrivateDnsMap.remove(network.netId); mPrivateDnsValidationMap.remove(network.netId); } } public PrivateDnsConfig updatePrivateDns(Network network, PrivateDnsConfig cfg) { public PrivateDnsConfig updatePrivateDns(Network network, PrivateDnsConfig cfg) { Loading @@ -223,6 +308,40 @@ public class DnsManager { : mPrivateDnsMap.remove(network.netId); : mPrivateDnsMap.remove(network.netId); } } public void updatePrivateDnsStatus(int netId, LinkProperties lp) { // Use the PrivateDnsConfig data pushed to this class instance // from ConnectivityService. final PrivateDnsConfig privateDnsCfg = mPrivateDnsMap.getOrDefault(netId, PRIVATE_DNS_OFF); final boolean useTls = privateDnsCfg.useTls; final boolean strictMode = privateDnsCfg.inStrictMode(); final String tlsHostname = strictMode ? privateDnsCfg.hostname : ""; if (strictMode) { lp.setUsePrivateDns(true); lp.setPrivateDnsServerName(tlsHostname); } else if (useTls) { // We are in opportunistic mode. Private DNS should be used if there // is a known DNS-over-TLS validated server. boolean validated = mPrivateDnsValidationMap.containsKey(netId) && mPrivateDnsValidationMap.get(netId).hasValidatedServer(); lp.setUsePrivateDns(validated); lp.setPrivateDnsServerName(null); } else { // Private DNS is disabled. lp.setUsePrivateDns(false); lp.setPrivateDnsServerName(null); } } public void updatePrivateDnsValidation(PrivateDnsValidationUpdate update) { final PrivateDnsValidationStatuses statuses = mPrivateDnsValidationMap.get(update.netId); if (statuses == null) return; statuses.updateStatus(update); } public void setDnsConfigurationForNetwork( public void setDnsConfigurationForNetwork( int netId, LinkProperties lp, boolean isDefaultNetwork) { int netId, LinkProperties lp, boolean isDefaultNetwork) { final String[] assignedServers = NetworkUtils.makeStrings(lp.getDnsServers()); final String[] assignedServers = NetworkUtils.makeStrings(lp.getDnsServers()); Loading @@ -238,10 +357,11 @@ public class DnsManager { // // // At this time we do not attempt to enable Private DNS on non-Internet // At this time we do not attempt to enable Private DNS on non-Internet // networks like IMS. // networks like IMS. final PrivateDnsConfig privateDnsCfg = mPrivateDnsMap.get(netId); final PrivateDnsConfig privateDnsCfg = mPrivateDnsMap.getOrDefault(netId, PRIVATE_DNS_OFF); final boolean useTls = (privateDnsCfg != null) && privateDnsCfg.useTls; final boolean useTls = privateDnsCfg.useTls; final boolean strictMode = (privateDnsCfg != null) && privateDnsCfg.inStrictMode(); final boolean strictMode = privateDnsCfg.inStrictMode(); final String tlsHostname = strictMode ? privateDnsCfg.hostname : ""; final String tlsHostname = strictMode ? privateDnsCfg.hostname : ""; final String[] tlsServers = final String[] tlsServers = strictMode ? NetworkUtils.makeStrings( strictMode ? NetworkUtils.makeStrings( Loading @@ -251,6 +371,17 @@ public class DnsManager { : useTls ? assignedServers // Opportunistic : useTls ? assignedServers // Opportunistic : new String[0]; // Off : new String[0]; // Off // Prepare to track the validation status of the DNS servers in the // resolver config when private DNS is in opportunistic or strict mode. if (useTls) { if (!mPrivateDnsValidationMap.containsKey(netId)) { mPrivateDnsValidationMap.put(netId, new PrivateDnsValidationStatuses()); } mPrivateDnsValidationMap.get(netId).updateTrackedDnses(tlsServers, tlsHostname); } else { mPrivateDnsValidationMap.remove(netId); } Slog.d(TAG, String.format("setDnsConfigurationForNetwork(%d, %s, %s, %s, %s, %s)", Slog.d(TAG, String.format("setDnsConfigurationForNetwork(%d, %s, %s, %s, %s, %s)", netId, Arrays.toString(assignedServers), Arrays.toString(domainStrs), netId, Arrays.toString(assignedServers), Arrays.toString(domainStrs), Arrays.toString(params), tlsHostname, Arrays.toString(tlsServers))); Arrays.toString(params), tlsHostname, Arrays.toString(tlsServers))); Loading
tests/net/java/com/android/server/ConnectivityServiceTest.java +131 −1 Original line number Original line Diff line number Diff line Loading @@ -161,6 +161,7 @@ import java.net.InetAddress; import java.util.ArrayList; import java.util.ArrayList; import java.util.Arrays; import java.util.Arrays; import java.util.Collection; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.List; import java.util.Objects; import java.util.Objects; import java.util.Set; import java.util.Set; Loading Loading @@ -879,6 +880,10 @@ public class ConnectivityServiceTest { return mMetricsService; return mMetricsService; } } @Override protected void registerNetdEventCallback() { } public WrappedNetworkMonitor getLastCreatedWrappedNetworkMonitor() { public WrappedNetworkMonitor getLastCreatedWrappedNetworkMonitor() { return mLastCreatedNetworkMonitor; return mLastCreatedNetworkMonitor; } } Loading Loading @@ -3777,6 +3782,11 @@ public class ConnectivityServiceTest { // The default on Android is opportunistic mode ("Automatic"). // The default on Android is opportunistic mode ("Automatic"). setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com"); setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com"); final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback(); final NetworkRequest cellRequest = new NetworkRequest.Builder() .addTransportType(TRANSPORT_CELLULAR).build(); mCm.requestNetwork(cellRequest, cellNetworkCallback); mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); waitForIdle(); waitForIdle(); // CS tells netd about the empty DNS config for this network. // CS tells netd about the empty DNS config for this network. Loading Loading @@ -3812,6 +3822,14 @@ public class ConnectivityServiceTest { assertTrue(ArrayUtils.containsAll(tlsServers.getValue(), assertTrue(ArrayUtils.containsAll(tlsServers.getValue(), new String[]{"2001:db8::1", "192.0.2.1"})); new String[]{"2001:db8::1", "192.0.2.1"})); reset(mNetworkManagementService); reset(mNetworkManagementService); cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent); cellNetworkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, mCellNetworkAgent); CallbackInfo cbi = cellNetworkCallback.expectCallback( CallbackState.LINK_PROPERTIES, mCellNetworkAgent); cellNetworkCallback.assertNoCallback(); assertFalse(((LinkProperties)cbi.arg).isPrivateDnsActive()); assertNull(((LinkProperties)cbi.arg).getPrivateDnsServerName()); setPrivateDnsSettings(PRIVATE_DNS_MODE_OFF, "ignored.example.com"); setPrivateDnsSettings(PRIVATE_DNS_MODE_OFF, "ignored.example.com"); verify(mNetworkManagementService, times(1)).setDnsConfigurationForNetwork( verify(mNetworkManagementService, times(1)).setDnsConfigurationForNetwork( Loading @@ -3821,6 +3839,7 @@ public class ConnectivityServiceTest { assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(), assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(), new String[]{"2001:db8::1", "192.0.2.1"})); new String[]{"2001:db8::1", "192.0.2.1"})); reset(mNetworkManagementService); reset(mNetworkManagementService); cellNetworkCallback.assertNoCallback(); setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com"); setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com"); verify(mNetworkManagementService, atLeastOnce()).setDnsConfigurationForNetwork( verify(mNetworkManagementService, atLeastOnce()).setDnsConfigurationForNetwork( Loading @@ -3833,8 +3852,112 @@ public class ConnectivityServiceTest { assertTrue(ArrayUtils.containsAll(tlsServers.getValue(), assertTrue(ArrayUtils.containsAll(tlsServers.getValue(), new String[]{"2001:db8::1", "192.0.2.1"})); new String[]{"2001:db8::1", "192.0.2.1"})); reset(mNetworkManagementService); reset(mNetworkManagementService); cellNetworkCallback.assertNoCallback(); // Can't test strict mode without properly mocking out the DNS lookups. setPrivateDnsSettings(PRIVATE_DNS_MODE_PROVIDER_HOSTNAME, "strict.example.com"); // Can't test dns configuration for strict mode without properly mocking // out the DNS lookups, but can test that LinkProperties is updated. cbi = cellNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent); cellNetworkCallback.assertNoCallback(); assertTrue(((LinkProperties)cbi.arg).isPrivateDnsActive()); assertEquals("strict.example.com", ((LinkProperties)cbi.arg).getPrivateDnsServerName()); } @Test public void testLinkPropertiesWithPrivateDnsValidationEvents() throws Exception { // The default on Android is opportunistic mode ("Automatic"). setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com"); final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback(); final NetworkRequest cellRequest = new NetworkRequest.Builder() .addTransportType(TRANSPORT_CELLULAR).build(); mCm.requestNetwork(cellRequest, cellNetworkCallback); mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); waitForIdle(); LinkProperties lp = new LinkProperties(); mCellNetworkAgent.sendLinkProperties(lp); mCellNetworkAgent.connect(false); waitForIdle(); cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent); cellNetworkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, mCellNetworkAgent); CallbackInfo cbi = cellNetworkCallback.expectCallback( CallbackState.LINK_PROPERTIES, mCellNetworkAgent); cellNetworkCallback.assertNoCallback(); assertFalse(((LinkProperties)cbi.arg).isPrivateDnsActive()); assertNull(((LinkProperties)cbi.arg).getPrivateDnsServerName()); Set<InetAddress> dnsServers = new HashSet<>(); checkDnsServers(cbi.arg, dnsServers); // Send a validation event for a server that is not part of the current // resolver config. The validation event should be ignored. mService.mNetdEventCallback.onPrivateDnsValidationEvent( mCellNetworkAgent.getNetwork().netId, "", "145.100.185.18", true); cellNetworkCallback.assertNoCallback(); // Add a dns server to the LinkProperties. LinkProperties lp2 = new LinkProperties(lp); lp2.addDnsServer(InetAddress.getByName("145.100.185.16")); mCellNetworkAgent.sendLinkProperties(lp2); cbi = cellNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent); cellNetworkCallback.assertNoCallback(); assertFalse(((LinkProperties)cbi.arg).isPrivateDnsActive()); assertNull(((LinkProperties)cbi.arg).getPrivateDnsServerName()); dnsServers.add(InetAddress.getByName("145.100.185.16")); checkDnsServers(cbi.arg, dnsServers); // Send a validation event containing a hostname that is not part of // the current resolver config. The validation event should be ignored. mService.mNetdEventCallback.onPrivateDnsValidationEvent( mCellNetworkAgent.getNetwork().netId, "145.100.185.16", "hostname", true); cellNetworkCallback.assertNoCallback(); // Send a validation event where validation failed. mService.mNetdEventCallback.onPrivateDnsValidationEvent( mCellNetworkAgent.getNetwork().netId, "145.100.185.16", "", false); cellNetworkCallback.assertNoCallback(); // Send a validation event where validation succeeded for a server in // the current resolver config. A LinkProperties callback with updated // private dns fields should be sent. mService.mNetdEventCallback.onPrivateDnsValidationEvent( mCellNetworkAgent.getNetwork().netId, "145.100.185.16", "", true); cbi = cellNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent); cellNetworkCallback.assertNoCallback(); assertTrue(((LinkProperties)cbi.arg).isPrivateDnsActive()); assertNull(((LinkProperties)cbi.arg).getPrivateDnsServerName()); checkDnsServers(cbi.arg, dnsServers); // The private dns fields in LinkProperties should be preserved when // the network agent sends unrelated changes. LinkProperties lp3 = new LinkProperties(lp2); lp3.setMtu(1300); mCellNetworkAgent.sendLinkProperties(lp3); cbi = cellNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent); cellNetworkCallback.assertNoCallback(); assertTrue(((LinkProperties)cbi.arg).isPrivateDnsActive()); assertNull(((LinkProperties)cbi.arg).getPrivateDnsServerName()); checkDnsServers(cbi.arg, dnsServers); assertEquals(1300, ((LinkProperties)cbi.arg).getMtu()); // Removing the only validated server should affect the private dns // fields in LinkProperties. LinkProperties lp4 = new LinkProperties(lp3); lp4.removeDnsServer(InetAddress.getByName("145.100.185.16")); mCellNetworkAgent.sendLinkProperties(lp4); cbi = cellNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent); cellNetworkCallback.assertNoCallback(); assertFalse(((LinkProperties)cbi.arg).isPrivateDnsActive()); assertNull(((LinkProperties)cbi.arg).getPrivateDnsServerName()); dnsServers.remove(InetAddress.getByName("145.100.185.16")); checkDnsServers(cbi.arg, dnsServers); assertEquals(1300, ((LinkProperties)cbi.arg).getMtu()); } } private void checkDirectlyConnectedRoutes(Object callbackObj, private void checkDirectlyConnectedRoutes(Object callbackObj, Loading @@ -3854,6 +3977,13 @@ public class ConnectivityServiceTest { assertTrue(observedRoutes.containsAll(expectedRoutes)); assertTrue(observedRoutes.containsAll(expectedRoutes)); } } private static void checkDnsServers(Object callbackObj, Set<InetAddress> dnsServers) { assertTrue(callbackObj instanceof LinkProperties); LinkProperties lp = (LinkProperties) callbackObj; assertEquals(dnsServers.size(), lp.getDnsServers().size()); assertTrue(lp.getDnsServers().containsAll(dnsServers)); } private static <T> void assertEmpty(T[] ts) { private static <T> void assertEmpty(T[] ts) { int length = ts.length; int length = ts.length; assertEquals("expected empty array, but length was " + length, 0, length); assertEquals("expected empty array, but length was " + length, 0, length); Loading
tests/net/java/com/android/server/connectivity/DnsManagerTest.java 0 → 100644 +201 −0 File added.Preview size limit exceeded, changes collapsed. Show changes