Merge "Support strict mode private DNS on VPNs that provide Internet."
This commit is contained in:
@@ -40,7 +40,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
|
||||
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
|
||||
import static android.net.NetworkPolicyManager.RULE_NONE;
|
||||
import static android.net.NetworkPolicyManager.uidRulesToString;
|
||||
import static android.net.shared.NetworkMonitorUtils.isValidationRequired;
|
||||
import static android.net.shared.NetworkMonitorUtils.isPrivateDnsValidationRequired;
|
||||
import static android.os.Process.INVALID_UID;
|
||||
import static android.system.OsConstants.IPPROTO_TCP;
|
||||
import static android.system.OsConstants.IPPROTO_UDP;
|
||||
@@ -2824,8 +2824,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
}
|
||||
}
|
||||
|
||||
private boolean networkRequiresValidation(NetworkAgentInfo nai) {
|
||||
return isValidationRequired(nai.networkCapabilities);
|
||||
private boolean networkRequiresPrivateDnsValidation(NetworkAgentInfo nai) {
|
||||
return isPrivateDnsValidationRequired(nai.networkCapabilities);
|
||||
}
|
||||
|
||||
private void handleFreshlyValidatedNetwork(NetworkAgentInfo nai) {
|
||||
@@ -2843,7 +2843,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
|
||||
for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
|
||||
handlePerNetworkPrivateDnsConfig(nai, cfg);
|
||||
if (networkRequiresValidation(nai)) {
|
||||
if (networkRequiresPrivateDnsValidation(nai)) {
|
||||
handleUpdateLinkProperties(nai, new LinkProperties(nai.linkProperties));
|
||||
}
|
||||
}
|
||||
@@ -2852,7 +2852,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
private void handlePerNetworkPrivateDnsConfig(NetworkAgentInfo nai, PrivateDnsConfig cfg) {
|
||||
// Private DNS only ever applies to networks that might provide
|
||||
// Internet access and therefore also require validation.
|
||||
if (!networkRequiresValidation(nai)) return;
|
||||
if (!networkRequiresPrivateDnsValidation(nai)) return;
|
||||
|
||||
// Notify the NetworkAgentInfo/NetworkMonitor in case NetworkMonitor needs to cancel or
|
||||
// schedule DNS resolutions. If a DNS resolution is required the
|
||||
|
||||
@@ -483,11 +483,11 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
|
||||
// down an explicitly selected network before the user gets a chance to prefer it when
|
||||
// a higher-scoring network (e.g., Ethernet) is available.
|
||||
if (networkMisc.explicitlySelected && (networkMisc.acceptUnvalidated || pretendValidated)) {
|
||||
return ConnectivityConstants.MAXIMUM_NETWORK_SCORE;
|
||||
return ConnectivityConstants.EXPLICITLY_SELECTED_NETWORK_SCORE;
|
||||
}
|
||||
|
||||
int score = currentScore;
|
||||
if (!lastValidated && !pretendValidated && !ignoreWifiUnvalidationPenalty()) {
|
||||
if (!lastValidated && !pretendValidated && !ignoreWifiUnvalidationPenalty() && !isVPN()) {
|
||||
score -= ConnectivityConstants.UNVALIDATED_SCORE_PENALTY;
|
||||
}
|
||||
if (score < 0) score = 0;
|
||||
|
||||
@@ -28,6 +28,7 @@ import static android.net.ConnectivityManager.TYPE_MOBILE;
|
||||
import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA;
|
||||
import static android.net.ConnectivityManager.TYPE_MOBILE_MMS;
|
||||
import static android.net.ConnectivityManager.TYPE_NONE;
|
||||
import static android.net.ConnectivityManager.TYPE_VPN;
|
||||
import static android.net.ConnectivityManager.TYPE_WIFI;
|
||||
import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_INVALID;
|
||||
import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY;
|
||||
@@ -489,7 +490,7 @@ public class ConnectivityServiceTest {
|
||||
|
||||
MockNetworkAgent(int transport, LinkProperties linkProperties) {
|
||||
final int type = transportToLegacyType(transport);
|
||||
final String typeName = ConnectivityManager.getNetworkTypeName(transport);
|
||||
final String typeName = ConnectivityManager.getNetworkTypeName(type);
|
||||
mNetworkInfo = new NetworkInfo(type, 0, typeName, "Mock");
|
||||
mNetworkCapabilities = new NetworkCapabilities();
|
||||
mNetworkCapabilities.addTransportType(transport);
|
||||
@@ -619,6 +620,10 @@ public class ConnectivityServiceTest {
|
||||
mNetworkAgent.sendNetworkScore(mScore);
|
||||
}
|
||||
|
||||
public int getScore() {
|
||||
return mScore;
|
||||
}
|
||||
|
||||
public void explicitlySelected(boolean acceptUnvalidated) {
|
||||
mNetworkAgent.explicitlySelected(acceptUnvalidated);
|
||||
}
|
||||
@@ -1330,6 +1335,8 @@ public class ConnectivityServiceTest {
|
||||
return TYPE_WIFI;
|
||||
case TRANSPORT_CELLULAR:
|
||||
return TYPE_MOBILE;
|
||||
case TRANSPORT_VPN:
|
||||
return TYPE_VPN;
|
||||
default:
|
||||
return TYPE_NONE;
|
||||
}
|
||||
@@ -5369,6 +5376,58 @@ public class ConnectivityServiceTest {
|
||||
mCm.unregisterNetworkCallback(defaultCallback);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVpnUnvalidated() throws Exception {
|
||||
final TestNetworkCallback callback = new TestNetworkCallback();
|
||||
mCm.registerDefaultNetworkCallback(callback);
|
||||
|
||||
// Bring up Ethernet.
|
||||
mEthernetNetworkAgent = new MockNetworkAgent(TRANSPORT_ETHERNET);
|
||||
mEthernetNetworkAgent.connect(true);
|
||||
callback.expectAvailableThenValidatedCallbacks(mEthernetNetworkAgent);
|
||||
callback.assertNoCallback();
|
||||
|
||||
// Bring up a VPN that has the INTERNET capability, initially unvalidated.
|
||||
final int uid = Process.myUid();
|
||||
final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
|
||||
final ArraySet<UidRange> ranges = new ArraySet<>();
|
||||
ranges.add(new UidRange(uid, uid));
|
||||
mMockVpn.setNetworkAgent(vpnNetworkAgent);
|
||||
mMockVpn.setUids(ranges);
|
||||
vpnNetworkAgent.connect(false /* validated */, true /* hasInternet */);
|
||||
mMockVpn.connect();
|
||||
|
||||
// Even though the VPN is unvalidated, it becomes the default network for our app.
|
||||
callback.expectAvailableCallbacksUnvalidated(vpnNetworkAgent);
|
||||
// TODO: this looks like a spurious callback.
|
||||
callback.expectCallback(CallbackState.NETWORK_CAPABILITIES, vpnNetworkAgent);
|
||||
callback.assertNoCallback();
|
||||
|
||||
assertTrue(vpnNetworkAgent.getScore() > mEthernetNetworkAgent.getScore());
|
||||
assertEquals(ConnectivityConstants.VPN_DEFAULT_SCORE, vpnNetworkAgent.getScore());
|
||||
assertEquals(vpnNetworkAgent.getNetwork(), mCm.getActiveNetwork());
|
||||
|
||||
NetworkCapabilities nc = mCm.getNetworkCapabilities(vpnNetworkAgent.getNetwork());
|
||||
assertFalse(nc.hasCapability(NET_CAPABILITY_VALIDATED));
|
||||
assertTrue(nc.hasCapability(NET_CAPABILITY_INTERNET));
|
||||
|
||||
assertFalse(NetworkMonitorUtils.isValidationRequired(vpnNetworkAgent.mNetworkCapabilities));
|
||||
assertTrue(NetworkMonitorUtils.isPrivateDnsValidationRequired(
|
||||
vpnNetworkAgent.mNetworkCapabilities));
|
||||
|
||||
// Pretend that the VPN network validates.
|
||||
vpnNetworkAgent.setNetworkValid();
|
||||
vpnNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid());
|
||||
// Expect to see the validated capability, but no other changes, because the VPN is already
|
||||
// the default network for the app.
|
||||
callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, vpnNetworkAgent);
|
||||
callback.assertNoCallback();
|
||||
|
||||
vpnNetworkAgent.disconnect();
|
||||
callback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
|
||||
callback.expectAvailableCallbacksValidated(mEthernetNetworkAgent);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVpnSetUnderlyingNetworks() {
|
||||
final int uid = Process.myUid();
|
||||
|
||||
Reference in New Issue
Block a user