Merge "Add and implement API for VpnManagers to request validation"
This commit is contained in:
@@ -124,6 +124,7 @@ package android.net {
|
|||||||
|
|
||||||
public final class NetworkAgentConfig implements android.os.Parcelable {
|
public final class NetworkAgentConfig implements android.os.Parcelable {
|
||||||
method @Nullable public String getSubscriberId();
|
method @Nullable public String getSubscriberId();
|
||||||
|
method public boolean getVpnRequiresValidation();
|
||||||
method public boolean isBypassableVpn();
|
method public boolean isBypassableVpn();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,6 +132,7 @@ package android.net {
|
|||||||
method @NonNull public android.net.NetworkAgentConfig.Builder setBypassableVpn(boolean);
|
method @NonNull public android.net.NetworkAgentConfig.Builder setBypassableVpn(boolean);
|
||||||
method @NonNull public android.net.NetworkAgentConfig.Builder setExcludeLocalRoutesVpn(boolean);
|
method @NonNull public android.net.NetworkAgentConfig.Builder setExcludeLocalRoutesVpn(boolean);
|
||||||
method @NonNull public android.net.NetworkAgentConfig.Builder setSubscriberId(@Nullable String);
|
method @NonNull public android.net.NetworkAgentConfig.Builder setSubscriberId(@Nullable String);
|
||||||
|
method @NonNull public android.net.NetworkAgentConfig.Builder setVpnRequiresValidation(boolean);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class NetworkCapabilities implements android.os.Parcelable {
|
public final class NetworkCapabilities implements android.os.Parcelable {
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ import java.util.Objects;
|
|||||||
*/
|
*/
|
||||||
@SystemApi
|
@SystemApi
|
||||||
public final class NetworkAgentConfig implements Parcelable {
|
public final class NetworkAgentConfig implements Parcelable {
|
||||||
|
// TODO : make this object immutable. The fields that should stay mutable should likely
|
||||||
|
// migrate to NetworkAgentInfo.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the {@link Network} is a VPN, whether apps are allowed to bypass the
|
* If the {@link Network} is a VPN, whether apps are allowed to bypass the
|
||||||
@@ -246,6 +248,27 @@ public final class NetworkAgentConfig implements Parcelable {
|
|||||||
return excludeLocalRouteVpn;
|
return excludeLocalRouteVpn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether network validation should be performed for this VPN network.
|
||||||
|
* {@see #getVpnRequiresValidation}
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
private boolean mVpnRequiresValidation = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether network validation should be performed for this VPN network.
|
||||||
|
*
|
||||||
|
* If this network isn't a VPN this should always be {@code false}, and will be ignored
|
||||||
|
* if set.
|
||||||
|
* If this network is a VPN, false means this network should always be considered validated;
|
||||||
|
* true means it follows the same validation semantics as general internet networks.
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
@SystemApi(client = MODULE_LIBRARIES)
|
||||||
|
public boolean getVpnRequiresValidation() {
|
||||||
|
return mVpnRequiresValidation;
|
||||||
|
}
|
||||||
|
|
||||||
/** @hide */
|
/** @hide */
|
||||||
public NetworkAgentConfig() {
|
public NetworkAgentConfig() {
|
||||||
}
|
}
|
||||||
@@ -266,6 +289,7 @@ public final class NetworkAgentConfig implements Parcelable {
|
|||||||
legacySubTypeName = nac.legacySubTypeName;
|
legacySubTypeName = nac.legacySubTypeName;
|
||||||
mLegacyExtraInfo = nac.mLegacyExtraInfo;
|
mLegacyExtraInfo = nac.mLegacyExtraInfo;
|
||||||
excludeLocalRouteVpn = nac.excludeLocalRouteVpn;
|
excludeLocalRouteVpn = nac.excludeLocalRouteVpn;
|
||||||
|
mVpnRequiresValidation = nac.mVpnRequiresValidation;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -408,6 +432,25 @@ public final class NetworkAgentConfig implements Parcelable {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether network validation should be performed for this VPN network.
|
||||||
|
*
|
||||||
|
* Only agents registering a VPN network should use this setter. On other network
|
||||||
|
* types it will be ignored.
|
||||||
|
* False means this network should always be considered validated;
|
||||||
|
* true means it follows the same validation semantics as general internet.
|
||||||
|
*
|
||||||
|
* @param vpnRequiresValidation whether this VPN requires validation.
|
||||||
|
* Default is {@code false}.
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
@SystemApi(client = MODULE_LIBRARIES)
|
||||||
|
public Builder setVpnRequiresValidation(boolean vpnRequiresValidation) {
|
||||||
|
mConfig.mVpnRequiresValidation = vpnRequiresValidation;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets whether the apps can bypass the VPN connection.
|
* Sets whether the apps can bypass the VPN connection.
|
||||||
*
|
*
|
||||||
@@ -458,14 +501,16 @@ public final class NetworkAgentConfig implements Parcelable {
|
|||||||
&& Objects.equals(subscriberId, that.subscriberId)
|
&& Objects.equals(subscriberId, that.subscriberId)
|
||||||
&& Objects.equals(legacyTypeName, that.legacyTypeName)
|
&& Objects.equals(legacyTypeName, that.legacyTypeName)
|
||||||
&& Objects.equals(mLegacyExtraInfo, that.mLegacyExtraInfo)
|
&& Objects.equals(mLegacyExtraInfo, that.mLegacyExtraInfo)
|
||||||
&& excludeLocalRouteVpn == that.excludeLocalRouteVpn;
|
&& excludeLocalRouteVpn == that.excludeLocalRouteVpn
|
||||||
|
&& mVpnRequiresValidation == that.mVpnRequiresValidation;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hash(allowBypass, explicitlySelected, acceptUnvalidated,
|
return Objects.hash(allowBypass, explicitlySelected, acceptUnvalidated,
|
||||||
acceptPartialConnectivity, provisioningNotificationDisabled, subscriberId,
|
acceptPartialConnectivity, provisioningNotificationDisabled, subscriberId,
|
||||||
skip464xlat, legacyType, legacyTypeName, mLegacyExtraInfo, excludeLocalRouteVpn);
|
skip464xlat, legacyType, legacyTypeName, mLegacyExtraInfo, excludeLocalRouteVpn,
|
||||||
|
mVpnRequiresValidation);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -483,6 +528,7 @@ public final class NetworkAgentConfig implements Parcelable {
|
|||||||
+ ", legacyTypeName = '" + legacyTypeName + '\''
|
+ ", legacyTypeName = '" + legacyTypeName + '\''
|
||||||
+ ", legacyExtraInfo = '" + mLegacyExtraInfo + '\''
|
+ ", legacyExtraInfo = '" + mLegacyExtraInfo + '\''
|
||||||
+ ", excludeLocalRouteVpn = '" + excludeLocalRouteVpn + '\''
|
+ ", excludeLocalRouteVpn = '" + excludeLocalRouteVpn + '\''
|
||||||
|
+ ", vpnRequiresValidation = '" + mVpnRequiresValidation + '\''
|
||||||
+ "}";
|
+ "}";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -506,6 +552,7 @@ public final class NetworkAgentConfig implements Parcelable {
|
|||||||
out.writeString(legacySubTypeName);
|
out.writeString(legacySubTypeName);
|
||||||
out.writeString(mLegacyExtraInfo);
|
out.writeString(mLegacyExtraInfo);
|
||||||
out.writeInt(excludeLocalRouteVpn ? 1 : 0);
|
out.writeInt(excludeLocalRouteVpn ? 1 : 0);
|
||||||
|
out.writeInt(mVpnRequiresValidation ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final @NonNull Creator<NetworkAgentConfig> CREATOR =
|
public static final @NonNull Creator<NetworkAgentConfig> CREATOR =
|
||||||
@@ -526,6 +573,7 @@ public final class NetworkAgentConfig implements Parcelable {
|
|||||||
networkAgentConfig.legacySubTypeName = in.readString();
|
networkAgentConfig.legacySubTypeName = in.readString();
|
||||||
networkAgentConfig.mLegacyExtraInfo = in.readString();
|
networkAgentConfig.mLegacyExtraInfo = in.readString();
|
||||||
networkAgentConfig.excludeLocalRouteVpn = in.readInt() != 0;
|
networkAgentConfig.excludeLocalRouteVpn = in.readInt() != 0;
|
||||||
|
networkAgentConfig.mVpnRequiresValidation = in.readInt() != 0;
|
||||||
return networkAgentConfig;
|
return networkAgentConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import android.os.Build
|
|||||||
import androidx.test.filters.SmallTest
|
import androidx.test.filters.SmallTest
|
||||||
import androidx.test.runner.AndroidJUnit4
|
import androidx.test.runner.AndroidJUnit4
|
||||||
import com.android.modules.utils.build.SdkLevel.isAtLeastS
|
import com.android.modules.utils.build.SdkLevel.isAtLeastS
|
||||||
|
import com.android.modules.utils.build.SdkLevel.isAtLeastT
|
||||||
import com.android.testutils.ConnectivityModuleTest
|
import com.android.testutils.ConnectivityModuleTest
|
||||||
import com.android.testutils.DevSdkIgnoreRule
|
import com.android.testutils.DevSdkIgnoreRule
|
||||||
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
|
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
|
||||||
@@ -49,6 +50,10 @@ class NetworkAgentConfigTest {
|
|||||||
if (isAtLeastS()) {
|
if (isAtLeastS()) {
|
||||||
setBypassableVpn(true)
|
setBypassableVpn(true)
|
||||||
}
|
}
|
||||||
|
if (isAtLeastT()) {
|
||||||
|
setExcludeLocalRoutesVpn(true)
|
||||||
|
setVpnRequiresValidation(true)
|
||||||
|
}
|
||||||
}.build()
|
}.build()
|
||||||
assertParcelingIsLossless(config)
|
assertParcelingIsLossless(config)
|
||||||
}
|
}
|
||||||
@@ -69,6 +74,10 @@ class NetworkAgentConfigTest {
|
|||||||
setProvisioningNotificationEnabled(false)
|
setProvisioningNotificationEnabled(false)
|
||||||
setBypassableVpn(true)
|
setBypassableVpn(true)
|
||||||
}
|
}
|
||||||
|
if (isAtLeastT()) {
|
||||||
|
setExcludeLocalRoutesVpn(true)
|
||||||
|
setVpnRequiresValidation(true)
|
||||||
|
}
|
||||||
}.build()
|
}.build()
|
||||||
|
|
||||||
assertTrue(config.isExplicitlySelected())
|
assertTrue(config.isExplicitlySelected())
|
||||||
@@ -77,6 +86,10 @@ class NetworkAgentConfigTest {
|
|||||||
assertFalse(config.isPartialConnectivityAcceptable())
|
assertFalse(config.isPartialConnectivityAcceptable())
|
||||||
assertTrue(config.isUnvalidatedConnectivityAcceptable())
|
assertTrue(config.isUnvalidatedConnectivityAcceptable())
|
||||||
assertEquals("TEST_NETWORK", config.getLegacyTypeName())
|
assertEquals("TEST_NETWORK", config.getLegacyTypeName())
|
||||||
|
if (isAtLeastT()) {
|
||||||
|
assertTrue(config.getExcludeLocalRouteVpn())
|
||||||
|
assertTrue(config.getVpnRequiresValidation())
|
||||||
|
}
|
||||||
if (isAtLeastS()) {
|
if (isAtLeastS()) {
|
||||||
assertEquals(testExtraInfo, config.getLegacyExtraInfo())
|
assertEquals(testExtraInfo, config.getLegacyExtraInfo())
|
||||||
assertFalse(config.isNat64DetectionEnabled())
|
assertFalse(config.isNat64DetectionEnabled())
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ public class VpnProfileTest {
|
|||||||
private static final int ENCODED_INDEX_AUTH_PARAMS_INLINE = 23;
|
private static final int ENCODED_INDEX_AUTH_PARAMS_INLINE = 23;
|
||||||
private static final int ENCODED_INDEX_RESTRICTED_TO_TEST_NETWORKS = 24;
|
private static final int ENCODED_INDEX_RESTRICTED_TO_TEST_NETWORKS = 24;
|
||||||
private static final int ENCODED_INDEX_EXCLUDE_LOCAL_ROUTE = 25;
|
private static final int ENCODED_INDEX_EXCLUDE_LOCAL_ROUTE = 25;
|
||||||
|
private static final int ENCODED_INDEX_REQUIRE_PLATFORM_VALIDATION = 26;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDefaults() throws Exception {
|
public void testDefaults() throws Exception {
|
||||||
@@ -78,10 +79,13 @@ public class VpnProfileTest {
|
|||||||
assertEquals(1360, p.maxMtu);
|
assertEquals(1360, p.maxMtu);
|
||||||
assertFalse(p.areAuthParamsInline);
|
assertFalse(p.areAuthParamsInline);
|
||||||
assertFalse(p.isRestrictedToTestNetworks);
|
assertFalse(p.isRestrictedToTestNetworks);
|
||||||
|
assertFalse(p.excludeLocalRoutes);
|
||||||
|
assertFalse(p.requiresInternetValidation);
|
||||||
}
|
}
|
||||||
|
|
||||||
private VpnProfile getSampleIkev2Profile(String key) {
|
private VpnProfile getSampleIkev2Profile(String key) {
|
||||||
final VpnProfile p = new VpnProfile(key, true /* isRestrictedToTestNetworks */);
|
final VpnProfile p = new VpnProfile(key, true /* isRestrictedToTestNetworks */,
|
||||||
|
false /* excludesLocalRoutes */, true /* requiresPlatformValidation */);
|
||||||
|
|
||||||
p.name = "foo";
|
p.name = "foo";
|
||||||
p.type = VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS;
|
p.type = VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS;
|
||||||
@@ -129,8 +133,8 @@ public class VpnProfileTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testParcelUnparcel() {
|
public void testParcelUnparcel() {
|
||||||
if (isAtLeastT()) {
|
if (isAtLeastT()) {
|
||||||
// excludeLocalRoutes is added in T.
|
// excludeLocalRoutes, requiresPlatformValidation were added in T.
|
||||||
assertParcelSane(getSampleIkev2Profile(DUMMY_PROFILE_KEY), 24);
|
assertParcelSane(getSampleIkev2Profile(DUMMY_PROFILE_KEY), 25);
|
||||||
} else {
|
} else {
|
||||||
assertParcelSane(getSampleIkev2Profile(DUMMY_PROFILE_KEY), 23);
|
assertParcelSane(getSampleIkev2Profile(DUMMY_PROFILE_KEY), 23);
|
||||||
}
|
}
|
||||||
@@ -174,7 +178,8 @@ public class VpnProfileTest {
|
|||||||
getEncodedDecodedIkev2ProfileMissingValues(
|
getEncodedDecodedIkev2ProfileMissingValues(
|
||||||
ENCODED_INDEX_AUTH_PARAMS_INLINE,
|
ENCODED_INDEX_AUTH_PARAMS_INLINE,
|
||||||
ENCODED_INDEX_RESTRICTED_TO_TEST_NETWORKS,
|
ENCODED_INDEX_RESTRICTED_TO_TEST_NETWORKS,
|
||||||
ENCODED_INDEX_EXCLUDE_LOCAL_ROUTE /* missingIndices */);
|
ENCODED_INDEX_EXCLUDE_LOCAL_ROUTE,
|
||||||
|
ENCODED_INDEX_REQUIRE_PLATFORM_VALIDATION /* missingIndices */);
|
||||||
|
|
||||||
assertNull(VpnProfile.decode(DUMMY_PROFILE_KEY, tooFewValues.getBytes()));
|
assertNull(VpnProfile.decode(DUMMY_PROFILE_KEY, tooFewValues.getBytes()));
|
||||||
}
|
}
|
||||||
@@ -194,13 +199,25 @@ public class VpnProfileTest {
|
|||||||
public void testEncodeDecodeMissingExcludeLocalRoutes() {
|
public void testEncodeDecodeMissingExcludeLocalRoutes() {
|
||||||
final String tooFewValues =
|
final String tooFewValues =
|
||||||
getEncodedDecodedIkev2ProfileMissingValues(
|
getEncodedDecodedIkev2ProfileMissingValues(
|
||||||
ENCODED_INDEX_EXCLUDE_LOCAL_ROUTE /* missingIndices */);
|
ENCODED_INDEX_EXCLUDE_LOCAL_ROUTE,
|
||||||
|
ENCODED_INDEX_REQUIRE_PLATFORM_VALIDATION /* missingIndices */);
|
||||||
|
|
||||||
// Verify decoding without isRestrictedToTestNetworks defaults to false
|
// Verify decoding without excludeLocalRoutes defaults to false
|
||||||
final VpnProfile decoded = VpnProfile.decode(DUMMY_PROFILE_KEY, tooFewValues.getBytes());
|
final VpnProfile decoded = VpnProfile.decode(DUMMY_PROFILE_KEY, tooFewValues.getBytes());
|
||||||
assertFalse(decoded.excludeLocalRoutes);
|
assertFalse(decoded.excludeLocalRoutes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEncodeDecodeMissingRequiresValidation() {
|
||||||
|
final String tooFewValues =
|
||||||
|
getEncodedDecodedIkev2ProfileMissingValues(
|
||||||
|
ENCODED_INDEX_REQUIRE_PLATFORM_VALIDATION /* missingIndices */);
|
||||||
|
|
||||||
|
// Verify decoding without requiresValidation defaults to false
|
||||||
|
final VpnProfile decoded = VpnProfile.decode(DUMMY_PROFILE_KEY, tooFewValues.getBytes());
|
||||||
|
assertFalse(decoded.requiresInternetValidation);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEncodeDecodeLoginsNotSaved() {
|
public void testEncodeDecodeLoginsNotSaved() {
|
||||||
final VpnProfile profile = getSampleIkev2Profile(DUMMY_PROFILE_KEY);
|
final VpnProfile profile = getSampleIkev2Profile(DUMMY_PROFILE_KEY);
|
||||||
|
|||||||
Reference in New Issue
Block a user