diff options
| author | 2018-01-24 15:59:26 +0900 | |
|---|---|---|
| committer | 2018-01-24 15:59:26 +0900 | |
| commit | 2c852db56499f68b53fae92b075df5f47412dcf4 (patch) | |
| tree | 1cd6e3ca1cbe2fd1af3fd2864ed684c21e115d2f | |
| parent | 8b314b2b5dcbba49dae55eadced4a968beeffff7 (diff) | |
| parent | 69791b68837bf5f19654937396f7e55e2117743e (diff) | |
Resolve merge conflicts of 69791b68837bf5f19654937396f7e55e2117743e to master
Test: this is the exact code these changes were meant to give
      without conflict had the auto-merger not squashed them
      together before it tried to merge them. It was tested on
      master in this state.
Change-Id: I5cbde17fb6016e5e6b5d0b04c8f41858d708ef4a
14 files changed, 612 insertions, 194 deletions
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java index 2dacf8f460bb..52a2354840c9 100644 --- a/core/java/android/net/NetworkAgent.java +++ b/core/java/android/net/NetworkAgent.java @@ -17,6 +17,7 @@  package android.net;  import android.content.Context; +import android.net.ConnectivityManager.PacketKeepalive;  import android.os.Bundle;  import android.os.Handler;  import android.os.Looper; @@ -26,7 +27,6 @@ import android.util.Log;  import com.android.internal.util.AsyncChannel;  import com.android.internal.util.Protocol; -import android.net.ConnectivityManager.PacketKeepalive;  import java.util.ArrayList;  import java.util.concurrent.atomic.AtomicBoolean; @@ -101,20 +101,6 @@ public abstract class NetworkAgent extends Handler {      public static final int EVENT_NETWORK_SCORE_CHANGED = BASE + 4;      /** -     * Sent by the NetworkAgent to ConnectivityService to add new UID ranges -     * to be forced into this Network.  For VPNs only. -     * obj = UidRange[] to forward -     */ -    public static final int EVENT_UID_RANGES_ADDED = BASE + 5; - -    /** -     * Sent by the NetworkAgent to ConnectivityService to remove UID ranges -     * from being forced into this Network.  For VPNs only. -     * obj = UidRange[] to stop forwarding -     */ -    public static final int EVENT_UID_RANGES_REMOVED = BASE + 6; - -    /**       * Sent by ConnectivityService to the NetworkAgent to inform the agent of the       * networks status - whether we could use the network or could not, due to       * either a bad network configuration (no internet link) or captive portal. @@ -390,22 +376,6 @@ public abstract class NetworkAgent extends Handler {      }      /** -     * Called by the VPN code when it wants to add ranges of UIDs to be routed -     * through the VPN network. -     */ -    public void addUidRanges(UidRange[] ranges) { -        queueOrSendMessage(EVENT_UID_RANGES_ADDED, ranges); -    } - -    /** -     * Called by the VPN code when it wants to remove ranges of UIDs from being routed -     * through the VPN network. -     */ -    public void removeUidRanges(UidRange[] ranges) { -        queueOrSendMessage(EVENT_UID_RANGES_REMOVED, ranges); -    } - -    /**       * Called by the bearer to indicate this network was manually selected by the user.       * This should be called before the NetworkInfo is marked CONNECTED so that this       * Network can be given special treatment at that time. If {@code acceptUnvalidated} is diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java index 214ff64c6315..1a4765bcf631 100644 --- a/core/java/android/net/NetworkCapabilities.java +++ b/core/java/android/net/NetworkCapabilities.java @@ -20,6 +20,7 @@ import android.annotation.IntDef;  import android.net.ConnectivityManager.NetworkCallback;  import android.os.Parcel;  import android.os.Parcelable; +import android.util.ArraySet;  import android.util.proto.ProtoOutputStream;  import com.android.internal.annotations.VisibleForTesting; @@ -29,6 +30,7 @@ import com.android.internal.util.Preconditions;  import java.lang.annotation.Retention;  import java.lang.annotation.RetentionPolicy;  import java.util.Objects; +import java.util.Set;  import java.util.StringJoiner;  /** @@ -47,6 +49,7 @@ import java.util.StringJoiner;   */  public final class NetworkCapabilities implements Parcelable {      private static final String TAG = "NetworkCapabilities"; +    private static final int INVALID_UID = -1;      /**       * @hide @@ -64,6 +67,8 @@ public final class NetworkCapabilities implements Parcelable {              mLinkDownBandwidthKbps = nc.mLinkDownBandwidthKbps;              mNetworkSpecifier = nc.mNetworkSpecifier;              mSignalStrength = nc.mSignalStrength; +            mUids = nc.mUids; +            mEstablishingVpnAppUid = nc.mEstablishingVpnAppUid;          }      } @@ -77,6 +82,8 @@ public final class NetworkCapabilities implements Parcelable {          mLinkUpBandwidthKbps = mLinkDownBandwidthKbps = LINK_BANDWIDTH_UNSPECIFIED;          mNetworkSpecifier = null;          mSignalStrength = SIGNAL_STRENGTH_UNSPECIFIED; +        mUids = null; +        mEstablishingVpnAppUid = INVALID_UID;      }      /** @@ -619,6 +626,29 @@ public final class NetworkCapabilities implements Parcelable {      }      /** +     * UID of the app that manages this network, or INVALID_UID if none/unknown. +     * +     * This field keeps track of the UID of the app that created this network and is in charge +     * of managing it. In the practice, it is used to store the UID of VPN apps so it is named +     * accordingly, but it may be renamed if other mechanisms are offered for third party apps +     * to create networks. +     * +     * Because this field is only used in the services side (and to avoid apps being able to +     * set this to whatever they want), this field is not parcelled and will not be conserved +     * across the IPC boundary. +     * @hide +     */ +    private int mEstablishingVpnAppUid = INVALID_UID; + +    /** +     * Set the UID of the managing app. +     * @hide +     */ +    public void setEstablishingVpnAppUid(final int uid) { +        mEstablishingVpnAppUid = uid; +    } + +    /**       * Value indicating that link bandwidth is unspecified.       * @hide       */ @@ -837,6 +867,174 @@ public final class NetworkCapabilities implements Parcelable {      }      /** +     * List of UIDs this network applies to. No restriction if null. +     * <p> +     * This is typically (and at this time, only) used by VPN. This network is only available to +     * the UIDs in this list, and it is their default network. Apps in this list that wish to +     * bypass the VPN can do so iff the VPN app allows them to or if they are privileged. If this +     * member is null, then the network is not restricted by app UID. If it's an empty list, then +     * it means nobody can use it. +     * As a special exception, the app managing this network (as identified by its UID stored in +     * mEstablishingVpnAppUid) can always see this network. This is embodied by a special check in +     * satisfiedByUids. That still does not mean the network necessarily <strong>applies</strong> +     * to the app that manages it as determined by #appliesToUid. +     * <p> +     * Please note that in principle a single app can be associated with multiple UIDs because +     * each app will have a different UID when it's run as a different (macro-)user. A single +     * macro user can only have a single active VPN app at any given time however. +     * <p> +     * Also please be aware this class does not try to enforce any normalization on this. Callers +     * can only alter the UIDs by setting them wholesale : this class does not provide any utility +     * to add or remove individual UIDs or ranges. If callers have any normalization needs on +     * their own (like requiring sortedness or no overlap) they need to enforce it +     * themselves. Some of the internal methods also assume this is normalized as in no adjacent +     * or overlapping ranges are present. +     * +     * @hide +     */ +    private Set<UidRange> mUids = null; + +    /** +     * Convenience method to set the UIDs this network applies to to a single UID. +     * @hide +     */ +    public NetworkCapabilities setSingleUid(int uid) { +        final ArraySet<UidRange> identity = new ArraySet<>(1); +        identity.add(new UidRange(uid, uid)); +        setUids(identity); +        return this; +    } + +    /** +     * Set the list of UIDs this network applies to. +     * This makes a copy of the set so that callers can't modify it after the call. +     * @hide +     */ +    public NetworkCapabilities setUids(Set<UidRange> uids) { +        if (null == uids) { +            mUids = null; +        } else { +            mUids = new ArraySet<>(uids); +        } +        return this; +    } + +    /** +     * Get the list of UIDs this network applies to. +     * This returns a copy of the set so that callers can't modify the original object. +     * @hide +     */ +    public Set<UidRange> getUids() { +        return null == mUids ? null : new ArraySet<>(mUids); +    } + +    /** +     * Test whether this network applies to this UID. +     * @hide +     */ +    public boolean appliesToUid(int uid) { +        if (null == mUids) return true; +        for (UidRange range : mUids) { +            if (range.contains(uid)) { +                return true; +            } +        } +        return false; +    } + +    /** +     * Tests if the set of UIDs that this network applies to is the same of the passed set of UIDs. +     * <p> +     * This test only checks whether equal range objects are in both sets. It will +     * return false if the ranges are not exactly the same, even if the covered UIDs +     * are for an equivalent result. +     * <p> +     * Note that this method is not very optimized, which is fine as long as it's not used very +     * often. +     * <p> +     * nc is assumed nonnull. +     * +     * @hide +     */ +    @VisibleForTesting +    public boolean equalsUids(NetworkCapabilities nc) { +        Set<UidRange> comparedUids = nc.mUids; +        if (null == comparedUids) return null == mUids; +        if (null == mUids) return false; +        // Make a copy so it can be mutated to check that all ranges in mUids +        // also are in uids. +        final Set<UidRange> uids = new ArraySet<>(mUids); +        for (UidRange range : comparedUids) { +            if (!uids.contains(range)) { +                return false; +            } +            uids.remove(range); +        } +        return uids.isEmpty(); +    } + +    /** +     * Test whether the passed NetworkCapabilities satisfies the UIDs this capabilities require. +     * +     * This method is called on the NetworkCapabilities embedded in a request with the +     * capabilities of an available network. It checks whether all the UIDs from this listen +     * (representing the UIDs that must have access to the network) are satisfied by the UIDs +     * in the passed nc (representing the UIDs that this network is available to). +     * <p> +     * As a special exception, the UID that created the passed network (as represented by its +     * mEstablishingVpnAppUid field) always satisfies a NetworkRequest requiring it (of LISTEN +     * or REQUEST types alike), even if the network does not apply to it. That is so a VPN app +     * can see its own network when it listens for it. +     * <p> +     * nc is assumed nonnull. Else, NPE. +     * @see #appliesToUid +     * @hide +     */ +    public boolean satisfiedByUids(NetworkCapabilities nc) { +        if (null == nc.mUids) return true; // The network satisfies everything. +        if (null == mUids) return false; // Not everything allowed but requires everything +        for (UidRange requiredRange : mUids) { +            if (requiredRange.contains(nc.mEstablishingVpnAppUid)) return true; +            if (!nc.appliesToUidRange(requiredRange)) { +                return false; +            } +        } +        return true; +    } + +    /** +     * Returns whether this network applies to the passed ranges. +     * This assumes that to apply, the passed range has to be entirely contained +     * within one of the ranges this network applies to. If the ranges are not normalized, +     * this method may return false even though all required UIDs are covered because no +     * single range contained them all. +     * @hide +     */ +    @VisibleForTesting +    public boolean appliesToUidRange(UidRange requiredRange) { +        if (null == mUids) return true; +        for (UidRange uidRange : mUids) { +            if (uidRange.containsRange(requiredRange)) { +                return true; +            } +        } +        return false; +    } + +    /** +     * Combine the UIDs this network currently applies to with the UIDs the passed +     * NetworkCapabilities apply to. +     * nc is assumed nonnull. +     */ +    private void combineUids(NetworkCapabilities nc) { +        if (null == nc.mUids || null == mUids) { +            mUids = null; +            return; +        } +        mUids.addAll(nc.mUids); +    } + +    /**       * Combine a set of Capabilities to this one.  Useful for coming up with the complete set       * @hide       */ @@ -846,6 +1044,7 @@ public final class NetworkCapabilities implements Parcelable {          combineLinkBandwidths(nc);          combineSpecifiers(nc);          combineSignalStrength(nc); +        combineUids(nc);      }      /** @@ -858,12 +1057,13 @@ public final class NetworkCapabilities implements Parcelable {       * @hide       */      private boolean satisfiedByNetworkCapabilities(NetworkCapabilities nc, boolean onlyImmutable) { -        return (nc != null && -                satisfiedByNetCapabilities(nc, onlyImmutable) && -                satisfiedByTransportTypes(nc) && -                (onlyImmutable || satisfiedByLinkBandwidths(nc)) && -                satisfiedBySpecifier(nc) && -                (onlyImmutable || satisfiedBySignalStrength(nc))); +        return (nc != null +                && satisfiedByNetCapabilities(nc, onlyImmutable) +                && satisfiedByTransportTypes(nc) +                && (onlyImmutable || satisfiedByLinkBandwidths(nc)) +                && satisfiedBySpecifier(nc) +                && (onlyImmutable || satisfiedBySignalStrength(nc)) +                && (onlyImmutable || satisfiedByUids(nc)));      }      /** @@ -944,24 +1144,26 @@ public final class NetworkCapabilities implements Parcelable {      @Override      public boolean equals(Object obj) {          if (obj == null || (obj instanceof NetworkCapabilities == false)) return false; -        NetworkCapabilities that = (NetworkCapabilities)obj; -        return (equalsNetCapabilities(that) && -                equalsTransportTypes(that) && -                equalsLinkBandwidths(that) && -                equalsSignalStrength(that) && -                equalsSpecifier(that)); +        NetworkCapabilities that = (NetworkCapabilities) obj; +        return (equalsNetCapabilities(that) +                && equalsTransportTypes(that) +                && equalsLinkBandwidths(that) +                && equalsSignalStrength(that) +                && equalsSpecifier(that) +                && equalsUids(that));      }      @Override      public int hashCode() { -        return ((int)(mNetworkCapabilities & 0xFFFFFFFF) + -                ((int)(mNetworkCapabilities >> 32) * 3) + -                ((int)(mTransportTypes & 0xFFFFFFFF) * 5) + -                ((int)(mTransportTypes >> 32) * 7) + -                (mLinkUpBandwidthKbps * 11) + -                (mLinkDownBandwidthKbps * 13) + -                Objects.hashCode(mNetworkSpecifier) * 17 + -                (mSignalStrength * 19)); +        return ((int) (mNetworkCapabilities & 0xFFFFFFFF) +                + ((int) (mNetworkCapabilities >> 32) * 3) +                + ((int) (mTransportTypes & 0xFFFFFFFF) * 5) +                + ((int) (mTransportTypes >> 32) * 7) +                + (mLinkUpBandwidthKbps * 11) +                + (mLinkDownBandwidthKbps * 13) +                + Objects.hashCode(mNetworkSpecifier) * 17 +                + (mSignalStrength * 19) +                + Objects.hashCode(mUids) * 23);      }      @Override @@ -976,6 +1178,7 @@ public final class NetworkCapabilities implements Parcelable {          dest.writeInt(mLinkDownBandwidthKbps);          dest.writeParcelable((Parcelable) mNetworkSpecifier, flags);          dest.writeInt(mSignalStrength); +        dest.writeArraySet(new ArraySet<>(mUids));      }      public static final Creator<NetworkCapabilities> CREATOR = @@ -990,6 +1193,8 @@ public final class NetworkCapabilities implements Parcelable {                  netCap.mLinkDownBandwidthKbps = in.readInt();                  netCap.mNetworkSpecifier = in.readParcelable(null);                  netCap.mSignalStrength = in.readInt(); +                netCap.mUids = (ArraySet<UidRange>) in.readArraySet( +                        null /* ClassLoader, null for default */);                  return netCap;              }              @Override @@ -1022,7 +1227,12 @@ public final class NetworkCapabilities implements Parcelable {          String signalStrength = (hasSignalStrength() ? " SignalStrength: " + mSignalStrength : ""); -        return "[" + transports + capabilities + upBand + dnBand + specifier + signalStrength + "]"; +        String uids = (null != mUids ? " Uids: <" + mUids + ">" : ""); + +        String establishingAppUid = " EstablishingAppUid: " + mEstablishingVpnAppUid; + +        return "[" + transports + capabilities + upBand + dnBand + specifier + signalStrength +            + uids + establishingAppUid + "]";      }      /** @hide */ diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 5030dce7cbf9..8a9f59b9550f 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -30,6 +30,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;  import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;  import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;  import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;  import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;  import static android.net.NetworkCapabilities.TRANSPORT_VPN; @@ -106,6 +107,7 @@ import android.security.Credentials;  import android.security.KeyStore;  import android.telephony.TelephonyManager;  import android.text.TextUtils; +import android.util.ArraySet;  import android.util.LocalLog;  import android.util.LocalLog.ReadOnlyLocalLog;  import android.util.Log; @@ -176,6 +178,7 @@ import java.util.HashSet;  import java.util.List;  import java.util.Map;  import java.util.Objects; +import java.util.Set;  import java.util.SortedSet;  import java.util.TreeSet; @@ -733,12 +736,12 @@ public class ConnectivityService extends IConnectivityManager.Stub          mSystemProperties = getSystemProperties();          mMetricsLog = logger; -        mDefaultRequest = createInternetRequestForTransport(-1, NetworkRequest.Type.REQUEST); +        mDefaultRequest = createDefaultInternetRequestForTransport(-1, NetworkRequest.Type.REQUEST);          NetworkRequestInfo defaultNRI = new NetworkRequestInfo(null, mDefaultRequest, new Binder());          mNetworkRequests.put(mDefaultRequest, defaultNRI);          mNetworkRequestInfoLogs.log("REGISTER " + defaultNRI); -        mDefaultMobileDataRequest = createInternetRequestForTransport( +        mDefaultMobileDataRequest = createDefaultInternetRequestForTransport(                  NetworkCapabilities.TRANSPORT_CELLULAR, NetworkRequest.Type.BACKGROUND_REQUEST);          mHandlerThread = new HandlerThread("ConnectivityServiceThread"); @@ -903,7 +906,7 @@ public class ConnectivityService extends IConnectivityManager.Stub                  deps);      } -    private NetworkRequest createInternetRequestForTransport( +    private NetworkRequest createDefaultInternetRequestForTransport(              int transportType, NetworkRequest.Type type) {          NetworkCapabilities netCap = new NetworkCapabilities();          netCap.addCapability(NET_CAPABILITY_INTERNET); @@ -1281,7 +1284,11 @@ public class ConnectivityService extends IConnectivityManager.Stub                          for (Network network : networks) {                              nai = getNetworkAgentInfoForNetwork(network);                              nc = getNetworkCapabilitiesInternal(nai); +                            // nc is a copy of the capabilities in nai, so it's fine to mutate it +                            // TODO : don't remove the UIDs when communicating with processes +                            // that have the NETWORK_SETTINGS permission.                              if (nc != null) { +                                nc.setSingleUid(userId);                                  result.put(network, nc);                              }                          } @@ -2079,24 +2086,6 @@ public class ConnectivityService extends IConnectivityManager.Stub                      if (score != null) updateNetworkScore(nai, score.intValue());                      break;                  } -                case NetworkAgent.EVENT_UID_RANGES_ADDED: { -                    try { -                        mNetd.addVpnUidRanges(nai.network.netId, (UidRange[])msg.obj); -                    } catch (Exception e) { -                        // Never crash! -                        loge("Exception in addVpnUidRanges: " + e); -                    } -                    break; -                } -                case NetworkAgent.EVENT_UID_RANGES_REMOVED: { -                    try { -                        mNetd.removeVpnUidRanges(nai.network.netId, (UidRange[])msg.obj); -                    } catch (Exception e) { -                        // Never crash! -                        loge("Exception in removeVpnUidRanges: " + e); -                    } -                    break; -                }                  case NetworkAgent.EVENT_SET_EXPLICITLY_SELECTED: {                      if (nai.everConnected && !nai.networkMisc.explicitlySelected) {                          loge("ERROR: already-connected network explicitly selected."); @@ -4235,6 +4224,7 @@ public class ConnectivityService extends IConnectivityManager.Stub          // the system default network.          if (type == NetworkRequest.Type.TRACK_DEFAULT) {              networkCapabilities = new NetworkCapabilities(mDefaultRequest.networkCapabilities); +            networkCapabilities.removeCapability(NET_CAPABILITY_NOT_VPN);              enforceAccessPermission();          } else {              networkCapabilities = new NetworkCapabilities(networkCapabilities); @@ -4245,6 +4235,13 @@ public class ConnectivityService extends IConnectivityManager.Stub              enforceMeteredApnPolicy(networkCapabilities);          }          ensureRequestableCapabilities(networkCapabilities); +        // Set the UID range for this request to the single UID of the requester. +        // This will overwrite any allowed UIDs in the requested capabilities. Though there +        // are no visible methods to set the UIDs, an app could use reflection to try and get +        // networks for other apps so it's essential that the UIDs are overwritten. +        // TODO : don't forcefully set the UID when communicating with processes +        // that have the NETWORK_SETTINGS permission. +        networkCapabilities.setSingleUid(Binder.getCallingUid());          if (timeoutMs < 0) {              throw new IllegalArgumentException("Bad timeout specified"); @@ -4318,6 +4315,9 @@ public class ConnectivityService extends IConnectivityManager.Stub          enforceMeteredApnPolicy(networkCapabilities);          ensureRequestableCapabilities(networkCapabilities);          ensureValidNetworkSpecifier(networkCapabilities); +        // TODO : don't forcefully set the UID when communicating with processes +        // that have the NETWORK_SETTINGS permission. +        networkCapabilities.setSingleUid(Binder.getCallingUid());          NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, TYPE_NONE,                  nextNetworkRequestId(), NetworkRequest.Type.REQUEST); @@ -4371,6 +4371,9 @@ public class ConnectivityService extends IConnectivityManager.Stub          }          NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities); +        // TODO : don't forcefully set the UIDs when communicating with processes +        // that have the NETWORK_SETTINGS permission. +        nc.setSingleUid(Binder.getCallingUid());          if (!ConnectivityManager.checkChangePermission(mContext)) {              // Apps without the CHANGE_NETWORK_STATE permission can't use background networks, so              // make all their listens include NET_CAPABILITY_FOREGROUND. That way, they will get @@ -4399,8 +4402,12 @@ public class ConnectivityService extends IConnectivityManager.Stub          }          ensureValidNetworkSpecifier(networkCapabilities); -        NetworkRequest networkRequest = new NetworkRequest( -                new NetworkCapabilities(networkCapabilities), TYPE_NONE, nextNetworkRequestId(), +        final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities); +        // TODO : don't forcefully set the UIDs when communicating with processes +        // that have the NETWORK_SETTINGS permission. +        nc.setSingleUid(Binder.getCallingUid()); + +        NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(),                  NetworkRequest.Type.LISTEN);          NetworkRequestInfo nri = new NetworkRequestInfo(networkRequest, operation);          if (VDBG) log("pendingListenForNetwork for " + nri); @@ -4543,6 +4550,7 @@ public class ConnectivityService extends IConnectivityManager.Stub          NetworkInfo networkInfo = na.networkInfo;          na.networkInfo = null;          updateNetworkInfo(na, networkInfo); +        updateUids(na, null, na.networkCapabilities);      }      private void updateLinkProperties(NetworkAgentInfo networkAgent, LinkProperties oldLp) { @@ -4791,6 +4799,8 @@ public class ConnectivityService extends IConnectivityManager.Stub              nai.networkCapabilities = newNc;          } +        updateUids(nai, prevNc, newNc); +          if (nai.getCurrentScore() == oldScore && newNc.equalRequestableCapabilities(prevNc)) {              // If the requestable capabilities haven't changed, and the score hasn't changed, then              // the change we're processing can't affect any requests, it can only affect the listens @@ -4827,6 +4837,34 @@ public class ConnectivityService extends IConnectivityManager.Stub          }      } +    private void updateUids(NetworkAgentInfo nai, NetworkCapabilities prevNc, +            NetworkCapabilities newNc) { +        Set<UidRange> prevRanges = null == prevNc ? null : prevNc.getUids(); +        Set<UidRange> newRanges = null == newNc ? null : newNc.getUids(); +        if (null == prevRanges) prevRanges = new ArraySet<>(); +        if (null == newRanges) newRanges = new ArraySet<>(); +        final Set<UidRange> prevRangesCopy = new ArraySet<>(prevRanges); + +        prevRanges.removeAll(newRanges); +        newRanges.removeAll(prevRangesCopy); + +        try { +            if (!newRanges.isEmpty()) { +                final UidRange[] addedRangesArray = new UidRange[newRanges.size()]; +                newRanges.toArray(addedRangesArray); +                mNetd.addVpnUidRanges(nai.network.netId, addedRangesArray); +            } +            if (!prevRanges.isEmpty()) { +                final UidRange[] removedRangesArray = new UidRange[prevRanges.size()]; +                prevRanges.toArray(removedRangesArray); +                mNetd.removeVpnUidRanges(nai.network.netId, removedRangesArray); +            } +        } catch (Exception e) { +            // Never crash! +            loge("Exception in updateUids: " + e); +        } +    } +      public void handleUpdateLinkProperties(NetworkAgentInfo nai, LinkProperties newLp) {          if (mNetworkForNetId.get(nai.network.netId) != nai) {              // Ignore updates for disconnected networks @@ -4918,7 +4956,12 @@ public class ConnectivityService extends IConnectivityManager.Stub                  break;              }              case ConnectivityManager.CALLBACK_CAP_CHANGED: { -                putParcelable(bundle, new NetworkCapabilities(networkAgent.networkCapabilities)); +                final NetworkCapabilities nc = +                        new NetworkCapabilities(networkAgent.networkCapabilities); +                // TODO : don't remove the UIDs when communicating with processes +                // that have the NETWORK_SETTINGS permission. +                nc.setSingleUid(nri.mUid); +                putParcelable(bundle, nc);                  break;              }              case ConnectivityManager.CALLBACK_IP_CHANGED: { @@ -5442,6 +5485,7 @@ public class ConnectivityService extends IConnectivityManager.Stub                          }                      }                  } +                updateUids(networkAgent, networkAgent.networkCapabilities, null);              }          } else if ((oldInfo != null && oldInfo.getState() == NetworkInfo.State.SUSPENDED) ||                  state == NetworkInfo.State.SUSPENDED) { diff --git a/services/core/java/com/android/server/connectivity/ConnectivityConstants.java b/services/core/java/com/android/server/connectivity/ConnectivityConstants.java new file mode 100644 index 000000000000..24865bcd9a09 --- /dev/null +++ b/services/core/java/com/android/server/connectivity/ConnectivityConstants.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.connectivity; + +/** + * A class encapsulating various constants used by Connectivity. + * @hide + */ +public class ConnectivityConstants { +    // IPC constants +    public static final String ACTION_NETWORK_CONDITIONS_MEASURED = +            "android.net.conn.NETWORK_CONDITIONS_MEASURED"; +    public static final String EXTRA_CONNECTIVITY_TYPE = "extra_connectivity_type"; +    public static final String EXTRA_NETWORK_TYPE = "extra_network_type"; +    public static final String EXTRA_RESPONSE_RECEIVED = "extra_response_received"; +    public static final String EXTRA_IS_CAPTIVE_PORTAL = "extra_is_captive_portal"; +    public static final String EXTRA_CELL_ID = "extra_cellid"; +    public static final String EXTRA_SSID = "extra_ssid"; +    public static final String EXTRA_BSSID = "extra_bssid"; +    /** real time since boot */ +    public static final String EXTRA_REQUEST_TIMESTAMP_MS = "extra_request_timestamp_ms"; +    public static final String EXTRA_RESPONSE_TIMESTAMP_MS = "extra_response_timestamp_ms"; + +    public static final String PERMISSION_ACCESS_NETWORK_CONDITIONS = +            "android.permission.ACCESS_NETWORK_CONDITIONS"; + +    // Penalty applied to scores of Networks that have not been validated. +    public static final int UNVALIDATED_SCORE_PENALTY = 40; + +    // Score for explicitly connected network. +    // +    // This ensures that a) the explicitly selected network is never trumped by anything else, and +    // b) the explicitly selected network is never torn down. +    public static final int MAXIMUM_NETWORK_SCORE = 100; +    // VPNs typically have priority over other networks. Give them a score that will +    // let them win every single time. +    public static final int VPN_DEFAULT_SCORE = 101; +} diff --git a/services/core/java/com/android/server/connectivity/KeepalivePacketData.java b/services/core/java/com/android/server/connectivity/KeepalivePacketData.java index 2ccfdd1f3136..f6b73b7d6949 100644 --- a/services/core/java/com/android/server/connectivity/KeepalivePacketData.java +++ b/services/core/java/com/android/server/connectivity/KeepalivePacketData.java @@ -16,6 +16,9 @@  package com.android.server.connectivity; +import static android.net.util.NetworkConstants.IPV4_HEADER_MIN_LEN; +import static android.net.util.NetworkConstants.UDP_HEADER_LEN; +  import android.system.OsConstants;  import android.net.ConnectivityManager;  import android.net.NetworkUtils; @@ -57,9 +60,6 @@ public class KeepalivePacketData {      /** Packet data. A raw byte string of packet data, not including the link-layer header. */      public final byte[] data; -    private static final int IPV4_HEADER_LENGTH = 20; -    private static final int UDP_HEADER_LENGTH = 8; -      protected KeepalivePacketData(InetAddress srcAddress, int srcPort,              InetAddress dstAddress, int dstPort, byte[] data) throws InvalidPacketException {          this.srcAddress = srcAddress; @@ -111,7 +111,7 @@ public class KeepalivePacketData {              throw new InvalidPacketException(ERROR_INVALID_PORT);          } -        int length = IPV4_HEADER_LENGTH + UDP_HEADER_LENGTH + 1; +        int length = IPV4_HEADER_MIN_LEN + UDP_HEADER_LEN + 1;          ByteBuffer buf = ByteBuffer.allocate(length);          buf.order(ByteOrder.BIG_ENDIAN);          buf.putShort((short) 0x4500);             // IP version and TOS @@ -130,7 +130,7 @@ public class KeepalivePacketData {          buf.putShort((short) 0);                  // UDP checksum          buf.put((byte) 0xff);                     // NAT-T keepalive          buf.putShort(ipChecksumOffset, IpUtils.ipChecksum(buf, 0)); -        buf.putShort(udpChecksumOffset, IpUtils.udpChecksum(buf, 0, IPV4_HEADER_LENGTH)); +        buf.putShort(udpChecksumOffset, IpUtils.udpChecksum(buf, 0, IPV4_HEADER_MIN_LEN));          return new KeepalivePacketData(srcAddress, srcPort, dstAddress, dstPort, buf.array());      } diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java index a4d7242086bf..85b70ca0ffcd 100644 --- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java +++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java @@ -223,14 +223,6 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {      // This represents the last score received from the NetworkAgent.      private int currentScore; -    // Penalty applied to scores of Networks that have not been validated. -    private static final int UNVALIDATED_SCORE_PENALTY = 40; - -    // Score for explicitly connected network. -    // -    // This ensures that a) the explicitly selected network is never trumped by anything else, and -    // b) the explicitly selected network is never torn down. -    private static final int MAXIMUM_NETWORK_SCORE = 100;      // The list of NetworkRequests being satisfied by this Network.      private final SparseArray<NetworkRequest> mNetworkRequests = new SparseArray<>(); @@ -428,12 +420,12 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {          // down an explicitly selected network before the user gets a chance to prefer it when          // a higher-scoring network (e.g., Ethernet) is available.          if (networkMisc.explicitlySelected && (networkMisc.acceptUnvalidated || pretendValidated)) { -            return MAXIMUM_NETWORK_SCORE; +            return ConnectivityConstants.MAXIMUM_NETWORK_SCORE;          }          int score = currentScore;          if (!lastValidated && !pretendValidated && !ignoreWifiUnvalidationPenalty()) { -            score -= UNVALIDATED_SCORE_PENALTY; +            score -= ConnectivityConstants.UNVALIDATED_SCORE_PENALTY;          }          if (score < 0) score = 0;          return score; diff --git a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java index 85d1d1ef1d75..c471f0caa3cc 100644 --- a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java +++ b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java @@ -24,6 +24,7 @@ import android.net.Network;  import android.net.NetworkUtils;  import android.net.RouteInfo;  import android.net.TrafficStats; +import android.net.util.NetworkConstants;  import android.os.SystemClock;  import android.system.ErrnoException;  import android.system.Os; @@ -421,8 +422,6 @@ public class NetworkDiagnostics {      private class IcmpCheck extends SimpleSocketCheck implements Runnable {          private static final int TIMEOUT_SEND = 100;          private static final int TIMEOUT_RECV = 300; -        private static final int ICMPV4_ECHO_REQUEST = 8; -        private static final int ICMPV6_ECHO_REQUEST = 128;          private static final int PACKET_BUFSIZE = 512;          private final int mProtocol;          private final int mIcmpType; @@ -432,11 +431,11 @@ public class NetworkDiagnostics {              if (mAddressFamily == AF_INET6) {                  mProtocol = IPPROTO_ICMPV6; -                mIcmpType = ICMPV6_ECHO_REQUEST; +                mIcmpType = NetworkConstants.ICMPV6_ECHO_REQUEST_TYPE;                  mMeasurement.description = "ICMPv6";              } else {                  mProtocol = IPPROTO_ICMP; -                mIcmpType = ICMPV4_ECHO_REQUEST; +                mIcmpType = NetworkConstants.ICMPV4_ECHO_REQUEST_TYPE;                  mMeasurement.description = "ICMPv4";              } @@ -504,7 +503,6 @@ public class NetworkDiagnostics {      private class DnsUdpCheck extends SimpleSocketCheck implements Runnable {          private static final int TIMEOUT_SEND = 100;          private static final int TIMEOUT_RECV = 500; -        private static final int DNS_SERVER_PORT = 53;          private static final int RR_TYPE_A = 1;          private static final int RR_TYPE_AAAA = 28;          private static final int PACKET_BUFSIZE = 512; @@ -546,7 +544,8 @@ public class NetworkDiagnostics {              }              try { -                setupSocket(SOCK_DGRAM, IPPROTO_UDP, TIMEOUT_SEND, TIMEOUT_RECV, DNS_SERVER_PORT); +                setupSocket(SOCK_DGRAM, IPPROTO_UDP, TIMEOUT_SEND, TIMEOUT_RECV, +                        NetworkConstants.DNS_SERVER_PORT);              } catch (ErrnoException | IOException e) {                  mMeasurement.recordFailure(e.toString());                  return; diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java index ed268581b50c..8a2e71c1fba8 100644 --- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java +++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java @@ -122,22 +122,6 @@ public class NetworkMonitor extends StateMachine {          }      } -    public static final String ACTION_NETWORK_CONDITIONS_MEASURED = -            "android.net.conn.NETWORK_CONDITIONS_MEASURED"; -    public static final String EXTRA_CONNECTIVITY_TYPE = "extra_connectivity_type"; -    public static final String EXTRA_NETWORK_TYPE = "extra_network_type"; -    public static final String EXTRA_RESPONSE_RECEIVED = "extra_response_received"; -    public static final String EXTRA_IS_CAPTIVE_PORTAL = "extra_is_captive_portal"; -    public static final String EXTRA_CELL_ID = "extra_cellid"; -    public static final String EXTRA_SSID = "extra_ssid"; -    public static final String EXTRA_BSSID = "extra_bssid"; -    /** real time since boot */ -    public static final String EXTRA_REQUEST_TIMESTAMP_MS = "extra_request_timestamp_ms"; -    public static final String EXTRA_RESPONSE_TIMESTAMP_MS = "extra_response_timestamp_ms"; - -    private static final String PERMISSION_ACCESS_NETWORK_CONDITIONS = -            "android.permission.ACCESS_NETWORK_CONDITIONS"; -      // After a network has been tested this result can be sent with EVENT_NETWORK_TESTED.      // The network should be used as a default internet connection.  It was found to be:      // 1. a functioning network providing internet access, or @@ -1136,7 +1120,8 @@ public class NetworkMonitor extends StateMachine {              return;          } -        Intent latencyBroadcast = new Intent(ACTION_NETWORK_CONDITIONS_MEASURED); +        Intent latencyBroadcast = +                new Intent(ConnectivityConstants.ACTION_NETWORK_CONDITIONS_MEASURED);          switch (mNetworkAgentInfo.networkInfo.getType()) {              case ConnectivityManager.TYPE_WIFI:                  WifiInfo currentWifiInfo = mWifiManager.getConnectionInfo(); @@ -1148,15 +1133,18 @@ public class NetworkMonitor extends StateMachine {                      // not change it here as it would become impossible to tell whether the SSID is                      // simply being surrounded by quotes due to the API, or whether those quotes                      // are actually part of the SSID. -                    latencyBroadcast.putExtra(EXTRA_SSID, currentWifiInfo.getSSID()); -                    latencyBroadcast.putExtra(EXTRA_BSSID, currentWifiInfo.getBSSID()); +                    latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_SSID, +                            currentWifiInfo.getSSID()); +                    latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_BSSID, +                            currentWifiInfo.getBSSID());                  } else {                      if (VDBG) logw("network info is TYPE_WIFI but no ConnectionInfo found");                      return;                  }                  break;              case ConnectivityManager.TYPE_MOBILE: -                latencyBroadcast.putExtra(EXTRA_NETWORK_TYPE, mTelephonyManager.getNetworkType()); +                latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_NETWORK_TYPE, +                        mTelephonyManager.getNetworkType());                  List<CellInfo> info = mTelephonyManager.getAllCellInfo();                  if (info == null) return;                  int numRegisteredCellInfo = 0; @@ -1170,16 +1158,16 @@ public class NetworkMonitor extends StateMachine {                          }                          if (cellInfo instanceof CellInfoCdma) {                              CellIdentityCdma cellId = ((CellInfoCdma) cellInfo).getCellIdentity(); -                            latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId); +                            latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_CELL_ID, cellId);                          } else if (cellInfo instanceof CellInfoGsm) {                              CellIdentityGsm cellId = ((CellInfoGsm) cellInfo).getCellIdentity(); -                            latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId); +                            latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_CELL_ID, cellId);                          } else if (cellInfo instanceof CellInfoLte) {                              CellIdentityLte cellId = ((CellInfoLte) cellInfo).getCellIdentity(); -                            latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId); +                            latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_CELL_ID, cellId);                          } else if (cellInfo instanceof CellInfoWcdma) {                              CellIdentityWcdma cellId = ((CellInfoWcdma) cellInfo).getCellIdentity(); -                            latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId); +                            latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_CELL_ID, cellId);                          } else {                              if (VDBG) logw("Registered cellinfo is unrecognized");                              return; @@ -1190,16 +1178,21 @@ public class NetworkMonitor extends StateMachine {              default:                  return;          } -        latencyBroadcast.putExtra(EXTRA_CONNECTIVITY_TYPE, mNetworkAgentInfo.networkInfo.getType()); -        latencyBroadcast.putExtra(EXTRA_RESPONSE_RECEIVED, responseReceived); -        latencyBroadcast.putExtra(EXTRA_REQUEST_TIMESTAMP_MS, requestTimestampMs); +        latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_CONNECTIVITY_TYPE, +                mNetworkAgentInfo.networkInfo.getType()); +        latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_RESPONSE_RECEIVED, +                responseReceived); +        latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_REQUEST_TIMESTAMP_MS, +                requestTimestampMs);          if (responseReceived) { -            latencyBroadcast.putExtra(EXTRA_IS_CAPTIVE_PORTAL, isCaptivePortal); -            latencyBroadcast.putExtra(EXTRA_RESPONSE_TIMESTAMP_MS, responseTimestampMs); +            latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_IS_CAPTIVE_PORTAL, +                    isCaptivePortal); +            latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_RESPONSE_TIMESTAMP_MS, +                    responseTimestampMs);          }          mContext.sendBroadcastAsUser(latencyBroadcast, UserHandle.CURRENT, -                PERMISSION_ACCESS_NETWORK_CONDITIONS); +                ConnectivityConstants.PERMISSION_ACCESS_NETWORK_CONDITIONS);      }      private void logNetworkEvent(int evtype) { diff --git a/services/core/java/com/android/server/connectivity/PacManager.java b/services/core/java/com/android/server/connectivity/PacManager.java index d56fb1ab09f9..3a27fcb352aa 100644 --- a/services/core/java/com/android/server/connectivity/PacManager.java +++ b/services/core/java/com/android/server/connectivity/PacManager.java @@ -54,12 +54,12 @@ import java.net.URLConnection;   * @hide   */  public class PacManager { -    public static final String PAC_PACKAGE = "com.android.pacprocessor"; -    public static final String PAC_SERVICE = "com.android.pacprocessor.PacService"; -    public static final String PAC_SERVICE_NAME = "com.android.net.IProxyService"; +    private static final String PAC_PACKAGE = "com.android.pacprocessor"; +    private static final String PAC_SERVICE = "com.android.pacprocessor.PacService"; +    private static final String PAC_SERVICE_NAME = "com.android.net.IProxyService"; -    public static final String PROXY_PACKAGE = "com.android.proxyhandler"; -    public static final String PROXY_SERVICE = "com.android.proxyhandler.ProxyService"; +    private static final String PROXY_PACKAGE = "com.android.proxyhandler"; +    private static final String PROXY_SERVICE = "com.android.proxyhandler.ProxyService";      private static final String TAG = "PacManager"; @@ -71,8 +71,6 @@ public class PacManager {      private static final int DELAY_LONG = 4;      private static final long MAX_PAC_SIZE = 20 * 1000 * 1000; -    /** Keep these values up-to-date with ProxyService.java */ -    public static final String KEY_PROXY = "keyProxy";      private String mCurrentPac;      @GuardedBy("mProxyLock")      private volatile Uri mPacUrl = Uri.EMPTY; diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index aa174e3ad715..bb46d5e23696 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -164,19 +164,6 @@ public class Vpn {      private boolean mLockdown = false;      /** -     * List of UIDs that are set to use this VPN by default. Normally, every UID in the user is -     * added to this set but that can be changed by adding allowed or disallowed applications. It -     * is non-null iff the VPN is connected. -     * -     * Unless the VPN has set allowBypass=true, these UIDs are forced into the VPN. -     * -     * @see VpnService.Builder#addAllowedApplication(String) -     * @see VpnService.Builder#addDisallowedApplication(String) -     */ -    @GuardedBy("this") -    private Set<UidRange> mVpnUsers = null; - -    /**       * List of UIDs for which networking should be blocked until VPN is ready, during brief periods       * when VPN is not running. For example, during system startup or after a crash.       * @see mLockdown @@ -688,7 +675,7 @@ public class Vpn {                  agentDisconnect();                  jniReset(mInterface);                  mInterface = null; -                mVpnUsers = null; +                mNetworkCapabilities.setUids(null);              }              // Revoke the connection or stop LegacyVpnRunner. @@ -857,10 +844,14 @@ public class Vpn {          NetworkMisc networkMisc = new NetworkMisc();          networkMisc.allowBypass = mConfig.allowBypass && !mLockdown; +        mNetworkCapabilities.setEstablishingVpnAppUid(Binder.getCallingUid()); +        mNetworkCapabilities.setUids(createUserAndRestrictedProfilesRanges(mUserHandle, +                mConfig.allowedApplications, mConfig.disallowedApplications));          long token = Binder.clearCallingIdentity();          try {              mNetworkAgent = new NetworkAgent(mLooper, mContext, NETWORKTYPE /* logtag */, -                    mNetworkInfo, mNetworkCapabilities, lp, 0 /* score */, networkMisc) { +                    mNetworkInfo, mNetworkCapabilities, lp, +                    ConnectivityConstants.VPN_DEFAULT_SCORE, networkMisc) {                              @Override                              public void unwanted() {                                  // We are user controlled, not driven by NetworkRequest. @@ -869,11 +860,6 @@ public class Vpn {          } finally {              Binder.restoreCallingIdentity(token);          } - -        mVpnUsers = createUserAndRestrictedProfilesRanges(mUserHandle, -                mConfig.allowedApplications, mConfig.disallowedApplications); -        mNetworkAgent.addUidRanges(mVpnUsers.toArray(new UidRange[mVpnUsers.size()])); -          mNetworkInfo.setIsAvailable(true);          updateState(DetailedState.CONNECTED, "agentConnect");      } @@ -953,7 +939,7 @@ public class Vpn {          Connection oldConnection = mConnection;          NetworkAgent oldNetworkAgent = mNetworkAgent;          mNetworkAgent = null; -        Set<UidRange> oldUsers = mVpnUsers; +        Set<UidRange> oldUsers = mNetworkCapabilities.getUids();          // Configure the interface. Abort if any of these steps fails.          ParcelFileDescriptor tun = ParcelFileDescriptor.adoptFd(jniCreate(config.mtu)); @@ -1011,7 +997,7 @@ public class Vpn {              // restore old state              mConfig = oldConfig;              mConnection = oldConnection; -            mVpnUsers = oldUsers; +            mNetworkCapabilities.setUids(oldUsers);              mNetworkAgent = oldNetworkAgent;              mInterface = oldInterface;              throw e; @@ -1131,10 +1117,12 @@ public class Vpn {      // Returns the subset of the full list of active UID ranges the VPN applies to (mVpnUsers) that      // apply to userHandle. -    private List<UidRange> uidRangesForUser(int userHandle) { +    static private List<UidRange> uidRangesForUser(int userHandle, Set<UidRange> existingRanges) { +        // UidRange#createForUser returns the entire range of UIDs available to a macro-user. +        // This is something like 0-99999 ; {@see UserHandle#PER_USER_RANGE}          final UidRange userRange = UidRange.createForUser(userHandle);          final List<UidRange> ranges = new ArrayList<UidRange>(); -        for (UidRange range : mVpnUsers) { +        for (UidRange range : existingRanges) {              if (userRange.containsRange(range)) {                  ranges.add(range);              } @@ -1142,30 +1130,18 @@ public class Vpn {          return ranges;      } -    private void removeVpnUserLocked(int userHandle) { -        if (mVpnUsers == null) { -            throw new IllegalStateException("VPN is not active"); -        } -        final List<UidRange> ranges = uidRangesForUser(userHandle); -        if (mNetworkAgent != null) { -            mNetworkAgent.removeUidRanges(ranges.toArray(new UidRange[ranges.size()])); -        } -        mVpnUsers.removeAll(ranges); -    } -      public void onUserAdded(int userHandle) {          // If the user is restricted tie them to the parent user's VPN          UserInfo user = UserManager.get(mContext).getUserInfo(userHandle);          if (user.isRestricted() && user.restrictedProfileParentId == mUserHandle) {              synchronized(Vpn.this) { -                if (mVpnUsers != null) { +                final Set<UidRange> existingRanges = mNetworkCapabilities.getUids(); +                if (existingRanges != null) {                      try { -                        addUserToRanges(mVpnUsers, userHandle, mConfig.allowedApplications, +                        addUserToRanges(existingRanges, userHandle, mConfig.allowedApplications,                                  mConfig.disallowedApplications); -                        if (mNetworkAgent != null) { -                            final List<UidRange> ranges = uidRangesForUser(userHandle); -                            mNetworkAgent.addUidRanges(ranges.toArray(new UidRange[ranges.size()])); -                        } +                        mNetworkCapabilities.setUids(existingRanges); +                        updateCapabilities();                      } catch (Exception e) {                          Log.wtf(TAG, "Failed to add restricted user to owner", e);                      } @@ -1180,9 +1156,14 @@ public class Vpn {          UserInfo user = UserManager.get(mContext).getUserInfo(userHandle);          if (user.isRestricted() && user.restrictedProfileParentId == mUserHandle) {              synchronized(Vpn.this) { -                if (mVpnUsers != null) { +                final Set<UidRange> existingRanges = mNetworkCapabilities.getUids(); +                if (existingRanges != null) {                      try { -                        removeVpnUserLocked(userHandle); +                        final List<UidRange> removedRanges = +                            uidRangesForUser(userHandle, existingRanges); +                        existingRanges.removeAll(removedRanges); +                        mNetworkCapabilities.setUids(existingRanges); +                        updateCapabilities();                      } catch (Exception e) {                          Log.wtf(TAG, "Failed to remove restricted user to owner", e);                      } @@ -1226,15 +1207,6 @@ public class Vpn {      private void setVpnForcedLocked(boolean enforce) {          final List<String> exemptedPackages =                  isNullOrLegacyVpn(mPackage) ? null : Collections.singletonList(mPackage); -        setVpnForcedWithExemptionsLocked(enforce, exemptedPackages); -    } - -    /** -     * @see #setVpnForcedLocked -     */ -    @GuardedBy("this") -    private void setVpnForcedWithExemptionsLocked(boolean enforce, -            @Nullable List<String> exemptedPackages) {          final Set<UidRange> removedRanges = new ArraySet<>(mBlockedUsers);          Set<UidRange> addedRanges = Collections.emptySet(); @@ -1314,7 +1286,7 @@ public class Vpn {              synchronized (Vpn.this) {                  if (interfaze.equals(mInterface) && jniCheck(interfaze) == 0) {                      mStatusIntent = null; -                    mVpnUsers = null; +                    mNetworkCapabilities.setUids(null);                      mConfig = null;                      mInterface = null;                      if (mConnection != null) { @@ -1433,12 +1405,7 @@ public class Vpn {          if (!isRunningLocked()) {              return false;          } -        for (UidRange uidRange : mVpnUsers) { -            if (uidRange.contains(uid)) { -                return true; -            } -        } -        return false; +        return mNetworkCapabilities.appliesToUid(uid);      }      /** diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java index acbc10b9dc43..09bce7f4feb6 100644 --- a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java +++ b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java @@ -28,6 +28,8 @@ import android.net.ConnectivityManager;  import android.telephony.TelephonyManager;  import android.net.util.SharedLog; +import com.android.internal.annotations.VisibleForTesting; +  import java.io.PrintWriter;  import java.util.ArrayList;  import java.util.Arrays; @@ -49,6 +51,7 @@ import java.util.StringJoiner;  public class TetheringConfiguration {      private static final String TAG = TetheringConfiguration.class.getSimpleName(); +    @VisibleForTesting      public static final int DUN_NOT_REQUIRED = 0;      public static final int DUN_REQUIRED = 1;      public static final int DUN_UNSPECIFIED = 2; diff --git a/services/net/java/android/net/util/NetworkConstants.java b/services/net/java/android/net/util/NetworkConstants.java index 5a3a8be923af..984c9f817d75 100644 --- a/services/net/java/android/net/util/NetworkConstants.java +++ b/services/net/java/android/net/util/NetworkConstants.java @@ -121,6 +121,14 @@ public final class NetworkConstants {      public static final int ICMP_ECHO_DATA_OFFSET = 8;      /** +     * ICMPv4 constants. +     * +     * See also: +     *     - https://tools.ietf.org/html/rfc792 +     */ +    public static final int ICMPV4_ECHO_REQUEST_TYPE = 8; + +    /**       * ICMPv6 constants.       *       * See also: @@ -139,6 +147,8 @@ public final class NetworkConstants {      public static final int ICMPV6_ND_OPTION_TLLA = 2;      public static final int ICMPV6_ND_OPTION_MTU  = 5; +    public static final int ICMPV6_ECHO_REQUEST_TYPE = 128; +      /**       * UDP constants.       * @@ -157,6 +167,14 @@ public final class NetworkConstants {      public static final int DHCP4_CLIENT_PORT = 68;      /** +     * DNS constants. +     * +     * See also: +     *     - https://tools.ietf.org/html/rfc1035 +     */ +    public static final int DNS_SERVER_PORT = 53; + +    /**       * Utility functions.       */      public static byte asByte(int i) { return (byte) i; } diff --git a/tests/net/java/android/net/NetworkCapabilitiesTest.java b/tests/net/java/android/net/NetworkCapabilitiesTest.java index cd2d0985c793..2e1519b8717b 100644 --- a/tests/net/java/android/net/NetworkCapabilitiesTest.java +++ b/tests/net/java/android/net/NetworkCapabilitiesTest.java @@ -33,12 +33,15 @@ import static org.junit.Assert.assertFalse;  import static org.junit.Assert.assertNotEquals;  import static org.junit.Assert.assertTrue; +import android.os.Parcel;  import android.support.test.runner.AndroidJUnit4;  import android.test.suitebuilder.annotation.SmallTest; +import android.util.ArraySet;  import org.junit.Test;  import org.junit.runner.RunWith; +import java.util.Set;  @RunWith(AndroidJUnit4.class)  @SmallTest @@ -180,4 +183,84 @@ public class NetworkCapabilitiesTest {          assertEquals(20, NetworkCapabilities                  .maxBandwidth(10, 20));      } + +    @Test +    public void testSetUids() { +        final NetworkCapabilities netCap = new NetworkCapabilities(); +        final Set<UidRange> uids = new ArraySet<>(); +        uids.add(new UidRange(50, 100)); +        uids.add(new UidRange(3000, 4000)); +        netCap.setUids(uids); +        assertTrue(netCap.appliesToUid(50)); +        assertTrue(netCap.appliesToUid(80)); +        assertTrue(netCap.appliesToUid(100)); +        assertTrue(netCap.appliesToUid(3000)); +        assertTrue(netCap.appliesToUid(3001)); +        assertFalse(netCap.appliesToUid(10)); +        assertFalse(netCap.appliesToUid(25)); +        assertFalse(netCap.appliesToUid(49)); +        assertFalse(netCap.appliesToUid(101)); +        assertFalse(netCap.appliesToUid(2000)); +        assertFalse(netCap.appliesToUid(100000)); + +        assertTrue(netCap.appliesToUidRange(new UidRange(50, 100))); +        assertTrue(netCap.appliesToUidRange(new UidRange(70, 72))); +        assertTrue(netCap.appliesToUidRange(new UidRange(3500, 3912))); +        assertFalse(netCap.appliesToUidRange(new UidRange(1, 100))); +        assertFalse(netCap.appliesToUidRange(new UidRange(49, 100))); +        assertFalse(netCap.appliesToUidRange(new UidRange(1, 10))); +        assertFalse(netCap.appliesToUidRange(new UidRange(60, 101))); +        assertFalse(netCap.appliesToUidRange(new UidRange(60, 3400))); + +        NetworkCapabilities netCap2 = new NetworkCapabilities(); +        assertFalse(netCap2.satisfiedByUids(netCap)); +        assertFalse(netCap2.equalsUids(netCap)); +        netCap2.setUids(uids); +        assertTrue(netCap2.satisfiedByUids(netCap)); +        assertTrue(netCap.equalsUids(netCap2)); +        assertTrue(netCap2.equalsUids(netCap)); + +        uids.add(new UidRange(600, 700)); +        netCap2.setUids(uids); +        assertFalse(netCap2.satisfiedByUids(netCap)); +        assertFalse(netCap.appliesToUid(650)); +        assertTrue(netCap2.appliesToUid(650)); +        netCap.combineCapabilities(netCap2); +        assertTrue(netCap2.satisfiedByUids(netCap)); +        assertTrue(netCap.appliesToUid(650)); +        assertFalse(netCap.appliesToUid(500)); + +        assertFalse(new NetworkCapabilities().satisfiedByUids(netCap)); +        netCap.combineCapabilities(new NetworkCapabilities()); +        assertTrue(netCap.appliesToUid(500)); +        assertTrue(netCap.appliesToUidRange(new UidRange(1, 100000))); +        assertFalse(netCap2.appliesToUid(500)); +        assertFalse(netCap2.appliesToUidRange(new UidRange(1, 100000))); +        assertTrue(new NetworkCapabilities().satisfiedByUids(netCap)); +    } + +    @Test +    public void testParcelNetworkCapabilities() { +        final Set<UidRange> uids = new ArraySet<>(); +        uids.add(new UidRange(50, 100)); +        uids.add(new UidRange(3000, 4000)); +        final NetworkCapabilities netCap = new NetworkCapabilities() +            .addCapability(NET_CAPABILITY_INTERNET) +            .setUids(uids) +            .addCapability(NET_CAPABILITY_EIMS) +            .addCapability(NET_CAPABILITY_NOT_METERED); +        assertEqualsThroughMarshalling(netCap); +    } + +    private void assertEqualsThroughMarshalling(NetworkCapabilities netCap) { +        Parcel p = Parcel.obtain(); +        netCap.writeToParcel(p, /* flags */ 0); +        p.setDataPosition(0); +        byte[] marshalledData = p.marshall(); + +        p = Parcel.obtain(); +        p.unmarshall(marshalledData, 0, marshalledData.length); +        p.setDataPosition(0); +        assertEquals(NetworkCapabilities.CREATOR.createFromParcel(p), netCap); +    }  } diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 70cacb3af009..6e643a3dae12 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -44,6 +44,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P;  import static android.net.NetworkCapabilities.NET_CAPABILITY_XCAP;  import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;  import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET; +import static android.net.NetworkCapabilities.TRANSPORT_VPN;  import static android.net.NetworkCapabilities.TRANSPORT_WIFI;  import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE; @@ -101,6 +102,7 @@ import android.net.NetworkSpecifier;  import android.net.NetworkUtils;  import android.net.RouteInfo;  import android.net.StringNetworkSpecifier; +import android.net.UidRange;  import android.net.metrics.IpConnectivityLog;  import android.net.util.MultinetworkPolicyTracker;  import android.os.ConditionVariable; @@ -126,11 +128,13 @@ import com.android.internal.util.ArrayUtils;  import com.android.internal.util.WakeupMessage;  import com.android.internal.util.test.BroadcastInterceptingContext;  import com.android.internal.util.test.FakeSettingsProvider; +import com.android.server.connectivity.ConnectivityConstants;  import com.android.server.connectivity.DefaultNetworkMetrics;  import com.android.server.connectivity.IpConnectivityMetrics;  import com.android.server.connectivity.MockableSystemProperties;  import com.android.server.connectivity.NetworkAgentInfo;  import com.android.server.connectivity.NetworkMonitor; +import com.android.server.connectivity.Vpn;  import com.android.server.net.NetworkPinner;  import com.android.server.net.NetworkPolicyManagerInternal; @@ -360,7 +364,7 @@ public class ConnectivityServiceTest {          MockNetworkAgent(int transport, LinkProperties linkProperties) {              final int type = transportToLegacyType(transport); -            final String typeName = ConnectivityManager.getNetworkTypeName(type); +            final String typeName = ConnectivityManager.getNetworkTypeName(transport);              mNetworkInfo = new NetworkInfo(type, 0, typeName, "Mock");              mNetworkCapabilities = new NetworkCapabilities();              mNetworkCapabilities.addTransportType(transport); @@ -377,6 +381,9 @@ public class ConnectivityServiceTest {                  case TRANSPORT_WIFI_AWARE:                      mScore = 20;                      break; +                case TRANSPORT_VPN: +                    mScore = ConnectivityConstants.VPN_DEFAULT_SCORE; +                    break;                  default:                      throw new UnsupportedOperationException("unimplemented network type");              } @@ -438,6 +445,11 @@ public class ConnectivityServiceTest {              mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);          } +        public void setUids(Set<UidRange> uids) { +            mNetworkCapabilities.setUids(uids); +            mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); +        } +          public void setSignalStrength(int signalStrength) {              mNetworkCapabilities.setSignalStrength(signalStrength);              mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); @@ -1463,6 +1475,11 @@ public class ConnectivityServiceTest {              return nc;          } +        void expectCapabilitiesLike(Predicate<NetworkCapabilities> fn, MockNetworkAgent agent) { +            CallbackInfo cbi = expectCallback(CallbackState.NETWORK_CAPABILITIES, agent); +            assertTrue(fn.test((NetworkCapabilities) cbi.arg)); +        } +          void assertNoCallback() {              waitForIdle();              CallbackInfo c = mCallbacks.peek(); @@ -3625,4 +3642,76 @@ public class ConnectivityServiceTest {              return;          }      } + +    @Test +    public void testVpnNetworkActive() { +        final int uid = Process.myUid(); + +        final TestNetworkCallback genericNetworkCallback = new TestNetworkCallback(); +        final TestNetworkCallback wifiNetworkCallback = new TestNetworkCallback(); +        final TestNetworkCallback vpnNetworkCallback = new TestNetworkCallback(); +        final NetworkRequest genericRequest = new NetworkRequest.Builder().build(); +        final NetworkRequest wifiRequest = new NetworkRequest.Builder() +                .addTransportType(TRANSPORT_WIFI).build(); +        final NetworkRequest vpnNetworkRequest = new NetworkRequest.Builder() +                .addTransportType(TRANSPORT_VPN).build(); +        mCm.registerNetworkCallback(genericRequest, genericNetworkCallback); +        mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback); +        mCm.registerNetworkCallback(vpnNetworkRequest, vpnNetworkCallback); + +        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); +        mWiFiNetworkAgent.connect(false); + +        genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); +        wifiNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); +        vpnNetworkCallback.assertNoCallback(); + +        // TODO : check callbacks agree with the return value of mCm.getActiveNetwork(). +        // Right now this is not possible because establish() is not adequately instrumented +        // in this test. + +        final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN); +        final ArraySet<UidRange> ranges = new ArraySet<>(); +        ranges.add(new UidRange(uid, uid)); +        vpnNetworkAgent.setUids(ranges); +        vpnNetworkAgent.connect(false); + +        genericNetworkCallback.expectAvailableCallbacksUnvalidated(vpnNetworkAgent); +        wifiNetworkCallback.assertNoCallback(); +        vpnNetworkCallback.expectAvailableCallbacksUnvalidated(vpnNetworkAgent); + +        genericNetworkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, vpnNetworkAgent); +        vpnNetworkCallback.expectCapabilitiesLike( +                nc -> nc.appliesToUid(uid) && !nc.appliesToUid(uid + 1), vpnNetworkAgent); + +        ranges.clear(); +        vpnNetworkAgent.setUids(ranges); + +        genericNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent); +        wifiNetworkCallback.assertNoCallback(); +        vpnNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent); + +        ranges.add(new UidRange(uid, uid)); +        vpnNetworkAgent.setUids(ranges); + +        genericNetworkCallback.expectAvailableCallbacksValidated(vpnNetworkAgent); +        wifiNetworkCallback.assertNoCallback(); +        vpnNetworkCallback.expectAvailableCallbacksValidated(vpnNetworkAgent); + +        mWiFiNetworkAgent.disconnect(); + +        genericNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent); +        wifiNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent); +        vpnNetworkCallback.assertNoCallback(); + +        vpnNetworkAgent.disconnect(); + +        genericNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent); +        wifiNetworkCallback.assertNoCallback(); +        vpnNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent); + +        mCm.unregisterNetworkCallback(genericNetworkCallback); +        mCm.unregisterNetworkCallback(wifiNetworkCallback); +        mCm.unregisterNetworkCallback(vpnNetworkCallback); +    }  }  |