Vpn.java revision 628ae0d84180c5f7c52725e02506021e532ed252
1ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh/* 2ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * Copyright (C) 2011 The Android Open Source Project 3ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * 4ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * Licensed under the Apache License, Version 2.0 (the "License"); 5ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * you may not use this file except in compliance with the License. 6ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * You may obtain a copy of the License at 7ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * 8ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * http://www.apache.org/licenses/LICENSE-2.0 9ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * 10ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * Unless required by applicable law or agreed to in writing, software 11ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * distributed under the License is distributed on an "AS IS" BASIS, 12ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * See the License for the specific language governing permissions and 14ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * limitations under the License. 15ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh */ 16ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 17ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehpackage com.android.server.connectivity; 18ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 19899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkeyimport static android.Manifest.permission.BIND_VPN_SERVICE; 2031a94f48bf8014cf6a1127bd23cf9a8541a9abedPaul Jensenimport static android.net.ConnectivityManager.NETID_UNSET; 215026279ce45ae78126046607a2634dc9dae93199Lorenzo Colittiimport static android.net.RouteInfo.RTN_THROW; 2260446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colittiimport static android.net.RouteInfo.RTN_UNREACHABLE; 23899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey 24bc19c181c8c058c824e4fee907a05129e142c388Jeff Davidsonimport android.Manifest; 254d03abcd49af490dba3850d341b955dd72f24959Robin Leeimport android.annotation.NonNull; 264d03abcd49af490dba3850d341b955dd72f24959Robin Leeimport android.annotation.Nullable; 274d03abcd49af490dba3850d341b955dd72f24959Robin Leeimport android.annotation.UserIdInt; 284ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubakerimport android.app.AppGlobals; 2905542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidsonimport android.app.AppOpsManager; 3090b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidsonimport android.app.PendingIntent; 311b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwaltimport android.content.BroadcastReceiver; 32199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yehimport android.content.ComponentName; 33ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.content.Context; 34ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.content.Intent; 351b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwaltimport android.content.IntentFilter; 36199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yehimport android.content.ServiceConnection; 37ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.content.pm.PackageManager; 386bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensenimport android.content.pm.PackageManager.NameNotFoundException; 39199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yehimport android.content.pm.ResolveInfo; 40c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubakerimport android.content.pm.UserInfo; 41899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkeyimport android.net.ConnectivityManager; 42ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.net.INetworkManagementEventObserver; 435026279ce45ae78126046607a2634dc9dae93199Lorenzo Colittiimport android.net.IpPrefix; 444ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubakerimport android.net.LinkAddress; 4582f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkeyimport android.net.LinkProperties; 4685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yehimport android.net.LocalSocket; 4785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yehimport android.net.LocalSocketAddress; 48c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandranimport android.net.Network; 496bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensenimport android.net.NetworkAgent; 506bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensenimport android.net.NetworkCapabilities; 51899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkeyimport android.net.NetworkInfo; 526bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensenimport android.net.NetworkInfo.DetailedState; 538cd33ed84e94036a5e1201485af7603dc6fb0d9bSreeram Ramachandranimport android.net.NetworkMisc; 5482f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkeyimport android.net.RouteInfo; 556bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensenimport android.net.UidRange; 56ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.os.Binder; 57c1bac3a6e240c1c9a14a7b515f585977fb908930Chia-chi Yehimport android.os.FileUtils; 58199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yehimport android.os.IBinder; 59899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkeyimport android.os.INetworkManagementService; 606bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensenimport android.os.Looper; 61199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yehimport android.os.Parcel; 62ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.os.ParcelFileDescriptor; 6385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yehimport android.os.Process; 64899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkeyimport android.os.RemoteException; 6585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yehimport android.os.SystemClock; 66088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkeyimport android.os.SystemService; 6750cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackbornimport android.os.UserHandle; 68c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubakerimport android.os.UserManager; 6982f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkeyimport android.security.Credentials; 7082f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkeyimport android.security.KeyStore; 71e75b9e355500b7c6a05e4d6ec54ef48835707caaPaul Jensenimport android.text.TextUtils; 724d03abcd49af490dba3850d341b955dd72f24959Robin Leeimport android.util.ArraySet; 73ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.util.Log; 74ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 75c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubakerimport com.android.internal.annotations.GuardedBy; 764d03abcd49af490dba3850d341b955dd72f24959Robin Leeimport com.android.internal.annotations.VisibleForTesting; 772e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yehimport com.android.internal.net.LegacyVpnInfo; 7804ba25c418bc4538e9dc0f047cfb9608d358f679Chia-chi Yehimport com.android.internal.net.VpnConfig; 79f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tongimport com.android.internal.net.VpnInfo; 8082f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkeyimport com.android.internal.net.VpnProfile; 81899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkeyimport com.android.server.net.BaseNetworkObserver; 82ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 8305542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidsonimport libcore.io.IoUtils; 8405542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson 8597a61565ea95472e65899070e64853f8c147bb11Chia-chi Yehimport java.io.File; 866bbf39cf6b81222f32d2b66b8fa85d562e0ad71cJeff Davidsonimport java.io.IOException; 8797a61565ea95472e65899070e64853f8c147bb11Chia-chi Yehimport java.io.InputStream; 8885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yehimport java.io.OutputStream; 8982f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkeyimport java.net.Inet4Address; 90f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandranimport java.net.Inet6Address; 91f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandranimport java.net.InetAddress; 92d396a448b2e36e29598c954b64bfddef73f3fae0Elliott Hughesimport java.nio.charset.StandardCharsets; 936bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensenimport java.util.ArrayList; 9441d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yehimport java.util.Arrays; 954d03abcd49af490dba3850d341b955dd72f24959Robin Leeimport java.util.Collection; 964d03abcd49af490dba3850d341b955dd72f24959Robin Leeimport java.util.Collections; 976bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensenimport java.util.List; 984d03abcd49af490dba3850d341b955dd72f24959Robin Leeimport java.util.Set; 990784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensenimport java.util.SortedSet; 1000784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensenimport java.util.TreeSet; 1011b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwaltimport java.util.concurrent.atomic.AtomicInteger; 10285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 103ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh/** 104ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * @hide 105ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh */ 1066bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensenpublic class Vpn { 1076bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen private static final String NETWORKTYPE = "VPN"; 108899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey private static final String TAG = "Vpn"; 109899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey private static final boolean LOGD = true; 1106bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen 111899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey // TODO: create separate trackers for each unique VPN to support 112899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey // automated reconnection 113199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh 1146bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen private Context mContext; 1156bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen private NetworkInfo mNetworkInfo; 1166bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen private String mPackage; 1176bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen private int mOwnerUID; 118c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh private String mInterface; 119199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh private Connection mConnection; 12085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh private LegacyVpnRunner mLegacyVpnRunner; 12190b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson private PendingIntent mStatusIntent; 12257666934b4a161cc2fb77eef15d0b894aaf8f173Jeff Sharkey private volatile boolean mEnableTeardown = true; 1236bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen private final INetworkManagementService mNetd; 124c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker private VpnConfig mConfig; 1256bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen private NetworkAgent mNetworkAgent; 1266bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen private final Looper mLooper; 1276bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen private final NetworkCapabilities mNetworkCapabilities; 128c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker 1294d03abcd49af490dba3850d341b955dd72f24959Robin Lee /** 13017e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * Whether to keep the connection active after rebooting, or upgrading or reinstalling. This 13117e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * only applies to {@link VpnService} connections. 13217e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee */ 13317e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee private boolean mAlwaysOn = false; 13417e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee 13517e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee /** 13617e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * Whether to disable traffic outside of this VPN even when the VPN is not connected. System 13717e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * apps can still bypass by choosing explicit networks. Has no effect if {@link mAlwaysOn} is 13817e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * not set. 13917e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee */ 14017e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee private boolean mLockdown = false; 14117e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee 14217e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee /** 1434d03abcd49af490dba3850d341b955dd72f24959Robin Lee * List of UIDs that are set to use this VPN by default. Normally, every UID in the user is 1444d03abcd49af490dba3850d341b955dd72f24959Robin Lee * added to this set but that can be changed by adding allowed or disallowed applications. It 1454d03abcd49af490dba3850d341b955dd72f24959Robin Lee * is non-null iff the VPN is connected. 1464d03abcd49af490dba3850d341b955dd72f24959Robin Lee * 1474d03abcd49af490dba3850d341b955dd72f24959Robin Lee * Unless the VPN has set allowBypass=true, these UIDs are forced into the VPN. 1484d03abcd49af490dba3850d341b955dd72f24959Robin Lee * 1494d03abcd49af490dba3850d341b955dd72f24959Robin Lee * @see VpnService.Builder#addAllowedApplication(String) 1504d03abcd49af490dba3850d341b955dd72f24959Robin Lee * @see VpnService.Builder#addDisallowedApplication(String) 1514d03abcd49af490dba3850d341b955dd72f24959Robin Lee */ 152c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker @GuardedBy("this") 1534d03abcd49af490dba3850d341b955dd72f24959Robin Lee private Set<UidRange> mVpnUsers = null; 154c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker 15517e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee /** 15617e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * List of UIDs for which networking should be blocked until VPN is ready, during brief periods 15717e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * when VPN is not running. For example, during system startup or after a crash. 15817e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * @see mLockdown 15917e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee */ 16017e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee @GuardedBy("this") 16117e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee private Set<UidRange> mBlockedUsers = new ArraySet<>(); 16217e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee 1630784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen // Handle of user initiating VPN. 1640784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen private final int mUserHandle; 165ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 1666bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen public Vpn(Looper looper, Context context, INetworkManagementService netService, 167e75b9e355500b7c6a05e4d6ec54ef48835707caaPaul Jensen int userHandle) { 168ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh mContext = context; 1696bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen mNetd = netService; 1700784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen mUserHandle = userHandle; 1716bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen mLooper = looper; 1726bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen 1736bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen mPackage = VpnConfig.LEGACY_VPN; 1740784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen mOwnerUID = getAppUid(mPackage, mUserHandle); 175899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey 176899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey try { 177899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey netService.registerObserver(mObserver); 178899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } catch (RemoteException e) { 179899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey Log.wtf(TAG, "Problem registering observer", e); 180899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } 1816bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen 1826bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_VPN, 0, NETWORKTYPE, ""); 1836bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen // TODO: Copy metered attribute and bandwidths from physical transport, b/16207332 1846bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen mNetworkCapabilities = new NetworkCapabilities(); 1856bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen mNetworkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_VPN); 1866bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN); 187899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } 188899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey 18957666934b4a161cc2fb77eef15d0b894aaf8f173Jeff Sharkey /** 19057666934b4a161cc2fb77eef15d0b894aaf8f173Jeff Sharkey * Set if this object is responsible for watching for {@link NetworkInfo} 19157666934b4a161cc2fb77eef15d0b894aaf8f173Jeff Sharkey * teardown. When {@code false}, teardown is handled externally by someone 19257666934b4a161cc2fb77eef15d0b894aaf8f173Jeff Sharkey * else. 19357666934b4a161cc2fb77eef15d0b894aaf8f173Jeff Sharkey */ 19457666934b4a161cc2fb77eef15d0b894aaf8f173Jeff Sharkey public void setEnableTeardown(boolean enableTeardown) { 19557666934b4a161cc2fb77eef15d0b894aaf8f173Jeff Sharkey mEnableTeardown = enableTeardown; 19657666934b4a161cc2fb77eef15d0b894aaf8f173Jeff Sharkey } 19757666934b4a161cc2fb77eef15d0b894aaf8f173Jeff Sharkey 198899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey /** 199899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey * Update current state, dispaching event to listeners. 200899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey */ 201899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey private void updateState(DetailedState detailedState, String reason) { 202899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey if (LOGD) Log.d(TAG, "setting state=" + detailedState + ", reason=" + reason); 203899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey mNetworkInfo.setDetailedState(detailedState, reason, null); 2046bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen if (mNetworkAgent != null) { 2056bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen mNetworkAgent.sendNetworkInfo(mNetworkInfo); 2066bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 207ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 208ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 209ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh /** 210244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee * Configures an always-on VPN connection through a specific application. 211244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee * This connection is automatically granted and persisted after a reboot. 212244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee * 213244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee * <p>The designated package should exist and declare a {@link VpnService} in its 214244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee * manifest guarded by {@link android.Manifest.permission.BIND_VPN_SERVICE}, 215244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee * otherwise the call will fail. 216244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee * 21717e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * @param packageName the package to designate as always-on VPN supplier. 21817e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * @param lockdown whether to prevent traffic outside of a VPN, for example while connecting. 219244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee */ 22017e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee public synchronized boolean setAlwaysOnPackage(String packageName, boolean lockdown) { 221244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee enforceControlPermissionOrInternalCaller(); 222244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee 223244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee // Disconnect current VPN. 224244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee prepareInternal(VpnConfig.LEGACY_VPN); 225244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee 226244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee // Pre-authorize new always-on VPN package. 227244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee if (packageName != null) { 228244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee if (!setPackageAuthorization(packageName, true)) { 229244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee return false; 230244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee } 23178378845ff64c11b688aaa784b01eef8616a690dRobin Lee prepareInternal(packageName); 232244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee } 233244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee 23417e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee mAlwaysOn = (packageName != null); 23517e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee mLockdown = (mAlwaysOn && lockdown); 23617e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee setVpnForcedLocked(mLockdown); 237244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee return true; 238244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee } 239244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee 240244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee /** 241244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee * @return the package name of the VPN controller responsible for always-on VPN, 242244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee * or {@code null} if none is set or always-on VPN is controlled through 243244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee * lockdown instead. 244244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee * @hide 245244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee */ 246244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee public synchronized String getAlwaysOnPackage() { 247244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee enforceControlPermissionOrInternalCaller(); 24817e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee return (mAlwaysOn ? mPackage : null); 249244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee } 250244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee 251244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee /** 252100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * Prepare for a VPN application. This method is designed to solve 253100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * race conditions. It first compares the current prepared package 254100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * with {@code oldPackage}. If they are the same, the prepared 255100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * package is revoked and replaced with {@code newPackage}. If 256100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * {@code oldPackage} is {@code null}, the comparison is omitted. 257100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * If {@code newPackage} is the same package or {@code null}, the 258100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * revocation is omitted. This method returns {@code true} if the 259100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * operation is succeeded. 260e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh * 261100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * Legacy VPN is handled specially since it is not a real package. 262100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * It uses {@link VpnConfig#LEGACY_VPN} as its package name, and 263100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * it can be revoked by itself. 264100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * 265100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * @param oldPackage The package name of the old VPN application. 266100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * @param newPackage The package name of the new VPN application. 267100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * @return true if the operation is succeeded. 268ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh */ 269100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh public synchronized boolean prepare(String oldPackage, String newPackage) { 27017e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee // Stop an existing always-on VPN from being dethroned by other apps. 27117e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee if (mAlwaysOn && !TextUtils.equals(mPackage, newPackage)) { 27217e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee return false; 27317e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee } 27417e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee 2750a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson if (oldPackage != null) { 2760a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson if (getAppUid(oldPackage, mUserHandle) != mOwnerUID) { 2770a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson // The package doesn't match. We return false (to obtain user consent) unless the 2780a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson // user has already consented to that VPN package. 2790a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson if (!oldPackage.equals(VpnConfig.LEGACY_VPN) && isVpnUserPreConsented(oldPackage)) { 2800a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson prepareInternal(oldPackage); 2810a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson return true; 2820a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson } 2830a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson return false; 2840a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson } else if (!oldPackage.equals(VpnConfig.LEGACY_VPN) 2850a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson && !isVpnUserPreConsented(oldPackage)) { 2860a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson // Currently prepared VPN is revoked, so unprepare it and return false. 2870a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson prepareInternal(VpnConfig.LEGACY_VPN); 2880a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson return false; 28905542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson } 290100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh } 291100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh 292100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh // Return true if we do not need to revoke. 293be08587510edbc149c841638db721eb97d2351b6Jeff Davidson if (newPackage == null || (!newPackage.equals(VpnConfig.LEGACY_VPN) && 294be08587510edbc149c841638db721eb97d2351b6Jeff Davidson getAppUid(newPackage, mUserHandle) == mOwnerUID)) { 295100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh return true; 296ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 297ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 2981b1bcd7b7370866bc00ce3361be8d5167bf3e28dRobin Lee // Check that the caller is authorized. 299dadc857d9de364fded10d4f69eb82bc9cd35d4b7Chia-chi Yeh enforceControlPermission(); 3007b0b834c3d12564c44ac134879a6dbc70e74be6eChia-chi Yeh 30111008a78b8e30910cedd8b8431980c7738183292Jeff Davidson prepareInternal(newPackage); 30211008a78b8e30910cedd8b8431980c7738183292Jeff Davidson return true; 30311008a78b8e30910cedd8b8431980c7738183292Jeff Davidson } 30411008a78b8e30910cedd8b8431980c7738183292Jeff Davidson 30511008a78b8e30910cedd8b8431980c7738183292Jeff Davidson /** Prepare the VPN for the given package. Does not perform permission checks. */ 30611008a78b8e30910cedd8b8431980c7738183292Jeff Davidson private void prepareInternal(String newPackage) { 30711008a78b8e30910cedd8b8431980c7738183292Jeff Davidson long token = Binder.clearCallingIdentity(); 30811008a78b8e30910cedd8b8431980c7738183292Jeff Davidson try { 30911008a78b8e30910cedd8b8431980c7738183292Jeff Davidson // Reset the interface. 31011008a78b8e30910cedd8b8431980c7738183292Jeff Davidson if (mInterface != null) { 31111008a78b8e30910cedd8b8431980c7738183292Jeff Davidson mStatusIntent = null; 31211008a78b8e30910cedd8b8431980c7738183292Jeff Davidson agentDisconnect(); 31311008a78b8e30910cedd8b8431980c7738183292Jeff Davidson jniReset(mInterface); 31411008a78b8e30910cedd8b8431980c7738183292Jeff Davidson mInterface = null; 31511008a78b8e30910cedd8b8431980c7738183292Jeff Davidson mVpnUsers = null; 31611008a78b8e30910cedd8b8431980c7738183292Jeff Davidson } 31711008a78b8e30910cedd8b8431980c7738183292Jeff Davidson 31811008a78b8e30910cedd8b8431980c7738183292Jeff Davidson // Revoke the connection or stop LegacyVpnRunner. 31911008a78b8e30910cedd8b8431980c7738183292Jeff Davidson if (mConnection != null) { 32011008a78b8e30910cedd8b8431980c7738183292Jeff Davidson try { 32111008a78b8e30910cedd8b8431980c7738183292Jeff Davidson mConnection.mService.transact(IBinder.LAST_CALL_TRANSACTION, 32211008a78b8e30910cedd8b8431980c7738183292Jeff Davidson Parcel.obtain(), null, IBinder.FLAG_ONEWAY); 32311008a78b8e30910cedd8b8431980c7738183292Jeff Davidson } catch (Exception e) { 32411008a78b8e30910cedd8b8431980c7738183292Jeff Davidson // ignore 32511008a78b8e30910cedd8b8431980c7738183292Jeff Davidson } 32611008a78b8e30910cedd8b8431980c7738183292Jeff Davidson mContext.unbindService(mConnection); 32711008a78b8e30910cedd8b8431980c7738183292Jeff Davidson mConnection = null; 32811008a78b8e30910cedd8b8431980c7738183292Jeff Davidson } else if (mLegacyVpnRunner != null) { 32911008a78b8e30910cedd8b8431980c7738183292Jeff Davidson mLegacyVpnRunner.exit(); 33011008a78b8e30910cedd8b8431980c7738183292Jeff Davidson mLegacyVpnRunner = null; 33111008a78b8e30910cedd8b8431980c7738183292Jeff Davidson } 332ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 333199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh try { 33411008a78b8e30910cedd8b8431980c7738183292Jeff Davidson mNetd.denyProtect(mOwnerUID); 335199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh } catch (Exception e) { 33611008a78b8e30910cedd8b8431980c7738183292Jeff Davidson Log.wtf(TAG, "Failed to disallow UID " + mOwnerUID + " to call protect() " + e); 337199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh } 33841d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh 33911008a78b8e30910cedd8b8431980c7738183292Jeff Davidson Log.i(TAG, "Switched from " + mPackage + " to " + newPackage); 34011008a78b8e30910cedd8b8431980c7738183292Jeff Davidson mPackage = newPackage; 34111008a78b8e30910cedd8b8431980c7738183292Jeff Davidson mOwnerUID = getAppUid(newPackage, mUserHandle); 34211008a78b8e30910cedd8b8431980c7738183292Jeff Davidson try { 34311008a78b8e30910cedd8b8431980c7738183292Jeff Davidson mNetd.allowProtect(mOwnerUID); 34411008a78b8e30910cedd8b8431980c7738183292Jeff Davidson } catch (Exception e) { 34511008a78b8e30910cedd8b8431980c7738183292Jeff Davidson Log.wtf(TAG, "Failed to allow UID " + mOwnerUID + " to call protect() " + e); 34611008a78b8e30910cedd8b8431980c7738183292Jeff Davidson } 34711008a78b8e30910cedd8b8431980c7738183292Jeff Davidson mConfig = null; 3486bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen 34911008a78b8e30910cedd8b8431980c7738183292Jeff Davidson updateState(DetailedState.IDLE, "prepare"); 3506bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } finally { 3516bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen Binder.restoreCallingIdentity(token); 3526bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 353ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 354ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 35505542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson /** 3563b3dd942ec6a0beaccd1cef0723d72786435d8f3Robin Lee * Set whether a package has the ability to launch VPNs without user intervention. 35705542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson */ 358244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee public boolean setPackageAuthorization(String packageName, boolean authorized) { 35905542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson // Check if the caller is authorized. 360244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee enforceControlPermissionOrInternalCaller(); 36105542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson 3623b3dd942ec6a0beaccd1cef0723d72786435d8f3Robin Lee int uid = getAppUid(packageName, mUserHandle); 3633b3dd942ec6a0beaccd1cef0723d72786435d8f3Robin Lee if (uid == -1 || VpnConfig.LEGACY_VPN.equals(packageName)) { 3643b3dd942ec6a0beaccd1cef0723d72786435d8f3Robin Lee // Authorization for nonexistent packages (or fake ones) can't be updated. 365244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee return false; 36605542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson } 36705542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson 36805542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson long token = Binder.clearCallingIdentity(); 36905542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson try { 37005542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson AppOpsManager appOps = 37105542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); 3723b3dd942ec6a0beaccd1cef0723d72786435d8f3Robin Lee appOps.setMode(AppOpsManager.OP_ACTIVATE_VPN, uid, packageName, 37305542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson authorized ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED); 374244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee return true; 37505542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson } catch (Exception e) { 3763b3dd942ec6a0beaccd1cef0723d72786435d8f3Robin Lee Log.wtf(TAG, "Failed to set app ops for package " + packageName + ", uid " + uid, e); 37705542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson } finally { 37805542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson Binder.restoreCallingIdentity(token); 37905542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson } 380244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee return false; 38105542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson } 38205542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson 38305542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson private boolean isVpnUserPreConsented(String packageName) { 38405542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson AppOpsManager appOps = 38505542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); 38605542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson 38705542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson // Verify that the caller matches the given package and has permission to activate VPNs. 38805542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson return appOps.noteOpNoThrow(AppOpsManager.OP_ACTIVATE_VPN, Binder.getCallingUid(), 38905542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson packageName) == AppOpsManager.MODE_ALLOWED; 39005542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson } 39105542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson 3920784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen private int getAppUid(String app, int userHandle) { 39305542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson if (VpnConfig.LEGACY_VPN.equals(app)) { 3946bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen return Process.myUid(); 3956bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 396fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh PackageManager pm = mContext.getPackageManager(); 3976bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen int result; 3986bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen try { 399e06b4d1d9f718b9fe02980fea794a36831a16db2Jeff Sharkey result = pm.getPackageUidAsUser(app, userHandle); 4006bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } catch (NameNotFoundException e) { 4016bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen result = -1; 402fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh } 4036bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen return result; 4046bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 4056bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen 4066bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen public NetworkInfo getNetworkInfo() { 4076bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen return mNetworkInfo; 4086bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 4096bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen 41031a94f48bf8014cf6a1127bd23cf9a8541a9abedPaul Jensen public int getNetId() { 41131a94f48bf8014cf6a1127bd23cf9a8541a9abedPaul Jensen return mNetworkAgent != null ? mNetworkAgent.netId : NETID_UNSET; 41231a94f48bf8014cf6a1127bd23cf9a8541a9abedPaul Jensen } 41331a94f48bf8014cf6a1127bd23cf9a8541a9abedPaul Jensen 41460446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti private LinkProperties makeLinkProperties() { 41560446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti boolean allowIPv4 = mConfig.allowIPv4; 41660446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti boolean allowIPv6 = mConfig.allowIPv6; 41760446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti 4186bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen LinkProperties lp = new LinkProperties(); 41960446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti 4206bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen lp.setInterfaceName(mInterface); 42142065ac64cba166dc0fe602957ea8fe80bf406e2Sreeram Ramachandran 42260446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti if (mConfig.addresses != null) { 42360446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti for (LinkAddress address : mConfig.addresses) { 42460446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti lp.addLinkAddress(address); 42560446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti allowIPv4 |= address.getAddress() instanceof Inet4Address; 42660446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti allowIPv6 |= address.getAddress() instanceof Inet6Address; 42760446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti } 4286bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 42960446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti 43060446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti if (mConfig.routes != null) { 43160446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti for (RouteInfo route : mConfig.routes) { 43260446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti lp.addRoute(route); 43360446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti InetAddress address = route.getDestination().getAddress(); 43460446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti allowIPv4 |= address instanceof Inet4Address; 43560446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti allowIPv6 |= address instanceof Inet6Address; 43660446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti } 4376bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 43842065ac64cba166dc0fe602957ea8fe80bf406e2Sreeram Ramachandran 4396bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen if (mConfig.dnsServers != null) { 4406bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen for (String dnsServer : mConfig.dnsServers) { 44142065ac64cba166dc0fe602957ea8fe80bf406e2Sreeram Ramachandran InetAddress address = InetAddress.parseNumericAddress(dnsServer); 44242065ac64cba166dc0fe602957ea8fe80bf406e2Sreeram Ramachandran lp.addDnsServer(address); 44360446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti allowIPv4 |= address instanceof Inet4Address; 44460446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti allowIPv6 |= address instanceof Inet6Address; 4456bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 4466bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 44742065ac64cba166dc0fe602957ea8fe80bf406e2Sreeram Ramachandran 44860446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti if (!allowIPv4) { 44960446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE)); 45060446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti } 45160446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti if (!allowIPv6) { 45260446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE)); 45360446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti } 45460446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti 4556bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen // Concatenate search domains into a string. 4566bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen StringBuilder buffer = new StringBuilder(); 4576bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen if (mConfig.searchDomains != null) { 4586bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen for (String domain : mConfig.searchDomains) { 4596bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen buffer.append(domain).append(' '); 4606bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 4616bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 4626bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen lp.setDomains(buffer.toString().trim()); 46342065ac64cba166dc0fe602957ea8fe80bf406e2Sreeram Ramachandran 46460446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti // TODO: Stop setting the MTU in jniCreate and set it here. 46560446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti 46660446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti return lp; 46760446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti } 46860446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti 46960446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti private void agentConnect() { 47060446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti LinkProperties lp = makeLinkProperties(); 47160446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti 47260446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti if (lp.hasIPv4DefaultRoute() || lp.hasIPv6DefaultRoute()) { 47360446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); 47460446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti } else { 47560446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); 47660446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti } 47760446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti 478323f29df583e9338e3b2bf90fc8c0785a934a61bRobin Lee mNetworkInfo.setDetailedState(DetailedState.CONNECTING, null, null); 47942065ac64cba166dc0fe602957ea8fe80bf406e2Sreeram Ramachandran 4808cd33ed84e94036a5e1201485af7603dc6fb0d9bSreeram Ramachandran NetworkMisc networkMisc = new NetworkMisc(); 48117e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee networkMisc.allowBypass = mConfig.allowBypass && !mLockdown; 48242065ac64cba166dc0fe602957ea8fe80bf406e2Sreeram Ramachandran 4836bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen long token = Binder.clearCallingIdentity(); 4844ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker try { 4856bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen mNetworkAgent = new NetworkAgent(mLooper, mContext, NETWORKTYPE, 4868cd33ed84e94036a5e1201485af7603dc6fb0d9bSreeram Ramachandran mNetworkInfo, mNetworkCapabilities, lp, 0, networkMisc) { 48705542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson @Override 4886bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen public void unwanted() { 4896bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen // We are user controlled, not driven by NetworkRequest. 49005542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson } 4916bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen }; 4924ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker } finally { 4934ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker Binder.restoreCallingIdentity(token); 4944ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker } 49542065ac64cba166dc0fe602957ea8fe80bf406e2Sreeram Ramachandran 4964d03abcd49af490dba3850d341b955dd72f24959Robin Lee mVpnUsers = createUserAndRestrictedProfilesRanges(mUserHandle, 4974d03abcd49af490dba3850d341b955dd72f24959Robin Lee mConfig.allowedApplications, mConfig.disallowedApplications); 4986bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen mNetworkAgent.addUidRanges(mVpnUsers.toArray(new UidRange[mVpnUsers.size()])); 499323f29df583e9338e3b2bf90fc8c0785a934a61bRobin Lee 500323f29df583e9338e3b2bf90fc8c0785a934a61bRobin Lee mNetworkInfo.setIsAvailable(true); 501323f29df583e9338e3b2bf90fc8c0785a934a61bRobin Lee updateState(DetailedState.CONNECTED, "agentConnect"); 5026bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 5036bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen 5041c36315a36962321dfe870b07e28b04a1d6777e9Fyodor Kupolov private boolean canHaveRestrictedProfile(int userId) { 5051c36315a36962321dfe870b07e28b04a1d6777e9Fyodor Kupolov long token = Binder.clearCallingIdentity(); 5061c36315a36962321dfe870b07e28b04a1d6777e9Fyodor Kupolov try { 5071c36315a36962321dfe870b07e28b04a1d6777e9Fyodor Kupolov return UserManager.get(mContext).canHaveRestrictedProfile(userId); 5081c36315a36962321dfe870b07e28b04a1d6777e9Fyodor Kupolov } finally { 5091c36315a36962321dfe870b07e28b04a1d6777e9Fyodor Kupolov Binder.restoreCallingIdentity(token); 5101c36315a36962321dfe870b07e28b04a1d6777e9Fyodor Kupolov } 5111c36315a36962321dfe870b07e28b04a1d6777e9Fyodor Kupolov } 5121c36315a36962321dfe870b07e28b04a1d6777e9Fyodor Kupolov 5136bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen private void agentDisconnect(NetworkInfo networkInfo, NetworkAgent networkAgent) { 5146bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen networkInfo.setIsAvailable(false); 5156bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen networkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null); 5166bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen if (networkAgent != null) { 5176bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen networkAgent.sendNetworkInfo(networkInfo); 5186bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 5196bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 5206bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen 5216bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen private void agentDisconnect(NetworkAgent networkAgent) { 5226bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen NetworkInfo networkInfo = new NetworkInfo(mNetworkInfo); 5236bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen agentDisconnect(networkInfo, networkAgent); 5246bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 5254ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker 5266bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen private void agentDisconnect() { 5276bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen if (mNetworkInfo.isConnected()) { 5286bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen agentDisconnect(mNetworkInfo, mNetworkAgent); 5296bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen mNetworkAgent = null; 5306bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 531fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh } 532fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh 533fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh /** 534e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh * Establish a VPN network and return the file descriptor of the VPN 535e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh * interface. This methods returns {@code null} if the application is 536100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * revoked or not prepared. 537ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * 538e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh * @param config The parameters to configure the network. 539e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh * @return The file descriptor of the VPN interface. 540ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh */ 54104ba25c418bc4538e9dc0f047cfb9608d358f679Chia-chi Yeh public synchronized ParcelFileDescriptor establish(VpnConfig config) { 542ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh // Check if the caller is already prepared. 543c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker UserManager mgr = UserManager.get(mContext); 5446bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen if (Binder.getCallingUid() != mOwnerUID) { 5457b0b834c3d12564c44ac134879a6dbc70e74be6eChia-chi Yeh return null; 546ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 5470a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson // Check to ensure consent hasn't been revoked since we were prepared. 5480a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson if (!isVpnUserPreConsented(mPackage)) { 5490a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson return null; 5500a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson } 551fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh // Check if the service is properly declared. 552199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh Intent intent = new Intent(VpnConfig.SERVICE_INTERFACE); 553199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh intent.setClassName(mPackage, config.user); 5544ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker long token = Binder.clearCallingIdentity(); 5554ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker try { 556c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker // Restricted users are not allowed to create VPNs, they are tied to Owner 5570784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen UserInfo user = mgr.getUserInfo(mUserHandle); 558628ae0d84180c5f7c52725e02506021e532ed252Robin Lee if (user.isRestricted()) { 559c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker throw new SecurityException("Restricted users cannot establish VPNs"); 560c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker } 561c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker 5624ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker ResolveInfo info = AppGlobals.getPackageManager().resolveService(intent, 5630784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen null, 0, mUserHandle); 5644ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker if (info == null) { 5654ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker throw new SecurityException("Cannot find " + config.user); 5664ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker } 5674ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker if (!BIND_VPN_SERVICE.equals(info.serviceInfo.permission)) { 5684ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker throw new SecurityException(config.user + " does not require " + BIND_VPN_SERVICE); 5694ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker } 5704ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker } catch (RemoteException e) { 5714ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker throw new SecurityException("Cannot find " + config.user); 5724ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker } finally { 5734ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker Binder.restoreCallingIdentity(token); 574199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh } 575fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh 5764c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker // Save the old config in case we need to go back. 5774c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker VpnConfig oldConfig = mConfig; 5784c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker String oldInterface = mInterface; 5794c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker Connection oldConnection = mConnection; 5806bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen NetworkAgent oldNetworkAgent = mNetworkAgent; 5816bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen mNetworkAgent = null; 5824d03abcd49af490dba3850d341b955dd72f24959Robin Lee Set<UidRange> oldUsers = mVpnUsers; 5834c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker 584e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh // Configure the interface. Abort if any of these steps fails. 58597a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh ParcelFileDescriptor tun = ParcelFileDescriptor.adoptFd(jniCreate(config.mtu)); 586ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh try { 587899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey updateState(DetailedState.CONNECTING, "establish"); 588c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh String interfaze = jniGetName(tun.getFd()); 5894ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker 590c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker // TEMP use the old jni calls until there is support for netd address setting 5914ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker StringBuilder builder = new StringBuilder(); 5924ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker for (LinkAddress address : config.addresses) { 5934ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker builder.append(" " + address); 59497a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh } 5954ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker if (jniSetAddresses(interfaze, builder.toString()) < 1) { 5964ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker throw new IllegalArgumentException("At least one address must be specified"); 59797a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh } 598199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh Connection connection = new Connection(); 599d69e4c1460017062e7c36be55801cb434ad19d97Dianne Hackborn if (!mContext.bindServiceAsUser(intent, connection, 600d69e4c1460017062e7c36be55801cb434ad19d97Dianne Hackborn Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE, 601d69e4c1460017062e7c36be55801cb434ad19d97Dianne Hackborn new UserHandle(mUserHandle))) { 602199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh throw new IllegalStateException("Cannot bind " + config.user); 603199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh } 6044c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker 605199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh mConnection = connection; 606c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh mInterface = interfaze; 6074ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker 6084ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker // Fill more values. 6094ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker config.user = mPackage; 6104ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker config.interfaze = mInterface; 611c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker config.startTime = SystemClock.elapsedRealtime(); 612c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker mConfig = config; 6134c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker 6144ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker // Set up forwarding and DNS rules. 6156bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen agentConnect(); 6164ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker 6174c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker if (oldConnection != null) { 6184c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker mContext.unbindService(oldConnection); 6194c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker } 6206bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen // Remove the old tun's user forwarding rules 6216bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen // The new tun's user rules have already been added so they will take over 6226bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen // as rules are deleted. This prevents data leakage as the rules are moved over. 6236bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen agentDisconnect(oldNetworkAgent); 6244c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker if (oldInterface != null && !oldInterface.equals(interfaze)) { 6254c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker jniReset(oldInterface); 6264c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker } 6276bbf39cf6b81222f32d2b66b8fa85d562e0ad71cJeff Davidson 6286bbf39cf6b81222f32d2b66b8fa85d562e0ad71cJeff Davidson try { 6296bbf39cf6b81222f32d2b66b8fa85d562e0ad71cJeff Davidson IoUtils.setBlocking(tun.getFileDescriptor(), config.blocking); 6306bbf39cf6b81222f32d2b66b8fa85d562e0ad71cJeff Davidson } catch (IOException e) { 6316bbf39cf6b81222f32d2b66b8fa85d562e0ad71cJeff Davidson throw new IllegalStateException( 6326bbf39cf6b81222f32d2b66b8fa85d562e0ad71cJeff Davidson "Cannot set tunnel's fd as blocking=" + config.blocking, e); 6336bbf39cf6b81222f32d2b66b8fa85d562e0ad71cJeff Davidson } 634ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } catch (RuntimeException e) { 635065b299df4159602327977dd007cb2cd6b64ab20Jeff Sharkey IoUtils.closeQuietly(tun); 6366bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen agentDisconnect(); 6374c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker // restore old state 6384c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker mConfig = oldConfig; 6394c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker mConnection = oldConnection; 6404c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker mVpnUsers = oldUsers; 6416bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen mNetworkAgent = oldNetworkAgent; 6424c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker mInterface = oldInterface; 643ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh throw e; 644ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 645199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh Log.i(TAG, "Established by " + config.user + " on " + mInterface); 646c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh return tun; 647ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 648ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 649c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker private boolean isRunningLocked() { 650c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran return mNetworkAgent != null && mInterface != null; 651c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran } 652c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran 653c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran // Returns true if the VPN has been established and the calling UID is its owner. Used to check 654c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran // that a call to mutate VPN state is admissible. 655c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran private boolean isCallerEstablishedOwnerLocked() { 656c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran return isRunningLocked() && Binder.getCallingUid() == mOwnerUID; 657c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker } 658c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker 6590784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen // Note: Return type guarantees results are deduped and sorted, which callers require. 6600784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen private SortedSet<Integer> getAppsUids(List<String> packageNames, int userHandle) { 6610784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen SortedSet<Integer> uids = new TreeSet<Integer>(); 6620784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen for (String app : packageNames) { 6630784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen int uid = getAppUid(app, userHandle); 6640784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen if (uid != -1) uids.add(uid); 6650784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen } 6660784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen return uids; 6670784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen } 6680784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen 6694d03abcd49af490dba3850d341b955dd72f24959Robin Lee /** 6704d03abcd49af490dba3850d341b955dd72f24959Robin Lee * Creates a {@link Set} of non-intersecting {@link UidRange} objects including all UIDs 6714d03abcd49af490dba3850d341b955dd72f24959Robin Lee * associated with one user, and any restricted profiles attached to that user. 6724d03abcd49af490dba3850d341b955dd72f24959Robin Lee * 6734d03abcd49af490dba3850d341b955dd72f24959Robin Lee * <p>If one of {@param allowedApplications} or {@param disallowedApplications} is provided, 6744d03abcd49af490dba3850d341b955dd72f24959Robin Lee * the UID ranges will match the app whitelist or blacklist specified there. Otherwise, all UIDs 6754d03abcd49af490dba3850d341b955dd72f24959Robin Lee * in each user and profile will be included. 6764d03abcd49af490dba3850d341b955dd72f24959Robin Lee * 6774d03abcd49af490dba3850d341b955dd72f24959Robin Lee * @param userHandle The userId to create UID ranges for along with any of its restricted 6784d03abcd49af490dba3850d341b955dd72f24959Robin Lee * profiles. 6794d03abcd49af490dba3850d341b955dd72f24959Robin Lee * @param allowedApplications (optional) whitelist of applications to include. 6804d03abcd49af490dba3850d341b955dd72f24959Robin Lee * @param disallowedApplications (optional) blacklist of applications to exclude. 6814d03abcd49af490dba3850d341b955dd72f24959Robin Lee */ 6824d03abcd49af490dba3850d341b955dd72f24959Robin Lee @VisibleForTesting 6834d03abcd49af490dba3850d341b955dd72f24959Robin Lee Set<UidRange> createUserAndRestrictedProfilesRanges(@UserIdInt int userHandle, 6844d03abcd49af490dba3850d341b955dd72f24959Robin Lee @Nullable List<String> allowedApplications, 6854d03abcd49af490dba3850d341b955dd72f24959Robin Lee @Nullable List<String> disallowedApplications) { 6864d03abcd49af490dba3850d341b955dd72f24959Robin Lee final Set<UidRange> ranges = new ArraySet<>(); 6874d03abcd49af490dba3850d341b955dd72f24959Robin Lee 6884d03abcd49af490dba3850d341b955dd72f24959Robin Lee // Assign the top-level user to the set of ranges 6894d03abcd49af490dba3850d341b955dd72f24959Robin Lee addUserToRanges(ranges, userHandle, allowedApplications, disallowedApplications); 6904d03abcd49af490dba3850d341b955dd72f24959Robin Lee 6914d03abcd49af490dba3850d341b955dd72f24959Robin Lee // If the user can have restricted profiles, assign all its restricted profiles too 6924d03abcd49af490dba3850d341b955dd72f24959Robin Lee if (canHaveRestrictedProfile(userHandle)) { 6934d03abcd49af490dba3850d341b955dd72f24959Robin Lee final long token = Binder.clearCallingIdentity(); 6944d03abcd49af490dba3850d341b955dd72f24959Robin Lee List<UserInfo> users; 6954d03abcd49af490dba3850d341b955dd72f24959Robin Lee try { 69617e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee users = UserManager.get(mContext).getUsers(true); 6974d03abcd49af490dba3850d341b955dd72f24959Robin Lee } finally { 6984d03abcd49af490dba3850d341b955dd72f24959Robin Lee Binder.restoreCallingIdentity(token); 6994d03abcd49af490dba3850d341b955dd72f24959Robin Lee } 7004d03abcd49af490dba3850d341b955dd72f24959Robin Lee for (UserInfo user : users) { 7014d03abcd49af490dba3850d341b955dd72f24959Robin Lee if (user.isRestricted() && (user.restrictedProfileParentId == userHandle)) { 7024d03abcd49af490dba3850d341b955dd72f24959Robin Lee addUserToRanges(ranges, user.id, allowedApplications, disallowedApplications); 7034d03abcd49af490dba3850d341b955dd72f24959Robin Lee } 7044d03abcd49af490dba3850d341b955dd72f24959Robin Lee } 705c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker } 7064d03abcd49af490dba3850d341b955dd72f24959Robin Lee return ranges; 7074d03abcd49af490dba3850d341b955dd72f24959Robin Lee } 70869887e838814642a7ae78fc810656c7c8afc2a19Robert Greenwalt 7094d03abcd49af490dba3850d341b955dd72f24959Robin Lee /** 7104d03abcd49af490dba3850d341b955dd72f24959Robin Lee * Updates a {@link Set} of non-intersecting {@link UidRange} objects to include all UIDs 7114d03abcd49af490dba3850d341b955dd72f24959Robin Lee * associated with one user. 7124d03abcd49af490dba3850d341b955dd72f24959Robin Lee * 7134d03abcd49af490dba3850d341b955dd72f24959Robin Lee * <p>If one of {@param allowedApplications} or {@param disallowedApplications} is provided, 7144d03abcd49af490dba3850d341b955dd72f24959Robin Lee * the UID ranges will match the app whitelist or blacklist specified there. Otherwise, all UIDs 7154d03abcd49af490dba3850d341b955dd72f24959Robin Lee * in the user will be included. 7164d03abcd49af490dba3850d341b955dd72f24959Robin Lee * 7174d03abcd49af490dba3850d341b955dd72f24959Robin Lee * @param ranges {@link Set} of {@link UidRange}s to which to add. 7184d03abcd49af490dba3850d341b955dd72f24959Robin Lee * @param userHandle The userId to add to {@param ranges}. 7194d03abcd49af490dba3850d341b955dd72f24959Robin Lee * @param allowedApplications (optional) whitelist of applications to include. 7204d03abcd49af490dba3850d341b955dd72f24959Robin Lee * @param disallowedApplications (optional) blacklist of applications to exclude. 7214d03abcd49af490dba3850d341b955dd72f24959Robin Lee */ 7224d03abcd49af490dba3850d341b955dd72f24959Robin Lee @VisibleForTesting 7234d03abcd49af490dba3850d341b955dd72f24959Robin Lee void addUserToRanges(@NonNull Set<UidRange> ranges, @UserIdInt int userHandle, 7244d03abcd49af490dba3850d341b955dd72f24959Robin Lee @Nullable List<String> allowedApplications, 7254d03abcd49af490dba3850d341b955dd72f24959Robin Lee @Nullable List<String> disallowedApplications) { 7264d03abcd49af490dba3850d341b955dd72f24959Robin Lee if (allowedApplications != null) { 7270784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen // Add ranges covering all UIDs for allowedApplications. 7280784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen int start = -1, stop = -1; 7294d03abcd49af490dba3850d341b955dd72f24959Robin Lee for (int uid : getAppsUids(allowedApplications, userHandle)) { 7300784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen if (start == -1) { 7310784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen start = uid; 7320784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen } else if (uid != stop + 1) { 7334d03abcd49af490dba3850d341b955dd72f24959Robin Lee ranges.add(new UidRange(start, stop)); 7340784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen start = uid; 7350784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen } 7360784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen stop = uid; 7370784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen } 7384d03abcd49af490dba3850d341b955dd72f24959Robin Lee if (start != -1) ranges.add(new UidRange(start, stop)); 7394d03abcd49af490dba3850d341b955dd72f24959Robin Lee } else if (disallowedApplications != null) { 7400784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen // Add all ranges for user skipping UIDs for disallowedApplications. 7410784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen final UidRange userRange = UidRange.createForUser(userHandle); 7420784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen int start = userRange.start; 7434d03abcd49af490dba3850d341b955dd72f24959Robin Lee for (int uid : getAppsUids(disallowedApplications, userHandle)) { 7440784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen if (uid == start) { 7450784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen start++; 7460784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen } else { 7474d03abcd49af490dba3850d341b955dd72f24959Robin Lee ranges.add(new UidRange(start, uid - 1)); 7480784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen start = uid + 1; 7490784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen } 7500784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen } 7514d03abcd49af490dba3850d341b955dd72f24959Robin Lee if (start <= userRange.stop) ranges.add(new UidRange(start, userRange.stop)); 7520784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen } else { 7530784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen // Add all UIDs for the user. 7544d03abcd49af490dba3850d341b955dd72f24959Robin Lee ranges.add(UidRange.createForUser(userHandle)); 7550784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen } 756c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker } 757c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker 7580784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen // Returns the subset of the full list of active UID ranges the VPN applies to (mVpnUsers) that 7590784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen // apply to userHandle. 7600784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen private List<UidRange> uidRangesForUser(int userHandle) { 7610784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen final UidRange userRange = UidRange.createForUser(userHandle); 7620784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen final List<UidRange> ranges = new ArrayList<UidRange>(); 7630784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen for (UidRange range : mVpnUsers) { 7644d03abcd49af490dba3850d341b955dd72f24959Robin Lee if (userRange.containsRange(range)) { 7650784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen ranges.add(range); 7660784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen } 7670784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen } 7680784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen return ranges; 7690784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen } 7700784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen 7710784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen private void removeVpnUserLocked(int userHandle) { 772c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran if (mVpnUsers == null) { 77390b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson throw new IllegalStateException("VPN is not active"); 77490b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson } 7750784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen final List<UidRange> ranges = uidRangesForUser(userHandle); 77690b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson if (mNetworkAgent != null) { 7770784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen mNetworkAgent.removeUidRanges(ranges.toArray(new UidRange[ranges.size()])); 77890b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson } 7790784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen mVpnUsers.removeAll(ranges); 780c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker } 781c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker 7821c36315a36962321dfe870b07e28b04a1d6777e9Fyodor Kupolov public void onUserAdded(int userHandle) { 7831c36315a36962321dfe870b07e28b04a1d6777e9Fyodor Kupolov // If the user is restricted tie them to the parent user's VPN 7841c36315a36962321dfe870b07e28b04a1d6777e9Fyodor Kupolov UserInfo user = UserManager.get(mContext).getUserInfo(userHandle); 78517e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee if (user.isRestricted() && user.restrictedProfileParentId == mUserHandle) { 7861c36315a36962321dfe870b07e28b04a1d6777e9Fyodor Kupolov synchronized(Vpn.this) { 78717e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee if (mVpnUsers != null) { 78817e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee try { 78917e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee addUserToRanges(mVpnUsers, userHandle, mConfig.allowedApplications, 79017e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee mConfig.disallowedApplications); 79117e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee if (mNetworkAgent != null) { 79217e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee final List<UidRange> ranges = uidRangesForUser(userHandle); 79317e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee mNetworkAgent.addUidRanges(ranges.toArray(new UidRange[ranges.size()])); 79417e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee } 79517e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee } catch (Exception e) { 79617e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee Log.wtf(TAG, "Failed to add restricted user to owner", e); 7976bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 79817e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee } 79917e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee if (mAlwaysOn) { 80017e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee setVpnForcedLocked(mLockdown); 801c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker } 802c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker } 803c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker } 804c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker } 805c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker 8061c36315a36962321dfe870b07e28b04a1d6777e9Fyodor Kupolov public void onUserRemoved(int userHandle) { 807c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker // clean up if restricted 8081c36315a36962321dfe870b07e28b04a1d6777e9Fyodor Kupolov UserInfo user = UserManager.get(mContext).getUserInfo(userHandle); 80917e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee if (user.isRestricted() && user.restrictedProfileParentId == mUserHandle) { 8101c36315a36962321dfe870b07e28b04a1d6777e9Fyodor Kupolov synchronized(Vpn.this) { 81117e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee if (mVpnUsers != null) { 81217e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee try { 81317e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee removeVpnUserLocked(userHandle); 81417e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee } catch (Exception e) { 81517e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee Log.wtf(TAG, "Failed to remove restricted user to owner", e); 81617e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee } 81717e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee } 81817e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee if (mAlwaysOn) { 81917e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee setVpnForcedLocked(mLockdown); 820c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker } 821c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker } 822c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker } 823c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker } 824c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker 825bf6ff2c025405a3af496fe558dfc4468a9b45cc8Chad Brubaker /** 82617e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * Called when the user associated with this VPN has just been stopped. 82717e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee */ 82817e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee public synchronized void onUserStopped() { 82917e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee // Switch off networking lockdown (if it was enabled) 83017e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee setVpnForcedLocked(false); 83117e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee mAlwaysOn = false; 83217e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee 83317e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee // Quit any active connections 83417e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee agentDisconnect(); 83517e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee } 83617e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee 83717e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee /** 83817e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * Restrict network access from all UIDs affected by this {@link Vpn}, apart from the VPN 83917e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * service app itself, to only sockets that have had {@code protect()} called on them. All 84017e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * non-VPN traffic is blocked via a {@code PROHIBIT} response from the kernel. 84117e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * 84217e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * The exception for the VPN UID isn't technically necessary -- setup should use protected 84317e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * sockets -- but in practice it saves apps that don't protect their sockets from breaking. 84417e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * 84517e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * Calling multiple times with {@param enforce} = {@code true} will recreate the set of UIDs to 84617e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * block every time, and if anything has changed update using {@link #setAllowOnlyVpnForUids}. 84717e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * 84817e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * @param enforce {@code true} to require that all traffic under the jurisdiction of this 84917e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * {@link Vpn} goes through a VPN connection or is blocked until one is 85017e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * available, {@code false} to lift the requirement. 85117e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * 85217e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * @see #mBlockedUsers 85317e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee */ 85417e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee @GuardedBy("this") 85517e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee private void setVpnForcedLocked(boolean enforce) { 85617e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee final Set<UidRange> removedRanges = new ArraySet<>(mBlockedUsers); 85717e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee if (enforce) { 85817e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee final Set<UidRange> addedRanges = createUserAndRestrictedProfilesRanges(mUserHandle, 85917e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee /* allowedApplications */ null, 86017e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee /* disallowedApplications */ Collections.singletonList(mPackage)); 86117e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee 86217e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee removedRanges.removeAll(addedRanges); 86317e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee addedRanges.removeAll(mBlockedUsers); 86417e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee 86517e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee setAllowOnlyVpnForUids(false, removedRanges); 86617e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee setAllowOnlyVpnForUids(true, addedRanges); 86717e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee } else { 86817e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee setAllowOnlyVpnForUids(false, removedRanges); 86917e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee } 87017e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee } 87117e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee 87217e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee /** 87317e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * Either add or remove a list of {@link UidRange}s to the list of UIDs that are only allowed 87417e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * to make connections through sockets that have had {@code protect()} called on them. 87517e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * 87617e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * @param enforce {@code true} to add to the blacklist, {@code false} to remove. 87717e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * @param ranges {@link Collection} of {@link UidRange}s to add (if {@param enforce} is 87817e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * {@code true}) or to remove. 87917e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * @return {@code true} if all of the UIDs were added/removed. {@code false} otherwise, 88017e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * including added ranges that already existed or removed ones that didn't. 88117e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee */ 88217e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee @GuardedBy("this") 88317e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee private boolean setAllowOnlyVpnForUids(boolean enforce, Collection<UidRange> ranges) { 88417e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee if (ranges.size() == 0) { 88517e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee return true; 88617e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee } 88717e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee final UidRange[] rangesArray = ranges.toArray(new UidRange[ranges.size()]); 88817e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee try { 88917e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee mNetd.setAllowOnlyVpnForUids(enforce, rangesArray); 89017e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee } catch (RemoteException | RuntimeException e) { 89117e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee Log.e(TAG, "Updating blocked=" + enforce 89217e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee + " for UIDs " + Arrays.toString(ranges.toArray()) + " failed", e); 89317e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee return false; 89417e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee } 89517e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee if (enforce) { 89617e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee mBlockedUsers.addAll(ranges); 89717e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee } else { 89817e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee mBlockedUsers.removeAll(ranges); 89917e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee } 90017e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee return true; 90117e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee } 90217e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee 90317e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee /** 904bf6ff2c025405a3af496fe558dfc4468a9b45cc8Chad Brubaker * Return the configuration of the currently running VPN. 905bf6ff2c025405a3af496fe558dfc4468a9b45cc8Chad Brubaker */ 906bf6ff2c025405a3af496fe558dfc4468a9b45cc8Chad Brubaker public VpnConfig getVpnConfig() { 907bf6ff2c025405a3af496fe558dfc4468a9b45cc8Chad Brubaker enforceControlPermission(); 908bf6ff2c025405a3af496fe558dfc4468a9b45cc8Chad Brubaker return mConfig; 909bf6ff2c025405a3af496fe558dfc4468a9b45cc8Chad Brubaker } 910bf6ff2c025405a3af496fe558dfc4468a9b45cc8Chad Brubaker 911899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey @Deprecated 912899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey public synchronized void interfaceStatusChanged(String iface, boolean up) { 913899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey try { 914899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey mObserver.interfaceStatusChanged(iface, up); 915899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } catch (RemoteException e) { 916899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey // ignored; target is local 917aa1727fe0cbb902c5f53a3fae601b4e15da0a2f4Chia-chi Yeh } 918ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 919ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 920899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey private INetworkManagementEventObserver mObserver = new BaseNetworkObserver() { 921899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey @Override 922899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey public void interfaceStatusChanged(String interfaze, boolean up) { 923899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey synchronized (Vpn.this) { 924899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey if (!up && mLegacyVpnRunner != null) { 925899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey mLegacyVpnRunner.check(interfaze); 926899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } 927199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh } 928ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 929ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 930899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey @Override 931899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey public void interfaceRemoved(String interfaze) { 932899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey synchronized (Vpn.this) { 933899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey if (interfaze.equals(mInterface) && jniCheck(interfaze) == 0) { 93490b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson mStatusIntent = null; 9356bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen mVpnUsers = null; 936c4c7231eb6d1efa9ecd7b693f8328a76a04e8bbbPaul Jensen mConfig = null; 937899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey mInterface = null; 938899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey if (mConnection != null) { 939899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey mContext.unbindService(mConnection); 940899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey mConnection = null; 9416bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen agentDisconnect(); 942899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } else if (mLegacyVpnRunner != null) { 943899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey mLegacyVpnRunner.exit(); 944899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey mLegacyVpnRunner = null; 945899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } 946899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } 947899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } 948899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } 949899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey }; 950db3c8678e5cbdfec011afaf25bde2091152c30adHaoyu Bai 951dadc857d9de364fded10d4f69eb82bc9cd35d4b7Chia-chi Yeh private void enforceControlPermission() { 952bc19c181c8c058c824e4fee907a05129e142c388Jeff Davidson mContext.enforceCallingPermission(Manifest.permission.CONTROL_VPN, "Unauthorized Caller"); 953dadc857d9de364fded10d4f69eb82bc9cd35d4b7Chia-chi Yeh } 954dadc857d9de364fded10d4f69eb82bc9cd35d4b7Chia-chi Yeh 955244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee private void enforceControlPermissionOrInternalCaller() { 956244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee // Require caller to be either an application with CONTROL_VPN permission or a process 957244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee // in the system server. 958244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee mContext.enforceCallingOrSelfPermission(Manifest.permission.CONTROL_VPN, 959244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee "Unauthorized Caller"); 960244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee } 961244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee 962199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh private class Connection implements ServiceConnection { 963199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh private IBinder mService; 964199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh 965199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh @Override 966199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh public void onServiceConnected(ComponentName name, IBinder service) { 967199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh mService = service; 968199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh } 969199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh 970199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh @Override 971199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh public void onServiceDisconnected(ComponentName name) { 972199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh mService = null; 973199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh } 974199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh } 975199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh 97690b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson private void prepareStatusIntent() { 97790b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson final long token = Binder.clearCallingIdentity(); 97890b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson try { 97990b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson mStatusIntent = VpnConfig.getIntentForStatusPanel(mContext); 98090b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson } finally { 98190b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson Binder.restoreCallingIdentity(token); 98290b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson } 98390b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson } 98490b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson 985f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandran public synchronized boolean addAddress(String address, int prefixLength) { 986c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran if (!isCallerEstablishedOwnerLocked()) { 987f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandran return false; 988f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandran } 989f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandran boolean success = jniAddAddress(mInterface, address, prefixLength); 990c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran mNetworkAgent.sendLinkProperties(makeLinkProperties()); 991f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandran return success; 992f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandran } 993f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandran 994f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandran public synchronized boolean removeAddress(String address, int prefixLength) { 995c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran if (!isCallerEstablishedOwnerLocked()) { 996f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandran return false; 997f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandran } 998f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandran boolean success = jniDelAddress(mInterface, address, prefixLength); 999c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran mNetworkAgent.sendLinkProperties(makeLinkProperties()); 1000f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandran return success; 1001f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandran } 1002f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandran 1003c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran public synchronized boolean setUnderlyingNetworks(Network[] networks) { 1004c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran if (!isCallerEstablishedOwnerLocked()) { 1005c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran return false; 1006c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran } 1007c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran if (networks == null) { 1008c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran mConfig.underlyingNetworks = null; 1009c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran } else { 1010c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran mConfig.underlyingNetworks = new Network[networks.length]; 1011c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran for (int i = 0; i < networks.length; ++i) { 1012c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran if (networks[i] == null) { 1013c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran mConfig.underlyingNetworks[i] = null; 1014c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran } else { 1015c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran mConfig.underlyingNetworks[i] = new Network(networks[i].netId); 1016c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran } 1017c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran } 1018c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran } 1019c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran return true; 1020c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran } 1021c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran 1022c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran public synchronized Network[] getUnderlyingNetworks() { 1023c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran if (!isRunningLocked()) { 1024c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran return null; 1025c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran } 1026c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran return mConfig.underlyingNetworks; 1027c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran } 1028c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran 1029f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong /** 1030f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong * This method should only be called by ConnectivityService. Because it doesn't 1031f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong * have enough data to fill VpnInfo.primaryUnderlyingIface field. 1032f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong */ 1033f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong public synchronized VpnInfo getVpnInfo() { 1034f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong if (!isRunningLocked()) { 1035f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong return null; 1036f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong } 1037f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong 1038f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong VpnInfo info = new VpnInfo(); 1039f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong info.ownerUid = mOwnerUID; 1040f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong info.vpnIface = mInterface; 1041f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong return info; 1042f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong } 1043f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong 1044c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran public synchronized boolean appliesToUid(int uid) { 1045c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran if (!isRunningLocked()) { 1046c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran return false; 1047c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran } 1048c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran for (UidRange uidRange : mVpnUsers) { 10494d03abcd49af490dba3850d341b955dd72f24959Robin Lee if (uidRange.contains(uid)) { 1050c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran return true; 1051c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran } 1052c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran } 1053c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran return false; 1054c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran } 1055c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran 105617e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee /** 105717e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * @return {@code true} if the set of users blocked whilst waiting for VPN to connect includes 105817e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * the UID {@param uid}, {@code false} otherwise. 105917e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * 106017e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * @see #mBlockedUsers 106117e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee */ 106217e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee public synchronized boolean isBlockingUid(int uid) { 106317e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee for (UidRange uidRange : mBlockedUsers) { 106417e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee if (uidRange.contains(uid)) { 106517e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee return true; 106617e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee } 106717e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee } 106817e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee return false; 106917e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee } 107017e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee 107197a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh private native int jniCreate(int mtu); 1072c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh private native String jniGetName(int tun); 107397a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh private native int jniSetAddresses(String interfaze, String addresses); 1074c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh private native void jniReset(String interfaze); 1075c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh private native int jniCheck(String interfaze); 1076f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandran private native boolean jniAddAddress(String interfaze, String address, int prefixLen); 1077f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandran private native boolean jniDelAddress(String interfaze, String address, int prefixLen); 107885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 107941fb98c8681cbe0040b8d4efc65d33717c3819f6Lorenzo Colitti private static RouteInfo findIPv4DefaultRoute(LinkProperties prop) { 108041fb98c8681cbe0040b8d4efc65d33717c3819f6Lorenzo Colitti for (RouteInfo route : prop.getAllRoutes()) { 108182f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey // Currently legacy VPN only works on IPv4. 108282f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey if (route.isDefaultRoute() && route.getGateway() instanceof Inet4Address) { 108341fb98c8681cbe0040b8d4efc65d33717c3819f6Lorenzo Colitti return route; 108482f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey } 108582f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey } 108682f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey 108741fb98c8681cbe0040b8d4efc65d33717c3819f6Lorenzo Colitti throw new IllegalStateException("Unable to find IPv4 default gateway"); 108882f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey } 108982f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey 109085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh /** 109182f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey * Start legacy VPN, controlling native daemons as needed. Creates a 109282f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey * secondary thread to perform connection work, returning quickly. 1093b21298a686b04d55ff97223dd317497845713f4bJeff Davidson * 1094b21298a686b04d55ff97223dd317497845713f4bJeff Davidson * Should only be called to respond to Binder requests as this enforces caller permission. Use 1095b21298a686b04d55ff97223dd317497845713f4bJeff Davidson * {@link #startLegacyVpnPrivileged(VpnProfile, KeyStore, LinkProperties)} to skip the 1096b21298a686b04d55ff97223dd317497845713f4bJeff Davidson * permission check only when the caller is trusted (or the call is initiated by the system). 109785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh */ 109882f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey public void startLegacyVpn(VpnProfile profile, KeyStore keyStore, LinkProperties egress) { 10995a6bdc46e2fdc8cfd930396773dd89efd19fa1f1Robert Greenwalt enforceControlPermission(); 1100b21298a686b04d55ff97223dd317497845713f4bJeff Davidson long token = Binder.clearCallingIdentity(); 1101b21298a686b04d55ff97223dd317497845713f4bJeff Davidson try { 1102b21298a686b04d55ff97223dd317497845713f4bJeff Davidson startLegacyVpnPrivileged(profile, keyStore, egress); 1103b21298a686b04d55ff97223dd317497845713f4bJeff Davidson } finally { 1104b21298a686b04d55ff97223dd317497845713f4bJeff Davidson Binder.restoreCallingIdentity(token); 1105b21298a686b04d55ff97223dd317497845713f4bJeff Davidson } 1106b21298a686b04d55ff97223dd317497845713f4bJeff Davidson } 1107b21298a686b04d55ff97223dd317497845713f4bJeff Davidson 1108b21298a686b04d55ff97223dd317497845713f4bJeff Davidson /** 1109b21298a686b04d55ff97223dd317497845713f4bJeff Davidson * Like {@link #startLegacyVpn(VpnProfile, KeyStore, LinkProperties)}, but does not check 1110b21298a686b04d55ff97223dd317497845713f4bJeff Davidson * permissions under the assumption that the caller is the system. 1111b21298a686b04d55ff97223dd317497845713f4bJeff Davidson * 1112b21298a686b04d55ff97223dd317497845713f4bJeff Davidson * Callers are responsible for checking permissions if needed. 1113b21298a686b04d55ff97223dd317497845713f4bJeff Davidson */ 1114b21298a686b04d55ff97223dd317497845713f4bJeff Davidson public void startLegacyVpnPrivileged(VpnProfile profile, KeyStore keyStore, 1115b21298a686b04d55ff97223dd317497845713f4bJeff Davidson LinkProperties egress) { 1116f5116d01b20f21ba32cd9eaa3412daf97f41c623Julia Reynolds UserManager mgr = UserManager.get(mContext); 11170784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen UserInfo user = mgr.getUserInfo(mUserHandle); 111895778ffc58979d19ff9f4aaed396a6eca49cf698Nicolas Prevot if (user.isRestricted() || mgr.hasUserRestriction(UserManager.DISALLOW_CONFIG_VPN, 111995778ffc58979d19ff9f4aaed396a6eca49cf698Nicolas Prevot new UserHandle(mUserHandle))) { 1120f5116d01b20f21ba32cd9eaa3412daf97f41c623Julia Reynolds throw new SecurityException("Restricted users cannot establish VPNs"); 1121f5116d01b20f21ba32cd9eaa3412daf97f41c623Julia Reynolds } 112282f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey 112341fb98c8681cbe0040b8d4efc65d33717c3819f6Lorenzo Colitti final RouteInfo ipv4DefaultRoute = findIPv4DefaultRoute(egress); 112441fb98c8681cbe0040b8d4efc65d33717c3819f6Lorenzo Colitti final String gateway = ipv4DefaultRoute.getGateway().getHostAddress(); 112541fb98c8681cbe0040b8d4efc65d33717c3819f6Lorenzo Colitti final String iface = ipv4DefaultRoute.getInterface(); 112682f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey 112782f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey // Load certificates. 112882f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey String privateKey = ""; 112982f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey String userCert = ""; 113082f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey String caCert = ""; 113182f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey String serverCert = ""; 113282f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey if (!profile.ipsecUserCert.isEmpty()) { 113382f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey privateKey = Credentials.USER_PRIVATE_KEY + profile.ipsecUserCert; 113482f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey byte[] value = keyStore.get(Credentials.USER_CERTIFICATE + profile.ipsecUserCert); 1135d396a448b2e36e29598c954b64bfddef73f3fae0Elliott Hughes userCert = (value == null) ? null : new String(value, StandardCharsets.UTF_8); 113682f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey } 113782f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey if (!profile.ipsecCaCert.isEmpty()) { 113882f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey byte[] value = keyStore.get(Credentials.CA_CERTIFICATE + profile.ipsecCaCert); 1139d396a448b2e36e29598c954b64bfddef73f3fae0Elliott Hughes caCert = (value == null) ? null : new String(value, StandardCharsets.UTF_8); 114082f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey } 114182f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey if (!profile.ipsecServerCert.isEmpty()) { 114282f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey byte[] value = keyStore.get(Credentials.USER_CERTIFICATE + profile.ipsecServerCert); 1143d396a448b2e36e29598c954b64bfddef73f3fae0Elliott Hughes serverCert = (value == null) ? null : new String(value, StandardCharsets.UTF_8); 114482f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey } 114582f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey if (privateKey == null || userCert == null || caCert == null || serverCert == null) { 114682f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey throw new IllegalStateException("Cannot load credentials"); 114782f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey } 114882f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey 114982f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey // Prepare arguments for racoon. 115082f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey String[] racoon = null; 115182f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey switch (profile.type) { 115282f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey case VpnProfile.TYPE_L2TP_IPSEC_PSK: 115382f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey racoon = new String[] { 115482f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey iface, profile.server, "udppsk", profile.ipsecIdentifier, 115582f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey profile.ipsecSecret, "1701", 115682f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey }; 115782f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey break; 115882f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey case VpnProfile.TYPE_L2TP_IPSEC_RSA: 115982f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey racoon = new String[] { 116082f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey iface, profile.server, "udprsa", privateKey, userCert, 116182f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey caCert, serverCert, "1701", 116282f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey }; 116382f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey break; 116482f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey case VpnProfile.TYPE_IPSEC_XAUTH_PSK: 116582f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey racoon = new String[] { 116682f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey iface, profile.server, "xauthpsk", profile.ipsecIdentifier, 116782f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey profile.ipsecSecret, profile.username, profile.password, "", gateway, 116882f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey }; 116982f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey break; 117082f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey case VpnProfile.TYPE_IPSEC_XAUTH_RSA: 117182f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey racoon = new String[] { 117282f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey iface, profile.server, "xauthrsa", privateKey, userCert, 117382f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey caCert, serverCert, profile.username, profile.password, "", gateway, 117482f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey }; 117582f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey break; 117682f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey case VpnProfile.TYPE_IPSEC_HYBRID_RSA: 117782f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey racoon = new String[] { 117882f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey iface, profile.server, "hybridrsa", 117982f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey caCert, serverCert, profile.username, profile.password, "", gateway, 118082f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey }; 118182f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey break; 118282f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey } 118382f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey 118482f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey // Prepare arguments for mtpd. 118582f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey String[] mtpd = null; 118682f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey switch (profile.type) { 118782f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey case VpnProfile.TYPE_PPTP: 118882f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey mtpd = new String[] { 118982f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey iface, "pptp", profile.server, "1723", 119082f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey "name", profile.username, "password", profile.password, 119182f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey "linkname", "vpn", "refuse-eap", "nodefaultroute", 119282f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey "usepeerdns", "idle", "1800", "mtu", "1400", "mru", "1400", 119382f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey (profile.mppe ? "+mppe" : "nomppe"), 119482f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey }; 119582f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey break; 119682f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey case VpnProfile.TYPE_L2TP_IPSEC_PSK: 119782f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey case VpnProfile.TYPE_L2TP_IPSEC_RSA: 119882f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey mtpd = new String[] { 119982f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey iface, "l2tp", profile.server, "1701", profile.l2tpSecret, 120082f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey "name", profile.username, "password", profile.password, 120182f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey "linkname", "vpn", "refuse-eap", "nodefaultroute", 120282f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey "usepeerdns", "idle", "1800", "mtu", "1400", "mru", "1400", 120382f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey }; 120482f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey break; 120582f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey } 1206899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey 120782f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey VpnConfig config = new VpnConfig(); 1208899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey config.legacy = true; 120982f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey config.user = profile.key; 121082f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey config.interfaze = iface; 121182f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey config.session = profile.name; 12124ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker 12134ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker config.addLegacyRoutes(profile.routes); 121482f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey if (!profile.dnsServers.isEmpty()) { 121582f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey config.dnsServers = Arrays.asList(profile.dnsServers.split(" +")); 121682f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey } 121782f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey if (!profile.searchDomains.isEmpty()) { 121882f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey config.searchDomains = Arrays.asList(profile.searchDomains.split(" +")); 121982f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey } 122082f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey startLegacyVpn(config, racoon, mtpd); 122182f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey } 122282f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey 122382f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey private synchronized void startLegacyVpn(VpnConfig config, String[] racoon, String[] mtpd) { 1224b21298a686b04d55ff97223dd317497845713f4bJeff Davidson stopLegacyVpnPrivileged(); 1225899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey 1226b21298a686b04d55ff97223dd317497845713f4bJeff Davidson // Prepare for the new request. 1227b21298a686b04d55ff97223dd317497845713f4bJeff Davidson prepareInternal(VpnConfig.LEGACY_VPN); 1228899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey updateState(DetailedState.CONNECTING, "startLegacyVpn"); 122985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 12302e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh // Start a new LegacyVpnRunner and we are done! 1231100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh mLegacyVpnRunner = new LegacyVpnRunner(config, racoon, mtpd); 1232100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh mLegacyVpnRunner.start(); 123385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 123485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 1235b21298a686b04d55ff97223dd317497845713f4bJeff Davidson /** Stop legacy VPN. Permissions must be checked by callers. */ 1236b21298a686b04d55ff97223dd317497845713f4bJeff Davidson public synchronized void stopLegacyVpnPrivileged() { 1237899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey if (mLegacyVpnRunner != null) { 1238899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey mLegacyVpnRunner.exit(); 1239899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey mLegacyVpnRunner = null; 1240899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey 1241899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey synchronized (LegacyVpnRunner.TAG) { 1242899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey // wait for old thread to completely finish before spinning up 1243899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey // new instance, otherwise state updates can be out of order. 1244899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } 1245899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } 1246899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } 1247899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey 124885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh /** 12492e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh * Return the information of the current ongoing legacy VPN. 12502e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh */ 12512e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh public synchronized LegacyVpnInfo getLegacyVpnInfo() { 1252dadc857d9de364fded10d4f69eb82bc9cd35d4b7Chia-chi Yeh // Check if the caller is authorized. 1253dadc857d9de364fded10d4f69eb82bc9cd35d4b7Chia-chi Yeh enforceControlPermission(); 125408bbca040fa921b99493cd9967453ed90b1b710asj.cha return getLegacyVpnInfoPrivileged(); 125508bbca040fa921b99493cd9967453ed90b1b710asj.cha } 125608bbca040fa921b99493cd9967453ed90b1b710asj.cha 125708bbca040fa921b99493cd9967453ed90b1b710asj.cha /** 125808bbca040fa921b99493cd9967453ed90b1b710asj.cha * Return the information of the current ongoing legacy VPN. 125908bbca040fa921b99493cd9967453ed90b1b710asj.cha * Callers are responsible for checking permissions if needed. 126008bbca040fa921b99493cd9967453ed90b1b710asj.cha */ 126108bbca040fa921b99493cd9967453ed90b1b710asj.cha public synchronized LegacyVpnInfo getLegacyVpnInfoPrivileged() { 1262899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey if (mLegacyVpnRunner == null) return null; 1263899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey 1264899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey final LegacyVpnInfo info = new LegacyVpnInfo(); 1265c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker info.key = mConfig.user; 1266899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey info.state = LegacyVpnInfo.stateFromNetworkInfo(mNetworkInfo); 126790b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson if (mNetworkInfo.isConnected()) { 126890b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson info.intent = mStatusIntent; 126990b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson } 1270899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey return info; 12712e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh } 12722e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh 127369ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey public VpnConfig getLegacyVpnConfig() { 127469ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey if (mLegacyVpnRunner != null) { 1275c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker return mConfig; 127669ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey } else { 127769ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey return null; 127869ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey } 127969ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey } 128069ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 12812e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh /** 128285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh * Bringing up a VPN connection takes time, and that is all this thread 128385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh * does. Here we have plenty of time. The only thing we need to take 128485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh * care of is responding to interruptions as soon as possible. Otherwise 128585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh * requests will be piled up. This can be done in a Handler as a state 128685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh * machine, but it is much easier to read in the current form. 128785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh */ 128885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh private class LegacyVpnRunner extends Thread { 128985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh private static final String TAG = "LegacyVpnRunner"; 129085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 12911f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh private final String[] mDaemons; 129285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh private final String[][] mArguments; 12935317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh private final LocalSocket[] mSockets; 129453c04bdd35a85aa65d1a1f18ca2ee34970e2c2d0Robert Greenwalt private final String mOuterInterface; 12951b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt private final AtomicInteger mOuterConnection = 12961b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt new AtomicInteger(ConnectivityManager.TYPE_NONE); 12972e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh 129885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh private long mTimer = -1; 129985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 13001b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt /** 13011b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt * Watch for the outer connection (passing in the constructor) going away. 13021b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt */ 13031b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 13041b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt @Override 13051b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt public void onReceive(Context context, Intent intent) { 130657666934b4a161cc2fb77eef15d0b894aaf8f173Jeff Sharkey if (!mEnableTeardown) return; 130757666934b4a161cc2fb77eef15d0b894aaf8f173Jeff Sharkey 13081b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) { 13091b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt if (intent.getIntExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, 13101b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt ConnectivityManager.TYPE_NONE) == mOuterConnection.get()) { 13111b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt NetworkInfo info = (NetworkInfo)intent.getExtra( 13121b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt ConnectivityManager.EXTRA_NETWORK_INFO); 13131b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt if (info != null && !info.isConnectedOrConnecting()) { 13141b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt try { 13151b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt mObserver.interfaceStatusChanged(mOuterInterface, false); 13161b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt } catch (RemoteException e) {} 13171b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt } 13181b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt } 13191b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt } 13201b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt } 13211b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt }; 13221b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt 132341d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh public LegacyVpnRunner(VpnConfig config, String[] racoon, String[] mtpd) { 132485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh super(TAG); 132541d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh mConfig = config; 132641d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh mDaemons = new String[] {"racoon", "mtpd"}; 1327899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey // TODO: clear arguments from memory once launched 132841d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh mArguments = new String[][] {racoon, mtpd}; 13295317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh mSockets = new LocalSocket[mDaemons.length]; 133053c04bdd35a85aa65d1a1f18ca2ee34970e2c2d0Robert Greenwalt 133153c04bdd35a85aa65d1a1f18ca2ee34970e2c2d0Robert Greenwalt // This is the interface which VPN is running on, 133253c04bdd35a85aa65d1a1f18ca2ee34970e2c2d0Robert Greenwalt // mConfig.interfaze will change to point to OUR 133353c04bdd35a85aa65d1a1f18ca2ee34970e2c2d0Robert Greenwalt // internal interface soon. TODO - add inner/outer to mconfig 13341b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt // TODO - we have a race - if the outer iface goes away/disconnects before we hit this 13354ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker // we will leave the VPN up. We should check that it's still there/connected after 13361b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt // registering 133753c04bdd35a85aa65d1a1f18ca2ee34970e2c2d0Robert Greenwalt mOuterInterface = mConfig.interfaze; 13381b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt 1339e75b9e355500b7c6a05e4d6ec54ef48835707caaPaul Jensen if (!TextUtils.isEmpty(mOuterInterface)) { 1340e75b9e355500b7c6a05e4d6ec54ef48835707caaPaul Jensen final ConnectivityManager cm = ConnectivityManager.from(mContext); 1341e75b9e355500b7c6a05e4d6ec54ef48835707caaPaul Jensen for (Network network : cm.getAllNetworks()) { 1342e75b9e355500b7c6a05e4d6ec54ef48835707caaPaul Jensen final LinkProperties lp = cm.getLinkProperties(network); 13431b60d11b8f54f1ade45b80668601bc955041cf4fLorenzo Colitti if (lp != null && lp.getAllInterfaceNames().contains(mOuterInterface)) { 1344e75b9e355500b7c6a05e4d6ec54ef48835707caaPaul Jensen final NetworkInfo networkInfo = cm.getNetworkInfo(network); 1345e75b9e355500b7c6a05e4d6ec54ef48835707caaPaul Jensen if (networkInfo != null) mOuterConnection.set(networkInfo.getType()); 1346e75b9e355500b7c6a05e4d6ec54ef48835707caaPaul Jensen } 1347e75b9e355500b7c6a05e4d6ec54ef48835707caaPaul Jensen } 13481b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt } 13491b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt 13501b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt IntentFilter filter = new IntentFilter(); 13511b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); 13521b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt mContext.registerReceiver(mBroadcastReceiver, filter); 135341d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh } 135441d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh 1355aa1727fe0cbb902c5f53a3fae601b4e15da0a2f4Chia-chi Yeh public void check(String interfaze) { 135653c04bdd35a85aa65d1a1f18ca2ee34970e2c2d0Robert Greenwalt if (interfaze.equals(mOuterInterface)) { 1357aa1727fe0cbb902c5f53a3fae601b4e15da0a2f4Chia-chi Yeh Log.i(TAG, "Legacy VPN is going down with " + interfaze); 1358aa1727fe0cbb902c5f53a3fae601b4e15da0a2f4Chia-chi Yeh exit(); 1359aa1727fe0cbb902c5f53a3fae601b4e15da0a2f4Chia-chi Yeh } 1360aa1727fe0cbb902c5f53a3fae601b4e15da0a2f4Chia-chi Yeh } 1361aa1727fe0cbb902c5f53a3fae601b4e15da0a2f4Chia-chi Yeh 136241d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh public void exit() { 13635317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh // We assume that everything is reset after stopping the daemons. 136497a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh interrupt(); 13655317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh for (LocalSocket socket : mSockets) { 1366065b299df4159602327977dd007cb2cd6b64ab20Jeff Sharkey IoUtils.closeQuietly(socket); 136741d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh } 13686bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen agentDisconnect(); 13691b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt try { 13701b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt mContext.unregisterReceiver(mBroadcastReceiver); 13711b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt } catch (IllegalArgumentException e) {} 13722e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh } 13732e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh 137485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh @Override 137585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh public void run() { 137685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Wait for the previous thread since it has been interrupted. 13772e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh Log.v(TAG, "Waiting"); 137885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh synchronized (TAG) { 13792e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh Log.v(TAG, "Executing"); 138085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh execute(); 1381899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey monitorDaemons(); 138285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 138385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 138485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 138585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh private void checkpoint(boolean yield) throws InterruptedException { 138685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh long now = SystemClock.elapsedRealtime(); 138785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh if (mTimer == -1) { 138885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh mTimer = now; 138985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh Thread.sleep(1); 13907ef8611b5f3a893a46c7b9e22bdd8ab252e373ffChia-chi Yeh } else if (now - mTimer <= 60000) { 139185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh Thread.sleep(yield ? 200 : 1); 139285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } else { 1393899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey updateState(DetailedState.FAILED, "checkpoint"); 139497a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh throw new IllegalStateException("Time is up"); 139585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 139685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 139785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 139885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh private void execute() { 139985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Catch all exceptions so we can clean up few things. 1400899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey boolean initFinished = false; 140185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh try { 140285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Initialize the timer. 140385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh checkpoint(false); 140485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 14051f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh // Wait for the daemons to stop. 14061f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh for (String daemon : mDaemons) { 1407088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey while (!SystemService.isStopped(daemon)) { 140885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh checkpoint(true); 140985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 141085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 141185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 141297a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh // Clear the previous state. 141397a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh File state = new File("/data/misc/vpn/state"); 141497a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh state.delete(); 141597a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh if (state.exists()) { 141697a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh throw new IllegalStateException("Cannot delete the state"); 141785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 1418c1872732922214de80f790e14865e41dd1b98203Chia-chi Yeh new File("/data/misc/vpn/abort").delete(); 1419899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey initFinished = true; 142085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 1421e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh // Check if we need to restart any of the daemons. 142285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh boolean restart = false; 142385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh for (String[] arguments : mArguments) { 142485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh restart = restart || (arguments != null); 142585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 142685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh if (!restart) { 14276bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen agentDisconnect(); 142885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh return; 142985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 1430899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey updateState(DetailedState.CONNECTING, "execute"); 143185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 14321f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh // Start the daemon with arguments. 14331f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh for (int i = 0; i < mDaemons.length; ++i) { 143485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh String[] arguments = mArguments[i]; 143585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh if (arguments == null) { 143685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh continue; 143785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 143885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 14391f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh // Start the daemon. 14401f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh String daemon = mDaemons[i]; 1441088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey SystemService.start(daemon); 144285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 14431f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh // Wait for the daemon to start. 1444088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey while (!SystemService.isRunning(daemon)) { 144585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh checkpoint(true); 144685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 144785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 144885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Create the control socket. 14495317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh mSockets[i] = new LocalSocket(); 145085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh LocalSocketAddress address = new LocalSocketAddress( 14511f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh daemon, LocalSocketAddress.Namespace.RESERVED); 145285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 145385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Wait for the socket to connect. 145485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh while (true) { 145585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh try { 14565317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh mSockets[i].connect(address); 145785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh break; 145885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } catch (Exception e) { 145985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // ignore 146085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 146185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh checkpoint(true); 146285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 14635317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh mSockets[i].setSoTimeout(500); 146485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 146585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Send over the arguments. 14665317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh OutputStream out = mSockets[i].getOutputStream(); 146785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh for (String argument : arguments) { 1468d396a448b2e36e29598c954b64bfddef73f3fae0Elliott Hughes byte[] bytes = argument.getBytes(StandardCharsets.UTF_8); 14695317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh if (bytes.length >= 0xFFFF) { 147097a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh throw new IllegalArgumentException("Argument is too large"); 147185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 14721f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh out.write(bytes.length >> 8); 14731f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh out.write(bytes.length); 14741f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh out.write(bytes); 147585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh checkpoint(false); 147685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 14775317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh out.write(0xFF); 14785317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh out.write(0xFF); 14791f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh out.flush(); 148097a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh 148197a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh // Wait for End-of-File. 14825317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh InputStream in = mSockets[i].getInputStream(); 148397a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh while (true) { 148497a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh try { 148597a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh if (in.read() == -1) { 148697a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh break; 148797a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh } 148897a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh } catch (Exception e) { 148997a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh // ignore 149097a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh } 149197a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh checkpoint(true); 149297a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh } 149385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 149485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 149597a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh // Wait for the daemons to create the new state. 149697a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh while (!state.exists()) { 14971f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh // Check if a running daemon is dead. 14981f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh for (int i = 0; i < mDaemons.length; ++i) { 14991f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh String daemon = mDaemons[i]; 1500088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey if (mArguments[i] != null && !SystemService.isRunning(daemon)) { 15012e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh throw new IllegalStateException(daemon + " is dead"); 150285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 150385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 150485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh checkpoint(true); 150585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 150685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 150797a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh // Now we are connected. Read and parse the new state. 1508c1bac3a6e240c1c9a14a7b515f585977fb908930Chia-chi Yeh String[] parameters = FileUtils.readTextFile(state, 0, null).split("\n", -1); 15095026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti if (parameters.length != 7) { 151097a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh throw new IllegalStateException("Cannot parse the state"); 151197a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh } 151297a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh 151397a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh // Set the interface and the addresses in the config. 151497a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh mConfig.interfaze = parameters[0].trim(); 151585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 15164ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker mConfig.addLegacyAddresses(parameters[1]); 151797a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh // Set the routes if they are not set in the config. 151897a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh if (mConfig.routes == null || mConfig.routes.isEmpty()) { 15194ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker mConfig.addLegacyRoutes(parameters[2]); 152097a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh } 152197a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh 152297a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh // Set the DNS servers if they are not set in the config. 152341d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh if (mConfig.dnsServers == null || mConfig.dnsServers.size() == 0) { 152497a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh String dnsServers = parameters[3].trim(); 152541d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh if (!dnsServers.isEmpty()) { 152641d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh mConfig.dnsServers = Arrays.asList(dnsServers.split(" ")); 152741d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh } 152841d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh } 152941d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh 153097a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh // Set the search domains if they are not set in the config. 153197a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh if (mConfig.searchDomains == null || mConfig.searchDomains.size() == 0) { 153297a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh String searchDomains = parameters[4].trim(); 153397a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh if (!searchDomains.isEmpty()) { 153497a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh mConfig.searchDomains = Arrays.asList(searchDomains.split(" ")); 153597a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh } 153697a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh } 153797a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh 15385026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti // Add a throw route for the VPN server endpoint, if one was specified. 15395026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti String endpoint = parameters[5]; 15405026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti if (!endpoint.isEmpty()) { 15415026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti try { 15425026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti InetAddress addr = InetAddress.parseNumericAddress(endpoint); 15435026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti if (addr instanceof Inet4Address) { 15445026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti mConfig.routes.add(new RouteInfo(new IpPrefix(addr, 32), RTN_THROW)); 15455026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti } else if (addr instanceof Inet6Address) { 15465026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti mConfig.routes.add(new RouteInfo(new IpPrefix(addr, 128), RTN_THROW)); 15475026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti } else { 15485026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti Log.e(TAG, "Unknown IP address family for VPN endpoint: " + endpoint); 15495026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti } 15505026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti } catch (IllegalArgumentException e) { 15515026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti Log.e(TAG, "Exception constructing throw route to " + endpoint + ": " + e); 15525026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti } 15535026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti } 15545026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti 155597a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh // Here is the last step and it must be done synchronously. 155641d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh synchronized (Vpn.this) { 15572b862e5e75ad419f17a4cea185b9349e0da70e7bVinit Deshapnde // Set the start time 15582b862e5e75ad419f17a4cea185b9349e0da70e7bVinit Deshapnde mConfig.startTime = SystemClock.elapsedRealtime(); 15592b862e5e75ad419f17a4cea185b9349e0da70e7bVinit Deshapnde 156041d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh // Check if the thread is interrupted while we are waiting. 156141d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh checkpoint(false); 156241d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh 1563e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh // Check if the interface is gone while we are waiting. 1564c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh if (jniCheck(mConfig.interfaze) == 0) { 156534e7813e962de99df9813014678ef5901227c5f1Chia-chi Yeh throw new IllegalStateException(mConfig.interfaze + " is gone"); 156641d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh } 1567e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh 1568e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh // Now INetworkManagementEventObserver is watching our back. 1569c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh mInterface = mConfig.interfaze; 15704d03abcd49af490dba3850d341b955dd72f24959Robin Lee prepareStatusIntent(); 15716bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen 15726bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen agentConnect(); 15732e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh 15742e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh Log.i(TAG, "Connected!"); 157541d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh } 157685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } catch (Exception e) { 15772e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh Log.i(TAG, "Aborting", e); 1578438406092ed71c658bf5a4e6ae2e7282fc4fab4dLorenzo Colitti updateState(DetailedState.FAILED, e.getMessage()); 1579e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh exit(); 15802e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh } finally { 15815317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh // Kill the daemons if they fail to stop. 1582899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey if (!initFinished) { 15835317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh for (String daemon : mDaemons) { 1584088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey SystemService.stop(daemon); 15855317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh } 15865317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh } 15875317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh 15882e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh // Do not leave an unstable state. 1589899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey if (!initFinished || mNetworkInfo.getDetailedState() == DetailedState.CONNECTING) { 15906bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen agentDisconnect(); 15912e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh } 159285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 159385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 1594899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey 1595899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey /** 1596899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey * Monitor the daemons we started, moving to disconnected state if the 1597899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey * underlying services fail. 1598899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey */ 1599899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey private void monitorDaemons() { 1600899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey if (!mNetworkInfo.isConnected()) { 1601899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey return; 1602899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } 1603899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey 1604899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey try { 1605899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey while (true) { 1606899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey Thread.sleep(2000); 1607899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey for (int i = 0; i < mDaemons.length; i++) { 1608899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey if (mArguments[i] != null && SystemService.isStopped(mDaemons[i])) { 1609899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey return; 1610899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } 1611899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } 1612899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } 1613899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } catch (InterruptedException e) { 1614899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey Log.d(TAG, "interrupted during monitorDaemons(); stopping services"); 1615899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } finally { 1616899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey for (String daemon : mDaemons) { 1617899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey SystemService.stop(daemon); 1618899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } 1619899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey 16206bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen agentDisconnect(); 1621899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } 1622899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } 162385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 1624ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh} 1625