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

Commit e43f81f6 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

am: eacc81f7

Change-Id: I26a69940636e362a3ff5d76ba2eecc012faf39d0
parents 19b51f4f eacc81f7
Loading
Loading
Loading
Loading
+53 −7
Original line number Original line Diff line number Diff line
@@ -115,6 +115,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.Collections;
import java.util.Comparator;
import java.util.Comparator;
import java.util.List;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.Set;
import java.util.SortedSet;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.TreeSet;
@@ -895,6 +896,42 @@ public class Vpn {
                .compareTo(MOST_IPV6_ADDRESSES_COUNT) >= 0;
                .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() {
    private void agentConnect() {
        LinkProperties lp = makeLinkProperties();
        LinkProperties lp = makeLinkProperties();


@@ -1003,13 +1040,11 @@ public class Vpn {
        String oldInterface = mInterface;
        String oldInterface = mInterface;
        Connection oldConnection = mConnection;
        Connection oldConnection = mConnection;
        NetworkAgent oldNetworkAgent = mNetworkAgent;
        NetworkAgent oldNetworkAgent = mNetworkAgent;
        mNetworkAgent = null;
        Set<UidRange> oldUsers = mNetworkCapabilities.getUids();
        Set<UidRange> oldUsers = mNetworkCapabilities.getUids();


        // Configure the interface. Abort if any of these steps fails.
        // Configure the interface. Abort if any of these steps fails.
        ParcelFileDescriptor tun = ParcelFileDescriptor.adoptFd(jniCreate(config.mtu));
        ParcelFileDescriptor tun = ParcelFileDescriptor.adoptFd(jniCreate(config.mtu));
        try {
        try {
            updateState(DetailedState.CONNECTING, "establish");
            String interfaze = jniGetName(tun.getFd());
            String interfaze = jniGetName(tun.getFd());


            // TEMP use the old jni calls until there is support for netd address setting
            // 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();
            config.startTime = SystemClock.elapsedRealtime();
            mConfig = config;
            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.
                // Set up forwarding and DNS rules.
                agentConnect();
                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) {
            if (oldConnection != null) {
                mContext.unbindService(oldConnection);
                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)) {
            if (oldInterface != null && !oldInterface.equals(interfaze)) {
                jniReset(oldInterface);
                jniReset(oldInterface);
            }
            }