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

Commit f35fd865 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

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

parents fe1d9dc1 d9dbfa65
Loading
Loading
Loading
Loading
+53 −7
Original line number Diff line number Diff line
@@ -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
@@ -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);
            }