Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit eacc81f7 authored by Lorenzo Colitti's avatar Lorenzo Colitti Committed by android-build-merger
Browse files

Merge "Support seamless handover between VPN fds." into pi-dev

am: f35fd865

Change-Id: Ia94a34a1f4763d12b6d5ca702640933bc5c84499
parents bbaf6a4a f35fd865
Loading
Loading
Loading
Loading
+53 −7
Original line number Diff line number Diff line
@@ -115,6 +115,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
@@ -1036,16 +1071,27 @@ public class Vpn {
            config.startTime = SystemClock.elapsedRealtime();
            mConfig = config;

            // Set up forwarding and DNS rules.
            // 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);
            }