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

Commit f336d722 authored by Chad Brubaker's avatar Chad Brubaker
Browse files

Fix supplimentary network connections with VPNs

Enables the use of supplimentary mobile networks like MMS, and HIPRI
while VPNs are running.

Change-Id: I313f57a905b4e16bd4322c68687cbff1cfbe9d3e
parent a5bc070e
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -479,6 +479,22 @@ public class ConnectivityManager {
        }
    }

    /**
     * Checks if the given network type should be exempt from VPN routing rules
     *
     * @hide
     */
    public static boolean isNetworkTypeExempt(int networkType) {
        switch (networkType) {
            case TYPE_MOBILE_MMS:
            case TYPE_MOBILE_SUPL:
            case TYPE_MOBILE_HIPRI:
                return true;
            default:
                return false;
        }
    }

    /**
     * Specifies the preferred network type.  When the device has more
     * than one type available the preferred network type will be used.
+12 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package android.os;

import android.net.InterfaceConfiguration;
import android.net.INetworkManagementEventObserver;
import android.net.LinkAddress;
import android.net.NetworkStats;
import android.net.RouteInfo;
import android.net.wifi.WifiConfiguration;
@@ -387,6 +388,17 @@ interface INetworkManagementService
     */
    void clearMarkedForwardingRoute(String iface, in RouteInfo route);

    /**
     * Exempts {@code host} from the routing set up by {@link setMarkedForwardingRoute}
     * All connects to {@code host} will use the global routing table
     */
    void setHostExemption(in LinkAddress host);

    /**
     * Clears an exemption set by {@link setHostExemption}
     */
    void clearHostExemption(in LinkAddress host);

    /**
     * Set a process (pid) to use the name servers associated with the specified interface.
     */
+70 −37
Original line number Diff line number Diff line
@@ -252,6 +252,9 @@ public class ConnectivityService extends IConnectivityManager.Stub {
    private static final boolean TO_DEFAULT_TABLE = true;
    private static final boolean TO_SECONDARY_TABLE = false;

    private static final boolean EXEMPT = true;
    private static final boolean UNEXEMPT = false;

    /**
     * used internally as a delayed event to make us switch back to the
     * default network
@@ -349,10 +352,19 @@ public class ConnectivityService extends IConnectivityManager.Stub {

    private InetAddress mDefaultDns;

    // Lock for protecting access to mAddedRoutes and mExemptAddresses
    private final Object mRoutesLock = new Object();

    // this collection is used to refcount the added routes - if there are none left
    // it's time to remove the route from the route table
    @GuardedBy("mRoutesLock")
    private Collection<RouteInfo> mAddedRoutes = new ArrayList<RouteInfo>();

    // this collection corresponds to the entries of mAddedRoutes that have routing exemptions
    // used to handle cleanup of exempt rules
    @GuardedBy("mRoutesLock")
    private Collection<LinkAddress> mExemptAddresses = new ArrayList<LinkAddress>();

    // used in DBG mode to track inet condition reports
    private static final int INET_CONDITION_LOG_MAX_SIZE = 15;
    private ArrayList mInetLog;
@@ -1470,7 +1482,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
        try {
            InetAddress addr = InetAddress.getByAddress(hostAddress);
            LinkProperties lp = tracker.getLinkProperties();
            boolean ok = addRouteToAddress(lp, addr);
            boolean ok = addRouteToAddress(lp, addr, EXEMPT);
            if (DBG) log("requestRouteToHostAddress ok=" + ok);
            return ok;
        } catch (UnknownHostException e) {
@@ -1482,24 +1494,25 @@ public class ConnectivityService extends IConnectivityManager.Stub {
        return false;
    }

    private boolean addRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable) {
        return modifyRoute(p, r, 0, ADD, toDefaultTable);
    private boolean addRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable,
            boolean exempt) {
        return modifyRoute(p, r, 0, ADD, toDefaultTable, exempt);
    }

    private boolean removeRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable) {
        return modifyRoute(p, r, 0, REMOVE, toDefaultTable);
        return modifyRoute(p, r, 0, REMOVE, toDefaultTable, UNEXEMPT);
    }

    private boolean addRouteToAddress(LinkProperties lp, InetAddress addr) {
        return modifyRouteToAddress(lp, addr, ADD, TO_DEFAULT_TABLE);
    private boolean addRouteToAddress(LinkProperties lp, InetAddress addr, boolean exempt) {
        return modifyRouteToAddress(lp, addr, ADD, TO_DEFAULT_TABLE, exempt);
    }

    private boolean removeRouteToAddress(LinkProperties lp, InetAddress addr) {
        return modifyRouteToAddress(lp, addr, REMOVE, TO_DEFAULT_TABLE);
        return modifyRouteToAddress(lp, addr, REMOVE, TO_DEFAULT_TABLE, UNEXEMPT);
    }

    private boolean modifyRouteToAddress(LinkProperties lp, InetAddress addr, boolean doAdd,
            boolean toDefaultTable) {
            boolean toDefaultTable, boolean exempt) {
        RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getAllRoutes(), addr);
        if (bestRoute == null) {
            bestRoute = RouteInfo.makeHostRoute(addr, lp.getInterfaceName());
@@ -1514,11 +1527,11 @@ public class ConnectivityService extends IConnectivityManager.Stub {
                bestRoute = RouteInfo.makeHostRoute(addr, bestRoute.getGateway(), iface);
            }
        }
        return modifyRoute(lp, bestRoute, 0, doAdd, toDefaultTable);
        return modifyRoute(lp, bestRoute, 0, doAdd, toDefaultTable, exempt);
    }

    private boolean modifyRoute(LinkProperties lp, RouteInfo r, int cycleCount, boolean doAdd,
            boolean toDefaultTable) {
            boolean toDefaultTable, boolean exempt) {
        if ((lp == null) || (r == null)) {
            if (DBG) log("modifyRoute got unexpected null: " + lp + ", " + r);
            return false;
@@ -1547,15 +1560,25 @@ public class ConnectivityService extends IConnectivityManager.Stub {
                                                        bestRoute.getGateway(),
                                                        ifaceName);
                }
                modifyRoute(lp, bestRoute, cycleCount+1, doAdd, toDefaultTable);
                modifyRoute(lp, bestRoute, cycleCount+1, doAdd, toDefaultTable, exempt);
            }
        }
        if (doAdd) {
            if (VDBG) log("Adding " + r + " for interface " + ifaceName);
            try {
                if (toDefaultTable) {
                    mAddedRoutes.add(r);  // only track default table - only one apps can effect
                    synchronized (mRoutesLock) {
                        // only track default table - only one apps can effect
                        mAddedRoutes.add(r);
                        mNetd.addRoute(ifaceName, r);
                        if (exempt) {
                            LinkAddress dest = r.getDestination();
                            if (!mExemptAddresses.contains(dest)) {
                                mNetd.setHostExemption(dest);
                                mExemptAddresses.add(dest);
                            }
                        }
                    }
                } else {
                    mNetd.addSecondaryRoute(ifaceName, r);
                }
@@ -1568,11 +1591,17 @@ public class ConnectivityService extends IConnectivityManager.Stub {
            // if we remove this one and there are no more like it, then refcount==0 and
            // we can remove it from the table
            if (toDefaultTable) {
                synchronized (mRoutesLock) {
                    mAddedRoutes.remove(r);
                    if (mAddedRoutes.contains(r) == false) {
                        if (VDBG) log("Removing " + r + " for interface " + ifaceName);
                        try {
                            mNetd.removeRoute(ifaceName, r);
                            LinkAddress dest = r.getDestination();
                            if (mExemptAddresses.contains(dest)) {
                                mNetd.clearHostExemption(dest);
                                mExemptAddresses.remove(dest);
                            }
                        } catch (Exception e) {
                            // never crash - catch them all
                            if (VDBG) loge("Exception trying to remove a route: " + e);
@@ -1581,6 +1610,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
                    } else {
                        if (VDBG) log("not removing " + r + " as it's still in use");
                    }
                }
            } else {
                if (VDBG) log("Removing " + r + " for interface " + ifaceName);
                try {
@@ -2260,6 +2290,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
     */
    private void handleConnectivityChange(int netType, boolean doReset) {
        int resetMask = doReset ? NetworkUtils.RESET_ALL_ADDRESSES : 0;
        boolean exempt = ConnectivityManager.isNetworkTypeExempt(netType);

        /*
         * If a non-default network is enabled, add the host routes that
@@ -2324,7 +2355,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
            }
        }
        mCurrentLinkProperties[netType] = newLp;
        boolean resetDns = updateRoutes(newLp, curLp, mNetConfigs[netType].isDefault());
        boolean resetDns = updateRoutes(newLp, curLp, mNetConfigs[netType].isDefault(), exempt);

        if (resetMask != 0 || resetDns) {
            if (curLp != null) {
@@ -2400,7 +2431,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
     * returns a boolean indicating the routes changed
     */
    private boolean updateRoutes(LinkProperties newLp, LinkProperties curLp,
            boolean isLinkDefault) {
            boolean isLinkDefault, boolean exempt) {
        Collection<RouteInfo> routesToAdd = null;
        CompareResult<InetAddress> dnsDiff = new CompareResult<InetAddress>();
        CompareResult<RouteInfo> routeDiff = new CompareResult<RouteInfo>();
@@ -2436,7 +2467,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
                }
                if (newLp != null) {
                    for (InetAddress newDns : newLp.getDnses()) {
                        addRouteToAddress(newLp, newDns);
                        addRouteToAddress(newLp, newDns, exempt);
                    }
                }
            } else {
@@ -2445,22 +2476,23 @@ public class ConnectivityService extends IConnectivityManager.Stub {
                    removeRouteToAddress(curLp, oldDns);
                }
                for (InetAddress newDns : dnsDiff.added) {
                    addRouteToAddress(newLp, newDns);
                    addRouteToAddress(newLp, newDns, exempt);
                }
            }
        }

        for (RouteInfo r :  routeDiff.added) {
            if (isLinkDefault || ! r.isDefaultRoute()) {
                addRoute(newLp, r, TO_DEFAULT_TABLE);
                addRoute(newLp, r, TO_DEFAULT_TABLE, exempt);
            } else {
                // add to a secondary route table
                addRoute(newLp, r, TO_SECONDARY_TABLE);
                addRoute(newLp, r, TO_SECONDARY_TABLE, UNEXEMPT);

                // many radios add a default route even when we don't want one.
                // remove the default route unless somebody else has asked for it
                String ifaceName = newLp.getInterfaceName();
                if (TextUtils.isEmpty(ifaceName) == false && mAddedRoutes.contains(r) == false) {
                synchronized (mRoutesLock) {
                    if (!TextUtils.isEmpty(ifaceName) && !mAddedRoutes.contains(r)) {
                        if (VDBG) log("Removing " + r + " for interface " + ifaceName);
                        try {
                            mNetd.removeRoute(ifaceName, r);
@@ -2471,6 +2503,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
                    }
                }
            }
        }

        return routesChanged;
    }
+20 −0
Original line number Diff line number Diff line
@@ -1472,6 +1472,26 @@ public class NetworkManagementService extends INetworkManagementService.Stub
        }
    }

    @Override
    public void setHostExemption(LinkAddress host) {
        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
        try {
            mConnector.execute("interface", "fwmark", "exempt", "add", host);
        } catch (NativeDaemonConnectorException e) {
            throw e.rethrowAsParcelableException();
        }
    }

    @Override
    public void clearHostExemption(LinkAddress host) {
        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
        try {
            mConnector.execute("interface", "fwmark", "exempt", "remove", host);
        } catch (NativeDaemonConnectorException e) {
            throw e.rethrowAsParcelableException();
        }
    }

    @Override
    public void setDnsInterfaceForUidRange(String iface, int uid_start, int uid_end) {
        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);