From bb754d6cc59611cc033928786cc51d93afc1ef89 Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Thu, 16 Dec 2021 10:01:45 +0800 Subject: [PATCH] Allow VPN network agent to exclude local traffic Add API to allow network agent to set whether the local traffic is excluded from the network. This commit is nonfunctional currently but only storing the boolean inside the NAI. Bug: 184750836 Test: atest FrameworksNetTests Change-Id: I3799216ac8fdf22eb4bcabc6c6136d8edbf69360 --- .../src/android/net/NetworkAgentConfig.java | 34 +++++++++++++++++-- .../android/net/NetworkAgentConfigTest.kt | 11 ++++-- .../android/internal/net/VpnProfileTest.java | 23 +++++++++++-- 3 files changed, 62 insertions(+), 6 deletions(-) diff --git a/framework/src/android/net/NetworkAgentConfig.java b/framework/src/android/net/NetworkAgentConfig.java index ad8396b06d..93fc379924 100644 --- a/framework/src/android/net/NetworkAgentConfig.java +++ b/framework/src/android/net/NetworkAgentConfig.java @@ -232,6 +232,20 @@ public final class NetworkAgentConfig implements Parcelable { return mLegacyExtraInfo; } + /** + * If the {@link Network} is a VPN, whether the local traffic is exempted from the VPN. + * @hide + */ + public boolean excludeLocalRouteVpn = false; + + /** + * @return whether local traffic is excluded from the VPN network. + * @hide + */ + public boolean getExcludeLocalRouteVpn() { + return excludeLocalRouteVpn; + } + /** @hide */ public NetworkAgentConfig() { } @@ -251,6 +265,7 @@ public final class NetworkAgentConfig implements Parcelable { legacySubType = nac.legacySubType; legacySubTypeName = nac.legacySubTypeName; mLegacyExtraInfo = nac.mLegacyExtraInfo; + excludeLocalRouteVpn = nac.excludeLocalRouteVpn; } } @@ -406,6 +421,17 @@ public final class NetworkAgentConfig implements Parcelable { return this; } + /** + * Sets whether the local traffic is exempted from VPN. + * + * @return this builder, to facilitate chaining. + * @hide TODO(184750836): Unhide once the implementation is completed. + */ + public Builder setExcludeLocalRoutesVpn(boolean excludeLocalRoutes) { + mConfig.excludeLocalRouteVpn = excludeLocalRoutes; + return this; + } + /** * Returns the constructed {@link NetworkAgentConfig} object. */ @@ -429,14 +455,15 @@ public final class NetworkAgentConfig implements Parcelable { && legacyType == that.legacyType && Objects.equals(subscriberId, that.subscriberId) && Objects.equals(legacyTypeName, that.legacyTypeName) - && Objects.equals(mLegacyExtraInfo, that.mLegacyExtraInfo); + && Objects.equals(mLegacyExtraInfo, that.mLegacyExtraInfo) + && excludeLocalRouteVpn == that.excludeLocalRouteVpn; } @Override public int hashCode() { return Objects.hash(allowBypass, explicitlySelected, acceptUnvalidated, acceptPartialConnectivity, provisioningNotificationDisabled, subscriberId, - skip464xlat, legacyType, legacyTypeName, mLegacyExtraInfo); + skip464xlat, legacyType, legacyTypeName, mLegacyExtraInfo, excludeLocalRouteVpn); } @Override @@ -453,6 +480,7 @@ public final class NetworkAgentConfig implements Parcelable { + ", hasShownBroken = " + hasShownBroken + ", legacyTypeName = '" + legacyTypeName + '\'' + ", legacyExtraInfo = '" + mLegacyExtraInfo + '\'' + + ", excludeLocalRouteVpn = '" + excludeLocalRouteVpn + '\'' + "}"; } @@ -475,6 +503,7 @@ public final class NetworkAgentConfig implements Parcelable { out.writeInt(legacySubType); out.writeString(legacySubTypeName); out.writeString(mLegacyExtraInfo); + out.writeInt(excludeLocalRouteVpn ? 1 : 0); } public static final @NonNull Creator CREATOR = @@ -494,6 +523,7 @@ public final class NetworkAgentConfig implements Parcelable { networkAgentConfig.legacySubType = in.readInt(); networkAgentConfig.legacySubTypeName = in.readString(); networkAgentConfig.mLegacyExtraInfo = in.readString(); + networkAgentConfig.excludeLocalRouteVpn = in.readInt() != 0; return networkAgentConfig; } diff --git a/tests/common/java/android/net/NetworkAgentConfigTest.kt b/tests/common/java/android/net/NetworkAgentConfigTest.kt index afaae1cf85..ed9995c97a 100644 --- a/tests/common/java/android/net/NetworkAgentConfigTest.kt +++ b/tests/common/java/android/net/NetworkAgentConfigTest.kt @@ -48,9 +48,16 @@ class NetworkAgentConfigTest { setBypassableVpn(true) } }.build() + // This test can be run as unit test against the latest system image, as CTS to verify + // an Android release that is as recent as the test, or as MTS to verify the + // Connectivity module. In the first two cases NetworkAgentConfig will be as recent + // as the test. In the last case, starting from S NetworkAgentConfig is updated as part + // of Connectivity, so it is also as recent as the test. For MTS on Q and R, + // NetworkAgentConfig is not updatable, so it may have a different number of fields. if (isAtLeastS()) { - // From S, the config will have 12 items - assertParcelSane(config, 12) + // When this test is run on S+, NetworkAgentConfig is as recent as the test, + // so this should be the most recent known number of fields. + assertParcelSane(config, 13) } else { // For R or below, the config will have 10 items assertParcelSane(config, 10) diff --git a/tests/unit/java/com/android/internal/net/VpnProfileTest.java b/tests/unit/java/com/android/internal/net/VpnProfileTest.java index a945a1f2cd..960a9f1b10 100644 --- a/tests/unit/java/com/android/internal/net/VpnProfileTest.java +++ b/tests/unit/java/com/android/internal/net/VpnProfileTest.java @@ -16,6 +16,7 @@ package com.android.internal.net; +import static com.android.modules.utils.build.SdkLevel.isAtLeastT; import static com.android.testutils.ParcelUtils.assertParcelSane; import static org.junit.Assert.assertEquals; @@ -48,6 +49,7 @@ public class VpnProfileTest { 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_EXCLUDE_LOCAL_ROUTE = 25; @Test public void testDefaults() throws Exception { @@ -126,7 +128,12 @@ public class VpnProfileTest { @Test public void testParcelUnparcel() { - assertParcelSane(getSampleIkev2Profile(DUMMY_PROFILE_KEY), 23); + if (isAtLeastT()) { + // excludeLocalRoutes is added in T. + assertParcelSane(getSampleIkev2Profile(DUMMY_PROFILE_KEY), 24); + } else { + assertParcelSane(getSampleIkev2Profile(DUMMY_PROFILE_KEY), 23); + } } @Test @@ -166,7 +173,8 @@ public class VpnProfileTest { final String tooFewValues = getEncodedDecodedIkev2ProfileMissingValues( ENCODED_INDEX_AUTH_PARAMS_INLINE, - ENCODED_INDEX_RESTRICTED_TO_TEST_NETWORKS /* missingIndices */); + ENCODED_INDEX_RESTRICTED_TO_TEST_NETWORKS, + ENCODED_INDEX_EXCLUDE_LOCAL_ROUTE /* missingIndices */); assertNull(VpnProfile.decode(DUMMY_PROFILE_KEY, tooFewValues.getBytes())); } @@ -182,6 +190,17 @@ public class VpnProfileTest { assertFalse(decoded.isRestrictedToTestNetworks); } + @Test + public void testEncodeDecodeMissingExcludeLocalRoutes() { + final String tooFewValues = + getEncodedDecodedIkev2ProfileMissingValues( + ENCODED_INDEX_EXCLUDE_LOCAL_ROUTE /* missingIndices */); + + // Verify decoding without isRestrictedToTestNetworks defaults to false + final VpnProfile decoded = VpnProfile.decode(DUMMY_PROFILE_KEY, tooFewValues.getBytes()); + assertFalse(decoded.excludeLocalRoutes); + } + @Test public void testEncodeDecodeLoginsNotSaved() { final VpnProfile profile = getSampleIkev2Profile(DUMMY_PROFILE_KEY);