blob: ede3bda5bea27bc8967f20a65f7b5152c641db9a [file] [log] [blame]
Chia-chi Yehff3bdca2011-05-23 17:26:46 -07001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.connectivity;
18
Jeff Sharkey899223b2012-08-04 15:24:58 -070019import static android.Manifest.permission.BIND_VPN_SERVICE;
Paul Jensen31a94f42015-02-13 14:18:39 -050020import static android.net.ConnectivityManager.NETID_UNSET;
Lorenzo Colitti50262792014-09-19 01:53:35 +090021import static android.net.RouteInfo.RTN_THROW;
Lorenzo Colitti60446162014-09-20 00:14:31 +090022import static android.net.RouteInfo.RTN_UNREACHABLE;
Jeff Sharkey899223b2012-08-04 15:24:58 -070023
Jeff Davidsonbc19c182014-11-11 13:20:01 -080024import android.Manifest;
Robin Lee4d03abc2016-05-09 12:32:27 +010025import android.annotation.NonNull;
26import android.annotation.Nullable;
27import android.annotation.UserIdInt;
Chad Brubaker4ca19e82013-06-14 11:16:51 -070028import android.app.AppGlobals;
Jeff Davidson05542602014-08-11 14:07:27 -070029import android.app.AppOpsManager;
Jeff Davidson90b1b9f2014-08-22 13:05:43 -070030import android.app.PendingIntent;
Robert Greenwalt1b0ca9d2013-04-22 11:13:02 -070031import android.content.BroadcastReceiver;
Chia-chi Yeh199ed6e2011-08-03 17:38:49 -070032import android.content.ComponentName;
Robin Lee812800c2016-05-13 15:38:08 +010033import android.content.ContentResolver;
Chia-chi Yehff3bdca2011-05-23 17:26:46 -070034import android.content.Context;
35import android.content.Intent;
Robert Greenwalt1b0ca9d2013-04-22 11:13:02 -070036import android.content.IntentFilter;
Chia-chi Yeh199ed6e2011-08-03 17:38:49 -070037import android.content.ServiceConnection;
Chia-chi Yehff3bdca2011-05-23 17:26:46 -070038import android.content.pm.PackageManager;
Paul Jensen6bc2c2c2014-05-07 15:27:40 -040039import android.content.pm.PackageManager.NameNotFoundException;
Chia-chi Yeh199ed6e2011-08-03 17:38:49 -070040import android.content.pm.ResolveInfo;
Chad Brubakerc2865192013-07-10 14:46:23 -070041import android.content.pm.UserInfo;
Jeff Sharkey899223b2012-08-04 15:24:58 -070042import android.net.ConnectivityManager;
Chia-chi Yehff3bdca2011-05-23 17:26:46 -070043import android.net.INetworkManagementEventObserver;
Lorenzo Colitti50262792014-09-19 01:53:35 +090044import android.net.IpPrefix;
Chad Brubaker4ca19e82013-06-14 11:16:51 -070045import android.net.LinkAddress;
Jeff Sharkey82f85212012-08-24 11:17:25 -070046import android.net.LinkProperties;
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -070047import android.net.LocalSocket;
48import android.net.LocalSocketAddress;
Sreeram Ramachandranc2c0bea2014-11-11 16:09:21 -080049import android.net.Network;
Paul Jensen6bc2c2c2014-05-07 15:27:40 -040050import android.net.NetworkAgent;
51import android.net.NetworkCapabilities;
Jeff Sharkey899223b2012-08-04 15:24:58 -070052import android.net.NetworkInfo;
Paul Jensen6bc2c2c2014-05-07 15:27:40 -040053import android.net.NetworkInfo.DetailedState;
Sreeram Ramachandran8cd33ed2014-07-23 15:23:15 -070054import android.net.NetworkMisc;
Jeff Sharkey82f85212012-08-24 11:17:25 -070055import android.net.RouteInfo;
Paul Jensen6bc2c2c2014-05-07 15:27:40 -040056import android.net.UidRange;
Robin Lee812800c2016-05-13 15:38:08 +010057import android.net.Uri;
Chia-chi Yehff3bdca2011-05-23 17:26:46 -070058import android.os.Binder;
Chia-chi Yehc1bac3a2011-12-16 15:00:31 -080059import android.os.FileUtils;
Chia-chi Yeh199ed6e2011-08-03 17:38:49 -070060import android.os.IBinder;
Jeff Sharkey899223b2012-08-04 15:24:58 -070061import android.os.INetworkManagementService;
Paul Jensen6bc2c2c2014-05-07 15:27:40 -040062import android.os.Looper;
Chia-chi Yeh199ed6e2011-08-03 17:38:49 -070063import android.os.Parcel;
Chia-chi Yehff3bdca2011-05-23 17:26:46 -070064import android.os.ParcelFileDescriptor;
Robin Lee812800c2016-05-13 15:38:08 +010065import android.os.PatternMatcher;
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -070066import android.os.Process;
Jeff Sharkey899223b2012-08-04 15:24:58 -070067import android.os.RemoteException;
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -070068import android.os.SystemClock;
Jeff Sharkey088f29f2012-08-05 14:55:04 -070069import android.os.SystemService;
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -070070import android.os.UserHandle;
Chad Brubakerc2865192013-07-10 14:46:23 -070071import android.os.UserManager;
Robin Lee812800c2016-05-13 15:38:08 +010072import android.provider.Settings;
Jeff Sharkey82f85212012-08-24 11:17:25 -070073import android.security.Credentials;
74import android.security.KeyStore;
Paul Jensene75b9e32015-04-06 11:54:53 -040075import android.text.TextUtils;
Robin Lee4d03abc2016-05-09 12:32:27 +010076import android.util.ArraySet;
Chia-chi Yehff3bdca2011-05-23 17:26:46 -070077import android.util.Log;
78
Chad Brubakerc2865192013-07-10 14:46:23 -070079import com.android.internal.annotations.GuardedBy;
Robin Lee4d03abc2016-05-09 12:32:27 +010080import com.android.internal.annotations.VisibleForTesting;
Chia-chi Yeh2e467642011-07-04 03:23:12 -070081import com.android.internal.net.LegacyVpnInfo;
Chia-chi Yeh04ba25c2011-06-15 17:07:27 -070082import com.android.internal.net.VpnConfig;
Wenchao Tongf5ea3402015-03-04 13:26:38 -080083import com.android.internal.net.VpnInfo;
Jeff Sharkey82f85212012-08-24 11:17:25 -070084import com.android.internal.net.VpnProfile;
Jeff Sharkey899223b2012-08-04 15:24:58 -070085import com.android.server.net.BaseNetworkObserver;
Chia-chi Yehff3bdca2011-05-23 17:26:46 -070086
Jeff Davidson05542602014-08-11 14:07:27 -070087import libcore.io.IoUtils;
88
Chia-chi Yeh97a61562011-07-14 15:05:05 -070089import java.io.File;
Jeff Davidson6bbf39c2014-07-23 10:14:53 -070090import java.io.IOException;
Chia-chi Yeh97a61562011-07-14 15:05:05 -070091import java.io.InputStream;
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -070092import java.io.OutputStream;
Jeff Sharkey82f85212012-08-24 11:17:25 -070093import java.net.Inet4Address;
Sreeram Ramachandranf4e0c0c2014-07-27 14:18:26 -070094import java.net.Inet6Address;
95import java.net.InetAddress;
Elliott Hughesd396a442013-06-28 16:24:48 -070096import java.nio.charset.StandardCharsets;
Paul Jensen6bc2c2c2014-05-07 15:27:40 -040097import java.util.ArrayList;
Chia-chi Yeh41d16852011-07-01 02:12:06 -070098import java.util.Arrays;
Robin Lee4d03abc2016-05-09 12:32:27 +010099import java.util.Collection;
100import java.util.Collections;
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400101import java.util.List;
Robin Lee4d03abc2016-05-09 12:32:27 +0100102import java.util.Set;
Paul Jensen0784eea2014-08-19 16:00:24 -0400103import java.util.SortedSet;
104import java.util.TreeSet;
Robert Greenwalt1b0ca9d2013-04-22 11:13:02 -0700105import java.util.concurrent.atomic.AtomicInteger;
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -0700106
Chia-chi Yehff3bdca2011-05-23 17:26:46 -0700107/**
108 * @hide
109 */
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400110public class Vpn {
111 private static final String NETWORKTYPE = "VPN";
Jeff Sharkey899223b2012-08-04 15:24:58 -0700112 private static final String TAG = "Vpn";
113 private static final boolean LOGD = true;
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400114
Jeff Sharkey899223b2012-08-04 15:24:58 -0700115 // TODO: create separate trackers for each unique VPN to support
116 // automated reconnection
Chia-chi Yehff3bdca2011-05-23 17:26:46 -0700117
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400118 private Context mContext;
119 private NetworkInfo mNetworkInfo;
120 private String mPackage;
121 private int mOwnerUID;
Chia-chi Yehc2b8aa02011-07-03 18:00:47 -0700122 private String mInterface;
Chia-chi Yeh199ed6e2011-08-03 17:38:49 -0700123 private Connection mConnection;
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -0700124 private LegacyVpnRunner mLegacyVpnRunner;
Jeff Davidson90b1b9f2014-08-22 13:05:43 -0700125 private PendingIntent mStatusIntent;
Jeff Sharkey57666932013-04-30 17:01:57 -0700126 private volatile boolean mEnableTeardown = true;
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400127 private final INetworkManagementService mNetd;
Chad Brubakerc2865192013-07-10 14:46:23 -0700128 private VpnConfig mConfig;
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400129 private NetworkAgent mNetworkAgent;
130 private final Looper mLooper;
131 private final NetworkCapabilities mNetworkCapabilities;
Chad Brubakerc2865192013-07-10 14:46:23 -0700132
Robin Lee4d03abc2016-05-09 12:32:27 +0100133 /**
Robin Lee17e61832016-05-09 13:46:28 +0100134 * Whether to keep the connection active after rebooting, or upgrading or reinstalling. This
135 * only applies to {@link VpnService} connections.
136 */
137 private boolean mAlwaysOn = false;
138
139 /**
140 * Whether to disable traffic outside of this VPN even when the VPN is not connected. System
141 * apps can still bypass by choosing explicit networks. Has no effect if {@link mAlwaysOn} is
142 * not set.
143 */
144 private boolean mLockdown = false;
145
146 /**
Robin Lee4d03abc2016-05-09 12:32:27 +0100147 * List of UIDs that are set to use this VPN by default. Normally, every UID in the user is
148 * added to this set but that can be changed by adding allowed or disallowed applications. It
149 * is non-null iff the VPN is connected.
150 *
151 * Unless the VPN has set allowBypass=true, these UIDs are forced into the VPN.
152 *
153 * @see VpnService.Builder#addAllowedApplication(String)
154 * @see VpnService.Builder#addDisallowedApplication(String)
155 */
Chad Brubakerc2865192013-07-10 14:46:23 -0700156 @GuardedBy("this")
Robin Lee4d03abc2016-05-09 12:32:27 +0100157 private Set<UidRange> mVpnUsers = null;
Chad Brubakerc2865192013-07-10 14:46:23 -0700158
Robin Lee17e61832016-05-09 13:46:28 +0100159 /**
160 * List of UIDs for which networking should be blocked until VPN is ready, during brief periods
161 * when VPN is not running. For example, during system startup or after a crash.
162 * @see mLockdown
163 */
164 @GuardedBy("this")
165 private Set<UidRange> mBlockedUsers = new ArraySet<>();
166
Paul Jensen0784eea2014-08-19 16:00:24 -0400167 // Handle of user initiating VPN.
168 private final int mUserHandle;
Chia-chi Yehff3bdca2011-05-23 17:26:46 -0700169
Robin Lee812800c2016-05-13 15:38:08 +0100170 // Listen to package remove and change event in this user
171 private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
172 @Override
173 public void onReceive(Context context, Intent intent) {
174 final Uri data = intent.getData();
175 final String packageName = data == null ? null : data.getSchemeSpecificPart();
176 if (packageName == null) {
177 return;
178 }
179
180 synchronized (Vpn.this) {
181 // Avoid race that always-on package has been unset
182 if (!packageName.equals(getAlwaysOnPackage())) {
183 return;
184 }
185
186 final String action = intent.getAction();
187 Log.i(TAG, "Received broadcast " + action + " for always-on package " + packageName
188 + " in user " + mUserHandle);
189
190 switch(action) {
191 case Intent.ACTION_PACKAGE_REPLACED:
192 // Start vpn after app upgrade
193 startAlwaysOnVpn();
194 break;
195 case Intent.ACTION_PACKAGE_REMOVED:
196 final boolean isPackageRemoved = !intent.getBooleanExtra(
197 Intent.EXTRA_REPLACING, false);
198 if (isPackageRemoved) {
199 setAndSaveAlwaysOnPackage(null, false);
200 }
201 break;
202 }
203 }
204 }
205 };
206
207 private boolean mIsPackageIntentReceiverRegistered = false;
208
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400209 public Vpn(Looper looper, Context context, INetworkManagementService netService,
Paul Jensene75b9e32015-04-06 11:54:53 -0400210 int userHandle) {
Chia-chi Yehff3bdca2011-05-23 17:26:46 -0700211 mContext = context;
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400212 mNetd = netService;
Paul Jensen0784eea2014-08-19 16:00:24 -0400213 mUserHandle = userHandle;
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400214 mLooper = looper;
215
216 mPackage = VpnConfig.LEGACY_VPN;
Paul Jensen0784eea2014-08-19 16:00:24 -0400217 mOwnerUID = getAppUid(mPackage, mUserHandle);
Jeff Sharkey899223b2012-08-04 15:24:58 -0700218
219 try {
220 netService.registerObserver(mObserver);
221 } catch (RemoteException e) {
222 Log.wtf(TAG, "Problem registering observer", e);
223 }
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400224
225 mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_VPN, 0, NETWORKTYPE, "");
226 // TODO: Copy metered attribute and bandwidths from physical transport, b/16207332
227 mNetworkCapabilities = new NetworkCapabilities();
228 mNetworkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_VPN);
229 mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN);
Jeff Sharkey899223b2012-08-04 15:24:58 -0700230 }
231
Jeff Sharkey57666932013-04-30 17:01:57 -0700232 /**
Jeff Sharkey57666932013-04-30 17:01:57 -0700233 * Set if this object is responsible for watching for {@link NetworkInfo}
234 * teardown. When {@code false}, teardown is handled externally by someone
235 * else.
236 */
237 public void setEnableTeardown(boolean enableTeardown) {
238 mEnableTeardown = enableTeardown;
239 }
240
Jeff Sharkey899223b2012-08-04 15:24:58 -0700241 /**
242 * Update current state, dispaching event to listeners.
243 */
244 private void updateState(DetailedState detailedState, String reason) {
245 if (LOGD) Log.d(TAG, "setting state=" + detailedState + ", reason=" + reason);
246 mNetworkInfo.setDetailedState(detailedState, reason, null);
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400247 if (mNetworkAgent != null) {
248 mNetworkAgent.sendNetworkInfo(mNetworkInfo);
249 }
Chia-chi Yehff3bdca2011-05-23 17:26:46 -0700250 }
251
252 /**
Robin Lee244ce8e2016-01-05 18:03:46 +0000253 * Configures an always-on VPN connection through a specific application.
254 * This connection is automatically granted and persisted after a reboot.
255 *
256 * <p>The designated package should exist and declare a {@link VpnService} in its
257 * manifest guarded by {@link android.Manifest.permission.BIND_VPN_SERVICE},
258 * otherwise the call will fail.
259 *
Robin Lee17e61832016-05-09 13:46:28 +0100260 * @param packageName the package to designate as always-on VPN supplier.
261 * @param lockdown whether to prevent traffic outside of a VPN, for example while connecting.
Robin Lee9ff1a582016-06-10 16:41:10 +0100262 * @return {@code true} if the package has been set as always-on, {@code false} otherwise.
Robin Lee244ce8e2016-01-05 18:03:46 +0000263 */
Robin Lee17e61832016-05-09 13:46:28 +0100264 public synchronized boolean setAlwaysOnPackage(String packageName, boolean lockdown) {
Robin Lee244ce8e2016-01-05 18:03:46 +0000265 enforceControlPermissionOrInternalCaller();
Robin Lee9ff1a582016-06-10 16:41:10 +0100266 if (VpnConfig.LEGACY_VPN.equals(packageName)) {
267 Log.w(TAG, "Not setting legacy VPN \"" + packageName + "\" as always-on.");
268 return false;
269 }
Robin Lee244ce8e2016-01-05 18:03:46 +0000270
Robin Lee244ce8e2016-01-05 18:03:46 +0000271 if (packageName != null) {
Robin Lee9ff1a582016-06-10 16:41:10 +0100272 // Pre-authorize new always-on VPN package.
Robin Lee244ce8e2016-01-05 18:03:46 +0000273 if (!setPackageAuthorization(packageName, true)) {
274 return false;
275 }
Robin Lee9ff1a582016-06-10 16:41:10 +0100276 mAlwaysOn = true;
277 } else {
278 packageName = VpnConfig.LEGACY_VPN;
279 mAlwaysOn = false;
Robin Lee244ce8e2016-01-05 18:03:46 +0000280 }
281
Robin Lee17e61832016-05-09 13:46:28 +0100282 mLockdown = (mAlwaysOn && lockdown);
Robin Lee9ff1a582016-06-10 16:41:10 +0100283 if (!isCurrentPreparedPackage(packageName)) {
284 prepareInternal(packageName);
285 }
Robin Lee812800c2016-05-13 15:38:08 +0100286 maybeRegisterPackageChangeReceiverLocked(packageName);
Robin Lee17e61832016-05-09 13:46:28 +0100287 setVpnForcedLocked(mLockdown);
Robin Lee244ce8e2016-01-05 18:03:46 +0000288 return true;
289 }
290
Robin Lee9ff1a582016-06-10 16:41:10 +0100291 private static boolean isNullOrLegacyVpn(String packageName) {
292 return packageName == null || VpnConfig.LEGACY_VPN.equals(packageName);
293 }
294
Robin Lee812800c2016-05-13 15:38:08 +0100295 private void unregisterPackageChangeReceiverLocked() {
296 // register previous intent filter
297 if (mIsPackageIntentReceiverRegistered) {
298 mContext.unregisterReceiver(mPackageIntentReceiver);
299 mIsPackageIntentReceiverRegistered = false;
300 }
301 }
302
303 private void maybeRegisterPackageChangeReceiverLocked(String packageName) {
304 // Unregister IntentFilter listening for previous always-on package change
305 unregisterPackageChangeReceiverLocked();
306
Robin Lee9ff1a582016-06-10 16:41:10 +0100307 if (!isNullOrLegacyVpn(packageName)) {
Robin Lee812800c2016-05-13 15:38:08 +0100308 mIsPackageIntentReceiverRegistered = true;
309
310 IntentFilter intentFilter = new IntentFilter();
311 // Protected intent can only be sent by system. No permission required in register.
312 intentFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
313 intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
314 intentFilter.addDataScheme("package");
315 intentFilter.addDataSchemeSpecificPart(packageName, PatternMatcher.PATTERN_LITERAL);
316 mContext.registerReceiverAsUser(
317 mPackageIntentReceiver, UserHandle.of(mUserHandle), intentFilter, null, null);
318 }
319 }
320
Robin Lee244ce8e2016-01-05 18:03:46 +0000321 /**
322 * @return the package name of the VPN controller responsible for always-on VPN,
323 * or {@code null} if none is set or always-on VPN is controlled through
324 * lockdown instead.
325 * @hide
326 */
327 public synchronized String getAlwaysOnPackage() {
328 enforceControlPermissionOrInternalCaller();
Robin Lee17e61832016-05-09 13:46:28 +0100329 return (mAlwaysOn ? mPackage : null);
Robin Lee244ce8e2016-01-05 18:03:46 +0000330 }
331
332 /**
Robin Lee812800c2016-05-13 15:38:08 +0100333 * Save the always-on package and lockdown config into Settings.Secure
334 */
335 public synchronized void saveAlwaysOnPackage() {
336 final long token = Binder.clearCallingIdentity();
337 try {
338 final ContentResolver cr = mContext.getContentResolver();
339 Settings.Secure.putStringForUser(cr, Settings.Secure.ALWAYS_ON_VPN_APP,
340 getAlwaysOnPackage(), mUserHandle);
341 Settings.Secure.putIntForUser(cr, Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN,
342 (mLockdown ? 1 : 0), mUserHandle);
343 } finally {
344 Binder.restoreCallingIdentity(token);
345 }
346 }
347
348 /**
349 * Set and save always-on package and lockdown config
350 * @see Vpn#setAlwaysOnPackage(String, boolean)
351 * @see Vpn#saveAlwaysOnPackage()
352 *
353 * @return result of Vpn#setAndSaveAlwaysOnPackage(String, boolean)
354 */
355 private synchronized boolean setAndSaveAlwaysOnPackage(String packageName, boolean lockdown) {
356 if (setAlwaysOnPackage(packageName, lockdown)) {
357 saveAlwaysOnPackage();
358 return true;
359 } else {
360 return false;
361 }
362 }
363
364 /**
365 * @return {@code true} if the service was started, the service was already connected, or there
366 * was no always-on VPN to start. {@code false} otherwise.
367 */
368 public boolean startAlwaysOnVpn() {
369 final String alwaysOnPackage;
370 synchronized (this) {
371 alwaysOnPackage = getAlwaysOnPackage();
372 // Skip if there is no service to start.
373 if (alwaysOnPackage == null) {
374 return true;
375 }
376 // Skip if the service is already established. This isn't bulletproof: it's not bound
377 // until after establish(), so if it's mid-setup onStartCommand will be sent twice,
378 // which may restart the connection.
379 if (getNetworkInfo().isConnected()) {
380 return true;
381 }
382 }
383
384 // Start the VPN service declared in the app's manifest.
385 Intent serviceIntent = new Intent(VpnConfig.SERVICE_INTERFACE);
386 serviceIntent.setPackage(alwaysOnPackage);
387 try {
388 return mContext.startServiceAsUser(serviceIntent, UserHandle.of(mUserHandle)) != null;
389 } catch (RuntimeException e) {
390 Log.e(TAG, "VpnService " + serviceIntent + " failed to start", e);
391 return false;
392 }
393 }
394
395 /**
Chia-chi Yeh100155a2011-07-03 16:52:38 -0700396 * Prepare for a VPN application. This method is designed to solve
397 * race conditions. It first compares the current prepared package
398 * with {@code oldPackage}. If they are the same, the prepared
399 * package is revoked and replaced with {@code newPackage}. If
400 * {@code oldPackage} is {@code null}, the comparison is omitted.
401 * If {@code newPackage} is the same package or {@code null}, the
402 * revocation is omitted. This method returns {@code true} if the
403 * operation is succeeded.
Chia-chi Yehff3bdca2011-05-23 17:26:46 -0700404 *
Chia-chi Yeh100155a2011-07-03 16:52:38 -0700405 * Legacy VPN is handled specially since it is not a real package.
406 * It uses {@link VpnConfig#LEGACY_VPN} as its package name, and
407 * it can be revoked by itself.
408 *
Victor Chang98a633a2016-05-27 17:30:49 +0100409 * Note: when we added VPN pre-consent in http://ag/522961 the names oldPackage
410 * and newPackage become misleading, because when an app is pre-consented, we
411 * actually prepare oldPackage, not newPackage.
412 *
413 * Their meanings actually are:
414 *
415 * - oldPackage non-null, newPackage null: App calling VpnService#prepare().
416 * - oldPackage null, newPackage non-null: ConfirmDialog calling prepareVpn().
Robin Lee812800c2016-05-13 15:38:08 +0100417 * - oldPackage null, newPackage=LEGACY_VPN: Used internally to disconnect
Victor Chang98a633a2016-05-27 17:30:49 +0100418 * and revoke any current app VPN and re-prepare legacy vpn.
419 *
Robin Lee812800c2016-05-13 15:38:08 +0100420 * TODO: Rename the variables - or split this method into two - and end this confusion.
421 * TODO: b/29032008 Migrate code from prepare(oldPackage=non-null, newPackage=LEGACY_VPN)
422 * to prepare(oldPackage=null, newPackage=LEGACY_VPN)
Victor Chang98a633a2016-05-27 17:30:49 +0100423 *
424 * @param oldPackage The package name of the old VPN application
425 * @param newPackage The package name of the new VPN application
426 *
Chia-chi Yeh100155a2011-07-03 16:52:38 -0700427 * @return true if the operation is succeeded.
Chia-chi Yehe9107902011-07-02 01:48:50 -0700428 */
Chia-chi Yeh100155a2011-07-03 16:52:38 -0700429 public synchronized boolean prepare(String oldPackage, String newPackage) {
Jeff Davidson0a775ce2015-04-27 15:02:48 -0700430 if (oldPackage != null) {
Victor Chang98a633a2016-05-27 17:30:49 +0100431 // Stop an existing always-on VPN from being dethroned by other apps.
Robin Lee812800c2016-05-13 15:38:08 +0100432 if (mAlwaysOn && !isCurrentPreparedPackage(oldPackage)) {
Victor Chang98a633a2016-05-27 17:30:49 +0100433 return false;
434 }
435
436 // Package is not same or old package was reinstalled.
437 if (!isCurrentPreparedPackage(oldPackage)) {
Jeff Davidson0a775ce2015-04-27 15:02:48 -0700438 // The package doesn't match. We return false (to obtain user consent) unless the
439 // user has already consented to that VPN package.
440 if (!oldPackage.equals(VpnConfig.LEGACY_VPN) && isVpnUserPreConsented(oldPackage)) {
441 prepareInternal(oldPackage);
442 return true;
443 }
444 return false;
445 } else if (!oldPackage.equals(VpnConfig.LEGACY_VPN)
446 && !isVpnUserPreConsented(oldPackage)) {
447 // Currently prepared VPN is revoked, so unprepare it and return false.
448 prepareInternal(VpnConfig.LEGACY_VPN);
449 return false;
Jeff Davidson05542602014-08-11 14:07:27 -0700450 }
Chia-chi Yehe9107902011-07-02 01:48:50 -0700451 }
452
Chia-chi Yeh100155a2011-07-03 16:52:38 -0700453 // Return true if we do not need to revoke.
Jeff Davidsonbe085872014-10-24 10:35:53 -0700454 if (newPackage == null || (!newPackage.equals(VpnConfig.LEGACY_VPN) &&
Victor Chang98a633a2016-05-27 17:30:49 +0100455 isCurrentPreparedPackage(newPackage))) {
Chia-chi Yeh100155a2011-07-03 16:52:38 -0700456 return true;
457 }
458
Robin Lee1b1bcd72016-02-12 18:11:30 +0000459 // Check that the caller is authorized.
Chia-chi Yehdadc8572012-06-08 13:05:58 -0700460 enforceControlPermission();
Chia-chi Yehe9107902011-07-02 01:48:50 -0700461
Victor Chang98a633a2016-05-27 17:30:49 +0100462 // Stop an existing always-on VPN from being dethroned by other apps.
Robin Lee812800c2016-05-13 15:38:08 +0100463 if (mAlwaysOn && !isCurrentPreparedPackage(newPackage)) {
Victor Chang98a633a2016-05-27 17:30:49 +0100464 return false;
465 }
466
Jeff Davidson11008a72014-11-20 13:12:46 -0800467 prepareInternal(newPackage);
468 return true;
469 }
Chia-chi Yehe9107902011-07-02 01:48:50 -0700470
Victor Chang98a633a2016-05-27 17:30:49 +0100471 private boolean isCurrentPreparedPackage(String packageName) {
472 // We can't just check that packageName matches mPackage, because if the app was uninstalled
473 // and reinstalled it will no longer be prepared. Instead check the UID.
474 return getAppUid(packageName, mUserHandle) == mOwnerUID;
475 }
476
Jeff Davidson11008a72014-11-20 13:12:46 -0800477 /** Prepare the VPN for the given package. Does not perform permission checks. */
478 private void prepareInternal(String newPackage) {
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400479 long token = Binder.clearCallingIdentity();
480 try {
Jeff Davidson11008a72014-11-20 13:12:46 -0800481 // Reset the interface.
482 if (mInterface != null) {
483 mStatusIntent = null;
484 agentDisconnect();
485 jniReset(mInterface);
486 mInterface = null;
487 mVpnUsers = null;
488 }
489
490 // Revoke the connection or stop LegacyVpnRunner.
491 if (mConnection != null) {
492 try {
493 mConnection.mService.transact(IBinder.LAST_CALL_TRANSACTION,
494 Parcel.obtain(), null, IBinder.FLAG_ONEWAY);
495 } catch (Exception e) {
496 // ignore
497 }
498 mContext.unbindService(mConnection);
499 mConnection = null;
500 } else if (mLegacyVpnRunner != null) {
501 mLegacyVpnRunner.exit();
502 mLegacyVpnRunner = null;
503 }
504
505 try {
506 mNetd.denyProtect(mOwnerUID);
507 } catch (Exception e) {
508 Log.wtf(TAG, "Failed to disallow UID " + mOwnerUID + " to call protect() " + e);
509 }
510
511 Log.i(TAG, "Switched from " + mPackage + " to " + newPackage);
512 mPackage = newPackage;
513 mOwnerUID = getAppUid(newPackage, mUserHandle);
514 try {
515 mNetd.allowProtect(mOwnerUID);
516 } catch (Exception e) {
517 Log.wtf(TAG, "Failed to allow UID " + mOwnerUID + " to call protect() " + e);
518 }
519 mConfig = null;
520
521 updateState(DetailedState.IDLE, "prepare");
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400522 } finally {
523 Binder.restoreCallingIdentity(token);
524 }
Chia-chi Yehe9107902011-07-02 01:48:50 -0700525 }
526
Jeff Davidson05542602014-08-11 14:07:27 -0700527 /**
Robin Lee3b3dd942015-05-12 18:14:58 +0100528 * Set whether a package has the ability to launch VPNs without user intervention.
Jeff Davidson05542602014-08-11 14:07:27 -0700529 */
Robin Lee244ce8e2016-01-05 18:03:46 +0000530 public boolean setPackageAuthorization(String packageName, boolean authorized) {
Jeff Davidson05542602014-08-11 14:07:27 -0700531 // Check if the caller is authorized.
Robin Lee244ce8e2016-01-05 18:03:46 +0000532 enforceControlPermissionOrInternalCaller();
Jeff Davidson05542602014-08-11 14:07:27 -0700533
Robin Lee3b3dd942015-05-12 18:14:58 +0100534 int uid = getAppUid(packageName, mUserHandle);
535 if (uid == -1 || VpnConfig.LEGACY_VPN.equals(packageName)) {
536 // Authorization for nonexistent packages (or fake ones) can't be updated.
Robin Lee244ce8e2016-01-05 18:03:46 +0000537 return false;
Jeff Davidson05542602014-08-11 14:07:27 -0700538 }
539
540 long token = Binder.clearCallingIdentity();
541 try {
542 AppOpsManager appOps =
543 (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
Robin Lee3b3dd942015-05-12 18:14:58 +0100544 appOps.setMode(AppOpsManager.OP_ACTIVATE_VPN, uid, packageName,
Jeff Davidson05542602014-08-11 14:07:27 -0700545 authorized ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
Robin Lee244ce8e2016-01-05 18:03:46 +0000546 return true;
Jeff Davidson05542602014-08-11 14:07:27 -0700547 } catch (Exception e) {
Robin Lee3b3dd942015-05-12 18:14:58 +0100548 Log.wtf(TAG, "Failed to set app ops for package " + packageName + ", uid " + uid, e);
Jeff Davidson05542602014-08-11 14:07:27 -0700549 } finally {
550 Binder.restoreCallingIdentity(token);
551 }
Robin Lee244ce8e2016-01-05 18:03:46 +0000552 return false;
Jeff Davidson05542602014-08-11 14:07:27 -0700553 }
554
555 private boolean isVpnUserPreConsented(String packageName) {
556 AppOpsManager appOps =
557 (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
558
559 // Verify that the caller matches the given package and has permission to activate VPNs.
560 return appOps.noteOpNoThrow(AppOpsManager.OP_ACTIVATE_VPN, Binder.getCallingUid(),
561 packageName) == AppOpsManager.MODE_ALLOWED;
562 }
563
Paul Jensen0784eea2014-08-19 16:00:24 -0400564 private int getAppUid(String app, int userHandle) {
Jeff Davidson05542602014-08-11 14:07:27 -0700565 if (VpnConfig.LEGACY_VPN.equals(app)) {
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400566 return Process.myUid();
Chia-chi Yehfcc1b412011-08-03 15:39:59 -0700567 }
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400568 PackageManager pm = mContext.getPackageManager();
569 int result;
Chad Brubaker4ca19e82013-06-14 11:16:51 -0700570 try {
Jeff Sharkeye06b4d12016-01-06 14:51:50 -0700571 result = pm.getPackageUidAsUser(app, userHandle);
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400572 } catch (NameNotFoundException e) {
573 result = -1;
574 }
575 return result;
576 }
577
578 public NetworkInfo getNetworkInfo() {
579 return mNetworkInfo;
580 }
581
Paul Jensen31a94f42015-02-13 14:18:39 -0500582 public int getNetId() {
583 return mNetworkAgent != null ? mNetworkAgent.netId : NETID_UNSET;
584 }
585
Lorenzo Colitti60446162014-09-20 00:14:31 +0900586 private LinkProperties makeLinkProperties() {
587 boolean allowIPv4 = mConfig.allowIPv4;
588 boolean allowIPv6 = mConfig.allowIPv6;
589
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400590 LinkProperties lp = new LinkProperties();
Lorenzo Colitti60446162014-09-20 00:14:31 +0900591
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400592 lp.setInterfaceName(mInterface);
Sreeram Ramachandran42065ac2014-07-27 00:37:35 -0700593
Lorenzo Colitti60446162014-09-20 00:14:31 +0900594 if (mConfig.addresses != null) {
595 for (LinkAddress address : mConfig.addresses) {
596 lp.addLinkAddress(address);
597 allowIPv4 |= address.getAddress() instanceof Inet4Address;
598 allowIPv6 |= address.getAddress() instanceof Inet6Address;
599 }
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400600 }
Lorenzo Colitti60446162014-09-20 00:14:31 +0900601
602 if (mConfig.routes != null) {
603 for (RouteInfo route : mConfig.routes) {
604 lp.addRoute(route);
605 InetAddress address = route.getDestination().getAddress();
606 allowIPv4 |= address instanceof Inet4Address;
607 allowIPv6 |= address instanceof Inet6Address;
608 }
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400609 }
Sreeram Ramachandran42065ac2014-07-27 00:37:35 -0700610
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400611 if (mConfig.dnsServers != null) {
612 for (String dnsServer : mConfig.dnsServers) {
Sreeram Ramachandran42065ac2014-07-27 00:37:35 -0700613 InetAddress address = InetAddress.parseNumericAddress(dnsServer);
614 lp.addDnsServer(address);
Lorenzo Colitti60446162014-09-20 00:14:31 +0900615 allowIPv4 |= address instanceof Inet4Address;
616 allowIPv6 |= address instanceof Inet6Address;
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400617 }
618 }
Sreeram Ramachandran42065ac2014-07-27 00:37:35 -0700619
Lorenzo Colitti60446162014-09-20 00:14:31 +0900620 if (!allowIPv4) {
621 lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE));
622 }
623 if (!allowIPv6) {
624 lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE));
625 }
626
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400627 // Concatenate search domains into a string.
628 StringBuilder buffer = new StringBuilder();
629 if (mConfig.searchDomains != null) {
630 for (String domain : mConfig.searchDomains) {
631 buffer.append(domain).append(' ');
632 }
633 }
634 lp.setDomains(buffer.toString().trim());
Sreeram Ramachandran42065ac2014-07-27 00:37:35 -0700635
Lorenzo Colitti60446162014-09-20 00:14:31 +0900636 // TODO: Stop setting the MTU in jniCreate and set it here.
637
638 return lp;
639 }
640
641 private void agentConnect() {
642 LinkProperties lp = makeLinkProperties();
643
644 if (lp.hasIPv4DefaultRoute() || lp.hasIPv6DefaultRoute()) {
645 mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
646 } else {
647 mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
648 }
649
Robin Lee323f29d2016-05-04 16:38:06 +0100650 mNetworkInfo.setDetailedState(DetailedState.CONNECTING, null, null);
Sreeram Ramachandran42065ac2014-07-27 00:37:35 -0700651
Sreeram Ramachandran8cd33ed2014-07-23 15:23:15 -0700652 NetworkMisc networkMisc = new NetworkMisc();
Robin Lee17e61832016-05-09 13:46:28 +0100653 networkMisc.allowBypass = mConfig.allowBypass && !mLockdown;
Sreeram Ramachandran42065ac2014-07-27 00:37:35 -0700654
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400655 long token = Binder.clearCallingIdentity();
656 try {
657 mNetworkAgent = new NetworkAgent(mLooper, mContext, NETWORKTYPE,
Sreeram Ramachandran8cd33ed2014-07-23 15:23:15 -0700658 mNetworkInfo, mNetworkCapabilities, lp, 0, networkMisc) {
Jeff Davidson05542602014-08-11 14:07:27 -0700659 @Override
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400660 public void unwanted() {
661 // We are user controlled, not driven by NetworkRequest.
Jeff Davidson05542602014-08-11 14:07:27 -0700662 }
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400663 };
Chad Brubaker4ca19e82013-06-14 11:16:51 -0700664 } finally {
665 Binder.restoreCallingIdentity(token);
666 }
Sreeram Ramachandran42065ac2014-07-27 00:37:35 -0700667
Robin Lee4d03abc2016-05-09 12:32:27 +0100668 mVpnUsers = createUserAndRestrictedProfilesRanges(mUserHandle,
669 mConfig.allowedApplications, mConfig.disallowedApplications);
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400670 mNetworkAgent.addUidRanges(mVpnUsers.toArray(new UidRange[mVpnUsers.size()]));
Robin Lee323f29d2016-05-04 16:38:06 +0100671
672 mNetworkInfo.setIsAvailable(true);
673 updateState(DetailedState.CONNECTED, "agentConnect");
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400674 }
Chad Brubaker4ca19e82013-06-14 11:16:51 -0700675
Fyodor Kupolov1c363152015-09-02 13:27:21 -0700676 private boolean canHaveRestrictedProfile(int userId) {
677 long token = Binder.clearCallingIdentity();
678 try {
679 return UserManager.get(mContext).canHaveRestrictedProfile(userId);
680 } finally {
681 Binder.restoreCallingIdentity(token);
682 }
683 }
684
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400685 private void agentDisconnect(NetworkInfo networkInfo, NetworkAgent networkAgent) {
686 networkInfo.setIsAvailable(false);
687 networkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
688 if (networkAgent != null) {
689 networkAgent.sendNetworkInfo(networkInfo);
690 }
691 }
692
693 private void agentDisconnect(NetworkAgent networkAgent) {
694 NetworkInfo networkInfo = new NetworkInfo(mNetworkInfo);
695 agentDisconnect(networkInfo, networkAgent);
696 }
697
698 private void agentDisconnect() {
699 if (mNetworkInfo.isConnected()) {
700 agentDisconnect(mNetworkInfo, mNetworkAgent);
701 mNetworkAgent = null;
702 }
Chia-chi Yehfcc1b412011-08-03 15:39:59 -0700703 }
704
705 /**
Chia-chi Yehe9107902011-07-02 01:48:50 -0700706 * Establish a VPN network and return the file descriptor of the VPN
707 * interface. This methods returns {@code null} if the application is
Chia-chi Yeh100155a2011-07-03 16:52:38 -0700708 * revoked or not prepared.
Chia-chi Yehe9107902011-07-02 01:48:50 -0700709 *
710 * @param config The parameters to configure the network.
711 * @return The file descriptor of the VPN interface.
Chia-chi Yehff3bdca2011-05-23 17:26:46 -0700712 */
Chia-chi Yeh04ba25c2011-06-15 17:07:27 -0700713 public synchronized ParcelFileDescriptor establish(VpnConfig config) {
Chia-chi Yehff3bdca2011-05-23 17:26:46 -0700714 // Check if the caller is already prepared.
Chad Brubakerc2865192013-07-10 14:46:23 -0700715 UserManager mgr = UserManager.get(mContext);
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400716 if (Binder.getCallingUid() != mOwnerUID) {
Chia-chi Yeh7b0b8342011-06-17 14:34:11 -0700717 return null;
Chia-chi Yehff3bdca2011-05-23 17:26:46 -0700718 }
Jeff Davidson0a775ce2015-04-27 15:02:48 -0700719 // Check to ensure consent hasn't been revoked since we were prepared.
720 if (!isVpnUserPreConsented(mPackage)) {
721 return null;
722 }
Chia-chi Yehfcc1b412011-08-03 15:39:59 -0700723 // Check if the service is properly declared.
Chia-chi Yeh199ed6e2011-08-03 17:38:49 -0700724 Intent intent = new Intent(VpnConfig.SERVICE_INTERFACE);
725 intent.setClassName(mPackage, config.user);
Chad Brubaker4ca19e82013-06-14 11:16:51 -0700726 long token = Binder.clearCallingIdentity();
727 try {
Chad Brubakerc2865192013-07-10 14:46:23 -0700728 // Restricted users are not allowed to create VPNs, they are tied to Owner
Paul Jensen0784eea2014-08-19 16:00:24 -0400729 UserInfo user = mgr.getUserInfo(mUserHandle);
Robin Lee628ae0d2016-05-20 14:53:48 +0100730 if (user.isRestricted()) {
Chad Brubakerc2865192013-07-10 14:46:23 -0700731 throw new SecurityException("Restricted users cannot establish VPNs");
732 }
733
Chad Brubaker4ca19e82013-06-14 11:16:51 -0700734 ResolveInfo info = AppGlobals.getPackageManager().resolveService(intent,
Paul Jensen0784eea2014-08-19 16:00:24 -0400735 null, 0, mUserHandle);
Chad Brubaker4ca19e82013-06-14 11:16:51 -0700736 if (info == null) {
737 throw new SecurityException("Cannot find " + config.user);
738 }
739 if (!BIND_VPN_SERVICE.equals(info.serviceInfo.permission)) {
740 throw new SecurityException(config.user + " does not require " + BIND_VPN_SERVICE);
741 }
742 } catch (RemoteException e) {
743 throw new SecurityException("Cannot find " + config.user);
744 } finally {
745 Binder.restoreCallingIdentity(token);
Chia-chi Yeh199ed6e2011-08-03 17:38:49 -0700746 }
Chia-chi Yehfcc1b412011-08-03 15:39:59 -0700747
Chad Brubaker850eb672014-03-21 21:02:47 +0000748 // Save the old config in case we need to go back.
749 VpnConfig oldConfig = mConfig;
750 String oldInterface = mInterface;
751 Connection oldConnection = mConnection;
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400752 NetworkAgent oldNetworkAgent = mNetworkAgent;
753 mNetworkAgent = null;
Robin Lee4d03abc2016-05-09 12:32:27 +0100754 Set<UidRange> oldUsers = mVpnUsers;
Chad Brubaker850eb672014-03-21 21:02:47 +0000755
Chia-chi Yehe9107902011-07-02 01:48:50 -0700756 // Configure the interface. Abort if any of these steps fails.
Chia-chi Yeh97a61562011-07-14 15:05:05 -0700757 ParcelFileDescriptor tun = ParcelFileDescriptor.adoptFd(jniCreate(config.mtu));
Chia-chi Yehff3bdca2011-05-23 17:26:46 -0700758 try {
Jeff Sharkey899223b2012-08-04 15:24:58 -0700759 updateState(DetailedState.CONNECTING, "establish");
Chia-chi Yehc2b8aa02011-07-03 18:00:47 -0700760 String interfaze = jniGetName(tun.getFd());
Chad Brubaker4ca19e82013-06-14 11:16:51 -0700761
Chad Brubakerc2865192013-07-10 14:46:23 -0700762 // TEMP use the old jni calls until there is support for netd address setting
Chad Brubaker4ca19e82013-06-14 11:16:51 -0700763 StringBuilder builder = new StringBuilder();
764 for (LinkAddress address : config.addresses) {
765 builder.append(" " + address);
766 }
767 if (jniSetAddresses(interfaze, builder.toString()) < 1) {
Chia-chi Yeh97a61562011-07-14 15:05:05 -0700768 throw new IllegalArgumentException("At least one address must be specified");
769 }
Chia-chi Yeh199ed6e2011-08-03 17:38:49 -0700770 Connection connection = new Connection();
Dianne Hackbornd69e4c12015-04-24 09:54:54 -0700771 if (!mContext.bindServiceAsUser(intent, connection,
772 Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
773 new UserHandle(mUserHandle))) {
Chia-chi Yeh199ed6e2011-08-03 17:38:49 -0700774 throw new IllegalStateException("Cannot bind " + config.user);
775 }
Chad Brubaker850eb672014-03-21 21:02:47 +0000776
Chia-chi Yeh199ed6e2011-08-03 17:38:49 -0700777 mConnection = connection;
Chia-chi Yehc2b8aa02011-07-03 18:00:47 -0700778 mInterface = interfaze;
Chad Brubaker4ca19e82013-06-14 11:16:51 -0700779
780 // Fill more values.
781 config.user = mPackage;
782 config.interfaze = mInterface;
Chad Brubakerc2865192013-07-10 14:46:23 -0700783 config.startTime = SystemClock.elapsedRealtime();
784 mConfig = config;
Chad Brubaker850eb672014-03-21 21:02:47 +0000785
Chad Brubaker4ca19e82013-06-14 11:16:51 -0700786 // Set up forwarding and DNS rules.
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400787 agentConnect();
Chad Brubaker850eb672014-03-21 21:02:47 +0000788
789 if (oldConnection != null) {
790 mContext.unbindService(oldConnection);
791 }
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400792 // Remove the old tun's user forwarding rules
793 // The new tun's user rules have already been added so they will take over
794 // as rules are deleted. This prevents data leakage as the rules are moved over.
795 agentDisconnect(oldNetworkAgent);
Chad Brubaker850eb672014-03-21 21:02:47 +0000796 if (oldInterface != null && !oldInterface.equals(interfaze)) {
Chad Brubaker850eb672014-03-21 21:02:47 +0000797 jniReset(oldInterface);
798 }
Jeff Davidson6bbf39c2014-07-23 10:14:53 -0700799
800 try {
801 IoUtils.setBlocking(tun.getFileDescriptor(), config.blocking);
802 } catch (IOException e) {
803 throw new IllegalStateException(
804 "Cannot set tunnel's fd as blocking=" + config.blocking, e);
805 }
Chad Brubaker850eb672014-03-21 21:02:47 +0000806 } catch (RuntimeException e) {
Chad Brubaker850eb672014-03-21 21:02:47 +0000807 IoUtils.closeQuietly(tun);
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400808 agentDisconnect();
Chad Brubaker850eb672014-03-21 21:02:47 +0000809 // restore old state
810 mConfig = oldConfig;
811 mConnection = oldConnection;
812 mVpnUsers = oldUsers;
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400813 mNetworkAgent = oldNetworkAgent;
Chad Brubaker850eb672014-03-21 21:02:47 +0000814 mInterface = oldInterface;
815 throw e;
Chad Brubakerc2865192013-07-10 14:46:23 -0700816 }
Chad Brubaker850eb672014-03-21 21:02:47 +0000817 Log.i(TAG, "Established by " + config.user + " on " + mInterface);
Chia-chi Yehc2b8aa02011-07-03 18:00:47 -0700818 return tun;
Chia-chi Yehff3bdca2011-05-23 17:26:46 -0700819 }
820
Chad Brubakerc2865192013-07-10 14:46:23 -0700821 private boolean isRunningLocked() {
Sreeram Ramachandranc2c0bea2014-11-11 16:09:21 -0800822 return mNetworkAgent != null && mInterface != null;
823 }
824
825 // Returns true if the VPN has been established and the calling UID is its owner. Used to check
826 // that a call to mutate VPN state is admissible.
827 private boolean isCallerEstablishedOwnerLocked() {
828 return isRunningLocked() && Binder.getCallingUid() == mOwnerUID;
Chad Brubakerc2865192013-07-10 14:46:23 -0700829 }
830
Paul Jensen0784eea2014-08-19 16:00:24 -0400831 // Note: Return type guarantees results are deduped and sorted, which callers require.
832 private SortedSet<Integer> getAppsUids(List<String> packageNames, int userHandle) {
833 SortedSet<Integer> uids = new TreeSet<Integer>();
834 for (String app : packageNames) {
835 int uid = getAppUid(app, userHandle);
836 if (uid != -1) uids.add(uid);
837 }
838 return uids;
839 }
840
Robin Lee4d03abc2016-05-09 12:32:27 +0100841 /**
842 * Creates a {@link Set} of non-intersecting {@link UidRange} objects including all UIDs
843 * associated with one user, and any restricted profiles attached to that user.
844 *
845 * <p>If one of {@param allowedApplications} or {@param disallowedApplications} is provided,
846 * the UID ranges will match the app whitelist or blacklist specified there. Otherwise, all UIDs
847 * in each user and profile will be included.
848 *
849 * @param userHandle The userId to create UID ranges for along with any of its restricted
850 * profiles.
851 * @param allowedApplications (optional) whitelist of applications to include.
852 * @param disallowedApplications (optional) blacklist of applications to exclude.
853 */
854 @VisibleForTesting
855 Set<UidRange> createUserAndRestrictedProfilesRanges(@UserIdInt int userHandle,
856 @Nullable List<String> allowedApplications,
857 @Nullable List<String> disallowedApplications) {
858 final Set<UidRange> ranges = new ArraySet<>();
Robert Greenwalt69887e82013-09-24 11:05:57 -0700859
Robin Lee4d03abc2016-05-09 12:32:27 +0100860 // Assign the top-level user to the set of ranges
861 addUserToRanges(ranges, userHandle, allowedApplications, disallowedApplications);
862
863 // If the user can have restricted profiles, assign all its restricted profiles too
864 if (canHaveRestrictedProfile(userHandle)) {
865 final long token = Binder.clearCallingIdentity();
866 List<UserInfo> users;
867 try {
Robin Lee17e61832016-05-09 13:46:28 +0100868 users = UserManager.get(mContext).getUsers(true);
Robin Lee4d03abc2016-05-09 12:32:27 +0100869 } finally {
870 Binder.restoreCallingIdentity(token);
871 }
872 for (UserInfo user : users) {
873 if (user.isRestricted() && (user.restrictedProfileParentId == userHandle)) {
874 addUserToRanges(ranges, user.id, allowedApplications, disallowedApplications);
875 }
876 }
877 }
878 return ranges;
879 }
880
881 /**
882 * Updates a {@link Set} of non-intersecting {@link UidRange} objects to include all UIDs
883 * associated with one user.
884 *
885 * <p>If one of {@param allowedApplications} or {@param disallowedApplications} is provided,
886 * the UID ranges will match the app whitelist or blacklist specified there. Otherwise, all UIDs
887 * in the user will be included.
888 *
889 * @param ranges {@link Set} of {@link UidRange}s to which to add.
890 * @param userHandle The userId to add to {@param ranges}.
891 * @param allowedApplications (optional) whitelist of applications to include.
892 * @param disallowedApplications (optional) blacklist of applications to exclude.
893 */
894 @VisibleForTesting
895 void addUserToRanges(@NonNull Set<UidRange> ranges, @UserIdInt int userHandle,
896 @Nullable List<String> allowedApplications,
897 @Nullable List<String> disallowedApplications) {
898 if (allowedApplications != null) {
Paul Jensen0784eea2014-08-19 16:00:24 -0400899 // Add ranges covering all UIDs for allowedApplications.
900 int start = -1, stop = -1;
Robin Lee4d03abc2016-05-09 12:32:27 +0100901 for (int uid : getAppsUids(allowedApplications, userHandle)) {
Paul Jensen0784eea2014-08-19 16:00:24 -0400902 if (start == -1) {
903 start = uid;
904 } else if (uid != stop + 1) {
Robin Lee4d03abc2016-05-09 12:32:27 +0100905 ranges.add(new UidRange(start, stop));
Paul Jensen0784eea2014-08-19 16:00:24 -0400906 start = uid;
907 }
908 stop = uid;
909 }
Robin Lee4d03abc2016-05-09 12:32:27 +0100910 if (start != -1) ranges.add(new UidRange(start, stop));
911 } else if (disallowedApplications != null) {
Paul Jensen0784eea2014-08-19 16:00:24 -0400912 // Add all ranges for user skipping UIDs for disallowedApplications.
913 final UidRange userRange = UidRange.createForUser(userHandle);
914 int start = userRange.start;
Robin Lee4d03abc2016-05-09 12:32:27 +0100915 for (int uid : getAppsUids(disallowedApplications, userHandle)) {
Paul Jensen0784eea2014-08-19 16:00:24 -0400916 if (uid == start) {
917 start++;
918 } else {
Robin Lee4d03abc2016-05-09 12:32:27 +0100919 ranges.add(new UidRange(start, uid - 1));
Paul Jensen0784eea2014-08-19 16:00:24 -0400920 start = uid + 1;
921 }
922 }
Robin Lee4d03abc2016-05-09 12:32:27 +0100923 if (start <= userRange.stop) ranges.add(new UidRange(start, userRange.stop));
Paul Jensen0784eea2014-08-19 16:00:24 -0400924 } else {
925 // Add all UIDs for the user.
Robin Lee4d03abc2016-05-09 12:32:27 +0100926 ranges.add(UidRange.createForUser(userHandle));
Paul Jensen0784eea2014-08-19 16:00:24 -0400927 }
Chad Brubakerc2865192013-07-10 14:46:23 -0700928 }
929
Paul Jensen0784eea2014-08-19 16:00:24 -0400930 // Returns the subset of the full list of active UID ranges the VPN applies to (mVpnUsers) that
931 // apply to userHandle.
932 private List<UidRange> uidRangesForUser(int userHandle) {
933 final UidRange userRange = UidRange.createForUser(userHandle);
934 final List<UidRange> ranges = new ArrayList<UidRange>();
935 for (UidRange range : mVpnUsers) {
Robin Lee4d03abc2016-05-09 12:32:27 +0100936 if (userRange.containsRange(range)) {
Paul Jensen0784eea2014-08-19 16:00:24 -0400937 ranges.add(range);
938 }
939 }
940 return ranges;
941 }
942
943 private void removeVpnUserLocked(int userHandle) {
Sreeram Ramachandranc2c0bea2014-11-11 16:09:21 -0800944 if (mVpnUsers == null) {
Jeff Davidson90b1b9f2014-08-22 13:05:43 -0700945 throw new IllegalStateException("VPN is not active");
946 }
Paul Jensen0784eea2014-08-19 16:00:24 -0400947 final List<UidRange> ranges = uidRangesForUser(userHandle);
Jeff Davidson90b1b9f2014-08-22 13:05:43 -0700948 if (mNetworkAgent != null) {
Paul Jensen0784eea2014-08-19 16:00:24 -0400949 mNetworkAgent.removeUidRanges(ranges.toArray(new UidRange[ranges.size()]));
Jeff Davidson90b1b9f2014-08-22 13:05:43 -0700950 }
Paul Jensen0784eea2014-08-19 16:00:24 -0400951 mVpnUsers.removeAll(ranges);
Chad Brubakerc2865192013-07-10 14:46:23 -0700952 }
953
Fyodor Kupolov1c363152015-09-02 13:27:21 -0700954 public void onUserAdded(int userHandle) {
955 // If the user is restricted tie them to the parent user's VPN
956 UserInfo user = UserManager.get(mContext).getUserInfo(userHandle);
Robin Lee17e61832016-05-09 13:46:28 +0100957 if (user.isRestricted() && user.restrictedProfileParentId == mUserHandle) {
Fyodor Kupolov1c363152015-09-02 13:27:21 -0700958 synchronized(Vpn.this) {
Robin Lee17e61832016-05-09 13:46:28 +0100959 if (mVpnUsers != null) {
960 try {
961 addUserToRanges(mVpnUsers, userHandle, mConfig.allowedApplications,
962 mConfig.disallowedApplications);
963 if (mNetworkAgent != null) {
964 final List<UidRange> ranges = uidRangesForUser(userHandle);
965 mNetworkAgent.addUidRanges(ranges.toArray(new UidRange[ranges.size()]));
966 }
967 } catch (Exception e) {
968 Log.wtf(TAG, "Failed to add restricted user to owner", e);
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400969 }
Robin Lee17e61832016-05-09 13:46:28 +0100970 }
971 if (mAlwaysOn) {
972 setVpnForcedLocked(mLockdown);
Chad Brubakerc2865192013-07-10 14:46:23 -0700973 }
974 }
975 }
976 }
977
Fyodor Kupolov1c363152015-09-02 13:27:21 -0700978 public void onUserRemoved(int userHandle) {
Chad Brubakerc2865192013-07-10 14:46:23 -0700979 // clean up if restricted
Fyodor Kupolov1c363152015-09-02 13:27:21 -0700980 UserInfo user = UserManager.get(mContext).getUserInfo(userHandle);
Robin Lee17e61832016-05-09 13:46:28 +0100981 if (user.isRestricted() && user.restrictedProfileParentId == mUserHandle) {
Fyodor Kupolov1c363152015-09-02 13:27:21 -0700982 synchronized(Vpn.this) {
Robin Lee17e61832016-05-09 13:46:28 +0100983 if (mVpnUsers != null) {
984 try {
985 removeVpnUserLocked(userHandle);
986 } catch (Exception e) {
987 Log.wtf(TAG, "Failed to remove restricted user to owner", e);
988 }
989 }
990 if (mAlwaysOn) {
991 setVpnForcedLocked(mLockdown);
Chad Brubakerc2865192013-07-10 14:46:23 -0700992 }
993 }
994 }
995 }
996
Chad Brubakerbf6ff2c2013-07-16 18:59:12 -0700997 /**
Robin Lee17e61832016-05-09 13:46:28 +0100998 * Called when the user associated with this VPN has just been stopped.
999 */
1000 public synchronized void onUserStopped() {
1001 // Switch off networking lockdown (if it was enabled)
1002 setVpnForcedLocked(false);
1003 mAlwaysOn = false;
1004
Robin Lee812800c2016-05-13 15:38:08 +01001005 unregisterPackageChangeReceiverLocked();
Robin Lee17e61832016-05-09 13:46:28 +01001006 // Quit any active connections
1007 agentDisconnect();
1008 }
1009
1010 /**
1011 * Restrict network access from all UIDs affected by this {@link Vpn}, apart from the VPN
1012 * service app itself, to only sockets that have had {@code protect()} called on them. All
1013 * non-VPN traffic is blocked via a {@code PROHIBIT} response from the kernel.
1014 *
1015 * The exception for the VPN UID isn't technically necessary -- setup should use protected
1016 * sockets -- but in practice it saves apps that don't protect their sockets from breaking.
1017 *
1018 * Calling multiple times with {@param enforce} = {@code true} will recreate the set of UIDs to
1019 * block every time, and if anything has changed update using {@link #setAllowOnlyVpnForUids}.
1020 *
1021 * @param enforce {@code true} to require that all traffic under the jurisdiction of this
1022 * {@link Vpn} goes through a VPN connection or is blocked until one is
1023 * available, {@code false} to lift the requirement.
1024 *
1025 * @see #mBlockedUsers
1026 */
1027 @GuardedBy("this")
1028 private void setVpnForcedLocked(boolean enforce) {
1029 final Set<UidRange> removedRanges = new ArraySet<>(mBlockedUsers);
1030 if (enforce) {
1031 final Set<UidRange> addedRanges = createUserAndRestrictedProfilesRanges(mUserHandle,
1032 /* allowedApplications */ null,
1033 /* disallowedApplications */ Collections.singletonList(mPackage));
1034
1035 removedRanges.removeAll(addedRanges);
1036 addedRanges.removeAll(mBlockedUsers);
1037
1038 setAllowOnlyVpnForUids(false, removedRanges);
1039 setAllowOnlyVpnForUids(true, addedRanges);
1040 } else {
1041 setAllowOnlyVpnForUids(false, removedRanges);
1042 }
1043 }
1044
1045 /**
1046 * Either add or remove a list of {@link UidRange}s to the list of UIDs that are only allowed
1047 * to make connections through sockets that have had {@code protect()} called on them.
1048 *
1049 * @param enforce {@code true} to add to the blacklist, {@code false} to remove.
1050 * @param ranges {@link Collection} of {@link UidRange}s to add (if {@param enforce} is
1051 * {@code true}) or to remove.
1052 * @return {@code true} if all of the UIDs were added/removed. {@code false} otherwise,
1053 * including added ranges that already existed or removed ones that didn't.
1054 */
1055 @GuardedBy("this")
1056 private boolean setAllowOnlyVpnForUids(boolean enforce, Collection<UidRange> ranges) {
1057 if (ranges.size() == 0) {
1058 return true;
1059 }
1060 final UidRange[] rangesArray = ranges.toArray(new UidRange[ranges.size()]);
1061 try {
1062 mNetd.setAllowOnlyVpnForUids(enforce, rangesArray);
1063 } catch (RemoteException | RuntimeException e) {
1064 Log.e(TAG, "Updating blocked=" + enforce
1065 + " for UIDs " + Arrays.toString(ranges.toArray()) + " failed", e);
1066 return false;
1067 }
1068 if (enforce) {
1069 mBlockedUsers.addAll(ranges);
1070 } else {
1071 mBlockedUsers.removeAll(ranges);
1072 }
1073 return true;
1074 }
1075
1076 /**
Chad Brubakerbf6ff2c2013-07-16 18:59:12 -07001077 * Return the configuration of the currently running VPN.
1078 */
1079 public VpnConfig getVpnConfig() {
1080 enforceControlPermission();
1081 return mConfig;
1082 }
1083
Jeff Sharkey899223b2012-08-04 15:24:58 -07001084 @Deprecated
1085 public synchronized void interfaceStatusChanged(String iface, boolean up) {
1086 try {
1087 mObserver.interfaceStatusChanged(iface, up);
1088 } catch (RemoteException e) {
1089 // ignored; target is local
Chia-chi Yehaa1727f2011-07-14 18:55:33 -07001090 }
1091 }
1092
Jeff Sharkey899223b2012-08-04 15:24:58 -07001093 private INetworkManagementEventObserver mObserver = new BaseNetworkObserver() {
1094 @Override
1095 public void interfaceStatusChanged(String interfaze, boolean up) {
1096 synchronized (Vpn.this) {
1097 if (!up && mLegacyVpnRunner != null) {
1098 mLegacyVpnRunner.check(interfaze);
1099 }
Chia-chi Yeh199ed6e2011-08-03 17:38:49 -07001100 }
Chia-chi Yehaa1727f2011-07-14 18:55:33 -07001101 }
Chia-chi Yehaa1727f2011-07-14 18:55:33 -07001102
Jeff Sharkey899223b2012-08-04 15:24:58 -07001103 @Override
1104 public void interfaceRemoved(String interfaze) {
1105 synchronized (Vpn.this) {
1106 if (interfaze.equals(mInterface) && jniCheck(interfaze) == 0) {
Jeff Davidson90b1b9f2014-08-22 13:05:43 -07001107 mStatusIntent = null;
Paul Jensen6bc2c2c2014-05-07 15:27:40 -04001108 mVpnUsers = null;
Paul Jensenc4c72312014-12-08 14:04:51 -05001109 mConfig = null;
Jeff Sharkey899223b2012-08-04 15:24:58 -07001110 mInterface = null;
1111 if (mConnection != null) {
1112 mContext.unbindService(mConnection);
1113 mConnection = null;
Paul Jensen6bc2c2c2014-05-07 15:27:40 -04001114 agentDisconnect();
Jeff Sharkey899223b2012-08-04 15:24:58 -07001115 } else if (mLegacyVpnRunner != null) {
1116 mLegacyVpnRunner.exit();
1117 mLegacyVpnRunner = null;
1118 }
1119 }
1120 }
1121 }
1122 };
Haoyu Baidb3c8672012-06-20 14:29:57 -07001123
Chia-chi Yehdadc8572012-06-08 13:05:58 -07001124 private void enforceControlPermission() {
Jeff Davidsonbc19c182014-11-11 13:20:01 -08001125 mContext.enforceCallingPermission(Manifest.permission.CONTROL_VPN, "Unauthorized Caller");
Chia-chi Yehdadc8572012-06-08 13:05:58 -07001126 }
1127
Robin Lee244ce8e2016-01-05 18:03:46 +00001128 private void enforceControlPermissionOrInternalCaller() {
1129 // Require caller to be either an application with CONTROL_VPN permission or a process
1130 // in the system server.
1131 mContext.enforceCallingOrSelfPermission(Manifest.permission.CONTROL_VPN,
1132 "Unauthorized Caller");
1133 }
1134
Chia-chi Yeh199ed6e2011-08-03 17:38:49 -07001135 private class Connection implements ServiceConnection {
1136 private IBinder mService;
1137
1138 @Override
1139 public void onServiceConnected(ComponentName name, IBinder service) {
1140 mService = service;
1141 }
1142
1143 @Override
1144 public void onServiceDisconnected(ComponentName name) {
1145 mService = null;
1146 }
1147 }
1148
Jeff Davidson90b1b9f2014-08-22 13:05:43 -07001149 private void prepareStatusIntent() {
1150 final long token = Binder.clearCallingIdentity();
1151 try {
1152 mStatusIntent = VpnConfig.getIntentForStatusPanel(mContext);
1153 } finally {
1154 Binder.restoreCallingIdentity(token);
1155 }
1156 }
1157
Sreeram Ramachandranf4e0c0c2014-07-27 14:18:26 -07001158 public synchronized boolean addAddress(String address, int prefixLength) {
Sreeram Ramachandranc2c0bea2014-11-11 16:09:21 -08001159 if (!isCallerEstablishedOwnerLocked()) {
Sreeram Ramachandranf4e0c0c2014-07-27 14:18:26 -07001160 return false;
1161 }
1162 boolean success = jniAddAddress(mInterface, address, prefixLength);
Sreeram Ramachandranc2c0bea2014-11-11 16:09:21 -08001163 mNetworkAgent.sendLinkProperties(makeLinkProperties());
Sreeram Ramachandranf4e0c0c2014-07-27 14:18:26 -07001164 return success;
1165 }
1166
1167 public synchronized boolean removeAddress(String address, int prefixLength) {
Sreeram Ramachandranc2c0bea2014-11-11 16:09:21 -08001168 if (!isCallerEstablishedOwnerLocked()) {
Sreeram Ramachandranf4e0c0c2014-07-27 14:18:26 -07001169 return false;
1170 }
1171 boolean success = jniDelAddress(mInterface, address, prefixLength);
Sreeram Ramachandranc2c0bea2014-11-11 16:09:21 -08001172 mNetworkAgent.sendLinkProperties(makeLinkProperties());
Sreeram Ramachandranf4e0c0c2014-07-27 14:18:26 -07001173 return success;
1174 }
1175
Sreeram Ramachandranc2c0bea2014-11-11 16:09:21 -08001176 public synchronized boolean setUnderlyingNetworks(Network[] networks) {
1177 if (!isCallerEstablishedOwnerLocked()) {
1178 return false;
1179 }
1180 if (networks == null) {
1181 mConfig.underlyingNetworks = null;
1182 } else {
1183 mConfig.underlyingNetworks = new Network[networks.length];
1184 for (int i = 0; i < networks.length; ++i) {
1185 if (networks[i] == null) {
1186 mConfig.underlyingNetworks[i] = null;
1187 } else {
1188 mConfig.underlyingNetworks[i] = new Network(networks[i].netId);
1189 }
1190 }
1191 }
1192 return true;
1193 }
1194
1195 public synchronized Network[] getUnderlyingNetworks() {
1196 if (!isRunningLocked()) {
1197 return null;
1198 }
1199 return mConfig.underlyingNetworks;
1200 }
1201
Wenchao Tongf5ea3402015-03-04 13:26:38 -08001202 /**
1203 * This method should only be called by ConnectivityService. Because it doesn't
1204 * have enough data to fill VpnInfo.primaryUnderlyingIface field.
1205 */
1206 public synchronized VpnInfo getVpnInfo() {
1207 if (!isRunningLocked()) {
1208 return null;
1209 }
1210
1211 VpnInfo info = new VpnInfo();
1212 info.ownerUid = mOwnerUID;
1213 info.vpnIface = mInterface;
1214 return info;
1215 }
1216
Sreeram Ramachandranc2c0bea2014-11-11 16:09:21 -08001217 public synchronized boolean appliesToUid(int uid) {
1218 if (!isRunningLocked()) {
1219 return false;
1220 }
1221 for (UidRange uidRange : mVpnUsers) {
Robin Lee4d03abc2016-05-09 12:32:27 +01001222 if (uidRange.contains(uid)) {
Sreeram Ramachandranc2c0bea2014-11-11 16:09:21 -08001223 return true;
1224 }
1225 }
1226 return false;
1227 }
1228
Robin Lee17e61832016-05-09 13:46:28 +01001229 /**
Robin Leeebbcb542016-05-24 16:35:10 +01001230 * @return {@code true} if {@param uid} is blocked by an always-on VPN.
1231 * A UID is blocked if it's included in one of the mBlockedUsers ranges and the VPN is
1232 * not connected, or if the VPN is connected but does not apply to the UID.
Robin Lee17e61832016-05-09 13:46:28 +01001233 *
1234 * @see #mBlockedUsers
1235 */
1236 public synchronized boolean isBlockingUid(int uid) {
Robin Leeebbcb542016-05-24 16:35:10 +01001237 if (!mLockdown) {
1238 return false;
Robin Lee17e61832016-05-09 13:46:28 +01001239 }
Robin Leeebbcb542016-05-24 16:35:10 +01001240
1241 if (mNetworkInfo.isConnected()) {
1242 return !appliesToUid(uid);
1243 } else {
1244 for (UidRange uidRange : mBlockedUsers) {
1245 if (uidRange.contains(uid)) {
1246 return true;
1247 }
1248 }
1249 return false;
1250 }
Robin Lee17e61832016-05-09 13:46:28 +01001251 }
1252
Chia-chi Yeh97a61562011-07-14 15:05:05 -07001253 private native int jniCreate(int mtu);
Chia-chi Yehc2b8aa02011-07-03 18:00:47 -07001254 private native String jniGetName(int tun);
Chia-chi Yeh97a61562011-07-14 15:05:05 -07001255 private native int jniSetAddresses(String interfaze, String addresses);
Chia-chi Yehc2b8aa02011-07-03 18:00:47 -07001256 private native void jniReset(String interfaze);
1257 private native int jniCheck(String interfaze);
Sreeram Ramachandranf4e0c0c2014-07-27 14:18:26 -07001258 private native boolean jniAddAddress(String interfaze, String address, int prefixLen);
1259 private native boolean jniDelAddress(String interfaze, String address, int prefixLen);
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001260
Lorenzo Colitti41fb98c2013-06-28 17:26:21 +09001261 private static RouteInfo findIPv4DefaultRoute(LinkProperties prop) {
1262 for (RouteInfo route : prop.getAllRoutes()) {
Jeff Sharkey82f85212012-08-24 11:17:25 -07001263 // Currently legacy VPN only works on IPv4.
1264 if (route.isDefaultRoute() && route.getGateway() instanceof Inet4Address) {
Lorenzo Colitti41fb98c2013-06-28 17:26:21 +09001265 return route;
Jeff Sharkey82f85212012-08-24 11:17:25 -07001266 }
1267 }
Jeff Sharkey899223b2012-08-04 15:24:58 -07001268
Lorenzo Colitti41fb98c2013-06-28 17:26:21 +09001269 throw new IllegalStateException("Unable to find IPv4 default gateway");
Jeff Sharkey82f85212012-08-24 11:17:25 -07001270 }
1271
1272 /**
1273 * Start legacy VPN, controlling native daemons as needed. Creates a
1274 * secondary thread to perform connection work, returning quickly.
Jeff Davidsonb21298a2015-02-10 10:02:11 -08001275 *
1276 * Should only be called to respond to Binder requests as this enforces caller permission. Use
1277 * {@link #startLegacyVpnPrivileged(VpnProfile, KeyStore, LinkProperties)} to skip the
1278 * permission check only when the caller is trusted (or the call is initiated by the system).
Jeff Sharkey82f85212012-08-24 11:17:25 -07001279 */
1280 public void startLegacyVpn(VpnProfile profile, KeyStore keyStore, LinkProperties egress) {
Robert Greenwalt5a6bdc42013-02-15 10:56:35 -08001281 enforceControlPermission();
Jeff Davidsonb21298a2015-02-10 10:02:11 -08001282 long token = Binder.clearCallingIdentity();
1283 try {
1284 startLegacyVpnPrivileged(profile, keyStore, egress);
1285 } finally {
1286 Binder.restoreCallingIdentity(token);
1287 }
1288 }
1289
1290 /**
1291 * Like {@link #startLegacyVpn(VpnProfile, KeyStore, LinkProperties)}, but does not check
1292 * permissions under the assumption that the caller is the system.
1293 *
1294 * Callers are responsible for checking permissions if needed.
1295 */
1296 public void startLegacyVpnPrivileged(VpnProfile profile, KeyStore keyStore,
1297 LinkProperties egress) {
Julia Reynoldsf5116d02014-07-01 11:10:41 -04001298 UserManager mgr = UserManager.get(mContext);
Paul Jensen0784eea2014-08-19 16:00:24 -04001299 UserInfo user = mgr.getUserInfo(mUserHandle);
Nicolas Prevot95778ff2015-01-06 15:43:05 +00001300 if (user.isRestricted() || mgr.hasUserRestriction(UserManager.DISALLOW_CONFIG_VPN,
1301 new UserHandle(mUserHandle))) {
Julia Reynoldsf5116d02014-07-01 11:10:41 -04001302 throw new SecurityException("Restricted users cannot establish VPNs");
1303 }
Jeff Sharkey82f85212012-08-24 11:17:25 -07001304
Lorenzo Colitti41fb98c2013-06-28 17:26:21 +09001305 final RouteInfo ipv4DefaultRoute = findIPv4DefaultRoute(egress);
1306 final String gateway = ipv4DefaultRoute.getGateway().getHostAddress();
1307 final String iface = ipv4DefaultRoute.getInterface();
Jeff Sharkey82f85212012-08-24 11:17:25 -07001308
1309 // Load certificates.
1310 String privateKey = "";
1311 String userCert = "";
1312 String caCert = "";
1313 String serverCert = "";
1314 if (!profile.ipsecUserCert.isEmpty()) {
1315 privateKey = Credentials.USER_PRIVATE_KEY + profile.ipsecUserCert;
1316 byte[] value = keyStore.get(Credentials.USER_CERTIFICATE + profile.ipsecUserCert);
Elliott Hughesd396a442013-06-28 16:24:48 -07001317 userCert = (value == null) ? null : new String(value, StandardCharsets.UTF_8);
Jeff Sharkey82f85212012-08-24 11:17:25 -07001318 }
1319 if (!profile.ipsecCaCert.isEmpty()) {
1320 byte[] value = keyStore.get(Credentials.CA_CERTIFICATE + profile.ipsecCaCert);
Elliott Hughesd396a442013-06-28 16:24:48 -07001321 caCert = (value == null) ? null : new String(value, StandardCharsets.UTF_8);
Jeff Sharkey82f85212012-08-24 11:17:25 -07001322 }
1323 if (!profile.ipsecServerCert.isEmpty()) {
1324 byte[] value = keyStore.get(Credentials.USER_CERTIFICATE + profile.ipsecServerCert);
Elliott Hughesd396a442013-06-28 16:24:48 -07001325 serverCert = (value == null) ? null : new String(value, StandardCharsets.UTF_8);
Jeff Sharkey82f85212012-08-24 11:17:25 -07001326 }
1327 if (privateKey == null || userCert == null || caCert == null || serverCert == null) {
1328 throw new IllegalStateException("Cannot load credentials");
1329 }
1330
1331 // Prepare arguments for racoon.
1332 String[] racoon = null;
1333 switch (profile.type) {
1334 case VpnProfile.TYPE_L2TP_IPSEC_PSK:
1335 racoon = new String[] {
1336 iface, profile.server, "udppsk", profile.ipsecIdentifier,
1337 profile.ipsecSecret, "1701",
1338 };
1339 break;
1340 case VpnProfile.TYPE_L2TP_IPSEC_RSA:
1341 racoon = new String[] {
1342 iface, profile.server, "udprsa", privateKey, userCert,
1343 caCert, serverCert, "1701",
1344 };
1345 break;
1346 case VpnProfile.TYPE_IPSEC_XAUTH_PSK:
1347 racoon = new String[] {
1348 iface, profile.server, "xauthpsk", profile.ipsecIdentifier,
1349 profile.ipsecSecret, profile.username, profile.password, "", gateway,
1350 };
1351 break;
1352 case VpnProfile.TYPE_IPSEC_XAUTH_RSA:
1353 racoon = new String[] {
1354 iface, profile.server, "xauthrsa", privateKey, userCert,
1355 caCert, serverCert, profile.username, profile.password, "", gateway,
1356 };
1357 break;
1358 case VpnProfile.TYPE_IPSEC_HYBRID_RSA:
1359 racoon = new String[] {
1360 iface, profile.server, "hybridrsa",
1361 caCert, serverCert, profile.username, profile.password, "", gateway,
1362 };
1363 break;
1364 }
1365
1366 // Prepare arguments for mtpd.
1367 String[] mtpd = null;
1368 switch (profile.type) {
1369 case VpnProfile.TYPE_PPTP:
1370 mtpd = new String[] {
1371 iface, "pptp", profile.server, "1723",
1372 "name", profile.username, "password", profile.password,
1373 "linkname", "vpn", "refuse-eap", "nodefaultroute",
1374 "usepeerdns", "idle", "1800", "mtu", "1400", "mru", "1400",
1375 (profile.mppe ? "+mppe" : "nomppe"),
1376 };
1377 break;
1378 case VpnProfile.TYPE_L2TP_IPSEC_PSK:
1379 case VpnProfile.TYPE_L2TP_IPSEC_RSA:
1380 mtpd = new String[] {
1381 iface, "l2tp", profile.server, "1701", profile.l2tpSecret,
1382 "name", profile.username, "password", profile.password,
1383 "linkname", "vpn", "refuse-eap", "nodefaultroute",
1384 "usepeerdns", "idle", "1800", "mtu", "1400", "mru", "1400",
1385 };
1386 break;
1387 }
1388
1389 VpnConfig config = new VpnConfig();
Jeff Sharkey899223b2012-08-04 15:24:58 -07001390 config.legacy = true;
Jeff Sharkey82f85212012-08-24 11:17:25 -07001391 config.user = profile.key;
1392 config.interfaze = iface;
1393 config.session = profile.name;
Chad Brubaker4ca19e82013-06-14 11:16:51 -07001394
1395 config.addLegacyRoutes(profile.routes);
Jeff Sharkey82f85212012-08-24 11:17:25 -07001396 if (!profile.dnsServers.isEmpty()) {
1397 config.dnsServers = Arrays.asList(profile.dnsServers.split(" +"));
1398 }
1399 if (!profile.searchDomains.isEmpty()) {
1400 config.searchDomains = Arrays.asList(profile.searchDomains.split(" +"));
1401 }
Jeff Sharkey82f85212012-08-24 11:17:25 -07001402 startLegacyVpn(config, racoon, mtpd);
1403 }
1404
1405 private synchronized void startLegacyVpn(VpnConfig config, String[] racoon, String[] mtpd) {
Jeff Davidsonb21298a2015-02-10 10:02:11 -08001406 stopLegacyVpnPrivileged();
Jeff Sharkey899223b2012-08-04 15:24:58 -07001407
Jeff Davidsonb21298a2015-02-10 10:02:11 -08001408 // Prepare for the new request.
1409 prepareInternal(VpnConfig.LEGACY_VPN);
Jeff Sharkey899223b2012-08-04 15:24:58 -07001410 updateState(DetailedState.CONNECTING, "startLegacyVpn");
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001411
Chia-chi Yeh2e467642011-07-04 03:23:12 -07001412 // Start a new LegacyVpnRunner and we are done!
Chia-chi Yeh100155a2011-07-03 16:52:38 -07001413 mLegacyVpnRunner = new LegacyVpnRunner(config, racoon, mtpd);
1414 mLegacyVpnRunner.start();
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001415 }
1416
Jeff Davidsonb21298a2015-02-10 10:02:11 -08001417 /** Stop legacy VPN. Permissions must be checked by callers. */
1418 public synchronized void stopLegacyVpnPrivileged() {
Jeff Sharkey899223b2012-08-04 15:24:58 -07001419 if (mLegacyVpnRunner != null) {
1420 mLegacyVpnRunner.exit();
1421 mLegacyVpnRunner = null;
1422
1423 synchronized (LegacyVpnRunner.TAG) {
1424 // wait for old thread to completely finish before spinning up
1425 // new instance, otherwise state updates can be out of order.
1426 }
1427 }
1428 }
1429
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001430 /**
Chia-chi Yeh2e467642011-07-04 03:23:12 -07001431 * Return the information of the current ongoing legacy VPN.
1432 */
1433 public synchronized LegacyVpnInfo getLegacyVpnInfo() {
Chia-chi Yehdadc8572012-06-08 13:05:58 -07001434 // Check if the caller is authorized.
1435 enforceControlPermission();
sj.cha08bbca02015-03-23 11:35:24 +09001436 return getLegacyVpnInfoPrivileged();
1437 }
1438
1439 /**
1440 * Return the information of the current ongoing legacy VPN.
1441 * Callers are responsible for checking permissions if needed.
1442 */
1443 public synchronized LegacyVpnInfo getLegacyVpnInfoPrivileged() {
Jeff Sharkey899223b2012-08-04 15:24:58 -07001444 if (mLegacyVpnRunner == null) return null;
1445
1446 final LegacyVpnInfo info = new LegacyVpnInfo();
Chad Brubakerc2865192013-07-10 14:46:23 -07001447 info.key = mConfig.user;
Jeff Sharkey899223b2012-08-04 15:24:58 -07001448 info.state = LegacyVpnInfo.stateFromNetworkInfo(mNetworkInfo);
Jeff Davidson90b1b9f2014-08-22 13:05:43 -07001449 if (mNetworkInfo.isConnected()) {
1450 info.intent = mStatusIntent;
1451 }
Jeff Sharkey899223b2012-08-04 15:24:58 -07001452 return info;
Chia-chi Yeh2e467642011-07-04 03:23:12 -07001453 }
1454
Jeff Sharkey69ddab42012-08-25 00:05:46 -07001455 public VpnConfig getLegacyVpnConfig() {
1456 if (mLegacyVpnRunner != null) {
Chad Brubakerc2865192013-07-10 14:46:23 -07001457 return mConfig;
Jeff Sharkey69ddab42012-08-25 00:05:46 -07001458 } else {
1459 return null;
1460 }
1461 }
1462
Chia-chi Yeh2e467642011-07-04 03:23:12 -07001463 /**
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001464 * Bringing up a VPN connection takes time, and that is all this thread
1465 * does. Here we have plenty of time. The only thing we need to take
1466 * care of is responding to interruptions as soon as possible. Otherwise
1467 * requests will be piled up. This can be done in a Handler as a state
1468 * machine, but it is much easier to read in the current form.
1469 */
1470 private class LegacyVpnRunner extends Thread {
1471 private static final String TAG = "LegacyVpnRunner";
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001472
Chia-chi Yeh1f7746b2011-07-01 00:29:06 -07001473 private final String[] mDaemons;
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001474 private final String[][] mArguments;
Chia-chi Yeh5317f032011-08-22 13:09:49 -07001475 private final LocalSocket[] mSockets;
Robert Greenwalt53c04bd2012-10-12 17:02:45 -07001476 private final String mOuterInterface;
Robert Greenwalt1b0ca9d2013-04-22 11:13:02 -07001477 private final AtomicInteger mOuterConnection =
1478 new AtomicInteger(ConnectivityManager.TYPE_NONE);
Chia-chi Yeh2e467642011-07-04 03:23:12 -07001479
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001480 private long mTimer = -1;
1481
Robert Greenwalt1b0ca9d2013-04-22 11:13:02 -07001482 /**
1483 * Watch for the outer connection (passing in the constructor) going away.
1484 */
1485 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
1486 @Override
1487 public void onReceive(Context context, Intent intent) {
Jeff Sharkey57666932013-04-30 17:01:57 -07001488 if (!mEnableTeardown) return;
1489
Robert Greenwalt1b0ca9d2013-04-22 11:13:02 -07001490 if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
1491 if (intent.getIntExtra(ConnectivityManager.EXTRA_NETWORK_TYPE,
1492 ConnectivityManager.TYPE_NONE) == mOuterConnection.get()) {
1493 NetworkInfo info = (NetworkInfo)intent.getExtra(
1494 ConnectivityManager.EXTRA_NETWORK_INFO);
1495 if (info != null && !info.isConnectedOrConnecting()) {
1496 try {
1497 mObserver.interfaceStatusChanged(mOuterInterface, false);
1498 } catch (RemoteException e) {}
1499 }
1500 }
1501 }
1502 }
1503 };
1504
Chia-chi Yeh41d16852011-07-01 02:12:06 -07001505 public LegacyVpnRunner(VpnConfig config, String[] racoon, String[] mtpd) {
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001506 super(TAG);
Chia-chi Yeh41d16852011-07-01 02:12:06 -07001507 mConfig = config;
1508 mDaemons = new String[] {"racoon", "mtpd"};
Jeff Sharkey899223b2012-08-04 15:24:58 -07001509 // TODO: clear arguments from memory once launched
Chia-chi Yeh41d16852011-07-01 02:12:06 -07001510 mArguments = new String[][] {racoon, mtpd};
Chia-chi Yeh5317f032011-08-22 13:09:49 -07001511 mSockets = new LocalSocket[mDaemons.length];
Robert Greenwalt53c04bd2012-10-12 17:02:45 -07001512
1513 // This is the interface which VPN is running on,
1514 // mConfig.interfaze will change to point to OUR
1515 // internal interface soon. TODO - add inner/outer to mconfig
Robert Greenwalt1b0ca9d2013-04-22 11:13:02 -07001516 // TODO - we have a race - if the outer iface goes away/disconnects before we hit this
Chad Brubaker4ca19e82013-06-14 11:16:51 -07001517 // we will leave the VPN up. We should check that it's still there/connected after
Robert Greenwalt1b0ca9d2013-04-22 11:13:02 -07001518 // registering
Robert Greenwalt53c04bd2012-10-12 17:02:45 -07001519 mOuterInterface = mConfig.interfaze;
Robert Greenwalt1b0ca9d2013-04-22 11:13:02 -07001520
Paul Jensene75b9e32015-04-06 11:54:53 -04001521 if (!TextUtils.isEmpty(mOuterInterface)) {
1522 final ConnectivityManager cm = ConnectivityManager.from(mContext);
1523 for (Network network : cm.getAllNetworks()) {
1524 final LinkProperties lp = cm.getLinkProperties(network);
Lorenzo Colitti1b60d112015-07-02 13:03:03 +09001525 if (lp != null && lp.getAllInterfaceNames().contains(mOuterInterface)) {
Paul Jensene75b9e32015-04-06 11:54:53 -04001526 final NetworkInfo networkInfo = cm.getNetworkInfo(network);
1527 if (networkInfo != null) mOuterConnection.set(networkInfo.getType());
1528 }
1529 }
Robert Greenwalt1b0ca9d2013-04-22 11:13:02 -07001530 }
1531
1532 IntentFilter filter = new IntentFilter();
1533 filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
1534 mContext.registerReceiver(mBroadcastReceiver, filter);
Chia-chi Yeh41d16852011-07-01 02:12:06 -07001535 }
1536
Chia-chi Yehaa1727f2011-07-14 18:55:33 -07001537 public void check(String interfaze) {
Robert Greenwalt53c04bd2012-10-12 17:02:45 -07001538 if (interfaze.equals(mOuterInterface)) {
Chia-chi Yehaa1727f2011-07-14 18:55:33 -07001539 Log.i(TAG, "Legacy VPN is going down with " + interfaze);
1540 exit();
1541 }
1542 }
1543
Chia-chi Yeh41d16852011-07-01 02:12:06 -07001544 public void exit() {
Chia-chi Yeh5317f032011-08-22 13:09:49 -07001545 // We assume that everything is reset after stopping the daemons.
Chia-chi Yeh97a61562011-07-14 15:05:05 -07001546 interrupt();
Chia-chi Yeh5317f032011-08-22 13:09:49 -07001547 for (LocalSocket socket : mSockets) {
Jeff Sharkey065b2992012-08-05 14:16:48 -07001548 IoUtils.closeQuietly(socket);
Chia-chi Yeh41d16852011-07-01 02:12:06 -07001549 }
Paul Jensen6bc2c2c2014-05-07 15:27:40 -04001550 agentDisconnect();
Robert Greenwalt1b0ca9d2013-04-22 11:13:02 -07001551 try {
1552 mContext.unregisterReceiver(mBroadcastReceiver);
1553 } catch (IllegalArgumentException e) {}
Chia-chi Yeh2e467642011-07-04 03:23:12 -07001554 }
1555
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001556 @Override
1557 public void run() {
1558 // Wait for the previous thread since it has been interrupted.
Chia-chi Yeh2e467642011-07-04 03:23:12 -07001559 Log.v(TAG, "Waiting");
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001560 synchronized (TAG) {
Chia-chi Yeh2e467642011-07-04 03:23:12 -07001561 Log.v(TAG, "Executing");
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001562 execute();
Jeff Sharkey899223b2012-08-04 15:24:58 -07001563 monitorDaemons();
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001564 }
1565 }
1566
1567 private void checkpoint(boolean yield) throws InterruptedException {
1568 long now = SystemClock.elapsedRealtime();
1569 if (mTimer == -1) {
1570 mTimer = now;
1571 Thread.sleep(1);
Chia-chi Yeh7ef86112011-07-22 15:46:52 -07001572 } else if (now - mTimer <= 60000) {
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001573 Thread.sleep(yield ? 200 : 1);
1574 } else {
Jeff Sharkey899223b2012-08-04 15:24:58 -07001575 updateState(DetailedState.FAILED, "checkpoint");
Chia-chi Yeh97a61562011-07-14 15:05:05 -07001576 throw new IllegalStateException("Time is up");
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001577 }
1578 }
1579
1580 private void execute() {
1581 // Catch all exceptions so we can clean up few things.
Jeff Sharkey899223b2012-08-04 15:24:58 -07001582 boolean initFinished = false;
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001583 try {
1584 // Initialize the timer.
1585 checkpoint(false);
1586
Chia-chi Yeh1f7746b2011-07-01 00:29:06 -07001587 // Wait for the daemons to stop.
1588 for (String daemon : mDaemons) {
Jeff Sharkey088f29f2012-08-05 14:55:04 -07001589 while (!SystemService.isStopped(daemon)) {
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001590 checkpoint(true);
1591 }
1592 }
1593
Chia-chi Yeh97a61562011-07-14 15:05:05 -07001594 // Clear the previous state.
1595 File state = new File("/data/misc/vpn/state");
1596 state.delete();
1597 if (state.exists()) {
1598 throw new IllegalStateException("Cannot delete the state");
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001599 }
Chia-chi Yehc1872732011-12-08 16:51:41 -08001600 new File("/data/misc/vpn/abort").delete();
Jeff Sharkey899223b2012-08-04 15:24:58 -07001601 initFinished = true;
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001602
Chia-chi Yehe9107902011-07-02 01:48:50 -07001603 // Check if we need to restart any of the daemons.
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001604 boolean restart = false;
1605 for (String[] arguments : mArguments) {
1606 restart = restart || (arguments != null);
1607 }
1608 if (!restart) {
Paul Jensen6bc2c2c2014-05-07 15:27:40 -04001609 agentDisconnect();
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001610 return;
1611 }
Jeff Sharkey899223b2012-08-04 15:24:58 -07001612 updateState(DetailedState.CONNECTING, "execute");
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001613
Chia-chi Yeh1f7746b2011-07-01 00:29:06 -07001614 // Start the daemon with arguments.
1615 for (int i = 0; i < mDaemons.length; ++i) {
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001616 String[] arguments = mArguments[i];
1617 if (arguments == null) {
1618 continue;
1619 }
1620
Chia-chi Yeh1f7746b2011-07-01 00:29:06 -07001621 // Start the daemon.
1622 String daemon = mDaemons[i];
Jeff Sharkey088f29f2012-08-05 14:55:04 -07001623 SystemService.start(daemon);
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001624
Chia-chi Yeh1f7746b2011-07-01 00:29:06 -07001625 // Wait for the daemon to start.
Jeff Sharkey088f29f2012-08-05 14:55:04 -07001626 while (!SystemService.isRunning(daemon)) {
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001627 checkpoint(true);
1628 }
1629
1630 // Create the control socket.
Chia-chi Yeh5317f032011-08-22 13:09:49 -07001631 mSockets[i] = new LocalSocket();
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001632 LocalSocketAddress address = new LocalSocketAddress(
Chia-chi Yeh1f7746b2011-07-01 00:29:06 -07001633 daemon, LocalSocketAddress.Namespace.RESERVED);
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001634
1635 // Wait for the socket to connect.
1636 while (true) {
1637 try {
Chia-chi Yeh5317f032011-08-22 13:09:49 -07001638 mSockets[i].connect(address);
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001639 break;
1640 } catch (Exception e) {
1641 // ignore
1642 }
1643 checkpoint(true);
1644 }
Chia-chi Yeh5317f032011-08-22 13:09:49 -07001645 mSockets[i].setSoTimeout(500);
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001646
1647 // Send over the arguments.
Chia-chi Yeh5317f032011-08-22 13:09:49 -07001648 OutputStream out = mSockets[i].getOutputStream();
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001649 for (String argument : arguments) {
Elliott Hughesd396a442013-06-28 16:24:48 -07001650 byte[] bytes = argument.getBytes(StandardCharsets.UTF_8);
Chia-chi Yeh5317f032011-08-22 13:09:49 -07001651 if (bytes.length >= 0xFFFF) {
Chia-chi Yeh97a61562011-07-14 15:05:05 -07001652 throw new IllegalArgumentException("Argument is too large");
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001653 }
Chia-chi Yeh1f7746b2011-07-01 00:29:06 -07001654 out.write(bytes.length >> 8);
1655 out.write(bytes.length);
1656 out.write(bytes);
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001657 checkpoint(false);
1658 }
Chia-chi Yeh5317f032011-08-22 13:09:49 -07001659 out.write(0xFF);
1660 out.write(0xFF);
Chia-chi Yeh1f7746b2011-07-01 00:29:06 -07001661 out.flush();
Chia-chi Yeh97a61562011-07-14 15:05:05 -07001662
1663 // Wait for End-of-File.
Chia-chi Yeh5317f032011-08-22 13:09:49 -07001664 InputStream in = mSockets[i].getInputStream();
Chia-chi Yeh97a61562011-07-14 15:05:05 -07001665 while (true) {
1666 try {
1667 if (in.read() == -1) {
1668 break;
1669 }
1670 } catch (Exception e) {
1671 // ignore
1672 }
1673 checkpoint(true);
1674 }
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001675 }
1676
Chia-chi Yeh97a61562011-07-14 15:05:05 -07001677 // Wait for the daemons to create the new state.
1678 while (!state.exists()) {
Chia-chi Yeh1f7746b2011-07-01 00:29:06 -07001679 // Check if a running daemon is dead.
1680 for (int i = 0; i < mDaemons.length; ++i) {
1681 String daemon = mDaemons[i];
Jeff Sharkey088f29f2012-08-05 14:55:04 -07001682 if (mArguments[i] != null && !SystemService.isRunning(daemon)) {
Chia-chi Yeh2e467642011-07-04 03:23:12 -07001683 throw new IllegalStateException(daemon + " is dead");
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001684 }
1685 }
1686 checkpoint(true);
1687 }
1688
Chia-chi Yeh97a61562011-07-14 15:05:05 -07001689 // Now we are connected. Read and parse the new state.
Chia-chi Yehc1bac3a2011-12-16 15:00:31 -08001690 String[] parameters = FileUtils.readTextFile(state, 0, null).split("\n", -1);
Lorenzo Colitti50262792014-09-19 01:53:35 +09001691 if (parameters.length != 7) {
Chia-chi Yeh97a61562011-07-14 15:05:05 -07001692 throw new IllegalStateException("Cannot parse the state");
1693 }
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001694
Chia-chi Yeh97a61562011-07-14 15:05:05 -07001695 // Set the interface and the addresses in the config.
1696 mConfig.interfaze = parameters[0].trim();
Chia-chi Yeh97a61562011-07-14 15:05:05 -07001697
Chad Brubaker4ca19e82013-06-14 11:16:51 -07001698 mConfig.addLegacyAddresses(parameters[1]);
Chia-chi Yeh97a61562011-07-14 15:05:05 -07001699 // Set the routes if they are not set in the config.
1700 if (mConfig.routes == null || mConfig.routes.isEmpty()) {
Chad Brubaker4ca19e82013-06-14 11:16:51 -07001701 mConfig.addLegacyRoutes(parameters[2]);
Chia-chi Yeh97a61562011-07-14 15:05:05 -07001702 }
1703
1704 // Set the DNS servers if they are not set in the config.
Chia-chi Yeh41d16852011-07-01 02:12:06 -07001705 if (mConfig.dnsServers == null || mConfig.dnsServers.size() == 0) {
Chia-chi Yeh97a61562011-07-14 15:05:05 -07001706 String dnsServers = parameters[3].trim();
Chia-chi Yeh41d16852011-07-01 02:12:06 -07001707 if (!dnsServers.isEmpty()) {
1708 mConfig.dnsServers = Arrays.asList(dnsServers.split(" "));
1709 }
1710 }
1711
Chia-chi Yeh97a61562011-07-14 15:05:05 -07001712 // Set the search domains if they are not set in the config.
1713 if (mConfig.searchDomains == null || mConfig.searchDomains.size() == 0) {
1714 String searchDomains = parameters[4].trim();
1715 if (!searchDomains.isEmpty()) {
1716 mConfig.searchDomains = Arrays.asList(searchDomains.split(" "));
1717 }
1718 }
Chia-chi Yehe9107902011-07-02 01:48:50 -07001719
Lorenzo Colitti50262792014-09-19 01:53:35 +09001720 // Add a throw route for the VPN server endpoint, if one was specified.
1721 String endpoint = parameters[5];
1722 if (!endpoint.isEmpty()) {
1723 try {
1724 InetAddress addr = InetAddress.parseNumericAddress(endpoint);
1725 if (addr instanceof Inet4Address) {
1726 mConfig.routes.add(new RouteInfo(new IpPrefix(addr, 32), RTN_THROW));
1727 } else if (addr instanceof Inet6Address) {
1728 mConfig.routes.add(new RouteInfo(new IpPrefix(addr, 128), RTN_THROW));
1729 } else {
1730 Log.e(TAG, "Unknown IP address family for VPN endpoint: " + endpoint);
1731 }
1732 } catch (IllegalArgumentException e) {
1733 Log.e(TAG, "Exception constructing throw route to " + endpoint + ": " + e);
1734 }
1735 }
1736
Chia-chi Yeh97a61562011-07-14 15:05:05 -07001737 // Here is the last step and it must be done synchronously.
Chia-chi Yeh41d16852011-07-01 02:12:06 -07001738 synchronized (Vpn.this) {
Vinit Deshapnde2b862e52013-10-02 11:50:39 -07001739 // Set the start time
1740 mConfig.startTime = SystemClock.elapsedRealtime();
1741
Chia-chi Yeh41d16852011-07-01 02:12:06 -07001742 // Check if the thread is interrupted while we are waiting.
1743 checkpoint(false);
1744
Chia-chi Yehe9107902011-07-02 01:48:50 -07001745 // Check if the interface is gone while we are waiting.
Chia-chi Yehc2b8aa02011-07-03 18:00:47 -07001746 if (jniCheck(mConfig.interfaze) == 0) {
Chia-chi Yeh34e78132011-07-03 03:07:07 -07001747 throw new IllegalStateException(mConfig.interfaze + " is gone");
Chia-chi Yeh41d16852011-07-01 02:12:06 -07001748 }
Chia-chi Yehe9107902011-07-02 01:48:50 -07001749
1750 // Now INetworkManagementEventObserver is watching our back.
Chia-chi Yehc2b8aa02011-07-03 18:00:47 -07001751 mInterface = mConfig.interfaze;
Robin Lee4d03abc2016-05-09 12:32:27 +01001752 prepareStatusIntent();
Chad Brubaker4ca19e82013-06-14 11:16:51 -07001753
Paul Jensen6bc2c2c2014-05-07 15:27:40 -04001754 agentConnect();
Chia-chi Yeh2e467642011-07-04 03:23:12 -07001755
1756 Log.i(TAG, "Connected!");
Chia-chi Yeh41d16852011-07-01 02:12:06 -07001757 }
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001758 } catch (Exception e) {
Chia-chi Yeh2e467642011-07-04 03:23:12 -07001759 Log.i(TAG, "Aborting", e);
Lorenzo Colitti43840602014-08-20 16:01:44 -07001760 updateState(DetailedState.FAILED, e.getMessage());
Chia-chi Yehe9107902011-07-02 01:48:50 -07001761 exit();
Chia-chi Yeh2e467642011-07-04 03:23:12 -07001762 } finally {
Chia-chi Yeh5317f032011-08-22 13:09:49 -07001763 // Kill the daemons if they fail to stop.
Jeff Sharkey899223b2012-08-04 15:24:58 -07001764 if (!initFinished) {
Chia-chi Yeh5317f032011-08-22 13:09:49 -07001765 for (String daemon : mDaemons) {
Jeff Sharkey088f29f2012-08-05 14:55:04 -07001766 SystemService.stop(daemon);
Chia-chi Yeh5317f032011-08-22 13:09:49 -07001767 }
1768 }
1769
Chia-chi Yeh2e467642011-07-04 03:23:12 -07001770 // Do not leave an unstable state.
Jeff Sharkey899223b2012-08-04 15:24:58 -07001771 if (!initFinished || mNetworkInfo.getDetailedState() == DetailedState.CONNECTING) {
Paul Jensen6bc2c2c2014-05-07 15:27:40 -04001772 agentDisconnect();
Chia-chi Yeh2e467642011-07-04 03:23:12 -07001773 }
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001774 }
1775 }
Jeff Sharkey899223b2012-08-04 15:24:58 -07001776
1777 /**
1778 * Monitor the daemons we started, moving to disconnected state if the
1779 * underlying services fail.
1780 */
1781 private void monitorDaemons() {
1782 if (!mNetworkInfo.isConnected()) {
1783 return;
1784 }
1785
1786 try {
1787 while (true) {
1788 Thread.sleep(2000);
1789 for (int i = 0; i < mDaemons.length; i++) {
1790 if (mArguments[i] != null && SystemService.isStopped(mDaemons[i])) {
1791 return;
1792 }
1793 }
1794 }
1795 } catch (InterruptedException e) {
1796 Log.d(TAG, "interrupted during monitorDaemons(); stopping services");
1797 } finally {
1798 for (String daemon : mDaemons) {
1799 SystemService.stop(daemon);
1800 }
1801
Paul Jensen6bc2c2c2014-05-07 15:27:40 -04001802 agentDisconnect();
Jeff Sharkey899223b2012-08-04 15:24:58 -07001803 }
1804 }
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001805 }
Chia-chi Yehff3bdca2011-05-23 17:26:46 -07001806}