Allow VPNs to specify their underlying networks.
These are used when responding to getActiveNetworkInfo() (and cousins)
when an app is subject to the VPN.
Bug: 17460017
Change-Id: Ief7a840c760777a41d3358aa6b8e4cdd99c29f24
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 03c05ec..6da186f 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -46,6 +46,7 @@
import android.net.LinkProperties;
import android.net.LocalSocket;
import android.net.LocalSocketAddress;
+import android.net.Network;
import android.net.NetworkAgent;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
@@ -580,7 +581,13 @@
}
private boolean isRunningLocked() {
- return mVpnUsers != null;
+ return mNetworkAgent != null && mInterface != null;
+ }
+
+ // Returns true if the VPN has been established and the calling UID is its owner. Used to check
+ // that a call to mutate VPN state is admissible.
+ private boolean isCallerEstablishedOwnerLocked() {
+ return isRunningLocked() && Binder.getCallingUid() == mOwnerUID;
}
// Note: Return type guarantees results are deduped and sorted, which callers require.
@@ -595,7 +602,7 @@
// Note: This function adds to mVpnUsers but does not publish list to NetworkAgent.
private void addVpnUserLocked(int userHandle) {
- if (!isRunningLocked()) {
+ if (mVpnUsers == null) {
throw new IllegalStateException("VPN is not active");
}
@@ -647,7 +654,7 @@
}
private void removeVpnUserLocked(int userHandle) {
- if (!isRunningLocked()) {
+ if (mVpnUsers == null) {
throw new IllegalStateException("VPN is not active");
}
final List<UidRange> ranges = uidRangesForUser(userHandle);
@@ -767,27 +774,61 @@
}
public synchronized boolean addAddress(String address, int prefixLength) {
- if (Binder.getCallingUid() != mOwnerUID || mInterface == null || mNetworkAgent == null) {
+ if (!isCallerEstablishedOwnerLocked()) {
return false;
}
boolean success = jniAddAddress(mInterface, address, prefixLength);
- if (mNetworkAgent != null) {
- mNetworkAgent.sendLinkProperties(makeLinkProperties());
- }
+ mNetworkAgent.sendLinkProperties(makeLinkProperties());
return success;
}
public synchronized boolean removeAddress(String address, int prefixLength) {
- if (Binder.getCallingUid() != mOwnerUID || mInterface == null || mNetworkAgent == null) {
+ if (!isCallerEstablishedOwnerLocked()) {
return false;
}
boolean success = jniDelAddress(mInterface, address, prefixLength);
- if (mNetworkAgent != null) {
- mNetworkAgent.sendLinkProperties(makeLinkProperties());
- }
+ mNetworkAgent.sendLinkProperties(makeLinkProperties());
return success;
}
+ public synchronized boolean setUnderlyingNetworks(Network[] networks) {
+ if (!isCallerEstablishedOwnerLocked()) {
+ return false;
+ }
+ if (networks == null) {
+ mConfig.underlyingNetworks = null;
+ } else {
+ mConfig.underlyingNetworks = new Network[networks.length];
+ for (int i = 0; i < networks.length; ++i) {
+ if (networks[i] == null) {
+ mConfig.underlyingNetworks[i] = null;
+ } else {
+ mConfig.underlyingNetworks[i] = new Network(networks[i].netId);
+ }
+ }
+ }
+ return true;
+ }
+
+ public synchronized Network[] getUnderlyingNetworks() {
+ if (!isRunningLocked()) {
+ return null;
+ }
+ return mConfig.underlyingNetworks;
+ }
+
+ public synchronized boolean appliesToUid(int uid) {
+ if (!isRunningLocked()) {
+ return false;
+ }
+ for (UidRange uidRange : mVpnUsers) {
+ if (uidRange.start <= uid && uid <= uidRange.stop) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private native int jniCreate(int mtu);
private native String jniGetName(int tun);
private native int jniSetAddresses(String interfaze, String addresses);