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; 301a405fe300950d6ceae2166fd074b596d8110dbeTony Makimport android.app.Notification; 311a405fe300950d6ceae2166fd074b596d8110dbeTony Makimport android.app.NotificationManager; 3290b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidsonimport android.app.PendingIntent; 331b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwaltimport android.content.BroadcastReceiver; 34199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yehimport android.content.ComponentName; 35812800cb92090db31f609b907c4458ba76cf7f42Robin Leeimport android.content.ContentResolver; 36ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.content.Context; 37ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.content.Intent; 381b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwaltimport android.content.IntentFilter; 39199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yehimport android.content.ServiceConnection; 40ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.content.pm.PackageManager; 416bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensenimport android.content.pm.PackageManager.NameNotFoundException; 42199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yehimport android.content.pm.ResolveInfo; 43c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubakerimport android.content.pm.UserInfo; 44899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkeyimport android.net.ConnectivityManager; 45ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.net.INetworkManagementEventObserver; 465026279ce45ae78126046607a2634dc9dae93199Lorenzo Colittiimport android.net.IpPrefix; 474ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubakerimport android.net.LinkAddress; 4882f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkeyimport android.net.LinkProperties; 4985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yehimport android.net.LocalSocket; 5085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yehimport android.net.LocalSocketAddress; 51c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandranimport android.net.Network; 526bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensenimport android.net.NetworkAgent; 536bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensenimport android.net.NetworkCapabilities; 54899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkeyimport android.net.NetworkInfo; 556bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensenimport android.net.NetworkInfo.DetailedState; 568cd33ed84e94036a5e1201485af7603dc6fb0d9bSreeram Ramachandranimport android.net.NetworkMisc; 5782f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkeyimport android.net.RouteInfo; 586bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensenimport android.net.UidRange; 59812800cb92090db31f609b907c4458ba76cf7f42Robin Leeimport android.net.Uri; 60ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.os.Binder; 61c1bac3a6e240c1c9a14a7b515f585977fb908930Chia-chi Yehimport android.os.FileUtils; 62199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yehimport android.os.IBinder; 63899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkeyimport android.os.INetworkManagementService; 646bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensenimport android.os.Looper; 65199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yehimport android.os.Parcel; 66ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.os.ParcelFileDescriptor; 67812800cb92090db31f609b907c4458ba76cf7f42Robin Leeimport android.os.PatternMatcher; 6885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yehimport android.os.Process; 69899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkeyimport android.os.RemoteException; 7085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yehimport android.os.SystemClock; 71088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkeyimport android.os.SystemService; 7250cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackbornimport android.os.UserHandle; 73c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubakerimport android.os.UserManager; 74812800cb92090db31f609b907c4458ba76cf7f42Robin Leeimport android.provider.Settings; 7582f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkeyimport android.security.Credentials; 7682f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkeyimport android.security.KeyStore; 77e75b9e355500b7c6a05e4d6ec54ef48835707caaPaul Jensenimport android.text.TextUtils; 784d03abcd49af490dba3850d341b955dd72f24959Robin Leeimport android.util.ArraySet; 79ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.util.Log; 80ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 811a405fe300950d6ceae2166fd074b596d8110dbeTony Makimport com.android.internal.R; 82c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubakerimport com.android.internal.annotations.GuardedBy; 834d03abcd49af490dba3850d341b955dd72f24959Robin Leeimport com.android.internal.annotations.VisibleForTesting; 84282cfefea0fbbd299839e353e6d30affdcd4a55cChris Wrenimport com.android.internal.messages.nano.SystemMessageProto.SystemMessage; 852e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yehimport com.android.internal.net.LegacyVpnInfo; 8604ba25c418bc4538e9dc0f047cfb9608d358f679Chia-chi Yehimport com.android.internal.net.VpnConfig; 87f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tongimport com.android.internal.net.VpnInfo; 8882f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkeyimport com.android.internal.net.VpnProfile; 89af759c52ce01fe6b5144957e38da956af01a217bGeoffrey Pitschimport com.android.internal.notification.SystemNotificationChannels; 90e0be7e859b37438ec88780979e373821054a11efChristopher Tateimport com.android.server.DeviceIdleController; 91e0be7e859b37438ec88780979e373821054a11efChristopher Tateimport com.android.server.LocalServices; 92899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkeyimport com.android.server.net.BaseNetworkObserver; 93ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 9405542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidsonimport libcore.io.IoUtils; 9505542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson 9697a61565ea95472e65899070e64853f8c147bb11Chia-chi Yehimport java.io.File; 976bbf39cf6b81222f32d2b66b8fa85d562e0ad71cJeff Davidsonimport java.io.IOException; 9897a61565ea95472e65899070e64853f8c147bb11Chia-chi Yehimport java.io.InputStream; 9985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yehimport java.io.OutputStream; 10082f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkeyimport java.net.Inet4Address; 101f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandranimport java.net.Inet6Address; 102f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandranimport java.net.InetAddress; 103d396a448b2e36e29598c954b64bfddef73f3fae0Elliott Hughesimport java.nio.charset.StandardCharsets; 1046bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensenimport java.util.ArrayList; 10541d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yehimport java.util.Arrays; 1064d03abcd49af490dba3850d341b955dd72f24959Robin Leeimport java.util.Collection; 1074d03abcd49af490dba3850d341b955dd72f24959Robin Leeimport java.util.Collections; 1086bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensenimport java.util.List; 1094d03abcd49af490dba3850d341b955dd72f24959Robin Leeimport java.util.Set; 1100784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensenimport java.util.SortedSet; 1110784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensenimport java.util.TreeSet; 1121b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwaltimport java.util.concurrent.atomic.AtomicInteger; 11385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 114ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh/** 115ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * @hide 116ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh */ 1176bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensenpublic class Vpn { 1186bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen private static final String NETWORKTYPE = "VPN"; 119899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey private static final String TAG = "Vpn"; 120899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey private static final boolean LOGD = true; 1216bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen 122e0be7e859b37438ec88780979e373821054a11efChristopher Tate // Length of time (in milliseconds) that an app hosting an always-on VPN is placed on 123e0be7e859b37438ec88780979e373821054a11efChristopher Tate // the device idle whitelist during service launch and VPN bootstrap. 124e0be7e859b37438ec88780979e373821054a11efChristopher Tate private static final long VPN_LAUNCH_IDLE_WHITELIST_DURATION = 60 * 1000; 125e0be7e859b37438ec88780979e373821054a11efChristopher Tate 126899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey // TODO: create separate trackers for each unique VPN to support 127899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey // automated reconnection 128199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh 1296bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen private Context mContext; 1306bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen private NetworkInfo mNetworkInfo; 1316bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen private String mPackage; 1326bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen private int mOwnerUID; 133c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh private String mInterface; 134199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh private Connection mConnection; 13585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh private LegacyVpnRunner mLegacyVpnRunner; 13690b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson private PendingIntent mStatusIntent; 13757666934b4a161cc2fb77eef15d0b894aaf8f173Jeff Sharkey private volatile boolean mEnableTeardown = true; 1386bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen private final INetworkManagementService mNetd; 139c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker private VpnConfig mConfig; 1406bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen private NetworkAgent mNetworkAgent; 1416bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen private final Looper mLooper; 1426bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen private final NetworkCapabilities mNetworkCapabilities; 143c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker 1444d03abcd49af490dba3850d341b955dd72f24959Robin Lee /** 14517e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * Whether to keep the connection active after rebooting, or upgrading or reinstalling. This 14617e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * only applies to {@link VpnService} connections. 14717e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee */ 14817e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee private boolean mAlwaysOn = false; 14917e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee 15017e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee /** 15117e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * Whether to disable traffic outside of this VPN even when the VPN is not connected. System 15217e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * apps can still bypass by choosing explicit networks. Has no effect if {@link mAlwaysOn} is 15317e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * not set. 15417e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee */ 15517e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee private boolean mLockdown = false; 15617e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee 15717e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee /** 1584d03abcd49af490dba3850d341b955dd72f24959Robin Lee * List of UIDs that are set to use this VPN by default. Normally, every UID in the user is 1594d03abcd49af490dba3850d341b955dd72f24959Robin Lee * added to this set but that can be changed by adding allowed or disallowed applications. It 1604d03abcd49af490dba3850d341b955dd72f24959Robin Lee * is non-null iff the VPN is connected. 1614d03abcd49af490dba3850d341b955dd72f24959Robin Lee * 1624d03abcd49af490dba3850d341b955dd72f24959Robin Lee * Unless the VPN has set allowBypass=true, these UIDs are forced into the VPN. 1634d03abcd49af490dba3850d341b955dd72f24959Robin Lee * 1644d03abcd49af490dba3850d341b955dd72f24959Robin Lee * @see VpnService.Builder#addAllowedApplication(String) 1654d03abcd49af490dba3850d341b955dd72f24959Robin Lee * @see VpnService.Builder#addDisallowedApplication(String) 1664d03abcd49af490dba3850d341b955dd72f24959Robin Lee */ 167c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker @GuardedBy("this") 1684d03abcd49af490dba3850d341b955dd72f24959Robin Lee private Set<UidRange> mVpnUsers = null; 169c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker 17017e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee /** 17117e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * List of UIDs for which networking should be blocked until VPN is ready, during brief periods 17217e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * when VPN is not running. For example, during system startup or after a crash. 17317e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * @see mLockdown 17417e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee */ 17517e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee @GuardedBy("this") 17617e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee private Set<UidRange> mBlockedUsers = new ArraySet<>(); 17717e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee 1780784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen // Handle of user initiating VPN. 1790784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen private final int mUserHandle; 180ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 181812800cb92090db31f609b907c4458ba76cf7f42Robin Lee // Listen to package remove and change event in this user 182812800cb92090db31f609b907c4458ba76cf7f42Robin Lee private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() { 183812800cb92090db31f609b907c4458ba76cf7f42Robin Lee @Override 184812800cb92090db31f609b907c4458ba76cf7f42Robin Lee public void onReceive(Context context, Intent intent) { 185812800cb92090db31f609b907c4458ba76cf7f42Robin Lee final Uri data = intent.getData(); 186812800cb92090db31f609b907c4458ba76cf7f42Robin Lee final String packageName = data == null ? null : data.getSchemeSpecificPart(); 187812800cb92090db31f609b907c4458ba76cf7f42Robin Lee if (packageName == null) { 188812800cb92090db31f609b907c4458ba76cf7f42Robin Lee return; 189812800cb92090db31f609b907c4458ba76cf7f42Robin Lee } 190812800cb92090db31f609b907c4458ba76cf7f42Robin Lee 191812800cb92090db31f609b907c4458ba76cf7f42Robin Lee synchronized (Vpn.this) { 192812800cb92090db31f609b907c4458ba76cf7f42Robin Lee // Avoid race that always-on package has been unset 193812800cb92090db31f609b907c4458ba76cf7f42Robin Lee if (!packageName.equals(getAlwaysOnPackage())) { 194812800cb92090db31f609b907c4458ba76cf7f42Robin Lee return; 195812800cb92090db31f609b907c4458ba76cf7f42Robin Lee } 196812800cb92090db31f609b907c4458ba76cf7f42Robin Lee 197812800cb92090db31f609b907c4458ba76cf7f42Robin Lee final String action = intent.getAction(); 198812800cb92090db31f609b907c4458ba76cf7f42Robin Lee Log.i(TAG, "Received broadcast " + action + " for always-on package " + packageName 199812800cb92090db31f609b907c4458ba76cf7f42Robin Lee + " in user " + mUserHandle); 200812800cb92090db31f609b907c4458ba76cf7f42Robin Lee 201812800cb92090db31f609b907c4458ba76cf7f42Robin Lee switch(action) { 202812800cb92090db31f609b907c4458ba76cf7f42Robin Lee case Intent.ACTION_PACKAGE_REPLACED: 203812800cb92090db31f609b907c4458ba76cf7f42Robin Lee // Start vpn after app upgrade 204812800cb92090db31f609b907c4458ba76cf7f42Robin Lee startAlwaysOnVpn(); 205812800cb92090db31f609b907c4458ba76cf7f42Robin Lee break; 206812800cb92090db31f609b907c4458ba76cf7f42Robin Lee case Intent.ACTION_PACKAGE_REMOVED: 207812800cb92090db31f609b907c4458ba76cf7f42Robin Lee final boolean isPackageRemoved = !intent.getBooleanExtra( 208812800cb92090db31f609b907c4458ba76cf7f42Robin Lee Intent.EXTRA_REPLACING, false); 209812800cb92090db31f609b907c4458ba76cf7f42Robin Lee if (isPackageRemoved) { 210812800cb92090db31f609b907c4458ba76cf7f42Robin Lee setAndSaveAlwaysOnPackage(null, false); 211812800cb92090db31f609b907c4458ba76cf7f42Robin Lee } 212812800cb92090db31f609b907c4458ba76cf7f42Robin Lee break; 213812800cb92090db31f609b907c4458ba76cf7f42Robin Lee } 214812800cb92090db31f609b907c4458ba76cf7f42Robin Lee } 215812800cb92090db31f609b907c4458ba76cf7f42Robin Lee } 216812800cb92090db31f609b907c4458ba76cf7f42Robin Lee }; 217812800cb92090db31f609b907c4458ba76cf7f42Robin Lee 218812800cb92090db31f609b907c4458ba76cf7f42Robin Lee private boolean mIsPackageIntentReceiverRegistered = false; 219812800cb92090db31f609b907c4458ba76cf7f42Robin Lee 2206bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen public Vpn(Looper looper, Context context, INetworkManagementService netService, 221e75b9e355500b7c6a05e4d6ec54ef48835707caaPaul Jensen int userHandle) { 222ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh mContext = context; 2236bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen mNetd = netService; 2240784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen mUserHandle = userHandle; 2256bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen mLooper = looper; 2266bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen 2276bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen mPackage = VpnConfig.LEGACY_VPN; 2280784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen mOwnerUID = getAppUid(mPackage, mUserHandle); 229899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey 230899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey try { 231899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey netService.registerObserver(mObserver); 232899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } catch (RemoteException e) { 233899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey Log.wtf(TAG, "Problem registering observer", e); 234899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } 2356bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen 2366bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_VPN, 0, NETWORKTYPE, ""); 2376bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen // TODO: Copy metered attribute and bandwidths from physical transport, b/16207332 2386bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen mNetworkCapabilities = new NetworkCapabilities(); 2396bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen mNetworkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_VPN); 2406bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN); 241899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } 242899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey 24357666934b4a161cc2fb77eef15d0b894aaf8f173Jeff Sharkey /** 24457666934b4a161cc2fb77eef15d0b894aaf8f173Jeff Sharkey * Set if this object is responsible for watching for {@link NetworkInfo} 24557666934b4a161cc2fb77eef15d0b894aaf8f173Jeff Sharkey * teardown. When {@code false}, teardown is handled externally by someone 24657666934b4a161cc2fb77eef15d0b894aaf8f173Jeff Sharkey * else. 24757666934b4a161cc2fb77eef15d0b894aaf8f173Jeff Sharkey */ 24857666934b4a161cc2fb77eef15d0b894aaf8f173Jeff Sharkey public void setEnableTeardown(boolean enableTeardown) { 24957666934b4a161cc2fb77eef15d0b894aaf8f173Jeff Sharkey mEnableTeardown = enableTeardown; 25057666934b4a161cc2fb77eef15d0b894aaf8f173Jeff Sharkey } 25157666934b4a161cc2fb77eef15d0b894aaf8f173Jeff Sharkey 252899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey /** 253899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey * Update current state, dispaching event to listeners. 254899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey */ 2551a405fe300950d6ceae2166fd074b596d8110dbeTony Mak @VisibleForTesting 2561a405fe300950d6ceae2166fd074b596d8110dbeTony Mak protected void updateState(DetailedState detailedState, String reason) { 257899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey if (LOGD) Log.d(TAG, "setting state=" + detailedState + ", reason=" + reason); 258899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey mNetworkInfo.setDetailedState(detailedState, reason, null); 2596bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen if (mNetworkAgent != null) { 2606bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen mNetworkAgent.sendNetworkInfo(mNetworkInfo); 2616bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 2621a405fe300950d6ceae2166fd074b596d8110dbeTony Mak updateAlwaysOnNotification(detailedState); 263ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 264ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 265ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh /** 266244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee * Configures an always-on VPN connection through a specific application. 267244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee * This connection is automatically granted and persisted after a reboot. 268244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee * 269244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee * <p>The designated package should exist and declare a {@link VpnService} in its 270244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee * manifest guarded by {@link android.Manifest.permission.BIND_VPN_SERVICE}, 271244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee * otherwise the call will fail. 272244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee * 27317e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * @param packageName the package to designate as always-on VPN supplier. 27417e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * @param lockdown whether to prevent traffic outside of a VPN, for example while connecting. 2759ff1a588786cb2963d76c75f3a077fc17fa1589cRobin Lee * @return {@code true} if the package has been set as always-on, {@code false} otherwise. 276244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee */ 27717e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee public synchronized boolean setAlwaysOnPackage(String packageName, boolean lockdown) { 278244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee enforceControlPermissionOrInternalCaller(); 2799ff1a588786cb2963d76c75f3a077fc17fa1589cRobin Lee if (VpnConfig.LEGACY_VPN.equals(packageName)) { 2809ff1a588786cb2963d76c75f3a077fc17fa1589cRobin Lee Log.w(TAG, "Not setting legacy VPN \"" + packageName + "\" as always-on."); 2819ff1a588786cb2963d76c75f3a077fc17fa1589cRobin Lee return false; 2829ff1a588786cb2963d76c75f3a077fc17fa1589cRobin Lee } 283244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee 284244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee if (packageName != null) { 2859ff1a588786cb2963d76c75f3a077fc17fa1589cRobin Lee // Pre-authorize new always-on VPN package. 286244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee if (!setPackageAuthorization(packageName, true)) { 287244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee return false; 288244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee } 2899ff1a588786cb2963d76c75f3a077fc17fa1589cRobin Lee mAlwaysOn = true; 2909ff1a588786cb2963d76c75f3a077fc17fa1589cRobin Lee } else { 2919ff1a588786cb2963d76c75f3a077fc17fa1589cRobin Lee packageName = VpnConfig.LEGACY_VPN; 2929ff1a588786cb2963d76c75f3a077fc17fa1589cRobin Lee mAlwaysOn = false; 293244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee } 294244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee 29517e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee mLockdown = (mAlwaysOn && lockdown); 2961a405fe300950d6ceae2166fd074b596d8110dbeTony Mak if (isCurrentPreparedPackage(packageName)) { 2971a405fe300950d6ceae2166fd074b596d8110dbeTony Mak updateAlwaysOnNotification(mNetworkInfo.getDetailedState()); 2981a405fe300950d6ceae2166fd074b596d8110dbeTony Mak } else { 2991a405fe300950d6ceae2166fd074b596d8110dbeTony Mak // Prepare this app. The notification will update as a side-effect of updateState(). 3009ff1a588786cb2963d76c75f3a077fc17fa1589cRobin Lee prepareInternal(packageName); 3019ff1a588786cb2963d76c75f3a077fc17fa1589cRobin Lee } 302812800cb92090db31f609b907c4458ba76cf7f42Robin Lee maybeRegisterPackageChangeReceiverLocked(packageName); 30317e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee setVpnForcedLocked(mLockdown); 304244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee return true; 305244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee } 306244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee 3079ff1a588786cb2963d76c75f3a077fc17fa1589cRobin Lee private static boolean isNullOrLegacyVpn(String packageName) { 3089ff1a588786cb2963d76c75f3a077fc17fa1589cRobin Lee return packageName == null || VpnConfig.LEGACY_VPN.equals(packageName); 3099ff1a588786cb2963d76c75f3a077fc17fa1589cRobin Lee } 3109ff1a588786cb2963d76c75f3a077fc17fa1589cRobin Lee 311812800cb92090db31f609b907c4458ba76cf7f42Robin Lee private void unregisterPackageChangeReceiverLocked() { 312812800cb92090db31f609b907c4458ba76cf7f42Robin Lee // register previous intent filter 313812800cb92090db31f609b907c4458ba76cf7f42Robin Lee if (mIsPackageIntentReceiverRegistered) { 314812800cb92090db31f609b907c4458ba76cf7f42Robin Lee mContext.unregisterReceiver(mPackageIntentReceiver); 315812800cb92090db31f609b907c4458ba76cf7f42Robin Lee mIsPackageIntentReceiverRegistered = false; 316812800cb92090db31f609b907c4458ba76cf7f42Robin Lee } 317812800cb92090db31f609b907c4458ba76cf7f42Robin Lee } 318812800cb92090db31f609b907c4458ba76cf7f42Robin Lee 319812800cb92090db31f609b907c4458ba76cf7f42Robin Lee private void maybeRegisterPackageChangeReceiverLocked(String packageName) { 320812800cb92090db31f609b907c4458ba76cf7f42Robin Lee // Unregister IntentFilter listening for previous always-on package change 321812800cb92090db31f609b907c4458ba76cf7f42Robin Lee unregisterPackageChangeReceiverLocked(); 322812800cb92090db31f609b907c4458ba76cf7f42Robin Lee 3239ff1a588786cb2963d76c75f3a077fc17fa1589cRobin Lee if (!isNullOrLegacyVpn(packageName)) { 324812800cb92090db31f609b907c4458ba76cf7f42Robin Lee mIsPackageIntentReceiverRegistered = true; 325812800cb92090db31f609b907c4458ba76cf7f42Robin Lee 326812800cb92090db31f609b907c4458ba76cf7f42Robin Lee IntentFilter intentFilter = new IntentFilter(); 327812800cb92090db31f609b907c4458ba76cf7f42Robin Lee // Protected intent can only be sent by system. No permission required in register. 328812800cb92090db31f609b907c4458ba76cf7f42Robin Lee intentFilter.addAction(Intent.ACTION_PACKAGE_REPLACED); 329812800cb92090db31f609b907c4458ba76cf7f42Robin Lee intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); 330812800cb92090db31f609b907c4458ba76cf7f42Robin Lee intentFilter.addDataScheme("package"); 331812800cb92090db31f609b907c4458ba76cf7f42Robin Lee intentFilter.addDataSchemeSpecificPart(packageName, PatternMatcher.PATTERN_LITERAL); 332812800cb92090db31f609b907c4458ba76cf7f42Robin Lee mContext.registerReceiverAsUser( 333812800cb92090db31f609b907c4458ba76cf7f42Robin Lee mPackageIntentReceiver, UserHandle.of(mUserHandle), intentFilter, null, null); 334812800cb92090db31f609b907c4458ba76cf7f42Robin Lee } 335812800cb92090db31f609b907c4458ba76cf7f42Robin Lee } 336812800cb92090db31f609b907c4458ba76cf7f42Robin Lee 337244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee /** 338244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee * @return the package name of the VPN controller responsible for always-on VPN, 339244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee * or {@code null} if none is set or always-on VPN is controlled through 340244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee * lockdown instead. 341244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee * @hide 342244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee */ 343244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee public synchronized String getAlwaysOnPackage() { 344244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee enforceControlPermissionOrInternalCaller(); 34517e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee return (mAlwaysOn ? mPackage : null); 346244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee } 347244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee 348244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee /** 349812800cb92090db31f609b907c4458ba76cf7f42Robin Lee * Save the always-on package and lockdown config into Settings.Secure 350812800cb92090db31f609b907c4458ba76cf7f42Robin Lee */ 351812800cb92090db31f609b907c4458ba76cf7f42Robin Lee public synchronized void saveAlwaysOnPackage() { 352812800cb92090db31f609b907c4458ba76cf7f42Robin Lee final long token = Binder.clearCallingIdentity(); 353812800cb92090db31f609b907c4458ba76cf7f42Robin Lee try { 354812800cb92090db31f609b907c4458ba76cf7f42Robin Lee final ContentResolver cr = mContext.getContentResolver(); 355812800cb92090db31f609b907c4458ba76cf7f42Robin Lee Settings.Secure.putStringForUser(cr, Settings.Secure.ALWAYS_ON_VPN_APP, 356812800cb92090db31f609b907c4458ba76cf7f42Robin Lee getAlwaysOnPackage(), mUserHandle); 357812800cb92090db31f609b907c4458ba76cf7f42Robin Lee Settings.Secure.putIntForUser(cr, Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN, 358812800cb92090db31f609b907c4458ba76cf7f42Robin Lee (mLockdown ? 1 : 0), mUserHandle); 359812800cb92090db31f609b907c4458ba76cf7f42Robin Lee } finally { 360812800cb92090db31f609b907c4458ba76cf7f42Robin Lee Binder.restoreCallingIdentity(token); 361812800cb92090db31f609b907c4458ba76cf7f42Robin Lee } 362812800cb92090db31f609b907c4458ba76cf7f42Robin Lee } 363812800cb92090db31f609b907c4458ba76cf7f42Robin Lee 364812800cb92090db31f609b907c4458ba76cf7f42Robin Lee /** 365812800cb92090db31f609b907c4458ba76cf7f42Robin Lee * Set and save always-on package and lockdown config 366812800cb92090db31f609b907c4458ba76cf7f42Robin Lee * @see Vpn#setAlwaysOnPackage(String, boolean) 367812800cb92090db31f609b907c4458ba76cf7f42Robin Lee * @see Vpn#saveAlwaysOnPackage() 368812800cb92090db31f609b907c4458ba76cf7f42Robin Lee * 369812800cb92090db31f609b907c4458ba76cf7f42Robin Lee * @return result of Vpn#setAndSaveAlwaysOnPackage(String, boolean) 370812800cb92090db31f609b907c4458ba76cf7f42Robin Lee */ 371812800cb92090db31f609b907c4458ba76cf7f42Robin Lee private synchronized boolean setAndSaveAlwaysOnPackage(String packageName, boolean lockdown) { 372812800cb92090db31f609b907c4458ba76cf7f42Robin Lee if (setAlwaysOnPackage(packageName, lockdown)) { 373812800cb92090db31f609b907c4458ba76cf7f42Robin Lee saveAlwaysOnPackage(); 374812800cb92090db31f609b907c4458ba76cf7f42Robin Lee return true; 375812800cb92090db31f609b907c4458ba76cf7f42Robin Lee } else { 376812800cb92090db31f609b907c4458ba76cf7f42Robin Lee return false; 377812800cb92090db31f609b907c4458ba76cf7f42Robin Lee } 378812800cb92090db31f609b907c4458ba76cf7f42Robin Lee } 379812800cb92090db31f609b907c4458ba76cf7f42Robin Lee 380812800cb92090db31f609b907c4458ba76cf7f42Robin Lee /** 381812800cb92090db31f609b907c4458ba76cf7f42Robin Lee * @return {@code true} if the service was started, the service was already connected, or there 382812800cb92090db31f609b907c4458ba76cf7f42Robin Lee * was no always-on VPN to start. {@code false} otherwise. 383812800cb92090db31f609b907c4458ba76cf7f42Robin Lee */ 384812800cb92090db31f609b907c4458ba76cf7f42Robin Lee public boolean startAlwaysOnVpn() { 385812800cb92090db31f609b907c4458ba76cf7f42Robin Lee final String alwaysOnPackage; 386812800cb92090db31f609b907c4458ba76cf7f42Robin Lee synchronized (this) { 387812800cb92090db31f609b907c4458ba76cf7f42Robin Lee alwaysOnPackage = getAlwaysOnPackage(); 388812800cb92090db31f609b907c4458ba76cf7f42Robin Lee // Skip if there is no service to start. 389812800cb92090db31f609b907c4458ba76cf7f42Robin Lee if (alwaysOnPackage == null) { 390812800cb92090db31f609b907c4458ba76cf7f42Robin Lee return true; 391812800cb92090db31f609b907c4458ba76cf7f42Robin Lee } 392812800cb92090db31f609b907c4458ba76cf7f42Robin Lee // Skip if the service is already established. This isn't bulletproof: it's not bound 393812800cb92090db31f609b907c4458ba76cf7f42Robin Lee // until after establish(), so if it's mid-setup onStartCommand will be sent twice, 394812800cb92090db31f609b907c4458ba76cf7f42Robin Lee // which may restart the connection. 395812800cb92090db31f609b907c4458ba76cf7f42Robin Lee if (getNetworkInfo().isConnected()) { 396812800cb92090db31f609b907c4458ba76cf7f42Robin Lee return true; 397812800cb92090db31f609b907c4458ba76cf7f42Robin Lee } 398812800cb92090db31f609b907c4458ba76cf7f42Robin Lee } 399812800cb92090db31f609b907c4458ba76cf7f42Robin Lee 400e0be7e859b37438ec88780979e373821054a11efChristopher Tate // Tell the OS that background services in this app need to be allowed for 401e0be7e859b37438ec88780979e373821054a11efChristopher Tate // a short time, so we can bootstrap the VPN service. 402e0be7e859b37438ec88780979e373821054a11efChristopher Tate final long oldId = Binder.clearCallingIdentity(); 403812800cb92090db31f609b907c4458ba76cf7f42Robin Lee try { 404e0be7e859b37438ec88780979e373821054a11efChristopher Tate DeviceIdleController.LocalService idleController = 405e0be7e859b37438ec88780979e373821054a11efChristopher Tate LocalServices.getService(DeviceIdleController.LocalService.class); 406e0be7e859b37438ec88780979e373821054a11efChristopher Tate idleController.addPowerSaveTempWhitelistApp(Process.myUid(), alwaysOnPackage, 407e0be7e859b37438ec88780979e373821054a11efChristopher Tate VPN_LAUNCH_IDLE_WHITELIST_DURATION, mUserHandle, false, "vpn"); 408e0be7e859b37438ec88780979e373821054a11efChristopher Tate 409e0be7e859b37438ec88780979e373821054a11efChristopher Tate // Start the VPN service declared in the app's manifest. 410e0be7e859b37438ec88780979e373821054a11efChristopher Tate Intent serviceIntent = new Intent(VpnConfig.SERVICE_INTERFACE); 411e0be7e859b37438ec88780979e373821054a11efChristopher Tate serviceIntent.setPackage(alwaysOnPackage); 412e0be7e859b37438ec88780979e373821054a11efChristopher Tate try { 413e0be7e859b37438ec88780979e373821054a11efChristopher Tate return mContext.startServiceAsUser(serviceIntent, UserHandle.of(mUserHandle)) != null; 414e0be7e859b37438ec88780979e373821054a11efChristopher Tate } catch (RuntimeException e) { 415e0be7e859b37438ec88780979e373821054a11efChristopher Tate Log.e(TAG, "VpnService " + serviceIntent + " failed to start", e); 416e0be7e859b37438ec88780979e373821054a11efChristopher Tate return false; 417e0be7e859b37438ec88780979e373821054a11efChristopher Tate } 418e0be7e859b37438ec88780979e373821054a11efChristopher Tate } finally { 419e0be7e859b37438ec88780979e373821054a11efChristopher Tate Binder.restoreCallingIdentity(oldId); 420812800cb92090db31f609b907c4458ba76cf7f42Robin Lee } 421812800cb92090db31f609b907c4458ba76cf7f42Robin Lee } 422812800cb92090db31f609b907c4458ba76cf7f42Robin Lee 423812800cb92090db31f609b907c4458ba76cf7f42Robin Lee /** 424100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * Prepare for a VPN application. This method is designed to solve 425100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * race conditions. It first compares the current prepared package 426100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * with {@code oldPackage}. If they are the same, the prepared 427100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * package is revoked and replaced with {@code newPackage}. If 428100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * {@code oldPackage} is {@code null}, the comparison is omitted. 429100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * If {@code newPackage} is the same package or {@code null}, the 430100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * revocation is omitted. This method returns {@code true} if the 431100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * operation is succeeded. 432e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh * 433100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * Legacy VPN is handled specially since it is not a real package. 434100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * It uses {@link VpnConfig#LEGACY_VPN} as its package name, and 435100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * it can be revoked by itself. 436100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * 43798a633a89cf3223f79ea625323ec2b91bee72584Victor Chang * Note: when we added VPN pre-consent in http://ag/522961 the names oldPackage 43898a633a89cf3223f79ea625323ec2b91bee72584Victor Chang * and newPackage become misleading, because when an app is pre-consented, we 43998a633a89cf3223f79ea625323ec2b91bee72584Victor Chang * actually prepare oldPackage, not newPackage. 44098a633a89cf3223f79ea625323ec2b91bee72584Victor Chang * 44198a633a89cf3223f79ea625323ec2b91bee72584Victor Chang * Their meanings actually are: 44298a633a89cf3223f79ea625323ec2b91bee72584Victor Chang * 44398a633a89cf3223f79ea625323ec2b91bee72584Victor Chang * - oldPackage non-null, newPackage null: App calling VpnService#prepare(). 44498a633a89cf3223f79ea625323ec2b91bee72584Victor Chang * - oldPackage null, newPackage non-null: ConfirmDialog calling prepareVpn(). 445812800cb92090db31f609b907c4458ba76cf7f42Robin Lee * - oldPackage null, newPackage=LEGACY_VPN: Used internally to disconnect 44698a633a89cf3223f79ea625323ec2b91bee72584Victor Chang * and revoke any current app VPN and re-prepare legacy vpn. 44798a633a89cf3223f79ea625323ec2b91bee72584Victor Chang * 448812800cb92090db31f609b907c4458ba76cf7f42Robin Lee * TODO: Rename the variables - or split this method into two - and end this confusion. 449812800cb92090db31f609b907c4458ba76cf7f42Robin Lee * TODO: b/29032008 Migrate code from prepare(oldPackage=non-null, newPackage=LEGACY_VPN) 450812800cb92090db31f609b907c4458ba76cf7f42Robin Lee * to prepare(oldPackage=null, newPackage=LEGACY_VPN) 45198a633a89cf3223f79ea625323ec2b91bee72584Victor Chang * 45298a633a89cf3223f79ea625323ec2b91bee72584Victor Chang * @param oldPackage The package name of the old VPN application 45398a633a89cf3223f79ea625323ec2b91bee72584Victor Chang * @param newPackage The package name of the new VPN application 45498a633a89cf3223f79ea625323ec2b91bee72584Victor Chang * 455100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * @return true if the operation is succeeded. 456ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh */ 457100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh public synchronized boolean prepare(String oldPackage, String newPackage) { 4580a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson if (oldPackage != null) { 45998a633a89cf3223f79ea625323ec2b91bee72584Victor Chang // Stop an existing always-on VPN from being dethroned by other apps. 460812800cb92090db31f609b907c4458ba76cf7f42Robin Lee if (mAlwaysOn && !isCurrentPreparedPackage(oldPackage)) { 46198a633a89cf3223f79ea625323ec2b91bee72584Victor Chang return false; 46298a633a89cf3223f79ea625323ec2b91bee72584Victor Chang } 46398a633a89cf3223f79ea625323ec2b91bee72584Victor Chang 46498a633a89cf3223f79ea625323ec2b91bee72584Victor Chang // Package is not same or old package was reinstalled. 46598a633a89cf3223f79ea625323ec2b91bee72584Victor Chang if (!isCurrentPreparedPackage(oldPackage)) { 4660a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson // The package doesn't match. We return false (to obtain user consent) unless the 4670a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson // user has already consented to that VPN package. 4680a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson if (!oldPackage.equals(VpnConfig.LEGACY_VPN) && isVpnUserPreConsented(oldPackage)) { 4690a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson prepareInternal(oldPackage); 4700a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson return true; 4710a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson } 4720a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson return false; 4730a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson } else if (!oldPackage.equals(VpnConfig.LEGACY_VPN) 4740a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson && !isVpnUserPreConsented(oldPackage)) { 4750a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson // Currently prepared VPN is revoked, so unprepare it and return false. 4760a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson prepareInternal(VpnConfig.LEGACY_VPN); 4770a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson return false; 47805542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson } 479100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh } 480100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh 481100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh // Return true if we do not need to revoke. 482be08587510edbc149c841638db721eb97d2351b6Jeff Davidson if (newPackage == null || (!newPackage.equals(VpnConfig.LEGACY_VPN) && 48398a633a89cf3223f79ea625323ec2b91bee72584Victor Chang isCurrentPreparedPackage(newPackage))) { 484100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh return true; 485ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 486ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 4871b1bcd7b7370866bc00ce3361be8d5167bf3e28dRobin Lee // Check that the caller is authorized. 488dadc857d9de364fded10d4f69eb82bc9cd35d4b7Chia-chi Yeh enforceControlPermission(); 4897b0b834c3d12564c44ac134879a6dbc70e74be6eChia-chi Yeh 49098a633a89cf3223f79ea625323ec2b91bee72584Victor Chang // Stop an existing always-on VPN from being dethroned by other apps. 491812800cb92090db31f609b907c4458ba76cf7f42Robin Lee if (mAlwaysOn && !isCurrentPreparedPackage(newPackage)) { 49298a633a89cf3223f79ea625323ec2b91bee72584Victor Chang return false; 49398a633a89cf3223f79ea625323ec2b91bee72584Victor Chang } 49498a633a89cf3223f79ea625323ec2b91bee72584Victor Chang 49511008a78b8e30910cedd8b8431980c7738183292Jeff Davidson prepareInternal(newPackage); 49611008a78b8e30910cedd8b8431980c7738183292Jeff Davidson return true; 49711008a78b8e30910cedd8b8431980c7738183292Jeff Davidson } 49811008a78b8e30910cedd8b8431980c7738183292Jeff Davidson 49998a633a89cf3223f79ea625323ec2b91bee72584Victor Chang private boolean isCurrentPreparedPackage(String packageName) { 50098a633a89cf3223f79ea625323ec2b91bee72584Victor Chang // We can't just check that packageName matches mPackage, because if the app was uninstalled 50198a633a89cf3223f79ea625323ec2b91bee72584Victor Chang // and reinstalled it will no longer be prepared. Instead check the UID. 50298a633a89cf3223f79ea625323ec2b91bee72584Victor Chang return getAppUid(packageName, mUserHandle) == mOwnerUID; 50398a633a89cf3223f79ea625323ec2b91bee72584Victor Chang } 50498a633a89cf3223f79ea625323ec2b91bee72584Victor Chang 50511008a78b8e30910cedd8b8431980c7738183292Jeff Davidson /** Prepare the VPN for the given package. Does not perform permission checks. */ 50611008a78b8e30910cedd8b8431980c7738183292Jeff Davidson private void prepareInternal(String newPackage) { 50711008a78b8e30910cedd8b8431980c7738183292Jeff Davidson long token = Binder.clearCallingIdentity(); 50811008a78b8e30910cedd8b8431980c7738183292Jeff Davidson try { 50911008a78b8e30910cedd8b8431980c7738183292Jeff Davidson // Reset the interface. 51011008a78b8e30910cedd8b8431980c7738183292Jeff Davidson if (mInterface != null) { 51111008a78b8e30910cedd8b8431980c7738183292Jeff Davidson mStatusIntent = null; 51211008a78b8e30910cedd8b8431980c7738183292Jeff Davidson agentDisconnect(); 51311008a78b8e30910cedd8b8431980c7738183292Jeff Davidson jniReset(mInterface); 51411008a78b8e30910cedd8b8431980c7738183292Jeff Davidson mInterface = null; 51511008a78b8e30910cedd8b8431980c7738183292Jeff Davidson mVpnUsers = null; 51611008a78b8e30910cedd8b8431980c7738183292Jeff Davidson } 51711008a78b8e30910cedd8b8431980c7738183292Jeff Davidson 51811008a78b8e30910cedd8b8431980c7738183292Jeff Davidson // Revoke the connection or stop LegacyVpnRunner. 51911008a78b8e30910cedd8b8431980c7738183292Jeff Davidson if (mConnection != null) { 52011008a78b8e30910cedd8b8431980c7738183292Jeff Davidson try { 52111008a78b8e30910cedd8b8431980c7738183292Jeff Davidson mConnection.mService.transact(IBinder.LAST_CALL_TRANSACTION, 52211008a78b8e30910cedd8b8431980c7738183292Jeff Davidson Parcel.obtain(), null, IBinder.FLAG_ONEWAY); 52311008a78b8e30910cedd8b8431980c7738183292Jeff Davidson } catch (Exception e) { 52411008a78b8e30910cedd8b8431980c7738183292Jeff Davidson // ignore 52511008a78b8e30910cedd8b8431980c7738183292Jeff Davidson } 52611008a78b8e30910cedd8b8431980c7738183292Jeff Davidson mContext.unbindService(mConnection); 52711008a78b8e30910cedd8b8431980c7738183292Jeff Davidson mConnection = null; 52811008a78b8e30910cedd8b8431980c7738183292Jeff Davidson } else if (mLegacyVpnRunner != null) { 52911008a78b8e30910cedd8b8431980c7738183292Jeff Davidson mLegacyVpnRunner.exit(); 53011008a78b8e30910cedd8b8431980c7738183292Jeff Davidson mLegacyVpnRunner = null; 53111008a78b8e30910cedd8b8431980c7738183292Jeff Davidson } 532ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 533199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh try { 53411008a78b8e30910cedd8b8431980c7738183292Jeff Davidson mNetd.denyProtect(mOwnerUID); 535199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh } catch (Exception e) { 53611008a78b8e30910cedd8b8431980c7738183292Jeff Davidson Log.wtf(TAG, "Failed to disallow UID " + mOwnerUID + " to call protect() " + e); 537199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh } 53841d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh 53911008a78b8e30910cedd8b8431980c7738183292Jeff Davidson Log.i(TAG, "Switched from " + mPackage + " to " + newPackage); 54011008a78b8e30910cedd8b8431980c7738183292Jeff Davidson mPackage = newPackage; 54111008a78b8e30910cedd8b8431980c7738183292Jeff Davidson mOwnerUID = getAppUid(newPackage, mUserHandle); 54211008a78b8e30910cedd8b8431980c7738183292Jeff Davidson try { 54311008a78b8e30910cedd8b8431980c7738183292Jeff Davidson mNetd.allowProtect(mOwnerUID); 54411008a78b8e30910cedd8b8431980c7738183292Jeff Davidson } catch (Exception e) { 54511008a78b8e30910cedd8b8431980c7738183292Jeff Davidson Log.wtf(TAG, "Failed to allow UID " + mOwnerUID + " to call protect() " + e); 54611008a78b8e30910cedd8b8431980c7738183292Jeff Davidson } 54711008a78b8e30910cedd8b8431980c7738183292Jeff Davidson mConfig = null; 5486bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen 54911008a78b8e30910cedd8b8431980c7738183292Jeff Davidson updateState(DetailedState.IDLE, "prepare"); 5506bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } finally { 5516bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen Binder.restoreCallingIdentity(token); 5526bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 553ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 554ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 55505542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson /** 5563b3dd942ec6a0beaccd1cef0723d72786435d8f3Robin Lee * Set whether a package has the ability to launch VPNs without user intervention. 55705542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson */ 558244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee public boolean setPackageAuthorization(String packageName, boolean authorized) { 55905542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson // Check if the caller is authorized. 560244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee enforceControlPermissionOrInternalCaller(); 56105542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson 5623b3dd942ec6a0beaccd1cef0723d72786435d8f3Robin Lee int uid = getAppUid(packageName, mUserHandle); 5633b3dd942ec6a0beaccd1cef0723d72786435d8f3Robin Lee if (uid == -1 || VpnConfig.LEGACY_VPN.equals(packageName)) { 5643b3dd942ec6a0beaccd1cef0723d72786435d8f3Robin Lee // Authorization for nonexistent packages (or fake ones) can't be updated. 565244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee return false; 56605542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson } 56705542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson 56805542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson long token = Binder.clearCallingIdentity(); 56905542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson try { 57005542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson AppOpsManager appOps = 57105542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); 5723b3dd942ec6a0beaccd1cef0723d72786435d8f3Robin Lee appOps.setMode(AppOpsManager.OP_ACTIVATE_VPN, uid, packageName, 57305542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson authorized ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED); 574244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee return true; 57505542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson } catch (Exception e) { 5763b3dd942ec6a0beaccd1cef0723d72786435d8f3Robin Lee Log.wtf(TAG, "Failed to set app ops for package " + packageName + ", uid " + uid, e); 57705542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson } finally { 57805542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson Binder.restoreCallingIdentity(token); 57905542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson } 580244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee return false; 58105542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson } 58205542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson 58305542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson private boolean isVpnUserPreConsented(String packageName) { 58405542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson AppOpsManager appOps = 58505542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); 58605542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson 58705542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson // Verify that the caller matches the given package and has permission to activate VPNs. 58805542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson return appOps.noteOpNoThrow(AppOpsManager.OP_ACTIVATE_VPN, Binder.getCallingUid(), 58905542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson packageName) == AppOpsManager.MODE_ALLOWED; 59005542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson } 59105542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson 5920784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen private int getAppUid(String app, int userHandle) { 59305542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson if (VpnConfig.LEGACY_VPN.equals(app)) { 5946bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen return Process.myUid(); 5956bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 596fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh PackageManager pm = mContext.getPackageManager(); 5976bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen int result; 5986bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen try { 599e06b4d1d9f718b9fe02980fea794a36831a16db2Jeff Sharkey result = pm.getPackageUidAsUser(app, userHandle); 6006bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } catch (NameNotFoundException e) { 6016bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen result = -1; 602fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh } 6036bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen return result; 6046bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 6056bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen 6066bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen public NetworkInfo getNetworkInfo() { 6076bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen return mNetworkInfo; 6086bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 6096bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen 61031a94f48bf8014cf6a1127bd23cf9a8541a9abedPaul Jensen public int getNetId() { 61131a94f48bf8014cf6a1127bd23cf9a8541a9abedPaul Jensen return mNetworkAgent != null ? mNetworkAgent.netId : NETID_UNSET; 61231a94f48bf8014cf6a1127bd23cf9a8541a9abedPaul Jensen } 61331a94f48bf8014cf6a1127bd23cf9a8541a9abedPaul Jensen 61460446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti private LinkProperties makeLinkProperties() { 61560446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti boolean allowIPv4 = mConfig.allowIPv4; 61660446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti boolean allowIPv6 = mConfig.allowIPv6; 61760446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti 6186bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen LinkProperties lp = new LinkProperties(); 61960446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti 6206bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen lp.setInterfaceName(mInterface); 62142065ac64cba166dc0fe602957ea8fe80bf406e2Sreeram Ramachandran 62260446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti if (mConfig.addresses != null) { 62360446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti for (LinkAddress address : mConfig.addresses) { 62460446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti lp.addLinkAddress(address); 62560446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti allowIPv4 |= address.getAddress() instanceof Inet4Address; 62660446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti allowIPv6 |= address.getAddress() instanceof Inet6Address; 62760446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti } 6286bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 62960446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti 63060446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti if (mConfig.routes != null) { 63160446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti for (RouteInfo route : mConfig.routes) { 63260446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti lp.addRoute(route); 63360446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti InetAddress address = route.getDestination().getAddress(); 63460446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti allowIPv4 |= address instanceof Inet4Address; 63560446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti allowIPv6 |= address instanceof Inet6Address; 63660446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti } 6376bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 63842065ac64cba166dc0fe602957ea8fe80bf406e2Sreeram Ramachandran 6396bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen if (mConfig.dnsServers != null) { 6406bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen for (String dnsServer : mConfig.dnsServers) { 64142065ac64cba166dc0fe602957ea8fe80bf406e2Sreeram Ramachandran InetAddress address = InetAddress.parseNumericAddress(dnsServer); 64242065ac64cba166dc0fe602957ea8fe80bf406e2Sreeram Ramachandran lp.addDnsServer(address); 64360446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti allowIPv4 |= address instanceof Inet4Address; 64460446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti allowIPv6 |= address instanceof Inet6Address; 6456bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 6466bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 64742065ac64cba166dc0fe602957ea8fe80bf406e2Sreeram Ramachandran 64860446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti if (!allowIPv4) { 64960446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE)); 65060446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti } 65160446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti if (!allowIPv6) { 65260446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE)); 65360446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti } 65460446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti 6556bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen // Concatenate search domains into a string. 6566bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen StringBuilder buffer = new StringBuilder(); 6576bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen if (mConfig.searchDomains != null) { 6586bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen for (String domain : mConfig.searchDomains) { 6596bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen buffer.append(domain).append(' '); 6606bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 6616bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 6626bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen lp.setDomains(buffer.toString().trim()); 66342065ac64cba166dc0fe602957ea8fe80bf406e2Sreeram Ramachandran 66460446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti // TODO: Stop setting the MTU in jniCreate and set it here. 66560446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti 66660446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti return lp; 66760446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti } 66860446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti 66960446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti private void agentConnect() { 67060446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti LinkProperties lp = makeLinkProperties(); 67160446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti 67260446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti if (lp.hasIPv4DefaultRoute() || lp.hasIPv6DefaultRoute()) { 67360446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); 67460446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti } else { 67560446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); 67660446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti } 67760446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti 678323f29df583e9338e3b2bf90fc8c0785a934a61bRobin Lee mNetworkInfo.setDetailedState(DetailedState.CONNECTING, null, null); 67942065ac64cba166dc0fe602957ea8fe80bf406e2Sreeram Ramachandran 6808cd33ed84e94036a5e1201485af7603dc6fb0d9bSreeram Ramachandran NetworkMisc networkMisc = new NetworkMisc(); 68117e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee networkMisc.allowBypass = mConfig.allowBypass && !mLockdown; 68242065ac64cba166dc0fe602957ea8fe80bf406e2Sreeram Ramachandran 6836bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen long token = Binder.clearCallingIdentity(); 6844ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker try { 6856bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen mNetworkAgent = new NetworkAgent(mLooper, mContext, NETWORKTYPE, 6868cd33ed84e94036a5e1201485af7603dc6fb0d9bSreeram Ramachandran mNetworkInfo, mNetworkCapabilities, lp, 0, networkMisc) { 68705542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson @Override 6886bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen public void unwanted() { 6896bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen // We are user controlled, not driven by NetworkRequest. 69005542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson } 6916bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen }; 6924ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker } finally { 6934ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker Binder.restoreCallingIdentity(token); 6944ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker } 69542065ac64cba166dc0fe602957ea8fe80bf406e2Sreeram Ramachandran 6964d03abcd49af490dba3850d341b955dd72f24959Robin Lee mVpnUsers = createUserAndRestrictedProfilesRanges(mUserHandle, 6974d03abcd49af490dba3850d341b955dd72f24959Robin Lee mConfig.allowedApplications, mConfig.disallowedApplications); 6986bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen mNetworkAgent.addUidRanges(mVpnUsers.toArray(new UidRange[mVpnUsers.size()])); 699323f29df583e9338e3b2bf90fc8c0785a934a61bRobin Lee 700323f29df583e9338e3b2bf90fc8c0785a934a61bRobin Lee mNetworkInfo.setIsAvailable(true); 701323f29df583e9338e3b2bf90fc8c0785a934a61bRobin Lee updateState(DetailedState.CONNECTED, "agentConnect"); 7026bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 7036bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen 7041c36315a36962321dfe870b07e28b04a1d6777e9Fyodor Kupolov private boolean canHaveRestrictedProfile(int userId) { 7051c36315a36962321dfe870b07e28b04a1d6777e9Fyodor Kupolov long token = Binder.clearCallingIdentity(); 7061c36315a36962321dfe870b07e28b04a1d6777e9Fyodor Kupolov try { 7071c36315a36962321dfe870b07e28b04a1d6777e9Fyodor Kupolov return UserManager.get(mContext).canHaveRestrictedProfile(userId); 7081c36315a36962321dfe870b07e28b04a1d6777e9Fyodor Kupolov } finally { 7091c36315a36962321dfe870b07e28b04a1d6777e9Fyodor Kupolov Binder.restoreCallingIdentity(token); 7101c36315a36962321dfe870b07e28b04a1d6777e9Fyodor Kupolov } 7111c36315a36962321dfe870b07e28b04a1d6777e9Fyodor Kupolov } 7121c36315a36962321dfe870b07e28b04a1d6777e9Fyodor Kupolov 7131a405fe300950d6ceae2166fd074b596d8110dbeTony Mak private void agentDisconnect(NetworkAgent networkAgent) { 7146bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen if (networkAgent != null) { 7151a405fe300950d6ceae2166fd074b596d8110dbeTony Mak NetworkInfo networkInfo = new NetworkInfo(mNetworkInfo); 7161a405fe300950d6ceae2166fd074b596d8110dbeTony Mak networkInfo.setIsAvailable(false); 7171a405fe300950d6ceae2166fd074b596d8110dbeTony Mak networkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null); 7186bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen networkAgent.sendNetworkInfo(networkInfo); 7196bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 7206bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 7216bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen 7226bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen private void agentDisconnect() { 7236bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen if (mNetworkInfo.isConnected()) { 7241a405fe300950d6ceae2166fd074b596d8110dbeTony Mak mNetworkInfo.setIsAvailable(false); 7251a405fe300950d6ceae2166fd074b596d8110dbeTony Mak updateState(DetailedState.DISCONNECTED, "agentDisconnect"); 7266bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen mNetworkAgent = null; 7276bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 728fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh } 729fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh 730fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh /** 731e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh * Establish a VPN network and return the file descriptor of the VPN 732e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh * interface. This methods returns {@code null} if the application is 733100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * revoked or not prepared. 734ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * 735e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh * @param config The parameters to configure the network. 736e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh * @return The file descriptor of the VPN interface. 737ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh */ 73804ba25c418bc4538e9dc0f047cfb9608d358f679Chia-chi Yeh public synchronized ParcelFileDescriptor establish(VpnConfig config) { 739ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh // Check if the caller is already prepared. 740c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker UserManager mgr = UserManager.get(mContext); 7416bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen if (Binder.getCallingUid() != mOwnerUID) { 7427b0b834c3d12564c44ac134879a6dbc70e74be6eChia-chi Yeh return null; 743ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 7440a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson // Check to ensure consent hasn't been revoked since we were prepared. 7450a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson if (!isVpnUserPreConsented(mPackage)) { 7460a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson return null; 7470a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson } 748fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh // Check if the service is properly declared. 749199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh Intent intent = new Intent(VpnConfig.SERVICE_INTERFACE); 750199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh intent.setClassName(mPackage, config.user); 7514ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker long token = Binder.clearCallingIdentity(); 7524ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker try { 753c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker // Restricted users are not allowed to create VPNs, they are tied to Owner 7540784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen UserInfo user = mgr.getUserInfo(mUserHandle); 755628ae0d84180c5f7c52725e02506021e532ed252Robin Lee if (user.isRestricted()) { 756c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker throw new SecurityException("Restricted users cannot establish VPNs"); 757c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker } 758c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker 7594ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker ResolveInfo info = AppGlobals.getPackageManager().resolveService(intent, 7600784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen null, 0, mUserHandle); 7614ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker if (info == null) { 7624ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker throw new SecurityException("Cannot find " + config.user); 7634ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker } 7644ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker if (!BIND_VPN_SERVICE.equals(info.serviceInfo.permission)) { 7654ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker throw new SecurityException(config.user + " does not require " + BIND_VPN_SERVICE); 7664ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker } 7674ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker } catch (RemoteException e) { 7684ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker throw new SecurityException("Cannot find " + config.user); 7694ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker } finally { 7704ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker Binder.restoreCallingIdentity(token); 771199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh } 772fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh 7734c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker // Save the old config in case we need to go back. 7744c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker VpnConfig oldConfig = mConfig; 7754c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker String oldInterface = mInterface; 7764c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker Connection oldConnection = mConnection; 7776bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen NetworkAgent oldNetworkAgent = mNetworkAgent; 7786bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen mNetworkAgent = null; 7794d03abcd49af490dba3850d341b955dd72f24959Robin Lee Set<UidRange> oldUsers = mVpnUsers; 7804c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker 781e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh // Configure the interface. Abort if any of these steps fails. 78297a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh ParcelFileDescriptor tun = ParcelFileDescriptor.adoptFd(jniCreate(config.mtu)); 783ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh try { 784899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey updateState(DetailedState.CONNECTING, "establish"); 785c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh String interfaze = jniGetName(tun.getFd()); 7864ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker 787c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker // TEMP use the old jni calls until there is support for netd address setting 7884ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker StringBuilder builder = new StringBuilder(); 7894ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker for (LinkAddress address : config.addresses) { 7904ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker builder.append(" " + address); 79197a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh } 7924ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker if (jniSetAddresses(interfaze, builder.toString()) < 1) { 7934ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker throw new IllegalArgumentException("At least one address must be specified"); 79497a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh } 795199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh Connection connection = new Connection(); 796d69e4c1460017062e7c36be55801cb434ad19d97Dianne Hackborn if (!mContext.bindServiceAsUser(intent, connection, 797d69e4c1460017062e7c36be55801cb434ad19d97Dianne Hackborn Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE, 798d69e4c1460017062e7c36be55801cb434ad19d97Dianne Hackborn new UserHandle(mUserHandle))) { 799199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh throw new IllegalStateException("Cannot bind " + config.user); 800199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh } 8014c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker 802199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh mConnection = connection; 803c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh mInterface = interfaze; 8044ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker 8054ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker // Fill more values. 8064ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker config.user = mPackage; 8074ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker config.interfaze = mInterface; 808c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker config.startTime = SystemClock.elapsedRealtime(); 809c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker mConfig = config; 8104c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker 8114ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker // Set up forwarding and DNS rules. 8126bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen agentConnect(); 8134ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker 8144c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker if (oldConnection != null) { 8154c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker mContext.unbindService(oldConnection); 8164c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker } 8176bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen // Remove the old tun's user forwarding rules 8186bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen // The new tun's user rules have already been added so they will take over 8196bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen // as rules are deleted. This prevents data leakage as the rules are moved over. 8206bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen agentDisconnect(oldNetworkAgent); 8214c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker if (oldInterface != null && !oldInterface.equals(interfaze)) { 8224c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker jniReset(oldInterface); 8234c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker } 8246bbf39cf6b81222f32d2b66b8fa85d562e0ad71cJeff Davidson 8256bbf39cf6b81222f32d2b66b8fa85d562e0ad71cJeff Davidson try { 8266bbf39cf6b81222f32d2b66b8fa85d562e0ad71cJeff Davidson IoUtils.setBlocking(tun.getFileDescriptor(), config.blocking); 8276bbf39cf6b81222f32d2b66b8fa85d562e0ad71cJeff Davidson } catch (IOException e) { 8286bbf39cf6b81222f32d2b66b8fa85d562e0ad71cJeff Davidson throw new IllegalStateException( 8296bbf39cf6b81222f32d2b66b8fa85d562e0ad71cJeff Davidson "Cannot set tunnel's fd as blocking=" + config.blocking, e); 8306bbf39cf6b81222f32d2b66b8fa85d562e0ad71cJeff Davidson } 831ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } catch (RuntimeException e) { 832065b299df4159602327977dd007cb2cd6b64ab20Jeff Sharkey IoUtils.closeQuietly(tun); 8336bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen agentDisconnect(); 8344c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker // restore old state 8354c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker mConfig = oldConfig; 8364c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker mConnection = oldConnection; 8374c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker mVpnUsers = oldUsers; 8386bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen mNetworkAgent = oldNetworkAgent; 8394c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker mInterface = oldInterface; 840ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh throw e; 841ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 842199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh Log.i(TAG, "Established by " + config.user + " on " + mInterface); 843c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh return tun; 844ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 845ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 846c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker private boolean isRunningLocked() { 847c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran return mNetworkAgent != null && mInterface != null; 848c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran } 849c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran 850c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran // Returns true if the VPN has been established and the calling UID is its owner. Used to check 851c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran // that a call to mutate VPN state is admissible. 852c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran private boolean isCallerEstablishedOwnerLocked() { 853c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran return isRunningLocked() && Binder.getCallingUid() == mOwnerUID; 854c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker } 855c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker 8560784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen // Note: Return type guarantees results are deduped and sorted, which callers require. 8570784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen private SortedSet<Integer> getAppsUids(List<String> packageNames, int userHandle) { 8580784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen SortedSet<Integer> uids = new TreeSet<Integer>(); 8590784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen for (String app : packageNames) { 8600784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen int uid = getAppUid(app, userHandle); 8610784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen if (uid != -1) uids.add(uid); 8620784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen } 8630784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen return uids; 8640784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen } 8650784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen 8664d03abcd49af490dba3850d341b955dd72f24959Robin Lee /** 8674d03abcd49af490dba3850d341b955dd72f24959Robin Lee * Creates a {@link Set} of non-intersecting {@link UidRange} objects including all UIDs 8684d03abcd49af490dba3850d341b955dd72f24959Robin Lee * associated with one user, and any restricted profiles attached to that user. 8694d03abcd49af490dba3850d341b955dd72f24959Robin Lee * 8704d03abcd49af490dba3850d341b955dd72f24959Robin Lee * <p>If one of {@param allowedApplications} or {@param disallowedApplications} is provided, 8714d03abcd49af490dba3850d341b955dd72f24959Robin Lee * the UID ranges will match the app whitelist or blacklist specified there. Otherwise, all UIDs 8724d03abcd49af490dba3850d341b955dd72f24959Robin Lee * in each user and profile will be included. 8734d03abcd49af490dba3850d341b955dd72f24959Robin Lee * 8744d03abcd49af490dba3850d341b955dd72f24959Robin Lee * @param userHandle The userId to create UID ranges for along with any of its restricted 8754d03abcd49af490dba3850d341b955dd72f24959Robin Lee * profiles. 8764d03abcd49af490dba3850d341b955dd72f24959Robin Lee * @param allowedApplications (optional) whitelist of applications to include. 8774d03abcd49af490dba3850d341b955dd72f24959Robin Lee * @param disallowedApplications (optional) blacklist of applications to exclude. 8784d03abcd49af490dba3850d341b955dd72f24959Robin Lee */ 8794d03abcd49af490dba3850d341b955dd72f24959Robin Lee @VisibleForTesting 8804d03abcd49af490dba3850d341b955dd72f24959Robin Lee Set<UidRange> createUserAndRestrictedProfilesRanges(@UserIdInt int userHandle, 8814d03abcd49af490dba3850d341b955dd72f24959Robin Lee @Nullable List<String> allowedApplications, 8824d03abcd49af490dba3850d341b955dd72f24959Robin Lee @Nullable List<String> disallowedApplications) { 8834d03abcd49af490dba3850d341b955dd72f24959Robin Lee final Set<UidRange> ranges = new ArraySet<>(); 8844d03abcd49af490dba3850d341b955dd72f24959Robin Lee 8854d03abcd49af490dba3850d341b955dd72f24959Robin Lee // Assign the top-level user to the set of ranges 8864d03abcd49af490dba3850d341b955dd72f24959Robin Lee addUserToRanges(ranges, userHandle, allowedApplications, disallowedApplications); 8874d03abcd49af490dba3850d341b955dd72f24959Robin Lee 8884d03abcd49af490dba3850d341b955dd72f24959Robin Lee // If the user can have restricted profiles, assign all its restricted profiles too 8894d03abcd49af490dba3850d341b955dd72f24959Robin Lee if (canHaveRestrictedProfile(userHandle)) { 8904d03abcd49af490dba3850d341b955dd72f24959Robin Lee final long token = Binder.clearCallingIdentity(); 8914d03abcd49af490dba3850d341b955dd72f24959Robin Lee List<UserInfo> users; 8924d03abcd49af490dba3850d341b955dd72f24959Robin Lee try { 89317e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee users = UserManager.get(mContext).getUsers(true); 8944d03abcd49af490dba3850d341b955dd72f24959Robin Lee } finally { 8954d03abcd49af490dba3850d341b955dd72f24959Robin Lee Binder.restoreCallingIdentity(token); 8964d03abcd49af490dba3850d341b955dd72f24959Robin Lee } 8974d03abcd49af490dba3850d341b955dd72f24959Robin Lee for (UserInfo user : users) { 8984d03abcd49af490dba3850d341b955dd72f24959Robin Lee if (user.isRestricted() && (user.restrictedProfileParentId == userHandle)) { 8994d03abcd49af490dba3850d341b955dd72f24959Robin Lee addUserToRanges(ranges, user.id, allowedApplications, disallowedApplications); 9004d03abcd49af490dba3850d341b955dd72f24959Robin Lee } 9014d03abcd49af490dba3850d341b955dd72f24959Robin Lee } 902c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker } 9034d03abcd49af490dba3850d341b955dd72f24959Robin Lee return ranges; 9044d03abcd49af490dba3850d341b955dd72f24959Robin Lee } 90569887e838814642a7ae78fc810656c7c8afc2a19Robert Greenwalt 9064d03abcd49af490dba3850d341b955dd72f24959Robin Lee /** 9074d03abcd49af490dba3850d341b955dd72f24959Robin Lee * Updates a {@link Set} of non-intersecting {@link UidRange} objects to include all UIDs 9084d03abcd49af490dba3850d341b955dd72f24959Robin Lee * associated with one user. 9094d03abcd49af490dba3850d341b955dd72f24959Robin Lee * 9104d03abcd49af490dba3850d341b955dd72f24959Robin Lee * <p>If one of {@param allowedApplications} or {@param disallowedApplications} is provided, 9114d03abcd49af490dba3850d341b955dd72f24959Robin Lee * the UID ranges will match the app whitelist or blacklist specified there. Otherwise, all UIDs 9124d03abcd49af490dba3850d341b955dd72f24959Robin Lee * in the user will be included. 9134d03abcd49af490dba3850d341b955dd72f24959Robin Lee * 9144d03abcd49af490dba3850d341b955dd72f24959Robin Lee * @param ranges {@link Set} of {@link UidRange}s to which to add. 9154d03abcd49af490dba3850d341b955dd72f24959Robin Lee * @param userHandle The userId to add to {@param ranges}. 9164d03abcd49af490dba3850d341b955dd72f24959Robin Lee * @param allowedApplications (optional) whitelist of applications to include. 9174d03abcd49af490dba3850d341b955dd72f24959Robin Lee * @param disallowedApplications (optional) blacklist of applications to exclude. 9184d03abcd49af490dba3850d341b955dd72f24959Robin Lee */ 9194d03abcd49af490dba3850d341b955dd72f24959Robin Lee @VisibleForTesting 9204d03abcd49af490dba3850d341b955dd72f24959Robin Lee void addUserToRanges(@NonNull Set<UidRange> ranges, @UserIdInt int userHandle, 9214d03abcd49af490dba3850d341b955dd72f24959Robin Lee @Nullable List<String> allowedApplications, 9224d03abcd49af490dba3850d341b955dd72f24959Robin Lee @Nullable List<String> disallowedApplications) { 9234d03abcd49af490dba3850d341b955dd72f24959Robin Lee if (allowedApplications != null) { 9240784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen // Add ranges covering all UIDs for allowedApplications. 9250784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen int start = -1, stop = -1; 9264d03abcd49af490dba3850d341b955dd72f24959Robin Lee for (int uid : getAppsUids(allowedApplications, userHandle)) { 9270784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen if (start == -1) { 9280784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen start = uid; 9290784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen } else if (uid != stop + 1) { 9304d03abcd49af490dba3850d341b955dd72f24959Robin Lee ranges.add(new UidRange(start, stop)); 9310784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen start = uid; 9320784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen } 9330784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen stop = uid; 9340784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen } 9354d03abcd49af490dba3850d341b955dd72f24959Robin Lee if (start != -1) ranges.add(new UidRange(start, stop)); 9364d03abcd49af490dba3850d341b955dd72f24959Robin Lee } else if (disallowedApplications != null) { 9370784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen // Add all ranges for user skipping UIDs for disallowedApplications. 9380784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen final UidRange userRange = UidRange.createForUser(userHandle); 9390784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen int start = userRange.start; 9404d03abcd49af490dba3850d341b955dd72f24959Robin Lee for (int uid : getAppsUids(disallowedApplications, userHandle)) { 9410784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen if (uid == start) { 9420784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen start++; 9430784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen } else { 9444d03abcd49af490dba3850d341b955dd72f24959Robin Lee ranges.add(new UidRange(start, uid - 1)); 9450784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen start = uid + 1; 9460784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen } 9470784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen } 9484d03abcd49af490dba3850d341b955dd72f24959Robin Lee if (start <= userRange.stop) ranges.add(new UidRange(start, userRange.stop)); 9490784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen } else { 9500784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen // Add all UIDs for the user. 9514d03abcd49af490dba3850d341b955dd72f24959Robin Lee ranges.add(UidRange.createForUser(userHandle)); 9520784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen } 953c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker } 954c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker 9550784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen // Returns the subset of the full list of active UID ranges the VPN applies to (mVpnUsers) that 9560784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen // apply to userHandle. 9570784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen private List<UidRange> uidRangesForUser(int userHandle) { 9580784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen final UidRange userRange = UidRange.createForUser(userHandle); 9590784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen final List<UidRange> ranges = new ArrayList<UidRange>(); 9600784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen for (UidRange range : mVpnUsers) { 9614d03abcd49af490dba3850d341b955dd72f24959Robin Lee if (userRange.containsRange(range)) { 9620784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen ranges.add(range); 9630784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen } 9640784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen } 9650784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen return ranges; 9660784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen } 9670784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen 9680784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen private void removeVpnUserLocked(int userHandle) { 969c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran if (mVpnUsers == null) { 97090b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson throw new IllegalStateException("VPN is not active"); 97190b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson } 9720784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen final List<UidRange> ranges = uidRangesForUser(userHandle); 97390b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson if (mNetworkAgent != null) { 9740784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen mNetworkAgent.removeUidRanges(ranges.toArray(new UidRange[ranges.size()])); 97590b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson } 9760784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen mVpnUsers.removeAll(ranges); 977c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker } 978c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker 9791c36315a36962321dfe870b07e28b04a1d6777e9Fyodor Kupolov public void onUserAdded(int userHandle) { 9801c36315a36962321dfe870b07e28b04a1d6777e9Fyodor Kupolov // If the user is restricted tie them to the parent user's VPN 9811c36315a36962321dfe870b07e28b04a1d6777e9Fyodor Kupolov UserInfo user = UserManager.get(mContext).getUserInfo(userHandle); 98217e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee if (user.isRestricted() && user.restrictedProfileParentId == mUserHandle) { 9831c36315a36962321dfe870b07e28b04a1d6777e9Fyodor Kupolov synchronized(Vpn.this) { 98417e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee if (mVpnUsers != null) { 98517e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee try { 98617e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee addUserToRanges(mVpnUsers, userHandle, mConfig.allowedApplications, 98717e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee mConfig.disallowedApplications); 98817e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee if (mNetworkAgent != null) { 98917e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee final List<UidRange> ranges = uidRangesForUser(userHandle); 99017e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee mNetworkAgent.addUidRanges(ranges.toArray(new UidRange[ranges.size()])); 99117e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee } 99217e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee } catch (Exception e) { 99317e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee Log.wtf(TAG, "Failed to add restricted user to owner", e); 9946bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 99517e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee } 99617e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee if (mAlwaysOn) { 99717e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee setVpnForcedLocked(mLockdown); 998c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker } 999c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker } 1000c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker } 1001c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker } 1002c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker 10031c36315a36962321dfe870b07e28b04a1d6777e9Fyodor Kupolov public void onUserRemoved(int userHandle) { 1004c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker // clean up if restricted 10051c36315a36962321dfe870b07e28b04a1d6777e9Fyodor Kupolov UserInfo user = UserManager.get(mContext).getUserInfo(userHandle); 100617e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee if (user.isRestricted() && user.restrictedProfileParentId == mUserHandle) { 10071c36315a36962321dfe870b07e28b04a1d6777e9Fyodor Kupolov synchronized(Vpn.this) { 100817e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee if (mVpnUsers != null) { 100917e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee try { 101017e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee removeVpnUserLocked(userHandle); 101117e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee } catch (Exception e) { 101217e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee Log.wtf(TAG, "Failed to remove restricted user to owner", e); 101317e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee } 101417e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee } 101517e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee if (mAlwaysOn) { 101617e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee setVpnForcedLocked(mLockdown); 1017c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker } 1018c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker } 1019c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker } 1020c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker } 1021c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker 1022bf6ff2c025405a3af496fe558dfc4468a9b45cc8Chad Brubaker /** 102317e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * Called when the user associated with this VPN has just been stopped. 102417e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee */ 102517e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee public synchronized void onUserStopped() { 102617e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee // Switch off networking lockdown (if it was enabled) 102717e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee setVpnForcedLocked(false); 102817e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee mAlwaysOn = false; 102917e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee 1030812800cb92090db31f609b907c4458ba76cf7f42Robin Lee unregisterPackageChangeReceiverLocked(); 103117e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee // Quit any active connections 103217e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee agentDisconnect(); 103317e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee } 103417e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee 103517e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee /** 103617e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * Restrict network access from all UIDs affected by this {@link Vpn}, apart from the VPN 103717e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * service app itself, to only sockets that have had {@code protect()} called on them. All 103817e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * non-VPN traffic is blocked via a {@code PROHIBIT} response from the kernel. 103917e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * 104017e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * The exception for the VPN UID isn't technically necessary -- setup should use protected 104117e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * sockets -- but in practice it saves apps that don't protect their sockets from breaking. 104217e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * 104317e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * Calling multiple times with {@param enforce} = {@code true} will recreate the set of UIDs to 104417e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * block every time, and if anything has changed update using {@link #setAllowOnlyVpnForUids}. 104517e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * 104617e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * @param enforce {@code true} to require that all traffic under the jurisdiction of this 104717e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * {@link Vpn} goes through a VPN connection or is blocked until one is 104817e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * available, {@code false} to lift the requirement. 104917e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * 105017e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * @see #mBlockedUsers 105117e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee */ 105217e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee @GuardedBy("this") 105317e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee private void setVpnForcedLocked(boolean enforce) { 105417e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee final Set<UidRange> removedRanges = new ArraySet<>(mBlockedUsers); 105517e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee if (enforce) { 105617e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee final Set<UidRange> addedRanges = createUserAndRestrictedProfilesRanges(mUserHandle, 105717e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee /* allowedApplications */ null, 105817e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee /* disallowedApplications */ Collections.singletonList(mPackage)); 105917e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee 106017e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee removedRanges.removeAll(addedRanges); 106117e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee addedRanges.removeAll(mBlockedUsers); 106217e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee 106317e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee setAllowOnlyVpnForUids(false, removedRanges); 106417e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee setAllowOnlyVpnForUids(true, addedRanges); 106517e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee } else { 106617e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee setAllowOnlyVpnForUids(false, removedRanges); 106717e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee } 106817e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee } 106917e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee 107017e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee /** 107117e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * Either add or remove a list of {@link UidRange}s to the list of UIDs that are only allowed 107217e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * to make connections through sockets that have had {@code protect()} called on them. 107317e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * 107417e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * @param enforce {@code true} to add to the blacklist, {@code false} to remove. 107517e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * @param ranges {@link Collection} of {@link UidRange}s to add (if {@param enforce} is 107617e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * {@code true}) or to remove. 107717e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * @return {@code true} if all of the UIDs were added/removed. {@code false} otherwise, 107817e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * including added ranges that already existed or removed ones that didn't. 107917e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee */ 108017e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee @GuardedBy("this") 108117e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee private boolean setAllowOnlyVpnForUids(boolean enforce, Collection<UidRange> ranges) { 108217e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee if (ranges.size() == 0) { 108317e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee return true; 108417e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee } 108517e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee final UidRange[] rangesArray = ranges.toArray(new UidRange[ranges.size()]); 108617e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee try { 108717e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee mNetd.setAllowOnlyVpnForUids(enforce, rangesArray); 108817e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee } catch (RemoteException | RuntimeException e) { 108917e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee Log.e(TAG, "Updating blocked=" + enforce 109017e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee + " for UIDs " + Arrays.toString(ranges.toArray()) + " failed", e); 109117e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee return false; 109217e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee } 109317e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee if (enforce) { 109417e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee mBlockedUsers.addAll(ranges); 109517e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee } else { 109617e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee mBlockedUsers.removeAll(ranges); 109717e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee } 109817e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee return true; 109917e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee } 110017e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee 110117e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee /** 1102bf6ff2c025405a3af496fe558dfc4468a9b45cc8Chad Brubaker * Return the configuration of the currently running VPN. 1103bf6ff2c025405a3af496fe558dfc4468a9b45cc8Chad Brubaker */ 1104bf6ff2c025405a3af496fe558dfc4468a9b45cc8Chad Brubaker public VpnConfig getVpnConfig() { 1105bf6ff2c025405a3af496fe558dfc4468a9b45cc8Chad Brubaker enforceControlPermission(); 1106bf6ff2c025405a3af496fe558dfc4468a9b45cc8Chad Brubaker return mConfig; 1107bf6ff2c025405a3af496fe558dfc4468a9b45cc8Chad Brubaker } 1108bf6ff2c025405a3af496fe558dfc4468a9b45cc8Chad Brubaker 1109899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey @Deprecated 1110899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey public synchronized void interfaceStatusChanged(String iface, boolean up) { 1111899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey try { 1112899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey mObserver.interfaceStatusChanged(iface, up); 1113899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } catch (RemoteException e) { 1114899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey // ignored; target is local 1115aa1727fe0cbb902c5f53a3fae601b4e15da0a2f4Chia-chi Yeh } 1116ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 1117ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 1118899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey private INetworkManagementEventObserver mObserver = new BaseNetworkObserver() { 1119899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey @Override 1120899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey public void interfaceStatusChanged(String interfaze, boolean up) { 1121899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey synchronized (Vpn.this) { 1122899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey if (!up && mLegacyVpnRunner != null) { 1123899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey mLegacyVpnRunner.check(interfaze); 1124899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } 1125199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh } 1126ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 1127ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 1128899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey @Override 1129899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey public void interfaceRemoved(String interfaze) { 1130899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey synchronized (Vpn.this) { 1131899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey if (interfaze.equals(mInterface) && jniCheck(interfaze) == 0) { 113290b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson mStatusIntent = null; 11336bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen mVpnUsers = null; 1134c4c7231eb6d1efa9ecd7b693f8328a76a04e8bbbPaul Jensen mConfig = null; 1135899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey mInterface = null; 1136899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey if (mConnection != null) { 1137899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey mContext.unbindService(mConnection); 1138899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey mConnection = null; 11396bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen agentDisconnect(); 1140899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } else if (mLegacyVpnRunner != null) { 1141899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey mLegacyVpnRunner.exit(); 1142899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey mLegacyVpnRunner = null; 1143899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } 1144899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } 1145899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } 1146899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } 1147899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey }; 1148db3c8678e5cbdfec011afaf25bde2091152c30adHaoyu Bai 1149dadc857d9de364fded10d4f69eb82bc9cd35d4b7Chia-chi Yeh private void enforceControlPermission() { 1150bc19c181c8c058c824e4fee907a05129e142c388Jeff Davidson mContext.enforceCallingPermission(Manifest.permission.CONTROL_VPN, "Unauthorized Caller"); 1151dadc857d9de364fded10d4f69eb82bc9cd35d4b7Chia-chi Yeh } 1152dadc857d9de364fded10d4f69eb82bc9cd35d4b7Chia-chi Yeh 1153244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee private void enforceControlPermissionOrInternalCaller() { 1154244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee // Require caller to be either an application with CONTROL_VPN permission or a process 1155244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee // in the system server. 1156244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee mContext.enforceCallingOrSelfPermission(Manifest.permission.CONTROL_VPN, 1157244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee "Unauthorized Caller"); 1158244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee } 1159244ce8ef5f201cf403bab43df8281671a9e94512Robin Lee 1160199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh private class Connection implements ServiceConnection { 1161199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh private IBinder mService; 1162199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh 1163199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh @Override 1164199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh public void onServiceConnected(ComponentName name, IBinder service) { 1165199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh mService = service; 1166199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh } 1167199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh 1168199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh @Override 1169199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh public void onServiceDisconnected(ComponentName name) { 1170199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh mService = null; 1171199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh } 1172199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh } 1173199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh 117490b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson private void prepareStatusIntent() { 117590b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson final long token = Binder.clearCallingIdentity(); 117690b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson try { 117790b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson mStatusIntent = VpnConfig.getIntentForStatusPanel(mContext); 117890b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson } finally { 117990b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson Binder.restoreCallingIdentity(token); 118090b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson } 118190b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson } 118290b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson 1183f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandran public synchronized boolean addAddress(String address, int prefixLength) { 1184c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran if (!isCallerEstablishedOwnerLocked()) { 1185f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandran return false; 1186f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandran } 1187f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandran boolean success = jniAddAddress(mInterface, address, prefixLength); 1188c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran mNetworkAgent.sendLinkProperties(makeLinkProperties()); 1189f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandran return success; 1190f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandran } 1191f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandran 1192f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandran public synchronized boolean removeAddress(String address, int prefixLength) { 1193c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran if (!isCallerEstablishedOwnerLocked()) { 1194f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandran return false; 1195f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandran } 1196f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandran boolean success = jniDelAddress(mInterface, address, prefixLength); 1197c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran mNetworkAgent.sendLinkProperties(makeLinkProperties()); 1198f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandran return success; 1199f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandran } 1200f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandran 1201c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran public synchronized boolean setUnderlyingNetworks(Network[] networks) { 1202c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran if (!isCallerEstablishedOwnerLocked()) { 1203c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran return false; 1204c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran } 1205c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran if (networks == null) { 1206c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran mConfig.underlyingNetworks = null; 1207c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran } else { 1208c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran mConfig.underlyingNetworks = new Network[networks.length]; 1209c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran for (int i = 0; i < networks.length; ++i) { 1210c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran if (networks[i] == null) { 1211c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran mConfig.underlyingNetworks[i] = null; 1212c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran } else { 1213c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran mConfig.underlyingNetworks[i] = new Network(networks[i].netId); 1214c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran } 1215c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran } 1216c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran } 1217c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran return true; 1218c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran } 1219c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran 1220c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran public synchronized Network[] getUnderlyingNetworks() { 1221c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran if (!isRunningLocked()) { 1222c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran return null; 1223c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran } 1224c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran return mConfig.underlyingNetworks; 1225c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran } 1226c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran 1227f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong /** 1228f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong * This method should only be called by ConnectivityService. Because it doesn't 1229f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong * have enough data to fill VpnInfo.primaryUnderlyingIface field. 1230f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong */ 1231f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong public synchronized VpnInfo getVpnInfo() { 1232f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong if (!isRunningLocked()) { 1233f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong return null; 1234f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong } 1235f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong 1236f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong VpnInfo info = new VpnInfo(); 1237f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong info.ownerUid = mOwnerUID; 1238f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong info.vpnIface = mInterface; 1239f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong return info; 1240f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong } 1241f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong 1242c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran public synchronized boolean appliesToUid(int uid) { 1243c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran if (!isRunningLocked()) { 1244c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran return false; 1245c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran } 1246c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran for (UidRange uidRange : mVpnUsers) { 12474d03abcd49af490dba3850d341b955dd72f24959Robin Lee if (uidRange.contains(uid)) { 1248c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran return true; 1249c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran } 1250c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran } 1251c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran return false; 1252c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran } 1253c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran 125417e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee /** 1255ebbcb54a4380239ea3d0c4d1a20cd6b3c9ec0590Robin Lee * @return {@code true} if {@param uid} is blocked by an always-on VPN. 1256ebbcb54a4380239ea3d0c4d1a20cd6b3c9ec0590Robin Lee * A UID is blocked if it's included in one of the mBlockedUsers ranges and the VPN is 1257ebbcb54a4380239ea3d0c4d1a20cd6b3c9ec0590Robin Lee * not connected, or if the VPN is connected but does not apply to the UID. 125817e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * 125917e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee * @see #mBlockedUsers 126017e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee */ 126117e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee public synchronized boolean isBlockingUid(int uid) { 1262ebbcb54a4380239ea3d0c4d1a20cd6b3c9ec0590Robin Lee if (!mLockdown) { 1263ebbcb54a4380239ea3d0c4d1a20cd6b3c9ec0590Robin Lee return false; 1264ebbcb54a4380239ea3d0c4d1a20cd6b3c9ec0590Robin Lee } 1265ebbcb54a4380239ea3d0c4d1a20cd6b3c9ec0590Robin Lee 1266ebbcb54a4380239ea3d0c4d1a20cd6b3c9ec0590Robin Lee if (mNetworkInfo.isConnected()) { 1267ebbcb54a4380239ea3d0c4d1a20cd6b3c9ec0590Robin Lee return !appliesToUid(uid); 1268ebbcb54a4380239ea3d0c4d1a20cd6b3c9ec0590Robin Lee } else { 1269ebbcb54a4380239ea3d0c4d1a20cd6b3c9ec0590Robin Lee for (UidRange uidRange : mBlockedUsers) { 1270ebbcb54a4380239ea3d0c4d1a20cd6b3c9ec0590Robin Lee if (uidRange.contains(uid)) { 1271ebbcb54a4380239ea3d0c4d1a20cd6b3c9ec0590Robin Lee return true; 1272ebbcb54a4380239ea3d0c4d1a20cd6b3c9ec0590Robin Lee } 127317e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee } 1274ebbcb54a4380239ea3d0c4d1a20cd6b3c9ec0590Robin Lee return false; 127517e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee } 127617e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee } 127717e6183b85ba3038acb935aaa01415058b2e6dddRobin Lee 12781a405fe300950d6ceae2166fd074b596d8110dbeTony Mak private void updateAlwaysOnNotification(DetailedState networkState) { 12791a405fe300950d6ceae2166fd074b596d8110dbeTony Mak final boolean visible = (mAlwaysOn && networkState != DetailedState.CONNECTED); 12801a405fe300950d6ceae2166fd074b596d8110dbeTony Mak updateAlwaysOnNotificationInternal(visible); 12811a405fe300950d6ceae2166fd074b596d8110dbeTony Mak } 12821a405fe300950d6ceae2166fd074b596d8110dbeTony Mak 12831a405fe300950d6ceae2166fd074b596d8110dbeTony Mak @VisibleForTesting 12841a405fe300950d6ceae2166fd074b596d8110dbeTony Mak protected void updateAlwaysOnNotificationInternal(boolean visible) { 12851a405fe300950d6ceae2166fd074b596d8110dbeTony Mak final UserHandle user = UserHandle.of(mUserHandle); 12861a405fe300950d6ceae2166fd074b596d8110dbeTony Mak final long token = Binder.clearCallingIdentity(); 12871a405fe300950d6ceae2166fd074b596d8110dbeTony Mak try { 12881a405fe300950d6ceae2166fd074b596d8110dbeTony Mak final NotificationManager notificationManager = NotificationManager.from(mContext); 12891a405fe300950d6ceae2166fd074b596d8110dbeTony Mak if (!visible) { 129015297a67d3240157906a3fb3ed028043d7454d1aCharles He notificationManager.cancelAsUser(TAG, SystemMessage.NOTE_VPN_DISCONNECTED, user); 12911a405fe300950d6ceae2166fd074b596d8110dbeTony Mak return; 12921a405fe300950d6ceae2166fd074b596d8110dbeTony Mak } 12931a405fe300950d6ceae2166fd074b596d8110dbeTony Mak final Intent intent = new Intent(Settings.ACTION_VPN_SETTINGS); 12941a405fe300950d6ceae2166fd074b596d8110dbeTony Mak final PendingIntent configIntent = PendingIntent.getActivityAsUser( 12951a405fe300950d6ceae2166fd074b596d8110dbeTony Mak mContext, /* request */ 0, intent, 12961a405fe300950d6ceae2166fd074b596d8110dbeTony Mak PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT, 12971a405fe300950d6ceae2166fd074b596d8110dbeTony Mak null, user); 1298af759c52ce01fe6b5144957e38da956af01a217bGeoffrey Pitsch final Notification.Builder builder = 1299af759c52ce01fe6b5144957e38da956af01a217bGeoffrey Pitsch new Notification.Builder(mContext, SystemNotificationChannels.VPN) 1300af759c52ce01fe6b5144957e38da956af01a217bGeoffrey Pitsch .setSmallIcon(R.drawable.vpn_connected) 1301af759c52ce01fe6b5144957e38da956af01a217bGeoffrey Pitsch .setContentTitle(mContext.getString(R.string.vpn_lockdown_disconnected)) 1302af759c52ce01fe6b5144957e38da956af01a217bGeoffrey Pitsch .setContentText(mContext.getString(R.string.vpn_lockdown_config)) 1303af759c52ce01fe6b5144957e38da956af01a217bGeoffrey Pitsch .setContentIntent(configIntent) 1304af759c52ce01fe6b5144957e38da956af01a217bGeoffrey Pitsch .setCategory(Notification.CATEGORY_SYSTEM) 1305af759c52ce01fe6b5144957e38da956af01a217bGeoffrey Pitsch .setVisibility(Notification.VISIBILITY_PUBLIC) 1306af759c52ce01fe6b5144957e38da956af01a217bGeoffrey Pitsch .setOngoing(true) 1307af759c52ce01fe6b5144957e38da956af01a217bGeoffrey Pitsch .setColor(mContext.getColor(R.color.system_notification_accent_color)); 1308282cfefea0fbbd299839e353e6d30affdcd4a55cChris Wren notificationManager.notifyAsUser(TAG, SystemMessage.NOTE_VPN_DISCONNECTED, 1309282cfefea0fbbd299839e353e6d30affdcd4a55cChris Wren builder.build(), user); 13101a405fe300950d6ceae2166fd074b596d8110dbeTony Mak } finally { 13111a405fe300950d6ceae2166fd074b596d8110dbeTony Mak Binder.restoreCallingIdentity(token); 13121a405fe300950d6ceae2166fd074b596d8110dbeTony Mak } 13131a405fe300950d6ceae2166fd074b596d8110dbeTony Mak } 13141a405fe300950d6ceae2166fd074b596d8110dbeTony Mak 131597a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh private native int jniCreate(int mtu); 1316c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh private native String jniGetName(int tun); 131797a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh private native int jniSetAddresses(String interfaze, String addresses); 1318c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh private native void jniReset(String interfaze); 1319c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh private native int jniCheck(String interfaze); 1320f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandran private native boolean jniAddAddress(String interfaze, String address, int prefixLen); 1321f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandran private native boolean jniDelAddress(String interfaze, String address, int prefixLen); 132285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 132341fb98c8681cbe0040b8d4efc65d33717c3819f6Lorenzo Colitti private static RouteInfo findIPv4DefaultRoute(LinkProperties prop) { 132441fb98c8681cbe0040b8d4efc65d33717c3819f6Lorenzo Colitti for (RouteInfo route : prop.getAllRoutes()) { 132582f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey // Currently legacy VPN only works on IPv4. 132682f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey if (route.isDefaultRoute() && route.getGateway() instanceof Inet4Address) { 132741fb98c8681cbe0040b8d4efc65d33717c3819f6Lorenzo Colitti return route; 132882f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey } 132982f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey } 133082f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey 133141fb98c8681cbe0040b8d4efc65d33717c3819f6Lorenzo Colitti throw new IllegalStateException("Unable to find IPv4 default gateway"); 133282f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey } 133382f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey 133485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh /** 133582f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey * Start legacy VPN, controlling native daemons as needed. Creates a 133682f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey * secondary thread to perform connection work, returning quickly. 1337b21298a686b04d55ff97223dd317497845713f4bJeff Davidson * 1338b21298a686b04d55ff97223dd317497845713f4bJeff Davidson * Should only be called to respond to Binder requests as this enforces caller permission. Use 1339b21298a686b04d55ff97223dd317497845713f4bJeff Davidson * {@link #startLegacyVpnPrivileged(VpnProfile, KeyStore, LinkProperties)} to skip the 1340b21298a686b04d55ff97223dd317497845713f4bJeff Davidson * permission check only when the caller is trusted (or the call is initiated by the system). 134185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh */ 134282f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey public void startLegacyVpn(VpnProfile profile, KeyStore keyStore, LinkProperties egress) { 13435a6bdc46e2fdc8cfd930396773dd89efd19fa1f1Robert Greenwalt enforceControlPermission(); 1344b21298a686b04d55ff97223dd317497845713f4bJeff Davidson long token = Binder.clearCallingIdentity(); 1345b21298a686b04d55ff97223dd317497845713f4bJeff Davidson try { 1346b21298a686b04d55ff97223dd317497845713f4bJeff Davidson startLegacyVpnPrivileged(profile, keyStore, egress); 1347b21298a686b04d55ff97223dd317497845713f4bJeff Davidson } finally { 1348b21298a686b04d55ff97223dd317497845713f4bJeff Davidson Binder.restoreCallingIdentity(token); 1349b21298a686b04d55ff97223dd317497845713f4bJeff Davidson } 1350b21298a686b04d55ff97223dd317497845713f4bJeff Davidson } 1351b21298a686b04d55ff97223dd317497845713f4bJeff Davidson 1352b21298a686b04d55ff97223dd317497845713f4bJeff Davidson /** 1353b21298a686b04d55ff97223dd317497845713f4bJeff Davidson * Like {@link #startLegacyVpn(VpnProfile, KeyStore, LinkProperties)}, but does not check 1354b21298a686b04d55ff97223dd317497845713f4bJeff Davidson * permissions under the assumption that the caller is the system. 1355b21298a686b04d55ff97223dd317497845713f4bJeff Davidson * 1356b21298a686b04d55ff97223dd317497845713f4bJeff Davidson * Callers are responsible for checking permissions if needed. 1357b21298a686b04d55ff97223dd317497845713f4bJeff Davidson */ 1358b21298a686b04d55ff97223dd317497845713f4bJeff Davidson public void startLegacyVpnPrivileged(VpnProfile profile, KeyStore keyStore, 1359b21298a686b04d55ff97223dd317497845713f4bJeff Davidson LinkProperties egress) { 1360f5116d01b20f21ba32cd9eaa3412daf97f41c623Julia Reynolds UserManager mgr = UserManager.get(mContext); 13610784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen UserInfo user = mgr.getUserInfo(mUserHandle); 136295778ffc58979d19ff9f4aaed396a6eca49cf698Nicolas Prevot if (user.isRestricted() || mgr.hasUserRestriction(UserManager.DISALLOW_CONFIG_VPN, 136395778ffc58979d19ff9f4aaed396a6eca49cf698Nicolas Prevot new UserHandle(mUserHandle))) { 1364f5116d01b20f21ba32cd9eaa3412daf97f41c623Julia Reynolds throw new SecurityException("Restricted users cannot establish VPNs"); 1365f5116d01b20f21ba32cd9eaa3412daf97f41c623Julia Reynolds } 136682f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey 136741fb98c8681cbe0040b8d4efc65d33717c3819f6Lorenzo Colitti final RouteInfo ipv4DefaultRoute = findIPv4DefaultRoute(egress); 136841fb98c8681cbe0040b8d4efc65d33717c3819f6Lorenzo Colitti final String gateway = ipv4DefaultRoute.getGateway().getHostAddress(); 136941fb98c8681cbe0040b8d4efc65d33717c3819f6Lorenzo Colitti final String iface = ipv4DefaultRoute.getInterface(); 137082f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey 137182f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey // Load certificates. 137282f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey String privateKey = ""; 137382f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey String userCert = ""; 137482f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey String caCert = ""; 137582f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey String serverCert = ""; 137682f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey if (!profile.ipsecUserCert.isEmpty()) { 137782f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey privateKey = Credentials.USER_PRIVATE_KEY + profile.ipsecUserCert; 137882f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey byte[] value = keyStore.get(Credentials.USER_CERTIFICATE + profile.ipsecUserCert); 1379d396a448b2e36e29598c954b64bfddef73f3fae0Elliott Hughes userCert = (value == null) ? null : new String(value, StandardCharsets.UTF_8); 138082f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey } 138182f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey if (!profile.ipsecCaCert.isEmpty()) { 138282f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey byte[] value = keyStore.get(Credentials.CA_CERTIFICATE + profile.ipsecCaCert); 1383d396a448b2e36e29598c954b64bfddef73f3fae0Elliott Hughes caCert = (value == null) ? null : new String(value, StandardCharsets.UTF_8); 138482f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey } 138582f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey if (!profile.ipsecServerCert.isEmpty()) { 138682f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey byte[] value = keyStore.get(Credentials.USER_CERTIFICATE + profile.ipsecServerCert); 1387d396a448b2e36e29598c954b64bfddef73f3fae0Elliott Hughes serverCert = (value == null) ? null : new String(value, StandardCharsets.UTF_8); 138882f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey } 138982f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey if (privateKey == null || userCert == null || caCert == null || serverCert == null) { 139082f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey throw new IllegalStateException("Cannot load credentials"); 139182f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey } 139282f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey 139382f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey // Prepare arguments for racoon. 139482f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey String[] racoon = null; 139582f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey switch (profile.type) { 139682f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey case VpnProfile.TYPE_L2TP_IPSEC_PSK: 139782f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey racoon = new String[] { 139882f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey iface, profile.server, "udppsk", profile.ipsecIdentifier, 139982f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey profile.ipsecSecret, "1701", 140082f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey }; 140182f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey break; 140282f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey case VpnProfile.TYPE_L2TP_IPSEC_RSA: 140382f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey racoon = new String[] { 140482f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey iface, profile.server, "udprsa", privateKey, userCert, 140582f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey caCert, serverCert, "1701", 140682f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey }; 140782f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey break; 140882f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey case VpnProfile.TYPE_IPSEC_XAUTH_PSK: 140982f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey racoon = new String[] { 141082f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey iface, profile.server, "xauthpsk", profile.ipsecIdentifier, 141182f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey profile.ipsecSecret, profile.username, profile.password, "", gateway, 141282f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey }; 141382f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey break; 141482f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey case VpnProfile.TYPE_IPSEC_XAUTH_RSA: 141582f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey racoon = new String[] { 141682f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey iface, profile.server, "xauthrsa", privateKey, userCert, 141782f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey caCert, serverCert, profile.username, profile.password, "", gateway, 141882f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey }; 141982f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey break; 142082f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey case VpnProfile.TYPE_IPSEC_HYBRID_RSA: 142182f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey racoon = new String[] { 142282f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey iface, profile.server, "hybridrsa", 142382f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey caCert, serverCert, profile.username, profile.password, "", gateway, 142482f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey }; 142582f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey break; 142682f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey } 142782f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey 142882f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey // Prepare arguments for mtpd. 142982f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey String[] mtpd = null; 143082f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey switch (profile.type) { 143182f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey case VpnProfile.TYPE_PPTP: 143282f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey mtpd = new String[] { 143382f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey iface, "pptp", profile.server, "1723", 143482f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey "name", profile.username, "password", profile.password, 143582f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey "linkname", "vpn", "refuse-eap", "nodefaultroute", 143682f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey "usepeerdns", "idle", "1800", "mtu", "1400", "mru", "1400", 143782f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey (profile.mppe ? "+mppe" : "nomppe"), 143882f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey }; 143982f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey break; 144082f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey case VpnProfile.TYPE_L2TP_IPSEC_PSK: 144182f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey case VpnProfile.TYPE_L2TP_IPSEC_RSA: 144282f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey mtpd = new String[] { 144382f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey iface, "l2tp", profile.server, "1701", profile.l2tpSecret, 144482f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey "name", profile.username, "password", profile.password, 144582f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey "linkname", "vpn", "refuse-eap", "nodefaultroute", 144682f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey "usepeerdns", "idle", "1800", "mtu", "1400", "mru", "1400", 144782f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey }; 144882f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey break; 144982f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey } 1450899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey 145182f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey VpnConfig config = new VpnConfig(); 1452899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey config.legacy = true; 145382f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey config.user = profile.key; 145482f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey config.interfaze = iface; 145582f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey config.session = profile.name; 14564ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker 14574ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker config.addLegacyRoutes(profile.routes); 145882f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey if (!profile.dnsServers.isEmpty()) { 145982f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey config.dnsServers = Arrays.asList(profile.dnsServers.split(" +")); 146082f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey } 146182f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey if (!profile.searchDomains.isEmpty()) { 146282f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey config.searchDomains = Arrays.asList(profile.searchDomains.split(" +")); 146382f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey } 146482f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey startLegacyVpn(config, racoon, mtpd); 146582f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey } 146682f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey 146782f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey private synchronized void startLegacyVpn(VpnConfig config, String[] racoon, String[] mtpd) { 1468b21298a686b04d55ff97223dd317497845713f4bJeff Davidson stopLegacyVpnPrivileged(); 1469899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey 1470b21298a686b04d55ff97223dd317497845713f4bJeff Davidson // Prepare for the new request. 1471b21298a686b04d55ff97223dd317497845713f4bJeff Davidson prepareInternal(VpnConfig.LEGACY_VPN); 1472899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey updateState(DetailedState.CONNECTING, "startLegacyVpn"); 147385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 14742e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh // Start a new LegacyVpnRunner and we are done! 1475100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh mLegacyVpnRunner = new LegacyVpnRunner(config, racoon, mtpd); 1476100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh mLegacyVpnRunner.start(); 147785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 147885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 1479b21298a686b04d55ff97223dd317497845713f4bJeff Davidson /** Stop legacy VPN. Permissions must be checked by callers. */ 1480b21298a686b04d55ff97223dd317497845713f4bJeff Davidson public synchronized void stopLegacyVpnPrivileged() { 1481899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey if (mLegacyVpnRunner != null) { 1482899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey mLegacyVpnRunner.exit(); 1483899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey mLegacyVpnRunner = null; 1484899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey 1485899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey synchronized (LegacyVpnRunner.TAG) { 1486899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey // wait for old thread to completely finish before spinning up 1487899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey // new instance, otherwise state updates can be out of order. 1488899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } 1489899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } 1490899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } 1491899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey 149285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh /** 14932e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh * Return the information of the current ongoing legacy VPN. 14942e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh */ 14952e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh public synchronized LegacyVpnInfo getLegacyVpnInfo() { 1496dadc857d9de364fded10d4f69eb82bc9cd35d4b7Chia-chi Yeh // Check if the caller is authorized. 1497dadc857d9de364fded10d4f69eb82bc9cd35d4b7Chia-chi Yeh enforceControlPermission(); 149808bbca040fa921b99493cd9967453ed90b1b710asj.cha return getLegacyVpnInfoPrivileged(); 149908bbca040fa921b99493cd9967453ed90b1b710asj.cha } 150008bbca040fa921b99493cd9967453ed90b1b710asj.cha 150108bbca040fa921b99493cd9967453ed90b1b710asj.cha /** 150208bbca040fa921b99493cd9967453ed90b1b710asj.cha * Return the information of the current ongoing legacy VPN. 150308bbca040fa921b99493cd9967453ed90b1b710asj.cha * Callers are responsible for checking permissions if needed. 150408bbca040fa921b99493cd9967453ed90b1b710asj.cha */ 150508bbca040fa921b99493cd9967453ed90b1b710asj.cha public synchronized LegacyVpnInfo getLegacyVpnInfoPrivileged() { 1506899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey if (mLegacyVpnRunner == null) return null; 1507899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey 1508899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey final LegacyVpnInfo info = new LegacyVpnInfo(); 1509c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker info.key = mConfig.user; 1510899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey info.state = LegacyVpnInfo.stateFromNetworkInfo(mNetworkInfo); 151190b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson if (mNetworkInfo.isConnected()) { 151290b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson info.intent = mStatusIntent; 151390b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson } 1514899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey return info; 15152e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh } 15162e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh 151769ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey public VpnConfig getLegacyVpnConfig() { 151869ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey if (mLegacyVpnRunner != null) { 1519c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker return mConfig; 152069ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey } else { 152169ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey return null; 152269ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey } 152369ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey } 152469ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 15252e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh /** 152685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh * Bringing up a VPN connection takes time, and that is all this thread 152785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh * does. Here we have plenty of time. The only thing we need to take 152885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh * care of is responding to interruptions as soon as possible. Otherwise 152985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh * requests will be piled up. This can be done in a Handler as a state 153085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh * machine, but it is much easier to read in the current form. 153185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh */ 153285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh private class LegacyVpnRunner extends Thread { 153385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh private static final String TAG = "LegacyVpnRunner"; 153485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 15351f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh private final String[] mDaemons; 153685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh private final String[][] mArguments; 15375317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh private final LocalSocket[] mSockets; 153853c04bdd35a85aa65d1a1f18ca2ee34970e2c2d0Robert Greenwalt private final String mOuterInterface; 15391b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt private final AtomicInteger mOuterConnection = 15401b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt new AtomicInteger(ConnectivityManager.TYPE_NONE); 15412e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh 154285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh private long mTimer = -1; 154385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 15441b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt /** 15451b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt * Watch for the outer connection (passing in the constructor) going away. 15461b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt */ 15471b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 15481b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt @Override 15491b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt public void onReceive(Context context, Intent intent) { 155057666934b4a161cc2fb77eef15d0b894aaf8f173Jeff Sharkey if (!mEnableTeardown) return; 155157666934b4a161cc2fb77eef15d0b894aaf8f173Jeff Sharkey 15521b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) { 15531b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt if (intent.getIntExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, 15541b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt ConnectivityManager.TYPE_NONE) == mOuterConnection.get()) { 15551b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt NetworkInfo info = (NetworkInfo)intent.getExtra( 15561b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt ConnectivityManager.EXTRA_NETWORK_INFO); 15571b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt if (info != null && !info.isConnectedOrConnecting()) { 15581b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt try { 15591b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt mObserver.interfaceStatusChanged(mOuterInterface, false); 15601b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt } catch (RemoteException e) {} 15611b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt } 15621b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt } 15631b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt } 15641b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt } 15651b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt }; 15661b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt 156741d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh public LegacyVpnRunner(VpnConfig config, String[] racoon, String[] mtpd) { 156885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh super(TAG); 156941d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh mConfig = config; 157041d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh mDaemons = new String[] {"racoon", "mtpd"}; 1571899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey // TODO: clear arguments from memory once launched 157241d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh mArguments = new String[][] {racoon, mtpd}; 15735317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh mSockets = new LocalSocket[mDaemons.length]; 157453c04bdd35a85aa65d1a1f18ca2ee34970e2c2d0Robert Greenwalt 157553c04bdd35a85aa65d1a1f18ca2ee34970e2c2d0Robert Greenwalt // This is the interface which VPN is running on, 157653c04bdd35a85aa65d1a1f18ca2ee34970e2c2d0Robert Greenwalt // mConfig.interfaze will change to point to OUR 157753c04bdd35a85aa65d1a1f18ca2ee34970e2c2d0Robert Greenwalt // internal interface soon. TODO - add inner/outer to mconfig 15781b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt // TODO - we have a race - if the outer iface goes away/disconnects before we hit this 15794ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker // we will leave the VPN up. We should check that it's still there/connected after 15801b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt // registering 158153c04bdd35a85aa65d1a1f18ca2ee34970e2c2d0Robert Greenwalt mOuterInterface = mConfig.interfaze; 15821b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt 1583e75b9e355500b7c6a05e4d6ec54ef48835707caaPaul Jensen if (!TextUtils.isEmpty(mOuterInterface)) { 1584e75b9e355500b7c6a05e4d6ec54ef48835707caaPaul Jensen final ConnectivityManager cm = ConnectivityManager.from(mContext); 1585e75b9e355500b7c6a05e4d6ec54ef48835707caaPaul Jensen for (Network network : cm.getAllNetworks()) { 1586e75b9e355500b7c6a05e4d6ec54ef48835707caaPaul Jensen final LinkProperties lp = cm.getLinkProperties(network); 15871b60d11b8f54f1ade45b80668601bc955041cf4fLorenzo Colitti if (lp != null && lp.getAllInterfaceNames().contains(mOuterInterface)) { 1588e75b9e355500b7c6a05e4d6ec54ef48835707caaPaul Jensen final NetworkInfo networkInfo = cm.getNetworkInfo(network); 1589e75b9e355500b7c6a05e4d6ec54ef48835707caaPaul Jensen if (networkInfo != null) mOuterConnection.set(networkInfo.getType()); 1590e75b9e355500b7c6a05e4d6ec54ef48835707caaPaul Jensen } 1591e75b9e355500b7c6a05e4d6ec54ef48835707caaPaul Jensen } 15921b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt } 15931b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt 15941b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt IntentFilter filter = new IntentFilter(); 15951b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); 15961b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt mContext.registerReceiver(mBroadcastReceiver, filter); 159741d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh } 159841d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh 1599aa1727fe0cbb902c5f53a3fae601b4e15da0a2f4Chia-chi Yeh public void check(String interfaze) { 160053c04bdd35a85aa65d1a1f18ca2ee34970e2c2d0Robert Greenwalt if (interfaze.equals(mOuterInterface)) { 1601aa1727fe0cbb902c5f53a3fae601b4e15da0a2f4Chia-chi Yeh Log.i(TAG, "Legacy VPN is going down with " + interfaze); 1602aa1727fe0cbb902c5f53a3fae601b4e15da0a2f4Chia-chi Yeh exit(); 1603aa1727fe0cbb902c5f53a3fae601b4e15da0a2f4Chia-chi Yeh } 1604aa1727fe0cbb902c5f53a3fae601b4e15da0a2f4Chia-chi Yeh } 1605aa1727fe0cbb902c5f53a3fae601b4e15da0a2f4Chia-chi Yeh 160641d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh public void exit() { 16075317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh // We assume that everything is reset after stopping the daemons. 160897a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh interrupt(); 16096bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen agentDisconnect(); 16101b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt try { 16111b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt mContext.unregisterReceiver(mBroadcastReceiver); 16121b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt } catch (IllegalArgumentException e) {} 16132e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh } 16142e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh 161585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh @Override 161685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh public void run() { 161785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Wait for the previous thread since it has been interrupted. 16182e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh Log.v(TAG, "Waiting"); 161985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh synchronized (TAG) { 16202e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh Log.v(TAG, "Executing"); 1621047454c759b46bbadb87ee3b64bf3e29afda48d6Hisanobu Watanabe try { 1622047454c759b46bbadb87ee3b64bf3e29afda48d6Hisanobu Watanabe execute(); 1623047454c759b46bbadb87ee3b64bf3e29afda48d6Hisanobu Watanabe monitorDaemons(); 1624047454c759b46bbadb87ee3b64bf3e29afda48d6Hisanobu Watanabe interrupted(); // Clear interrupt flag if execute called exit. 1625047454c759b46bbadb87ee3b64bf3e29afda48d6Hisanobu Watanabe } catch (InterruptedException e) { 1626047454c759b46bbadb87ee3b64bf3e29afda48d6Hisanobu Watanabe } finally { 1627047454c759b46bbadb87ee3b64bf3e29afda48d6Hisanobu Watanabe for (LocalSocket socket : mSockets) { 1628047454c759b46bbadb87ee3b64bf3e29afda48d6Hisanobu Watanabe IoUtils.closeQuietly(socket); 1629047454c759b46bbadb87ee3b64bf3e29afda48d6Hisanobu Watanabe } 1630047454c759b46bbadb87ee3b64bf3e29afda48d6Hisanobu Watanabe // This sleep is necessary for racoon to successfully complete sending delete 1631047454c759b46bbadb87ee3b64bf3e29afda48d6Hisanobu Watanabe // message to server. 1632047454c759b46bbadb87ee3b64bf3e29afda48d6Hisanobu Watanabe try { 1633047454c759b46bbadb87ee3b64bf3e29afda48d6Hisanobu Watanabe Thread.sleep(50); 1634047454c759b46bbadb87ee3b64bf3e29afda48d6Hisanobu Watanabe } catch (InterruptedException e) { 1635047454c759b46bbadb87ee3b64bf3e29afda48d6Hisanobu Watanabe } 1636047454c759b46bbadb87ee3b64bf3e29afda48d6Hisanobu Watanabe for (String daemon : mDaemons) { 1637047454c759b46bbadb87ee3b64bf3e29afda48d6Hisanobu Watanabe SystemService.stop(daemon); 1638047454c759b46bbadb87ee3b64bf3e29afda48d6Hisanobu Watanabe } 1639047454c759b46bbadb87ee3b64bf3e29afda48d6Hisanobu Watanabe } 1640047454c759b46bbadb87ee3b64bf3e29afda48d6Hisanobu Watanabe agentDisconnect(); 164185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 164285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 164385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 164485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh private void checkpoint(boolean yield) throws InterruptedException { 164585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh long now = SystemClock.elapsedRealtime(); 164685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh if (mTimer == -1) { 164785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh mTimer = now; 164885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh Thread.sleep(1); 16497ef8611b5f3a893a46c7b9e22bdd8ab252e373ffChia-chi Yeh } else if (now - mTimer <= 60000) { 165085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh Thread.sleep(yield ? 200 : 1); 165185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } else { 1652899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey updateState(DetailedState.FAILED, "checkpoint"); 165397a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh throw new IllegalStateException("Time is up"); 165485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 165585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 165685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 165785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh private void execute() { 165885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Catch all exceptions so we can clean up few things. 1659899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey boolean initFinished = false; 166085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh try { 166185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Initialize the timer. 166285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh checkpoint(false); 166385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 16641f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh // Wait for the daemons to stop. 16651f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh for (String daemon : mDaemons) { 1666088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey while (!SystemService.isStopped(daemon)) { 166785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh checkpoint(true); 166885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 166985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 167085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 167197a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh // Clear the previous state. 167297a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh File state = new File("/data/misc/vpn/state"); 167397a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh state.delete(); 167497a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh if (state.exists()) { 167597a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh throw new IllegalStateException("Cannot delete the state"); 167685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 1677c1872732922214de80f790e14865e41dd1b98203Chia-chi Yeh new File("/data/misc/vpn/abort").delete(); 1678899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey initFinished = true; 167985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 1680e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh // Check if we need to restart any of the daemons. 168185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh boolean restart = false; 168285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh for (String[] arguments : mArguments) { 168385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh restart = restart || (arguments != null); 168485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 168585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh if (!restart) { 16866bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen agentDisconnect(); 168785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh return; 168885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 1689899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey updateState(DetailedState.CONNECTING, "execute"); 169085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 16911f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh // Start the daemon with arguments. 16921f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh for (int i = 0; i < mDaemons.length; ++i) { 169385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh String[] arguments = mArguments[i]; 169485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh if (arguments == null) { 169585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh continue; 169685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 169785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 16981f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh // Start the daemon. 16991f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh String daemon = mDaemons[i]; 1700088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey SystemService.start(daemon); 170185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 17021f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh // Wait for the daemon to start. 1703088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey while (!SystemService.isRunning(daemon)) { 170485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh checkpoint(true); 170585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 170685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 170785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Create the control socket. 17085317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh mSockets[i] = new LocalSocket(); 170985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh LocalSocketAddress address = new LocalSocketAddress( 17101f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh daemon, LocalSocketAddress.Namespace.RESERVED); 171185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 171285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Wait for the socket to connect. 171385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh while (true) { 171485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh try { 17155317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh mSockets[i].connect(address); 171685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh break; 171785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } catch (Exception e) { 171885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // ignore 171985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 172085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh checkpoint(true); 172185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 17225317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh mSockets[i].setSoTimeout(500); 172385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 172485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Send over the arguments. 17255317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh OutputStream out = mSockets[i].getOutputStream(); 172685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh for (String argument : arguments) { 1727d396a448b2e36e29598c954b64bfddef73f3fae0Elliott Hughes byte[] bytes = argument.getBytes(StandardCharsets.UTF_8); 17285317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh if (bytes.length >= 0xFFFF) { 172997a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh throw new IllegalArgumentException("Argument is too large"); 173085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 17311f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh out.write(bytes.length >> 8); 17321f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh out.write(bytes.length); 17331f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh out.write(bytes); 173485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh checkpoint(false); 173585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 17365317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh out.write(0xFF); 17375317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh out.write(0xFF); 17381f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh out.flush(); 173997a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh 174097a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh // Wait for End-of-File. 17415317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh InputStream in = mSockets[i].getInputStream(); 174297a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh while (true) { 174397a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh try { 174497a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh if (in.read() == -1) { 174597a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh break; 174697a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh } 174797a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh } catch (Exception e) { 174897a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh // ignore 174997a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh } 175097a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh checkpoint(true); 175197a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh } 175285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 175385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 175497a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh // Wait for the daemons to create the new state. 175597a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh while (!state.exists()) { 17561f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh // Check if a running daemon is dead. 17571f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh for (int i = 0; i < mDaemons.length; ++i) { 17581f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh String daemon = mDaemons[i]; 1759088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey if (mArguments[i] != null && !SystemService.isRunning(daemon)) { 17602e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh throw new IllegalStateException(daemon + " is dead"); 176185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 176285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 176385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh checkpoint(true); 176485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 176585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 176697a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh // Now we are connected. Read and parse the new state. 1767c1bac3a6e240c1c9a14a7b515f585977fb908930Chia-chi Yeh String[] parameters = FileUtils.readTextFile(state, 0, null).split("\n", -1); 17685026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti if (parameters.length != 7) { 176997a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh throw new IllegalStateException("Cannot parse the state"); 177097a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh } 177197a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh 177297a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh // Set the interface and the addresses in the config. 177397a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh mConfig.interfaze = parameters[0].trim(); 177485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 17754ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker mConfig.addLegacyAddresses(parameters[1]); 177697a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh // Set the routes if they are not set in the config. 177797a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh if (mConfig.routes == null || mConfig.routes.isEmpty()) { 17784ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker mConfig.addLegacyRoutes(parameters[2]); 177997a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh } 178097a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh 178197a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh // Set the DNS servers if they are not set in the config. 178241d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh if (mConfig.dnsServers == null || mConfig.dnsServers.size() == 0) { 178397a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh String dnsServers = parameters[3].trim(); 178441d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh if (!dnsServers.isEmpty()) { 178541d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh mConfig.dnsServers = Arrays.asList(dnsServers.split(" ")); 178641d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh } 178741d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh } 178841d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh 178997a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh // Set the search domains if they are not set in the config. 179097a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh if (mConfig.searchDomains == null || mConfig.searchDomains.size() == 0) { 179197a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh String searchDomains = parameters[4].trim(); 179297a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh if (!searchDomains.isEmpty()) { 179397a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh mConfig.searchDomains = Arrays.asList(searchDomains.split(" ")); 179497a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh } 179597a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh } 179697a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh 17975026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti // Add a throw route for the VPN server endpoint, if one was specified. 17985026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti String endpoint = parameters[5]; 17995026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti if (!endpoint.isEmpty()) { 18005026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti try { 18015026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti InetAddress addr = InetAddress.parseNumericAddress(endpoint); 18025026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti if (addr instanceof Inet4Address) { 18035026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti mConfig.routes.add(new RouteInfo(new IpPrefix(addr, 32), RTN_THROW)); 18045026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti } else if (addr instanceof Inet6Address) { 18055026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti mConfig.routes.add(new RouteInfo(new IpPrefix(addr, 128), RTN_THROW)); 18065026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti } else { 18075026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti Log.e(TAG, "Unknown IP address family for VPN endpoint: " + endpoint); 18085026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti } 18095026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti } catch (IllegalArgumentException e) { 18105026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti Log.e(TAG, "Exception constructing throw route to " + endpoint + ": " + e); 18115026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti } 18125026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti } 18135026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti 181497a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh // Here is the last step and it must be done synchronously. 181541d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh synchronized (Vpn.this) { 18162b862e5e75ad419f17a4cea185b9349e0da70e7bVinit Deshapnde // Set the start time 18172b862e5e75ad419f17a4cea185b9349e0da70e7bVinit Deshapnde mConfig.startTime = SystemClock.elapsedRealtime(); 18182b862e5e75ad419f17a4cea185b9349e0da70e7bVinit Deshapnde 181941d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh // Check if the thread is interrupted while we are waiting. 182041d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh checkpoint(false); 182141d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh 1822e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh // Check if the interface is gone while we are waiting. 1823c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh if (jniCheck(mConfig.interfaze) == 0) { 182434e7813e962de99df9813014678ef5901227c5f1Chia-chi Yeh throw new IllegalStateException(mConfig.interfaze + " is gone"); 182541d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh } 1826e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh 1827e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh // Now INetworkManagementEventObserver is watching our back. 1828c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh mInterface = mConfig.interfaze; 18294d03abcd49af490dba3850d341b955dd72f24959Robin Lee prepareStatusIntent(); 18306bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen 18316bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen agentConnect(); 18322e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh 18332e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh Log.i(TAG, "Connected!"); 183441d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh } 183585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } catch (Exception e) { 18362e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh Log.i(TAG, "Aborting", e); 1837438406092ed71c658bf5a4e6ae2e7282fc4fab4dLorenzo Colitti updateState(DetailedState.FAILED, e.getMessage()); 1838e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh exit(); 183985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 184085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 1841899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey 1842899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey /** 1843899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey * Monitor the daemons we started, moving to disconnected state if the 1844899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey * underlying services fail. 1845899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey */ 1846047454c759b46bbadb87ee3b64bf3e29afda48d6Hisanobu Watanabe private void monitorDaemons() throws InterruptedException{ 1847899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey if (!mNetworkInfo.isConnected()) { 1848899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey return; 1849899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } 1850047454c759b46bbadb87ee3b64bf3e29afda48d6Hisanobu Watanabe while (true) { 1851047454c759b46bbadb87ee3b64bf3e29afda48d6Hisanobu Watanabe Thread.sleep(2000); 1852047454c759b46bbadb87ee3b64bf3e29afda48d6Hisanobu Watanabe for (int i = 0; i < mDaemons.length; i++) { 1853047454c759b46bbadb87ee3b64bf3e29afda48d6Hisanobu Watanabe if (mArguments[i] != null && SystemService.isStopped(mDaemons[i])) { 1854047454c759b46bbadb87ee3b64bf3e29afda48d6Hisanobu Watanabe return; 1855899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } 1856899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } 1857899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } 1858899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } 185985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 1860ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh} 1861