diff options
| author | 2017-09-22 21:27:32 +0900 | |
|---|---|---|
| committer | 2018-06-05 15:31:58 +0100 | |
| commit | d9dbfa65c662e9b4f8064191663252925161dbfc (patch) | |
| tree | b3ac3dc55a0a19d4af0efda98ead6304b61cbfb4 | |
| parent | b82d3d7e741ff8fe6bf7d1cae79d519fe4922d9a (diff) | |
Support seamless handover between VPN fds.
This used to work before SOCK_DESTROY allowed us to close
connections when VPNs connected and disconnected. Instead of
doing this like the old code did by registering a new
NetworkAgent, support (limited) seamless handover on the
same NetworkAgent and netId.
Bug: 64692591
Test: cts-tradefed run commandAndExit cts-dev -m CtsHostsideNetworkTests -t com.android.cts.net.HostsideVpnTests#testSeamlessHandover
Change-Id: Idad0ec5946e7eb9e1f4a13c92ea7138de6a46f16
| -rw-r--r-- | services/core/java/com/android/server/connectivity/Vpn.java | 60 |
1 files changed, 53 insertions, 7 deletions
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index a91989838521..b77c1443e850 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -117,6 +117,7 @@ import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.Objects; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; @@ -895,6 +896,42 @@ public class Vpn { .compareTo(MOST_IPV6_ADDRESSES_COUNT) >= 0; } + /** + * Attempt to perform a seamless handover of VPNs by only updating LinkProperties without + * registering a new NetworkAgent. This is not always possible if the new VPN configuration + * has certain changes, in which case this method would just return {@code false}. + */ + private boolean updateLinkPropertiesInPlaceIfPossible(NetworkAgent agent, VpnConfig oldConfig) { + // NetworkMisc cannot be updated without registering a new NetworkAgent. + if (oldConfig.allowBypass != mConfig.allowBypass) { + Log.i(TAG, "Handover not possible due to changes to allowBypass"); + return false; + } + + // TODO: we currently do not support seamless handover if the allowed or disallowed + // applications have changed. Consider diffing UID ranges and only applying the delta. + if (!Objects.equals(oldConfig.allowedApplications, mConfig.allowedApplications) || + !Objects.equals(oldConfig.disallowedApplications, mConfig.disallowedApplications)) { + Log.i(TAG, "Handover not possible due to changes to whitelisted/blacklisted apps"); + return false; + } + + LinkProperties lp = makeLinkProperties(); + final boolean hadInternetCapability = mNetworkCapabilities.hasCapability( + NetworkCapabilities.NET_CAPABILITY_INTERNET); + final boolean willHaveInternetCapability = providesRoutesToMostDestinations(lp); + if (hadInternetCapability != willHaveInternetCapability) { + // A seamless handover would have led to a change to INTERNET capability, which + // is supposed to be immutable for a given network. In this case bail out and do not + // perform handover. + Log.i(TAG, "Handover not possible due to changes to INTERNET capability"); + return false; + } + + agent.sendLinkProperties(lp); + return true; + } + private void agentConnect() { LinkProperties lp = makeLinkProperties(); @@ -1003,13 +1040,11 @@ public class Vpn { String oldInterface = mInterface; Connection oldConnection = mConnection; NetworkAgent oldNetworkAgent = mNetworkAgent; - mNetworkAgent = null; Set<UidRange> oldUsers = mNetworkCapabilities.getUids(); // Configure the interface. Abort if any of these steps fails. ParcelFileDescriptor tun = ParcelFileDescriptor.adoptFd(jniCreate(config.mtu)); try { - updateState(DetailedState.CONNECTING, "establish"); String interfaze = jniGetName(tun.getFd()); // TEMP use the old jni calls until there is support for netd address setting @@ -1037,15 +1072,26 @@ public class Vpn { mConfig = config; // Set up forwarding and DNS rules. - agentConnect(); + // First attempt to do a seamless handover that only changes the interface name and + // parameters. If that fails, disconnect. + if (oldConfig != null + && updateLinkPropertiesInPlaceIfPossible(mNetworkAgent, oldConfig)) { + // Keep mNetworkAgent unchanged + } else { + mNetworkAgent = null; + updateState(DetailedState.CONNECTING, "establish"); + // Set up forwarding and DNS rules. + agentConnect(); + // Remove the old tun's user forwarding rules + // The new tun's user rules have already been added above so they will take over + // as rules are deleted. This prevents data leakage as the rules are moved over. + agentDisconnect(oldNetworkAgent); + } if (oldConnection != null) { mContext.unbindService(oldConnection); } - // Remove the old tun's user forwarding rules - // The new tun's user rules have already been added so they will take over - // as rules are deleted. This prevents data leakage as the rules are moved over. - agentDisconnect(oldNetworkAgent); + if (oldInterface != null && !oldInterface.equals(interfaze)) { jniReset(oldInterface); } |