Vpn.java revision 3b3dd942ec6a0beaccd1cef0723d72786435d8f3
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; 2331a94f48bf8014cf6a1127bd23cf9a8541a9abedPaul Jensenimport static android.os.UserHandle.PER_USER_RANGE; 2442065ac64cba166dc0fe602957ea8fe80bf406e2Sreeram Ramachandranimport static android.system.OsConstants.AF_INET; 2542065ac64cba166dc0fe602957ea8fe80bf406e2Sreeram Ramachandranimport static android.system.OsConstants.AF_INET6; 26899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey 27bc19c181c8c058c824e4fee907a05129e142c388Jeff Davidsonimport android.Manifest; 284ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubakerimport android.app.AppGlobals; 2905542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidsonimport android.app.AppOpsManager; 3090b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidsonimport android.app.PendingIntent; 311b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwaltimport android.content.BroadcastReceiver; 32199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yehimport android.content.ComponentName; 33ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.content.Context; 34ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.content.Intent; 351b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwaltimport android.content.IntentFilter; 36199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yehimport android.content.ServiceConnection; 37ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.content.pm.ApplicationInfo; 38ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.content.pm.PackageManager; 396bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensenimport android.content.pm.PackageManager.NameNotFoundException; 40199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yehimport android.content.pm.ResolveInfo; 41c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubakerimport android.content.pm.UserInfo; 42899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkeyimport android.net.ConnectivityManager; 431b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwaltimport android.net.IConnectivityManager; 44ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.net.INetworkManagementEventObserver; 455026279ce45ae78126046607a2634dc9dae93199Lorenzo Colittiimport android.net.IpPrefix; 464ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubakerimport android.net.LinkAddress; 4782f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkeyimport android.net.LinkProperties; 4885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yehimport android.net.LocalSocket; 4985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yehimport android.net.LocalSocketAddress; 50c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandranimport android.net.Network; 516bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensenimport android.net.NetworkAgent; 526bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensenimport android.net.NetworkCapabilities; 53899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkeyimport android.net.NetworkInfo; 546bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensenimport android.net.NetworkInfo.DetailedState; 558cd33ed84e94036a5e1201485af7603dc6fb0d9bSreeram Ramachandranimport android.net.NetworkMisc; 5682f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkeyimport android.net.RouteInfo; 576bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensenimport android.net.UidRange; 58ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.os.Binder; 59c1bac3a6e240c1c9a14a7b515f585977fb908930Chia-chi Yehimport android.os.FileUtils; 60199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yehimport android.os.IBinder; 61899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkeyimport android.os.INetworkManagementService; 626bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensenimport android.os.Looper; 63199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yehimport android.os.Parcel; 64ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.os.ParcelFileDescriptor; 6585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yehimport android.os.Process; 66899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkeyimport android.os.RemoteException; 6785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yehimport android.os.SystemClock; 68088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkeyimport android.os.SystemService; 6950cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackbornimport android.os.UserHandle; 70c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubakerimport android.os.UserManager; 7182f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkeyimport android.security.Credentials; 7282f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkeyimport android.security.KeyStore; 73e75b9e355500b7c6a05e4d6ec54ef48835707caaPaul Jensenimport android.text.TextUtils; 74ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.util.Log; 75ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 76c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubakerimport com.android.internal.annotations.GuardedBy; 772e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yehimport com.android.internal.net.LegacyVpnInfo; 7804ba25c418bc4538e9dc0f047cfb9608d358f679Chia-chi Yehimport com.android.internal.net.VpnConfig; 79f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tongimport com.android.internal.net.VpnInfo; 8082f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkeyimport com.android.internal.net.VpnProfile; 81899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkeyimport com.android.server.net.BaseNetworkObserver; 82ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 8305542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidsonimport libcore.io.IoUtils; 8405542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson 8597a61565ea95472e65899070e64853f8c147bb11Chia-chi Yehimport java.io.File; 866bbf39cf6b81222f32d2b66b8fa85d562e0ad71cJeff Davidsonimport java.io.IOException; 8797a61565ea95472e65899070e64853f8c147bb11Chia-chi Yehimport java.io.InputStream; 8885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yehimport java.io.OutputStream; 8982f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkeyimport java.net.Inet4Address; 90f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandranimport java.net.Inet6Address; 91f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandranimport java.net.InetAddress; 92d396a448b2e36e29598c954b64bfddef73f3fae0Elliott Hughesimport java.nio.charset.StandardCharsets; 936bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensenimport java.util.ArrayList; 9441d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yehimport java.util.Arrays; 956bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensenimport java.util.List; 960784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensenimport java.util.SortedSet; 970784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensenimport java.util.TreeSet; 981b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwaltimport java.util.concurrent.atomic.AtomicInteger; 9985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 100ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh/** 101ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * @hide 102ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh */ 1036bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensenpublic class Vpn { 1046bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen private static final String NETWORKTYPE = "VPN"; 105899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey private static final String TAG = "Vpn"; 106899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey private static final boolean LOGD = true; 1076bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen 108899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey // TODO: create separate trackers for each unique VPN to support 109899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey // automated reconnection 110199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh 1116bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen private Context mContext; 1126bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen private NetworkInfo mNetworkInfo; 1136bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen private String mPackage; 1146bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen private int mOwnerUID; 115c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh private String mInterface; 116199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh private Connection mConnection; 11785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh private LegacyVpnRunner mLegacyVpnRunner; 11890b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson private PendingIntent mStatusIntent; 11957666934b4a161cc2fb77eef15d0b894aaf8f173Jeff Sharkey private volatile boolean mEnableTeardown = true; 1206bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen private final INetworkManagementService mNetd; 121c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker private VpnConfig mConfig; 1226bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen private NetworkAgent mNetworkAgent; 1236bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen private final Looper mLooper; 1246bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen private final NetworkCapabilities mNetworkCapabilities; 125c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker 126c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker /* list of users using this VPN. */ 127c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker @GuardedBy("this") 1286bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen private List<UidRange> mVpnUsers = null; 129c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker private BroadcastReceiver mUserIntentReceiver = null; 130c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker 1310784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen // Handle of user initiating VPN. 1320784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen private final int mUserHandle; 133ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 1346bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen public Vpn(Looper looper, Context context, INetworkManagementService netService, 135e75b9e355500b7c6a05e4d6ec54ef48835707caaPaul Jensen int userHandle) { 136ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh mContext = context; 1376bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen mNetd = netService; 1380784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen mUserHandle = userHandle; 1396bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen mLooper = looper; 1406bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen 1416bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen mPackage = VpnConfig.LEGACY_VPN; 1420784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen mOwnerUID = getAppUid(mPackage, mUserHandle); 143899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey 144899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey try { 145899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey netService.registerObserver(mObserver); 146899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } catch (RemoteException e) { 147899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey Log.wtf(TAG, "Problem registering observer", e); 148899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } 1490784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen if (userHandle == UserHandle.USER_OWNER) { 150c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker // Owner's VPN also needs to handle restricted users 151c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker mUserIntentReceiver = new BroadcastReceiver() { 152c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker @Override 153c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker public void onReceive(Context context, Intent intent) { 154c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker final String action = intent.getAction(); 1550784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 156c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker UserHandle.USER_NULL); 1570784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen if (userHandle == UserHandle.USER_NULL) return; 158c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker 159c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker if (Intent.ACTION_USER_ADDED.equals(action)) { 1600784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen onUserAdded(userHandle); 161c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker } else if (Intent.ACTION_USER_REMOVED.equals(action)) { 1620784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen onUserRemoved(userHandle); 163c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker } 164c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker } 165c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker }; 166c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker 167c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker IntentFilter intentFilter = new IntentFilter(); 168c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker intentFilter.addAction(Intent.ACTION_USER_ADDED); 169c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker intentFilter.addAction(Intent.ACTION_USER_REMOVED); 170c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker mContext.registerReceiverAsUser( 171c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker mUserIntentReceiver, UserHandle.ALL, intentFilter, null, null); 172c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker } 1736bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen 1746bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_VPN, 0, NETWORKTYPE, ""); 1756bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen // TODO: Copy metered attribute and bandwidths from physical transport, b/16207332 1766bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen mNetworkCapabilities = new NetworkCapabilities(); 1776bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen mNetworkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_VPN); 1786bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN); 179899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } 180899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey 18157666934b4a161cc2fb77eef15d0b894aaf8f173Jeff Sharkey /** 18257666934b4a161cc2fb77eef15d0b894aaf8f173Jeff Sharkey * Set if this object is responsible for watching for {@link NetworkInfo} 18357666934b4a161cc2fb77eef15d0b894aaf8f173Jeff Sharkey * teardown. When {@code false}, teardown is handled externally by someone 18457666934b4a161cc2fb77eef15d0b894aaf8f173Jeff Sharkey * else. 18557666934b4a161cc2fb77eef15d0b894aaf8f173Jeff Sharkey */ 18657666934b4a161cc2fb77eef15d0b894aaf8f173Jeff Sharkey public void setEnableTeardown(boolean enableTeardown) { 18757666934b4a161cc2fb77eef15d0b894aaf8f173Jeff Sharkey mEnableTeardown = enableTeardown; 18857666934b4a161cc2fb77eef15d0b894aaf8f173Jeff Sharkey } 18957666934b4a161cc2fb77eef15d0b894aaf8f173Jeff Sharkey 190899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey /** 191899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey * Update current state, dispaching event to listeners. 192899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey */ 193899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey private void updateState(DetailedState detailedState, String reason) { 194899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey if (LOGD) Log.d(TAG, "setting state=" + detailedState + ", reason=" + reason); 195899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey mNetworkInfo.setDetailedState(detailedState, reason, null); 1966bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen if (mNetworkAgent != null) { 1976bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen mNetworkAgent.sendNetworkInfo(mNetworkInfo); 1986bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 199ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 200ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 201ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh /** 202100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * Prepare for a VPN application. This method is designed to solve 203100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * race conditions. It first compares the current prepared package 204100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * with {@code oldPackage}. If they are the same, the prepared 205100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * package is revoked and replaced with {@code newPackage}. If 206100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * {@code oldPackage} is {@code null}, the comparison is omitted. 207100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * If {@code newPackage} is the same package or {@code null}, the 208100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * revocation is omitted. This method returns {@code true} if the 209100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * operation is succeeded. 210e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh * 211100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * Legacy VPN is handled specially since it is not a real package. 212100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * It uses {@link VpnConfig#LEGACY_VPN} as its package name, and 213100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * it can be revoked by itself. 214100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * 215100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * @param oldPackage The package name of the old VPN application. 216100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * @param newPackage The package name of the new VPN application. 217100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * @return true if the operation is succeeded. 218ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh */ 219100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh public synchronized boolean prepare(String oldPackage, String newPackage) { 2200a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson if (oldPackage != null) { 2210a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson if (getAppUid(oldPackage, mUserHandle) != mOwnerUID) { 2220a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson // The package doesn't match. We return false (to obtain user consent) unless the 2230a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson // user has already consented to that VPN package. 2240a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson if (!oldPackage.equals(VpnConfig.LEGACY_VPN) && isVpnUserPreConsented(oldPackage)) { 2250a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson prepareInternal(oldPackage); 2260a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson return true; 2270a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson } 2280a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson return false; 2290a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson } else if (!oldPackage.equals(VpnConfig.LEGACY_VPN) 2300a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson && !isVpnUserPreConsented(oldPackage)) { 2310a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson // Currently prepared VPN is revoked, so unprepare it and return false. 2320a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson prepareInternal(VpnConfig.LEGACY_VPN); 2330a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson return false; 23405542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson } 235100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh } 236100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh 237100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh // Return true if we do not need to revoke. 238be08587510edbc149c841638db721eb97d2351b6Jeff Davidson if (newPackage == null || (!newPackage.equals(VpnConfig.LEGACY_VPN) && 239be08587510edbc149c841638db721eb97d2351b6Jeff Davidson getAppUid(newPackage, mUserHandle) == mOwnerUID)) { 240100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh return true; 241ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 242ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 243dadc857d9de364fded10d4f69eb82bc9cd35d4b7Chia-chi Yeh // Check if the caller is authorized. 244dadc857d9de364fded10d4f69eb82bc9cd35d4b7Chia-chi Yeh enforceControlPermission(); 2457b0b834c3d12564c44ac134879a6dbc70e74be6eChia-chi Yeh 24611008a78b8e30910cedd8b8431980c7738183292Jeff Davidson prepareInternal(newPackage); 24711008a78b8e30910cedd8b8431980c7738183292Jeff Davidson return true; 24811008a78b8e30910cedd8b8431980c7738183292Jeff Davidson } 24911008a78b8e30910cedd8b8431980c7738183292Jeff Davidson 25011008a78b8e30910cedd8b8431980c7738183292Jeff Davidson /** Prepare the VPN for the given package. Does not perform permission checks. */ 25111008a78b8e30910cedd8b8431980c7738183292Jeff Davidson private void prepareInternal(String newPackage) { 25211008a78b8e30910cedd8b8431980c7738183292Jeff Davidson long token = Binder.clearCallingIdentity(); 25311008a78b8e30910cedd8b8431980c7738183292Jeff Davidson try { 25411008a78b8e30910cedd8b8431980c7738183292Jeff Davidson // Reset the interface. 25511008a78b8e30910cedd8b8431980c7738183292Jeff Davidson if (mInterface != null) { 25611008a78b8e30910cedd8b8431980c7738183292Jeff Davidson mStatusIntent = null; 25711008a78b8e30910cedd8b8431980c7738183292Jeff Davidson agentDisconnect(); 25811008a78b8e30910cedd8b8431980c7738183292Jeff Davidson jniReset(mInterface); 25911008a78b8e30910cedd8b8431980c7738183292Jeff Davidson mInterface = null; 26011008a78b8e30910cedd8b8431980c7738183292Jeff Davidson mVpnUsers = null; 26111008a78b8e30910cedd8b8431980c7738183292Jeff Davidson } 26211008a78b8e30910cedd8b8431980c7738183292Jeff Davidson 26311008a78b8e30910cedd8b8431980c7738183292Jeff Davidson // Revoke the connection or stop LegacyVpnRunner. 26411008a78b8e30910cedd8b8431980c7738183292Jeff Davidson if (mConnection != null) { 26511008a78b8e30910cedd8b8431980c7738183292Jeff Davidson try { 26611008a78b8e30910cedd8b8431980c7738183292Jeff Davidson mConnection.mService.transact(IBinder.LAST_CALL_TRANSACTION, 26711008a78b8e30910cedd8b8431980c7738183292Jeff Davidson Parcel.obtain(), null, IBinder.FLAG_ONEWAY); 26811008a78b8e30910cedd8b8431980c7738183292Jeff Davidson } catch (Exception e) { 26911008a78b8e30910cedd8b8431980c7738183292Jeff Davidson // ignore 27011008a78b8e30910cedd8b8431980c7738183292Jeff Davidson } 27111008a78b8e30910cedd8b8431980c7738183292Jeff Davidson mContext.unbindService(mConnection); 27211008a78b8e30910cedd8b8431980c7738183292Jeff Davidson mConnection = null; 27311008a78b8e30910cedd8b8431980c7738183292Jeff Davidson } else if (mLegacyVpnRunner != null) { 27411008a78b8e30910cedd8b8431980c7738183292Jeff Davidson mLegacyVpnRunner.exit(); 27511008a78b8e30910cedd8b8431980c7738183292Jeff Davidson mLegacyVpnRunner = null; 27611008a78b8e30910cedd8b8431980c7738183292Jeff Davidson } 277ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 278199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh try { 27911008a78b8e30910cedd8b8431980c7738183292Jeff Davidson mNetd.denyProtect(mOwnerUID); 280199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh } catch (Exception e) { 28111008a78b8e30910cedd8b8431980c7738183292Jeff Davidson Log.wtf(TAG, "Failed to disallow UID " + mOwnerUID + " to call protect() " + e); 282199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh } 28341d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh 28411008a78b8e30910cedd8b8431980c7738183292Jeff Davidson Log.i(TAG, "Switched from " + mPackage + " to " + newPackage); 28511008a78b8e30910cedd8b8431980c7738183292Jeff Davidson mPackage = newPackage; 28611008a78b8e30910cedd8b8431980c7738183292Jeff Davidson mOwnerUID = getAppUid(newPackage, mUserHandle); 28711008a78b8e30910cedd8b8431980c7738183292Jeff Davidson try { 28811008a78b8e30910cedd8b8431980c7738183292Jeff Davidson mNetd.allowProtect(mOwnerUID); 28911008a78b8e30910cedd8b8431980c7738183292Jeff Davidson } catch (Exception e) { 29011008a78b8e30910cedd8b8431980c7738183292Jeff Davidson Log.wtf(TAG, "Failed to allow UID " + mOwnerUID + " to call protect() " + e); 29111008a78b8e30910cedd8b8431980c7738183292Jeff Davidson } 29211008a78b8e30910cedd8b8431980c7738183292Jeff Davidson mConfig = null; 2936bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen 29411008a78b8e30910cedd8b8431980c7738183292Jeff Davidson updateState(DetailedState.IDLE, "prepare"); 2956bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } finally { 2966bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen Binder.restoreCallingIdentity(token); 2976bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 298ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 299ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 30005542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson /** 3013b3dd942ec6a0beaccd1cef0723d72786435d8f3Robin Lee * Set whether a package has the ability to launch VPNs without user intervention. 30205542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson */ 3033b3dd942ec6a0beaccd1cef0723d72786435d8f3Robin Lee public void setPackageAuthorization(String packageName, boolean authorized) { 30405542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson // Check if the caller is authorized. 30505542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson enforceControlPermission(); 30605542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson 3073b3dd942ec6a0beaccd1cef0723d72786435d8f3Robin Lee int uid = getAppUid(packageName, mUserHandle); 3083b3dd942ec6a0beaccd1cef0723d72786435d8f3Robin Lee if (uid == -1 || VpnConfig.LEGACY_VPN.equals(packageName)) { 3093b3dd942ec6a0beaccd1cef0723d72786435d8f3Robin Lee // Authorization for nonexistent packages (or fake ones) can't be updated. 31005542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson return; 31105542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson } 31205542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson 31305542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson long token = Binder.clearCallingIdentity(); 31405542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson try { 31505542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson AppOpsManager appOps = 31605542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); 3173b3dd942ec6a0beaccd1cef0723d72786435d8f3Robin Lee appOps.setMode(AppOpsManager.OP_ACTIVATE_VPN, uid, packageName, 31805542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson authorized ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED); 31905542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson } catch (Exception e) { 3203b3dd942ec6a0beaccd1cef0723d72786435d8f3Robin Lee Log.wtf(TAG, "Failed to set app ops for package " + packageName + ", uid " + uid, e); 32105542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson } finally { 32205542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson Binder.restoreCallingIdentity(token); 32305542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson } 32405542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson } 32505542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson 32605542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson private boolean isVpnUserPreConsented(String packageName) { 32705542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson AppOpsManager appOps = 32805542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); 32905542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson 33005542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson // Verify that the caller matches the given package and has permission to activate VPNs. 33105542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson return appOps.noteOpNoThrow(AppOpsManager.OP_ACTIVATE_VPN, Binder.getCallingUid(), 33205542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson packageName) == AppOpsManager.MODE_ALLOWED; 33305542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson } 33405542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson 3350784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen private int getAppUid(String app, int userHandle) { 33605542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson if (VpnConfig.LEGACY_VPN.equals(app)) { 3376bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen return Process.myUid(); 3386bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 339fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh PackageManager pm = mContext.getPackageManager(); 3406bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen int result; 3416bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen try { 3420784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen result = pm.getPackageUid(app, userHandle); 3436bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } catch (NameNotFoundException e) { 3446bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen result = -1; 345fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh } 3466bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen return result; 3476bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 3486bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen 3496bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen public NetworkInfo getNetworkInfo() { 3506bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen return mNetworkInfo; 3516bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 3526bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen 35331a94f48bf8014cf6a1127bd23cf9a8541a9abedPaul Jensen public int getNetId() { 35431a94f48bf8014cf6a1127bd23cf9a8541a9abedPaul Jensen return mNetworkAgent != null ? mNetworkAgent.netId : NETID_UNSET; 35531a94f48bf8014cf6a1127bd23cf9a8541a9abedPaul Jensen } 35631a94f48bf8014cf6a1127bd23cf9a8541a9abedPaul Jensen 35760446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti private LinkProperties makeLinkProperties() { 35860446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti boolean allowIPv4 = mConfig.allowIPv4; 35960446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti boolean allowIPv6 = mConfig.allowIPv6; 36060446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti 3616bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen LinkProperties lp = new LinkProperties(); 36260446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti 3636bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen lp.setInterfaceName(mInterface); 36442065ac64cba166dc0fe602957ea8fe80bf406e2Sreeram Ramachandran 36560446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti if (mConfig.addresses != null) { 36660446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti for (LinkAddress address : mConfig.addresses) { 36760446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti lp.addLinkAddress(address); 36860446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti allowIPv4 |= address.getAddress() instanceof Inet4Address; 36960446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti allowIPv6 |= address.getAddress() instanceof Inet6Address; 37060446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti } 3716bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 37260446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti 37360446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti if (mConfig.routes != null) { 37460446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti for (RouteInfo route : mConfig.routes) { 37560446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti lp.addRoute(route); 37660446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti InetAddress address = route.getDestination().getAddress(); 37760446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti allowIPv4 |= address instanceof Inet4Address; 37860446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti allowIPv6 |= address instanceof Inet6Address; 37960446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti } 3806bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 38142065ac64cba166dc0fe602957ea8fe80bf406e2Sreeram Ramachandran 3826bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen if (mConfig.dnsServers != null) { 3836bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen for (String dnsServer : mConfig.dnsServers) { 38442065ac64cba166dc0fe602957ea8fe80bf406e2Sreeram Ramachandran InetAddress address = InetAddress.parseNumericAddress(dnsServer); 38542065ac64cba166dc0fe602957ea8fe80bf406e2Sreeram Ramachandran lp.addDnsServer(address); 38660446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti allowIPv4 |= address instanceof Inet4Address; 38760446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti allowIPv6 |= address instanceof Inet6Address; 3886bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 3896bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 39042065ac64cba166dc0fe602957ea8fe80bf406e2Sreeram Ramachandran 39160446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti if (!allowIPv4) { 39260446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE)); 39360446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti } 39460446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti if (!allowIPv6) { 39560446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE)); 39660446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti } 39760446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti 3986bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen // Concatenate search domains into a string. 3996bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen StringBuilder buffer = new StringBuilder(); 4006bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen if (mConfig.searchDomains != null) { 4016bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen for (String domain : mConfig.searchDomains) { 4026bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen buffer.append(domain).append(' '); 4036bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 4046bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 4056bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen lp.setDomains(buffer.toString().trim()); 40642065ac64cba166dc0fe602957ea8fe80bf406e2Sreeram Ramachandran 40760446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti // TODO: Stop setting the MTU in jniCreate and set it here. 40860446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti 40960446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti return lp; 41060446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti } 41160446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti 41260446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti private void agentConnect() { 41360446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti LinkProperties lp = makeLinkProperties(); 41460446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti 41560446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti if (lp.hasIPv4DefaultRoute() || lp.hasIPv6DefaultRoute()) { 41660446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); 41760446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti } else { 41860446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); 41960446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti } 42060446165d8bd44f72cec8d0c5583a688369fa660Lorenzo Colitti 4216bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen mNetworkInfo.setIsAvailable(true); 4226bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null); 42342065ac64cba166dc0fe602957ea8fe80bf406e2Sreeram Ramachandran 4248cd33ed84e94036a5e1201485af7603dc6fb0d9bSreeram Ramachandran NetworkMisc networkMisc = new NetworkMisc(); 42542065ac64cba166dc0fe602957ea8fe80bf406e2Sreeram Ramachandran networkMisc.allowBypass = mConfig.allowBypass; 42642065ac64cba166dc0fe602957ea8fe80bf406e2Sreeram Ramachandran 4276bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen long token = Binder.clearCallingIdentity(); 4284ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker try { 4296bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen mNetworkAgent = new NetworkAgent(mLooper, mContext, NETWORKTYPE, 4308cd33ed84e94036a5e1201485af7603dc6fb0d9bSreeram Ramachandran mNetworkInfo, mNetworkCapabilities, lp, 0, networkMisc) { 43105542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson @Override 4326bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen public void unwanted() { 4336bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen // We are user controlled, not driven by NetworkRequest. 43405542603dd4f1e0ea47a3dca01de3999a9a329a9Jeff Davidson } 4356bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen }; 4364ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker } finally { 4374ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker Binder.restoreCallingIdentity(token); 4384ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker } 43942065ac64cba166dc0fe602957ea8fe80bf406e2Sreeram Ramachandran 4400784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen addVpnUserLocked(mUserHandle); 4416bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen // If we are owner assign all Restricted Users to this VPN 4420784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen if (mUserHandle == UserHandle.USER_OWNER) { 4436bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen token = Binder.clearCallingIdentity(); 4446bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen List<UserInfo> users; 4456bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen try { 4466bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen users = UserManager.get(mContext).getUsers(); 4476bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } finally { 4486bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen Binder.restoreCallingIdentity(token); 4496bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 4506bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen for (UserInfo user : users) { 4516bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen if (user.isRestricted()) { 4526bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen addVpnUserLocked(user.id); 4536bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 4546bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 4556bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 4566bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen mNetworkAgent.addUidRanges(mVpnUsers.toArray(new UidRange[mVpnUsers.size()])); 4576bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 4586bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen 4596bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen private void agentDisconnect(NetworkInfo networkInfo, NetworkAgent networkAgent) { 4606bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen networkInfo.setIsAvailable(false); 4616bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen networkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null); 4626bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen if (networkAgent != null) { 4636bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen networkAgent.sendNetworkInfo(networkInfo); 4646bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 4656bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 4666bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen 4676bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen private void agentDisconnect(NetworkAgent networkAgent) { 4686bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen NetworkInfo networkInfo = new NetworkInfo(mNetworkInfo); 4696bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen agentDisconnect(networkInfo, networkAgent); 4706bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 4714ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker 4726bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen private void agentDisconnect() { 4736bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen if (mNetworkInfo.isConnected()) { 4746bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen agentDisconnect(mNetworkInfo, mNetworkAgent); 4756bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen mNetworkAgent = null; 4766bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 477fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh } 478fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh 479fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh /** 480e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh * Establish a VPN network and return the file descriptor of the VPN 481e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh * interface. This methods returns {@code null} if the application is 482100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * revoked or not prepared. 483ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * 484e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh * @param config The parameters to configure the network. 485e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh * @return The file descriptor of the VPN interface. 486ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh */ 48704ba25c418bc4538e9dc0f047cfb9608d358f679Chia-chi Yeh public synchronized ParcelFileDescriptor establish(VpnConfig config) { 488ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh // Check if the caller is already prepared. 489c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker UserManager mgr = UserManager.get(mContext); 4906bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen if (Binder.getCallingUid() != mOwnerUID) { 4917b0b834c3d12564c44ac134879a6dbc70e74be6eChia-chi Yeh return null; 492ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 4930a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson // Check to ensure consent hasn't been revoked since we were prepared. 4940a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson if (!isVpnUserPreConsented(mPackage)) { 4950a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson return null; 4960a775ce9801f03071d1e9bcc177d79e6fe350702Jeff Davidson } 497fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh // Check if the service is properly declared. 498199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh Intent intent = new Intent(VpnConfig.SERVICE_INTERFACE); 499199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh intent.setClassName(mPackage, config.user); 5004ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker long token = Binder.clearCallingIdentity(); 5014ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker try { 502c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker // Restricted users are not allowed to create VPNs, they are tied to Owner 5030784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen UserInfo user = mgr.getUserInfo(mUserHandle); 50495778ffc58979d19ff9f4aaed396a6eca49cf698Nicolas Prevot if (user.isRestricted() || mgr.hasUserRestriction(UserManager.DISALLOW_CONFIG_VPN, 50595778ffc58979d19ff9f4aaed396a6eca49cf698Nicolas Prevot new UserHandle(mUserHandle))) { 506c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker throw new SecurityException("Restricted users cannot establish VPNs"); 507c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker } 508c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker 5094ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker ResolveInfo info = AppGlobals.getPackageManager().resolveService(intent, 5100784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen null, 0, mUserHandle); 5114ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker if (info == null) { 5124ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker throw new SecurityException("Cannot find " + config.user); 5134ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker } 5144ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker if (!BIND_VPN_SERVICE.equals(info.serviceInfo.permission)) { 5154ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker throw new SecurityException(config.user + " does not require " + BIND_VPN_SERVICE); 5164ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker } 5174ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker } catch (RemoteException e) { 5184ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker throw new SecurityException("Cannot find " + config.user); 5194ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker } finally { 5204ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker Binder.restoreCallingIdentity(token); 521199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh } 522fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh 5234c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker // Save the old config in case we need to go back. 5244c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker VpnConfig oldConfig = mConfig; 5254c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker String oldInterface = mInterface; 5264c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker Connection oldConnection = mConnection; 5276bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen NetworkAgent oldNetworkAgent = mNetworkAgent; 5286bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen mNetworkAgent = null; 5296bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen List<UidRange> oldUsers = mVpnUsers; 5304c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker 531e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh // Configure the interface. Abort if any of these steps fails. 53297a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh ParcelFileDescriptor tun = ParcelFileDescriptor.adoptFd(jniCreate(config.mtu)); 533ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh try { 534899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey updateState(DetailedState.CONNECTING, "establish"); 535c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh String interfaze = jniGetName(tun.getFd()); 5364ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker 537c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker // TEMP use the old jni calls until there is support for netd address setting 5384ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker StringBuilder builder = new StringBuilder(); 5394ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker for (LinkAddress address : config.addresses) { 5404ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker builder.append(" " + address); 54197a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh } 5424ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker if (jniSetAddresses(interfaze, builder.toString()) < 1) { 5434ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker throw new IllegalArgumentException("At least one address must be specified"); 54497a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh } 545199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh Connection connection = new Connection(); 546d69e4c1460017062e7c36be55801cb434ad19d97Dianne Hackborn if (!mContext.bindServiceAsUser(intent, connection, 547d69e4c1460017062e7c36be55801cb434ad19d97Dianne Hackborn Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE, 548d69e4c1460017062e7c36be55801cb434ad19d97Dianne Hackborn new UserHandle(mUserHandle))) { 549199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh throw new IllegalStateException("Cannot bind " + config.user); 550199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh } 5514c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker 552199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh mConnection = connection; 553c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh mInterface = interfaze; 5544ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker 5554ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker // Fill more values. 5564ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker config.user = mPackage; 5574ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker config.interfaze = mInterface; 558c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker config.startTime = SystemClock.elapsedRealtime(); 559c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker mConfig = config; 5604c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker 5614ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker // Set up forwarding and DNS rules. 5626bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen mVpnUsers = new ArrayList<UidRange>(); 56342065ac64cba166dc0fe602957ea8fe80bf406e2Sreeram Ramachandran 5646bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen agentConnect(); 5654ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker 5664c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker if (oldConnection != null) { 5674c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker mContext.unbindService(oldConnection); 5684c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker } 5696bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen // Remove the old tun's user forwarding rules 5706bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen // The new tun's user rules have already been added so they will take over 5716bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen // as rules are deleted. This prevents data leakage as the rules are moved over. 5726bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen agentDisconnect(oldNetworkAgent); 5734c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker if (oldInterface != null && !oldInterface.equals(interfaze)) { 5744c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker jniReset(oldInterface); 5754c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker } 5766bbf39cf6b81222f32d2b66b8fa85d562e0ad71cJeff Davidson 5776bbf39cf6b81222f32d2b66b8fa85d562e0ad71cJeff Davidson try { 5786bbf39cf6b81222f32d2b66b8fa85d562e0ad71cJeff Davidson IoUtils.setBlocking(tun.getFileDescriptor(), config.blocking); 5796bbf39cf6b81222f32d2b66b8fa85d562e0ad71cJeff Davidson } catch (IOException e) { 5806bbf39cf6b81222f32d2b66b8fa85d562e0ad71cJeff Davidson throw new IllegalStateException( 5816bbf39cf6b81222f32d2b66b8fa85d562e0ad71cJeff Davidson "Cannot set tunnel's fd as blocking=" + config.blocking, e); 5826bbf39cf6b81222f32d2b66b8fa85d562e0ad71cJeff Davidson } 583ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } catch (RuntimeException e) { 584065b299df4159602327977dd007cb2cd6b64ab20Jeff Sharkey IoUtils.closeQuietly(tun); 5856bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen agentDisconnect(); 5864c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker // restore old state 5874c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker mConfig = oldConfig; 5884c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker mConnection = oldConnection; 5894c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker mVpnUsers = oldUsers; 5906bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen mNetworkAgent = oldNetworkAgent; 5914c5c33e5e6fb37f85977c70a0baba4e1ed51fe0dChad Brubaker mInterface = oldInterface; 592ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh throw e; 593ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 594199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh Log.i(TAG, "Established by " + config.user + " on " + mInterface); 595c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh return tun; 596ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 597ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 598c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker private boolean isRunningLocked() { 599c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran return mNetworkAgent != null && mInterface != null; 600c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran } 601c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran 602c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran // Returns true if the VPN has been established and the calling UID is its owner. Used to check 603c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran // that a call to mutate VPN state is admissible. 604c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran private boolean isCallerEstablishedOwnerLocked() { 605c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran return isRunningLocked() && Binder.getCallingUid() == mOwnerUID; 606c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker } 607c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker 6080784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen // Note: Return type guarantees results are deduped and sorted, which callers require. 6090784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen private SortedSet<Integer> getAppsUids(List<String> packageNames, int userHandle) { 6100784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen SortedSet<Integer> uids = new TreeSet<Integer>(); 6110784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen for (String app : packageNames) { 6120784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen int uid = getAppUid(app, userHandle); 6130784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen if (uid != -1) uids.add(uid); 6140784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen } 6150784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen return uids; 6160784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen } 6170784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen 6186bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen // Note: This function adds to mVpnUsers but does not publish list to NetworkAgent. 6190784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen private void addVpnUserLocked(int userHandle) { 620c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran if (mVpnUsers == null) { 621c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker throw new IllegalStateException("VPN is not active"); 622c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker } 62369887e838814642a7ae78fc810656c7c8afc2a19Robert Greenwalt 6240784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen if (mConfig.allowedApplications != null) { 6250784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen // Add ranges covering all UIDs for allowedApplications. 6260784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen int start = -1, stop = -1; 6270784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen for (int uid : getAppsUids(mConfig.allowedApplications, userHandle)) { 6280784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen if (start == -1) { 6290784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen start = uid; 6300784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen } else if (uid != stop + 1) { 6310784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen mVpnUsers.add(new UidRange(start, stop)); 6320784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen start = uid; 6330784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen } 6340784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen stop = uid; 6350784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen } 6360784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen if (start != -1) mVpnUsers.add(new UidRange(start, stop)); 6370784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen } else if (mConfig.disallowedApplications != null) { 6380784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen // Add all ranges for user skipping UIDs for disallowedApplications. 6390784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen final UidRange userRange = UidRange.createForUser(userHandle); 6400784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen int start = userRange.start; 6410784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen for (int uid : getAppsUids(mConfig.disallowedApplications, userHandle)) { 6420784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen if (uid == start) { 6430784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen start++; 6440784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen } else { 6450784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen mVpnUsers.add(new UidRange(start, uid - 1)); 6460784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen start = uid + 1; 6470784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen } 6480784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen } 6490784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen if (start <= userRange.stop) mVpnUsers.add(new UidRange(start, userRange.stop)); 6500784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen } else { 6510784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen // Add all UIDs for the user. 6520784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen mVpnUsers.add(UidRange.createForUser(userHandle)); 6530784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen } 65490b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson 65590b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson prepareStatusIntent(); 656c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker } 657c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker 6580784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen // Returns the subset of the full list of active UID ranges the VPN applies to (mVpnUsers) that 6590784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen // apply to userHandle. 6600784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen private List<UidRange> uidRangesForUser(int userHandle) { 6610784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen final UidRange userRange = UidRange.createForUser(userHandle); 6620784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen final List<UidRange> ranges = new ArrayList<UidRange>(); 6630784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen for (UidRange range : mVpnUsers) { 6640784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen if (range.start >= userRange.start && range.stop <= userRange.stop) { 6650784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen ranges.add(range); 6660784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen } 6670784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen } 6680784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen return ranges; 6690784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen } 6700784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen 6710784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen private void removeVpnUserLocked(int userHandle) { 672c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran if (mVpnUsers == null) { 67390b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson throw new IllegalStateException("VPN is not active"); 67490b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson } 6750784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen final List<UidRange> ranges = uidRangesForUser(userHandle); 67690b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson if (mNetworkAgent != null) { 6770784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen mNetworkAgent.removeUidRanges(ranges.toArray(new UidRange[ranges.size()])); 67890b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson } 6790784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen mVpnUsers.removeAll(ranges); 68090b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson mStatusIntent = null; 681c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker } 682c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker 6830784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen private void onUserAdded(int userHandle) { 684c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker // If the user is restricted tie them to the owner's VPN 685c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker synchronized(Vpn.this) { 686c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker UserManager mgr = UserManager.get(mContext); 6870784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen UserInfo user = mgr.getUserInfo(userHandle); 688c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker if (user.isRestricted()) { 689c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker try { 6900784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen addVpnUserLocked(userHandle); 6916bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen if (mNetworkAgent != null) { 6920784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen final List<UidRange> ranges = uidRangesForUser(userHandle); 6930784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen mNetworkAgent.addUidRanges(ranges.toArray(new UidRange[ranges.size()])); 6946bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen } 695c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker } catch (Exception e) { 696c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker Log.wtf(TAG, "Failed to add restricted user to owner", e); 697c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker } 698c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker } 699c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker } 700c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker } 701c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker 7020784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen private void onUserRemoved(int userHandle) { 703c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker // clean up if restricted 704c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker synchronized(Vpn.this) { 705c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker UserManager mgr = UserManager.get(mContext); 7060784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen UserInfo user = mgr.getUserInfo(userHandle); 707c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker if (user.isRestricted()) { 708c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker try { 7090784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen removeVpnUserLocked(userHandle); 710c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker } catch (Exception e) { 711c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker Log.wtf(TAG, "Failed to remove restricted user to owner", e); 712c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker } 713c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker } 714c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker } 715c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker } 716c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker 717bf6ff2c025405a3af496fe558dfc4468a9b45cc8Chad Brubaker /** 718bf6ff2c025405a3af496fe558dfc4468a9b45cc8Chad Brubaker * Return the configuration of the currently running VPN. 719bf6ff2c025405a3af496fe558dfc4468a9b45cc8Chad Brubaker */ 720bf6ff2c025405a3af496fe558dfc4468a9b45cc8Chad Brubaker public VpnConfig getVpnConfig() { 721bf6ff2c025405a3af496fe558dfc4468a9b45cc8Chad Brubaker enforceControlPermission(); 722bf6ff2c025405a3af496fe558dfc4468a9b45cc8Chad Brubaker return mConfig; 723bf6ff2c025405a3af496fe558dfc4468a9b45cc8Chad Brubaker } 724bf6ff2c025405a3af496fe558dfc4468a9b45cc8Chad Brubaker 725899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey @Deprecated 726899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey public synchronized void interfaceStatusChanged(String iface, boolean up) { 727899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey try { 728899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey mObserver.interfaceStatusChanged(iface, up); 729899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } catch (RemoteException e) { 730899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey // ignored; target is local 731aa1727fe0cbb902c5f53a3fae601b4e15da0a2f4Chia-chi Yeh } 732ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 733ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 734899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey private INetworkManagementEventObserver mObserver = new BaseNetworkObserver() { 735899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey @Override 736899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey public void interfaceStatusChanged(String interfaze, boolean up) { 737899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey synchronized (Vpn.this) { 738899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey if (!up && mLegacyVpnRunner != null) { 739899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey mLegacyVpnRunner.check(interfaze); 740899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } 741199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh } 742ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 743ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 744899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey @Override 745899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey public void interfaceRemoved(String interfaze) { 746899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey synchronized (Vpn.this) { 747899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey if (interfaze.equals(mInterface) && jniCheck(interfaze) == 0) { 74890b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson mStatusIntent = null; 7496bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen mVpnUsers = null; 750c4c7231eb6d1efa9ecd7b693f8328a76a04e8bbbPaul Jensen mConfig = null; 751899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey mInterface = null; 752899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey if (mConnection != null) { 753899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey mContext.unbindService(mConnection); 754899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey mConnection = null; 7556bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen agentDisconnect(); 756899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } else if (mLegacyVpnRunner != null) { 757899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey mLegacyVpnRunner.exit(); 758899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey mLegacyVpnRunner = null; 759899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } 760899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } 761899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } 762899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } 763899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey }; 764db3c8678e5cbdfec011afaf25bde2091152c30adHaoyu Bai 765dadc857d9de364fded10d4f69eb82bc9cd35d4b7Chia-chi Yeh private void enforceControlPermission() { 766bc19c181c8c058c824e4fee907a05129e142c388Jeff Davidson mContext.enforceCallingPermission(Manifest.permission.CONTROL_VPN, "Unauthorized Caller"); 767dadc857d9de364fded10d4f69eb82bc9cd35d4b7Chia-chi Yeh } 768dadc857d9de364fded10d4f69eb82bc9cd35d4b7Chia-chi Yeh 769199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh private class Connection implements ServiceConnection { 770199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh private IBinder mService; 771199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh 772199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh @Override 773199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh public void onServiceConnected(ComponentName name, IBinder service) { 774199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh mService = service; 775199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh } 776199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh 777199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh @Override 778199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh public void onServiceDisconnected(ComponentName name) { 779199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh mService = null; 780199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh } 781199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh } 782199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh 78390b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson private void prepareStatusIntent() { 78490b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson final long token = Binder.clearCallingIdentity(); 78590b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson try { 78690b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson mStatusIntent = VpnConfig.getIntentForStatusPanel(mContext); 78790b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson } finally { 78890b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson Binder.restoreCallingIdentity(token); 78990b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson } 79090b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson } 79190b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson 792f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandran public synchronized boolean addAddress(String address, int prefixLength) { 793c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran if (!isCallerEstablishedOwnerLocked()) { 794f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandran return false; 795f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandran } 796f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandran boolean success = jniAddAddress(mInterface, address, prefixLength); 797c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran mNetworkAgent.sendLinkProperties(makeLinkProperties()); 798f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandran return success; 799f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandran } 800f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandran 801f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandran public synchronized boolean removeAddress(String address, int prefixLength) { 802c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran if (!isCallerEstablishedOwnerLocked()) { 803f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandran return false; 804f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandran } 805f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandran boolean success = jniDelAddress(mInterface, address, prefixLength); 806c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran mNetworkAgent.sendLinkProperties(makeLinkProperties()); 807f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandran return success; 808f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandran } 809f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandran 810c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran public synchronized boolean setUnderlyingNetworks(Network[] networks) { 811c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran if (!isCallerEstablishedOwnerLocked()) { 812c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran return false; 813c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran } 814c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran if (networks == null) { 815c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran mConfig.underlyingNetworks = null; 816c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran } else { 817c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran mConfig.underlyingNetworks = new Network[networks.length]; 818c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran for (int i = 0; i < networks.length; ++i) { 819c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran if (networks[i] == null) { 820c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran mConfig.underlyingNetworks[i] = null; 821c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran } else { 822c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran mConfig.underlyingNetworks[i] = new Network(networks[i].netId); 823c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran } 824c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran } 825c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran } 826c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran return true; 827c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran } 828c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran 829c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran public synchronized Network[] getUnderlyingNetworks() { 830c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran if (!isRunningLocked()) { 831c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran return null; 832c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran } 833c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran return mConfig.underlyingNetworks; 834c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran } 835c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran 836f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong /** 837f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong * This method should only be called by ConnectivityService. Because it doesn't 838f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong * have enough data to fill VpnInfo.primaryUnderlyingIface field. 839f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong */ 840f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong public synchronized VpnInfo getVpnInfo() { 841f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong if (!isRunningLocked()) { 842f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong return null; 843f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong } 844f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong 845f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong VpnInfo info = new VpnInfo(); 846f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong info.ownerUid = mOwnerUID; 847f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong info.vpnIface = mInterface; 848f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong return info; 849f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong } 850f5ea340aabee6e290448c8cc9fb0925da8b7db5eWenchao Tong 851c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran public synchronized boolean appliesToUid(int uid) { 852c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran if (!isRunningLocked()) { 853c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran return false; 854c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran } 855c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran for (UidRange uidRange : mVpnUsers) { 856c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran if (uidRange.start <= uid && uid <= uidRange.stop) { 857c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran return true; 858c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran } 859c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran } 860c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran return false; 861c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran } 862c2c0beab79a907f63e109eefe2a5aabcf2e3fd8fSreeram Ramachandran 86397a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh private native int jniCreate(int mtu); 864c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh private native String jniGetName(int tun); 86597a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh private native int jniSetAddresses(String interfaze, String addresses); 866c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh private native void jniReset(String interfaze); 867c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh private native int jniCheck(String interfaze); 868f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandran private native boolean jniAddAddress(String interfaze, String address, int prefixLen); 869f4e0c0cb8ef22fdb20ae74b444c9f4b7d15ded8bSreeram Ramachandran private native boolean jniDelAddress(String interfaze, String address, int prefixLen); 87085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 87141fb98c8681cbe0040b8d4efc65d33717c3819f6Lorenzo Colitti private static RouteInfo findIPv4DefaultRoute(LinkProperties prop) { 87241fb98c8681cbe0040b8d4efc65d33717c3819f6Lorenzo Colitti for (RouteInfo route : prop.getAllRoutes()) { 87382f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey // Currently legacy VPN only works on IPv4. 87482f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey if (route.isDefaultRoute() && route.getGateway() instanceof Inet4Address) { 87541fb98c8681cbe0040b8d4efc65d33717c3819f6Lorenzo Colitti return route; 87682f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey } 87782f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey } 87882f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey 87941fb98c8681cbe0040b8d4efc65d33717c3819f6Lorenzo Colitti throw new IllegalStateException("Unable to find IPv4 default gateway"); 88082f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey } 88182f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey 88285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh /** 88382f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey * Start legacy VPN, controlling native daemons as needed. Creates a 88482f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey * secondary thread to perform connection work, returning quickly. 885b21298a686b04d55ff97223dd317497845713f4bJeff Davidson * 886b21298a686b04d55ff97223dd317497845713f4bJeff Davidson * Should only be called to respond to Binder requests as this enforces caller permission. Use 887b21298a686b04d55ff97223dd317497845713f4bJeff Davidson * {@link #startLegacyVpnPrivileged(VpnProfile, KeyStore, LinkProperties)} to skip the 888b21298a686b04d55ff97223dd317497845713f4bJeff Davidson * permission check only when the caller is trusted (or the call is initiated by the system). 88985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh */ 89082f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey public void startLegacyVpn(VpnProfile profile, KeyStore keyStore, LinkProperties egress) { 8915a6bdc46e2fdc8cfd930396773dd89efd19fa1f1Robert Greenwalt enforceControlPermission(); 892b21298a686b04d55ff97223dd317497845713f4bJeff Davidson long token = Binder.clearCallingIdentity(); 893b21298a686b04d55ff97223dd317497845713f4bJeff Davidson try { 894b21298a686b04d55ff97223dd317497845713f4bJeff Davidson startLegacyVpnPrivileged(profile, keyStore, egress); 895b21298a686b04d55ff97223dd317497845713f4bJeff Davidson } finally { 896b21298a686b04d55ff97223dd317497845713f4bJeff Davidson Binder.restoreCallingIdentity(token); 897b21298a686b04d55ff97223dd317497845713f4bJeff Davidson } 898b21298a686b04d55ff97223dd317497845713f4bJeff Davidson } 899b21298a686b04d55ff97223dd317497845713f4bJeff Davidson 900b21298a686b04d55ff97223dd317497845713f4bJeff Davidson /** 901b21298a686b04d55ff97223dd317497845713f4bJeff Davidson * Like {@link #startLegacyVpn(VpnProfile, KeyStore, LinkProperties)}, but does not check 902b21298a686b04d55ff97223dd317497845713f4bJeff Davidson * permissions under the assumption that the caller is the system. 903b21298a686b04d55ff97223dd317497845713f4bJeff Davidson * 904b21298a686b04d55ff97223dd317497845713f4bJeff Davidson * Callers are responsible for checking permissions if needed. 905b21298a686b04d55ff97223dd317497845713f4bJeff Davidson */ 906b21298a686b04d55ff97223dd317497845713f4bJeff Davidson public void startLegacyVpnPrivileged(VpnProfile profile, KeyStore keyStore, 907b21298a686b04d55ff97223dd317497845713f4bJeff Davidson LinkProperties egress) { 908b9594ce9ebb3f5f303a280f04312ae5754ce3560Kenny Root if (!keyStore.isUnlocked()) { 90982f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey throw new IllegalStateException("KeyStore isn't unlocked"); 91082f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey } 911f5116d01b20f21ba32cd9eaa3412daf97f41c623Julia Reynolds UserManager mgr = UserManager.get(mContext); 9120784eeab28da094a87437ed454fe3dca01b1f9f2Paul Jensen UserInfo user = mgr.getUserInfo(mUserHandle); 91395778ffc58979d19ff9f4aaed396a6eca49cf698Nicolas Prevot if (user.isRestricted() || mgr.hasUserRestriction(UserManager.DISALLOW_CONFIG_VPN, 91495778ffc58979d19ff9f4aaed396a6eca49cf698Nicolas Prevot new UserHandle(mUserHandle))) { 915f5116d01b20f21ba32cd9eaa3412daf97f41c623Julia Reynolds throw new SecurityException("Restricted users cannot establish VPNs"); 916f5116d01b20f21ba32cd9eaa3412daf97f41c623Julia Reynolds } 91782f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey 91841fb98c8681cbe0040b8d4efc65d33717c3819f6Lorenzo Colitti final RouteInfo ipv4DefaultRoute = findIPv4DefaultRoute(egress); 91941fb98c8681cbe0040b8d4efc65d33717c3819f6Lorenzo Colitti final String gateway = ipv4DefaultRoute.getGateway().getHostAddress(); 92041fb98c8681cbe0040b8d4efc65d33717c3819f6Lorenzo Colitti final String iface = ipv4DefaultRoute.getInterface(); 92182f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey 92282f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey // Load certificates. 92382f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey String privateKey = ""; 92482f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey String userCert = ""; 92582f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey String caCert = ""; 92682f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey String serverCert = ""; 92782f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey if (!profile.ipsecUserCert.isEmpty()) { 92882f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey privateKey = Credentials.USER_PRIVATE_KEY + profile.ipsecUserCert; 92982f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey byte[] value = keyStore.get(Credentials.USER_CERTIFICATE + profile.ipsecUserCert); 930d396a448b2e36e29598c954b64bfddef73f3fae0Elliott Hughes userCert = (value == null) ? null : new String(value, StandardCharsets.UTF_8); 93182f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey } 93282f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey if (!profile.ipsecCaCert.isEmpty()) { 93382f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey byte[] value = keyStore.get(Credentials.CA_CERTIFICATE + profile.ipsecCaCert); 934d396a448b2e36e29598c954b64bfddef73f3fae0Elliott Hughes caCert = (value == null) ? null : new String(value, StandardCharsets.UTF_8); 93582f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey } 93682f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey if (!profile.ipsecServerCert.isEmpty()) { 93782f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey byte[] value = keyStore.get(Credentials.USER_CERTIFICATE + profile.ipsecServerCert); 938d396a448b2e36e29598c954b64bfddef73f3fae0Elliott Hughes serverCert = (value == null) ? null : new String(value, StandardCharsets.UTF_8); 93982f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey } 94082f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey if (privateKey == null || userCert == null || caCert == null || serverCert == null) { 94182f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey throw new IllegalStateException("Cannot load credentials"); 94282f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey } 94382f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey 94482f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey // Prepare arguments for racoon. 94582f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey String[] racoon = null; 94682f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey switch (profile.type) { 94782f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey case VpnProfile.TYPE_L2TP_IPSEC_PSK: 94882f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey racoon = new String[] { 94982f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey iface, profile.server, "udppsk", profile.ipsecIdentifier, 95082f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey profile.ipsecSecret, "1701", 95182f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey }; 95282f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey break; 95382f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey case VpnProfile.TYPE_L2TP_IPSEC_RSA: 95482f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey racoon = new String[] { 95582f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey iface, profile.server, "udprsa", privateKey, userCert, 95682f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey caCert, serverCert, "1701", 95782f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey }; 95882f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey break; 95982f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey case VpnProfile.TYPE_IPSEC_XAUTH_PSK: 96082f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey racoon = new String[] { 96182f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey iface, profile.server, "xauthpsk", profile.ipsecIdentifier, 96282f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey profile.ipsecSecret, profile.username, profile.password, "", gateway, 96382f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey }; 96482f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey break; 96582f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey case VpnProfile.TYPE_IPSEC_XAUTH_RSA: 96682f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey racoon = new String[] { 96782f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey iface, profile.server, "xauthrsa", privateKey, userCert, 96882f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey caCert, serverCert, profile.username, profile.password, "", gateway, 96982f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey }; 97082f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey break; 97182f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey case VpnProfile.TYPE_IPSEC_HYBRID_RSA: 97282f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey racoon = new String[] { 97382f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey iface, profile.server, "hybridrsa", 97482f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey caCert, serverCert, profile.username, profile.password, "", gateway, 97582f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey }; 97682f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey break; 97782f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey } 97882f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey 97982f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey // Prepare arguments for mtpd. 98082f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey String[] mtpd = null; 98182f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey switch (profile.type) { 98282f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey case VpnProfile.TYPE_PPTP: 98382f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey mtpd = new String[] { 98482f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey iface, "pptp", profile.server, "1723", 98582f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey "name", profile.username, "password", profile.password, 98682f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey "linkname", "vpn", "refuse-eap", "nodefaultroute", 98782f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey "usepeerdns", "idle", "1800", "mtu", "1400", "mru", "1400", 98882f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey (profile.mppe ? "+mppe" : "nomppe"), 98982f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey }; 99082f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey break; 99182f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey case VpnProfile.TYPE_L2TP_IPSEC_PSK: 99282f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey case VpnProfile.TYPE_L2TP_IPSEC_RSA: 99382f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey mtpd = new String[] { 99482f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey iface, "l2tp", profile.server, "1701", profile.l2tpSecret, 99582f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey "name", profile.username, "password", profile.password, 99682f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey "linkname", "vpn", "refuse-eap", "nodefaultroute", 99782f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey "usepeerdns", "idle", "1800", "mtu", "1400", "mru", "1400", 99882f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey }; 99982f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey break; 100082f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey } 1001899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey 100282f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey VpnConfig config = new VpnConfig(); 1003899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey config.legacy = true; 100482f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey config.user = profile.key; 100582f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey config.interfaze = iface; 100682f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey config.session = profile.name; 10074ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker 10084ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker config.addLegacyRoutes(profile.routes); 100982f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey if (!profile.dnsServers.isEmpty()) { 101082f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey config.dnsServers = Arrays.asList(profile.dnsServers.split(" +")); 101182f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey } 101282f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey if (!profile.searchDomains.isEmpty()) { 101382f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey config.searchDomains = Arrays.asList(profile.searchDomains.split(" +")); 101482f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey } 101582f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey startLegacyVpn(config, racoon, mtpd); 101682f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey } 101782f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey 101882f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey private synchronized void startLegacyVpn(VpnConfig config, String[] racoon, String[] mtpd) { 1019b21298a686b04d55ff97223dd317497845713f4bJeff Davidson stopLegacyVpnPrivileged(); 1020899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey 1021b21298a686b04d55ff97223dd317497845713f4bJeff Davidson // Prepare for the new request. 1022b21298a686b04d55ff97223dd317497845713f4bJeff Davidson prepareInternal(VpnConfig.LEGACY_VPN); 1023899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey updateState(DetailedState.CONNECTING, "startLegacyVpn"); 102485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 10252e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh // Start a new LegacyVpnRunner and we are done! 1026100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh mLegacyVpnRunner = new LegacyVpnRunner(config, racoon, mtpd); 1027100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh mLegacyVpnRunner.start(); 102885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 102985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 1030b21298a686b04d55ff97223dd317497845713f4bJeff Davidson /** Stop legacy VPN. Permissions must be checked by callers. */ 1031b21298a686b04d55ff97223dd317497845713f4bJeff Davidson public synchronized void stopLegacyVpnPrivileged() { 1032899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey if (mLegacyVpnRunner != null) { 1033899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey mLegacyVpnRunner.exit(); 1034899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey mLegacyVpnRunner = null; 1035899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey 1036899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey synchronized (LegacyVpnRunner.TAG) { 1037899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey // wait for old thread to completely finish before spinning up 1038899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey // new instance, otherwise state updates can be out of order. 1039899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } 1040899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } 1041899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } 1042899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey 104385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh /** 10442e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh * Return the information of the current ongoing legacy VPN. 10452e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh */ 10462e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh public synchronized LegacyVpnInfo getLegacyVpnInfo() { 1047dadc857d9de364fded10d4f69eb82bc9cd35d4b7Chia-chi Yeh // Check if the caller is authorized. 1048dadc857d9de364fded10d4f69eb82bc9cd35d4b7Chia-chi Yeh enforceControlPermission(); 104908bbca040fa921b99493cd9967453ed90b1b710asj.cha return getLegacyVpnInfoPrivileged(); 105008bbca040fa921b99493cd9967453ed90b1b710asj.cha } 105108bbca040fa921b99493cd9967453ed90b1b710asj.cha 105208bbca040fa921b99493cd9967453ed90b1b710asj.cha /** 105308bbca040fa921b99493cd9967453ed90b1b710asj.cha * Return the information of the current ongoing legacy VPN. 105408bbca040fa921b99493cd9967453ed90b1b710asj.cha * Callers are responsible for checking permissions if needed. 105508bbca040fa921b99493cd9967453ed90b1b710asj.cha */ 105608bbca040fa921b99493cd9967453ed90b1b710asj.cha public synchronized LegacyVpnInfo getLegacyVpnInfoPrivileged() { 1057899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey if (mLegacyVpnRunner == null) return null; 1058899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey 1059899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey final LegacyVpnInfo info = new LegacyVpnInfo(); 1060c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker info.key = mConfig.user; 1061899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey info.state = LegacyVpnInfo.stateFromNetworkInfo(mNetworkInfo); 106290b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson if (mNetworkInfo.isConnected()) { 106390b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson info.intent = mStatusIntent; 106490b1b9f985a91fb54254705515f822b09c68ac26Jeff Davidson } 1065899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey return info; 10662e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh } 10672e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh 106869ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey public VpnConfig getLegacyVpnConfig() { 106969ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey if (mLegacyVpnRunner != null) { 1070c2865195b66490bd1f9d3df4fe4f5e2a46e2196aChad Brubaker return mConfig; 107169ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey } else { 107269ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey return null; 107369ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey } 107469ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey } 107569ddab4575ff684c533c995e07ca15fe18543fc0Jeff Sharkey 10762e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh /** 107785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh * Bringing up a VPN connection takes time, and that is all this thread 107885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh * does. Here we have plenty of time. The only thing we need to take 107985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh * care of is responding to interruptions as soon as possible. Otherwise 108085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh * requests will be piled up. This can be done in a Handler as a state 108185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh * machine, but it is much easier to read in the current form. 108285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh */ 108385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh private class LegacyVpnRunner extends Thread { 108485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh private static final String TAG = "LegacyVpnRunner"; 108585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 10861f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh private final String[] mDaemons; 108785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh private final String[][] mArguments; 10885317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh private final LocalSocket[] mSockets; 108953c04bdd35a85aa65d1a1f18ca2ee34970e2c2d0Robert Greenwalt private final String mOuterInterface; 10901b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt private final AtomicInteger mOuterConnection = 10911b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt new AtomicInteger(ConnectivityManager.TYPE_NONE); 10922e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh 109385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh private long mTimer = -1; 109485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 10951b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt /** 10961b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt * Watch for the outer connection (passing in the constructor) going away. 10971b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt */ 10981b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 10991b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt @Override 11001b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt public void onReceive(Context context, Intent intent) { 110157666934b4a161cc2fb77eef15d0b894aaf8f173Jeff Sharkey if (!mEnableTeardown) return; 110257666934b4a161cc2fb77eef15d0b894aaf8f173Jeff Sharkey 11031b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) { 11041b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt if (intent.getIntExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, 11051b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt ConnectivityManager.TYPE_NONE) == mOuterConnection.get()) { 11061b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt NetworkInfo info = (NetworkInfo)intent.getExtra( 11071b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt ConnectivityManager.EXTRA_NETWORK_INFO); 11081b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt if (info != null && !info.isConnectedOrConnecting()) { 11091b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt try { 11101b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt mObserver.interfaceStatusChanged(mOuterInterface, false); 11111b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt } catch (RemoteException e) {} 11121b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt } 11131b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt } 11141b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt } 11151b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt } 11161b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt }; 11171b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt 111841d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh public LegacyVpnRunner(VpnConfig config, String[] racoon, String[] mtpd) { 111985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh super(TAG); 112041d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh mConfig = config; 112141d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh mDaemons = new String[] {"racoon", "mtpd"}; 1122899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey // TODO: clear arguments from memory once launched 112341d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh mArguments = new String[][] {racoon, mtpd}; 11245317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh mSockets = new LocalSocket[mDaemons.length]; 112553c04bdd35a85aa65d1a1f18ca2ee34970e2c2d0Robert Greenwalt 112653c04bdd35a85aa65d1a1f18ca2ee34970e2c2d0Robert Greenwalt // This is the interface which VPN is running on, 112753c04bdd35a85aa65d1a1f18ca2ee34970e2c2d0Robert Greenwalt // mConfig.interfaze will change to point to OUR 112853c04bdd35a85aa65d1a1f18ca2ee34970e2c2d0Robert Greenwalt // internal interface soon. TODO - add inner/outer to mconfig 11291b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt // TODO - we have a race - if the outer iface goes away/disconnects before we hit this 11304ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker // we will leave the VPN up. We should check that it's still there/connected after 11311b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt // registering 113253c04bdd35a85aa65d1a1f18ca2ee34970e2c2d0Robert Greenwalt mOuterInterface = mConfig.interfaze; 11331b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt 1134e75b9e355500b7c6a05e4d6ec54ef48835707caaPaul Jensen if (!TextUtils.isEmpty(mOuterInterface)) { 1135e75b9e355500b7c6a05e4d6ec54ef48835707caaPaul Jensen final ConnectivityManager cm = ConnectivityManager.from(mContext); 1136e75b9e355500b7c6a05e4d6ec54ef48835707caaPaul Jensen for (Network network : cm.getAllNetworks()) { 1137e75b9e355500b7c6a05e4d6ec54ef48835707caaPaul Jensen final LinkProperties lp = cm.getLinkProperties(network); 1138e75b9e355500b7c6a05e4d6ec54ef48835707caaPaul Jensen if (lp != null && mOuterInterface.equals(lp.getInterfaceName())) { 1139e75b9e355500b7c6a05e4d6ec54ef48835707caaPaul Jensen final NetworkInfo networkInfo = cm.getNetworkInfo(network); 1140e75b9e355500b7c6a05e4d6ec54ef48835707caaPaul Jensen if (networkInfo != null) mOuterConnection.set(networkInfo.getType()); 1141e75b9e355500b7c6a05e4d6ec54ef48835707caaPaul Jensen } 1142e75b9e355500b7c6a05e4d6ec54ef48835707caaPaul Jensen } 11431b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt } 11441b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt 11451b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt IntentFilter filter = new IntentFilter(); 11461b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); 11471b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt mContext.registerReceiver(mBroadcastReceiver, filter); 114841d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh } 114941d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh 1150aa1727fe0cbb902c5f53a3fae601b4e15da0a2f4Chia-chi Yeh public void check(String interfaze) { 115153c04bdd35a85aa65d1a1f18ca2ee34970e2c2d0Robert Greenwalt if (interfaze.equals(mOuterInterface)) { 1152aa1727fe0cbb902c5f53a3fae601b4e15da0a2f4Chia-chi Yeh Log.i(TAG, "Legacy VPN is going down with " + interfaze); 1153aa1727fe0cbb902c5f53a3fae601b4e15da0a2f4Chia-chi Yeh exit(); 1154aa1727fe0cbb902c5f53a3fae601b4e15da0a2f4Chia-chi Yeh } 1155aa1727fe0cbb902c5f53a3fae601b4e15da0a2f4Chia-chi Yeh } 1156aa1727fe0cbb902c5f53a3fae601b4e15da0a2f4Chia-chi Yeh 115741d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh public void exit() { 11585317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh // We assume that everything is reset after stopping the daemons. 115997a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh interrupt(); 11605317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh for (LocalSocket socket : mSockets) { 1161065b299df4159602327977dd007cb2cd6b64ab20Jeff Sharkey IoUtils.closeQuietly(socket); 116241d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh } 11636bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen agentDisconnect(); 11641b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt try { 11651b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt mContext.unregisterReceiver(mBroadcastReceiver); 11661b0ca9dace3fb3b84f8a87e539c0179e6093b423Robert Greenwalt } catch (IllegalArgumentException e) {} 11672e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh } 11682e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh 116985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh @Override 117085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh public void run() { 117185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Wait for the previous thread since it has been interrupted. 11722e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh Log.v(TAG, "Waiting"); 117385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh synchronized (TAG) { 11742e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh Log.v(TAG, "Executing"); 117585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh execute(); 1176899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey monitorDaemons(); 117785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 117885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 117985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 118085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh private void checkpoint(boolean yield) throws InterruptedException { 118185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh long now = SystemClock.elapsedRealtime(); 118285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh if (mTimer == -1) { 118385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh mTimer = now; 118485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh Thread.sleep(1); 11857ef8611b5f3a893a46c7b9e22bdd8ab252e373ffChia-chi Yeh } else if (now - mTimer <= 60000) { 118685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh Thread.sleep(yield ? 200 : 1); 118785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } else { 1188899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey updateState(DetailedState.FAILED, "checkpoint"); 118997a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh throw new IllegalStateException("Time is up"); 119085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 119185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 119285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 119385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh private void execute() { 119485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Catch all exceptions so we can clean up few things. 1195899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey boolean initFinished = false; 119685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh try { 119785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Initialize the timer. 119885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh checkpoint(false); 119985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 12001f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh // Wait for the daemons to stop. 12011f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh for (String daemon : mDaemons) { 1202088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey while (!SystemService.isStopped(daemon)) { 120385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh checkpoint(true); 120485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 120585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 120685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 120797a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh // Clear the previous state. 120897a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh File state = new File("/data/misc/vpn/state"); 120997a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh state.delete(); 121097a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh if (state.exists()) { 121197a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh throw new IllegalStateException("Cannot delete the state"); 121285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 1213c1872732922214de80f790e14865e41dd1b98203Chia-chi Yeh new File("/data/misc/vpn/abort").delete(); 1214899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey initFinished = true; 121585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 1216e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh // Check if we need to restart any of the daemons. 121785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh boolean restart = false; 121885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh for (String[] arguments : mArguments) { 121985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh restart = restart || (arguments != null); 122085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 122185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh if (!restart) { 12226bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen agentDisconnect(); 122385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh return; 122485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 1225899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey updateState(DetailedState.CONNECTING, "execute"); 122685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 12271f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh // Start the daemon with arguments. 12281f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh for (int i = 0; i < mDaemons.length; ++i) { 122985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh String[] arguments = mArguments[i]; 123085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh if (arguments == null) { 123185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh continue; 123285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 123385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 12341f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh // Start the daemon. 12351f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh String daemon = mDaemons[i]; 1236088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey SystemService.start(daemon); 123785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 12381f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh // Wait for the daemon to start. 1239088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey while (!SystemService.isRunning(daemon)) { 124085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh checkpoint(true); 124185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 124285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 124385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Create the control socket. 12445317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh mSockets[i] = new LocalSocket(); 124585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh LocalSocketAddress address = new LocalSocketAddress( 12461f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh daemon, LocalSocketAddress.Namespace.RESERVED); 124785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 124885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Wait for the socket to connect. 124985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh while (true) { 125085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh try { 12515317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh mSockets[i].connect(address); 125285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh break; 125385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } catch (Exception e) { 125485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // ignore 125585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 125685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh checkpoint(true); 125785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 12585317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh mSockets[i].setSoTimeout(500); 125985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 126085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Send over the arguments. 12615317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh OutputStream out = mSockets[i].getOutputStream(); 126285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh for (String argument : arguments) { 1263d396a448b2e36e29598c954b64bfddef73f3fae0Elliott Hughes byte[] bytes = argument.getBytes(StandardCharsets.UTF_8); 12645317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh if (bytes.length >= 0xFFFF) { 126597a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh throw new IllegalArgumentException("Argument is too large"); 126685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 12671f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh out.write(bytes.length >> 8); 12681f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh out.write(bytes.length); 12691f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh out.write(bytes); 127085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh checkpoint(false); 127185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 12725317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh out.write(0xFF); 12735317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh out.write(0xFF); 12741f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh out.flush(); 127597a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh 127697a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh // Wait for End-of-File. 12775317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh InputStream in = mSockets[i].getInputStream(); 127897a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh while (true) { 127997a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh try { 128097a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh if (in.read() == -1) { 128197a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh break; 128297a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh } 128397a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh } catch (Exception e) { 128497a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh // ignore 128597a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh } 128697a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh checkpoint(true); 128797a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh } 128885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 128985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 129097a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh // Wait for the daemons to create the new state. 129197a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh while (!state.exists()) { 12921f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh // Check if a running daemon is dead. 12931f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh for (int i = 0; i < mDaemons.length; ++i) { 12941f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh String daemon = mDaemons[i]; 1295088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey if (mArguments[i] != null && !SystemService.isRunning(daemon)) { 12962e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh throw new IllegalStateException(daemon + " is dead"); 129785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 129885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 129985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh checkpoint(true); 130085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 130185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 130297a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh // Now we are connected. Read and parse the new state. 1303c1bac3a6e240c1c9a14a7b515f585977fb908930Chia-chi Yeh String[] parameters = FileUtils.readTextFile(state, 0, null).split("\n", -1); 13045026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti if (parameters.length != 7) { 130597a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh throw new IllegalStateException("Cannot parse the state"); 130697a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh } 130797a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh 130897a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh // Set the interface and the addresses in the config. 130997a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh mConfig.interfaze = parameters[0].trim(); 131085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 13114ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker mConfig.addLegacyAddresses(parameters[1]); 131297a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh // Set the routes if they are not set in the config. 131397a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh if (mConfig.routes == null || mConfig.routes.isEmpty()) { 13144ca19e8377f33e8a80684fb4ee67f5a4bdc9ea76Chad Brubaker mConfig.addLegacyRoutes(parameters[2]); 131597a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh } 131697a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh 131797a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh // Set the DNS servers if they are not set in the config. 131841d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh if (mConfig.dnsServers == null || mConfig.dnsServers.size() == 0) { 131997a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh String dnsServers = parameters[3].trim(); 132041d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh if (!dnsServers.isEmpty()) { 132141d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh mConfig.dnsServers = Arrays.asList(dnsServers.split(" ")); 132241d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh } 132341d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh } 132441d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh 132597a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh // Set the search domains if they are not set in the config. 132697a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh if (mConfig.searchDomains == null || mConfig.searchDomains.size() == 0) { 132797a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh String searchDomains = parameters[4].trim(); 132897a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh if (!searchDomains.isEmpty()) { 132997a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh mConfig.searchDomains = Arrays.asList(searchDomains.split(" ")); 133097a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh } 133197a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh } 133297a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh 13335026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti // Add a throw route for the VPN server endpoint, if one was specified. 13345026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti String endpoint = parameters[5]; 13355026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti if (!endpoint.isEmpty()) { 13365026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti try { 13375026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti InetAddress addr = InetAddress.parseNumericAddress(endpoint); 13385026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti if (addr instanceof Inet4Address) { 13395026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti mConfig.routes.add(new RouteInfo(new IpPrefix(addr, 32), RTN_THROW)); 13405026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti } else if (addr instanceof Inet6Address) { 13415026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti mConfig.routes.add(new RouteInfo(new IpPrefix(addr, 128), RTN_THROW)); 13425026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti } else { 13435026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti Log.e(TAG, "Unknown IP address family for VPN endpoint: " + endpoint); 13445026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti } 13455026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti } catch (IllegalArgumentException e) { 13465026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti Log.e(TAG, "Exception constructing throw route to " + endpoint + ": " + e); 13475026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti } 13485026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti } 13495026279ce45ae78126046607a2634dc9dae93199Lorenzo Colitti 135097a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh // Here is the last step and it must be done synchronously. 135141d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh synchronized (Vpn.this) { 13522b862e5e75ad419f17a4cea185b9349e0da70e7bVinit Deshapnde // Set the start time 13532b862e5e75ad419f17a4cea185b9349e0da70e7bVinit Deshapnde mConfig.startTime = SystemClock.elapsedRealtime(); 13542b862e5e75ad419f17a4cea185b9349e0da70e7bVinit Deshapnde 135541d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh // Check if the thread is interrupted while we are waiting. 135641d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh checkpoint(false); 135741d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh 1358e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh // Check if the interface is gone while we are waiting. 1359c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh if (jniCheck(mConfig.interfaze) == 0) { 136034e7813e962de99df9813014678ef5901227c5f1Chia-chi Yeh throw new IllegalStateException(mConfig.interfaze + " is gone"); 136141d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh } 1362e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh 1363e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh // Now INetworkManagementEventObserver is watching our back. 1364c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh mInterface = mConfig.interfaze; 13656bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen mVpnUsers = new ArrayList<UidRange>(); 13666bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen 13676bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen agentConnect(); 13682e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh 13692e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh Log.i(TAG, "Connected!"); 137041d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh } 137185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } catch (Exception e) { 13722e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh Log.i(TAG, "Aborting", e); 1373438406092ed71c658bf5a4e6ae2e7282fc4fab4dLorenzo Colitti updateState(DetailedState.FAILED, e.getMessage()); 1374e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh exit(); 13752e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh } finally { 13765317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh // Kill the daemons if they fail to stop. 1377899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey if (!initFinished) { 13785317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh for (String daemon : mDaemons) { 1379088f29f55eebc6862a4cb5dddeaefacf24f74d95Jeff Sharkey SystemService.stop(daemon); 13805317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh } 13815317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh } 13825317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh 13832e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh // Do not leave an unstable state. 1384899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey if (!initFinished || mNetworkInfo.getDetailedState() == DetailedState.CONNECTING) { 13856bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen agentDisconnect(); 13862e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh } 138785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 138885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 1389899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey 1390899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey /** 1391899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey * Monitor the daemons we started, moving to disconnected state if the 1392899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey * underlying services fail. 1393899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey */ 1394899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey private void monitorDaemons() { 1395899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey if (!mNetworkInfo.isConnected()) { 1396899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey return; 1397899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } 1398899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey 1399899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey try { 1400899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey while (true) { 1401899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey Thread.sleep(2000); 1402899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey for (int i = 0; i < mDaemons.length; i++) { 1403899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey if (mArguments[i] != null && SystemService.isStopped(mDaemons[i])) { 1404899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey return; 1405899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } 1406899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } 1407899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } 1408899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } catch (InterruptedException e) { 1409899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey Log.d(TAG, "interrupted during monitorDaemons(); stopping services"); 1410899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } finally { 1411899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey for (String daemon : mDaemons) { 1412899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey SystemService.stop(daemon); 1413899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } 1414899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey 14156bc2c2c34f2b23eae79ad733c97a691734055c4fPaul Jensen agentDisconnect(); 1416899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } 1417899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey } 141885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 1419ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh} 1420