blob: 602aedbc2d00ef85ff91f59b40db3f8fdb11f375 [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;
Jeff Sharkey9b2a10f2018-01-17 13:27:03 +090021import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
Jeff Sharkey72f9c422017-10-27 17:22:59 -060022import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
23import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
Lorenzo Colitti50262792014-09-19 01:53:35 +090024import static android.net.RouteInfo.RTN_THROW;
Lorenzo Colitti60446162014-09-20 00:14:31 +090025import static android.net.RouteInfo.RTN_UNREACHABLE;
Jeff Sharkey899223b2012-08-04 15:24:58 -070026
Jeff Davidsonbc19c182014-11-11 13:20:01 -080027import android.Manifest;
Robin Lee4d03abc2016-05-09 12:32:27 +010028import android.annotation.NonNull;
29import android.annotation.Nullable;
30import android.annotation.UserIdInt;
Chad Brubaker4ca19e82013-06-14 11:16:51 -070031import android.app.AppGlobals;
Jeff Davidson05542602014-08-11 14:07:27 -070032import android.app.AppOpsManager;
Tony Mak1a405fe2016-06-30 11:19:20 +010033import android.app.Notification;
34import android.app.NotificationManager;
Jeff Davidson90b1b9f2014-08-22 13:05:43 -070035import android.app.PendingIntent;
Robert Greenwalt1b0ca9d2013-04-22 11:13:02 -070036import android.content.BroadcastReceiver;
Chia-chi Yeh199ed6e2011-08-03 17:38:49 -070037import android.content.ComponentName;
Chia-chi Yehff3bdca2011-05-23 17:26:46 -070038import android.content.Context;
39import android.content.Intent;
Robert Greenwalt1b0ca9d2013-04-22 11:13:02 -070040import android.content.IntentFilter;
Chia-chi Yeh199ed6e2011-08-03 17:38:49 -070041import android.content.ServiceConnection;
Charles Hea0a87e82017-05-15 17:07:18 +010042import android.content.pm.ApplicationInfo;
Chia-chi Yehff3bdca2011-05-23 17:26:46 -070043import android.content.pm.PackageManager;
Paul Jensen6bc2c2c2014-05-07 15:27:40 -040044import android.content.pm.PackageManager.NameNotFoundException;
Chia-chi Yeh199ed6e2011-08-03 17:38:49 -070045import android.content.pm.ResolveInfo;
Chad Brubakerc2865192013-07-10 14:46:23 -070046import android.content.pm.UserInfo;
Jeff Sharkey899223b2012-08-04 15:24:58 -070047import android.net.ConnectivityManager;
Chia-chi Yehff3bdca2011-05-23 17:26:46 -070048import android.net.INetworkManagementEventObserver;
Lorenzo Colitti50262792014-09-19 01:53:35 +090049import android.net.IpPrefix;
Chad Brubaker4ca19e82013-06-14 11:16:51 -070050import android.net.LinkAddress;
Jeff Sharkey82f85212012-08-24 11:17:25 -070051import android.net.LinkProperties;
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -070052import android.net.LocalSocket;
53import android.net.LocalSocketAddress;
Sreeram Ramachandranc2c0bea2014-11-11 16:09:21 -080054import android.net.Network;
Paul Jensen6bc2c2c2014-05-07 15:27:40 -040055import android.net.NetworkAgent;
56import android.net.NetworkCapabilities;
Jeff Sharkey899223b2012-08-04 15:24:58 -070057import android.net.NetworkInfo;
Paul Jensen6bc2c2c2014-05-07 15:27:40 -040058import android.net.NetworkInfo.DetailedState;
Sreeram Ramachandran8cd33ed2014-07-23 15:23:15 -070059import android.net.NetworkMisc;
Chalard Jeanadbf1d02018-02-26 11:52:46 +090060import android.net.NetworkUtils;
Jeff Sharkey82f85212012-08-24 11:17:25 -070061import android.net.RouteInfo;
Paul Jensen6bc2c2c2014-05-07 15:27:40 -040062import android.net.UidRange;
Robin Lee812800c2016-05-13 15:38:08 +010063import android.net.Uri;
Charles Hea0a87e82017-05-15 17:07:18 +010064import android.net.VpnService;
Chia-chi Yehff3bdca2011-05-23 17:26:46 -070065import android.os.Binder;
Charles Hea0a87e82017-05-15 17:07:18 +010066import android.os.Build.VERSION_CODES;
67import android.os.Bundle;
Chia-chi Yehc1bac3a2011-12-16 15:00:31 -080068import android.os.FileUtils;
Chia-chi Yeh199ed6e2011-08-03 17:38:49 -070069import android.os.IBinder;
Jeff Sharkey899223b2012-08-04 15:24:58 -070070import android.os.INetworkManagementService;
Paul Jensen6bc2c2c2014-05-07 15:27:40 -040071import android.os.Looper;
Chia-chi Yeh199ed6e2011-08-03 17:38:49 -070072import android.os.Parcel;
Chia-chi Yehff3bdca2011-05-23 17:26:46 -070073import android.os.ParcelFileDescriptor;
Robin Lee812800c2016-05-13 15:38:08 +010074import android.os.PatternMatcher;
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -070075import android.os.Process;
Jeff Sharkey899223b2012-08-04 15:24:58 -070076import android.os.RemoteException;
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -070077import android.os.SystemClock;
Jeff Sharkey088f29f2012-08-05 14:55:04 -070078import android.os.SystemService;
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -070079import android.os.UserHandle;
Chad Brubakerc2865192013-07-10 14:46:23 -070080import android.os.UserManager;
Robin Lee812800c2016-05-13 15:38:08 +010081import android.provider.Settings;
Jeff Sharkey82f85212012-08-24 11:17:25 -070082import android.security.Credentials;
83import android.security.KeyStore;
Paul Jensene75b9e32015-04-06 11:54:53 -040084import android.text.TextUtils;
Robin Lee4d03abc2016-05-09 12:32:27 +010085import android.util.ArraySet;
Chia-chi Yehff3bdca2011-05-23 17:26:46 -070086import android.util.Log;
87
Tony Mak1a405fe2016-06-30 11:19:20 +010088import com.android.internal.R;
Chad Brubakerc2865192013-07-10 14:46:23 -070089import com.android.internal.annotations.GuardedBy;
Robin Lee4d03abc2016-05-09 12:32:27 +010090import com.android.internal.annotations.VisibleForTesting;
Chris Wren282cfef2017-03-27 15:01:44 -040091import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
Chia-chi Yeh2e467642011-07-04 03:23:12 -070092import com.android.internal.net.LegacyVpnInfo;
Chia-chi Yeh04ba25c2011-06-15 17:07:27 -070093import com.android.internal.net.VpnConfig;
Wenchao Tongf5ea3402015-03-04 13:26:38 -080094import com.android.internal.net.VpnInfo;
Jeff Sharkey82f85212012-08-24 11:17:25 -070095import com.android.internal.net.VpnProfile;
Geoffrey Pitschaf759c52017-02-15 09:35:38 -050096import com.android.internal.notification.SystemNotificationChannels;
Jeff Sharkey72f9c422017-10-27 17:22:59 -060097import com.android.internal.util.ArrayUtils;
98import com.android.server.ConnectivityService;
Christopher Tatee0be7e82017-02-08 17:38:20 -080099import com.android.server.DeviceIdleController;
100import com.android.server.LocalServices;
Jeff Sharkey899223b2012-08-04 15:24:58 -0700101import com.android.server.net.BaseNetworkObserver;
Chia-chi Yehff3bdca2011-05-23 17:26:46 -0700102
Chia-chi Yeh97a61562011-07-14 15:05:05 -0700103import java.io.File;
Jeff Davidson6bbf39c2014-07-23 10:14:53 -0700104import java.io.IOException;
Chia-chi Yeh97a61562011-07-14 15:05:05 -0700105import java.io.InputStream;
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -0700106import java.io.OutputStream;
Chalard Jeanadbf1d02018-02-26 11:52:46 +0900107import java.math.BigInteger;
Jeff Sharkey82f85212012-08-24 11:17:25 -0700108import java.net.Inet4Address;
Sreeram Ramachandranf4e0c0c2014-07-27 14:18:26 -0700109import java.net.Inet6Address;
110import java.net.InetAddress;
Elliott Hughesd396a442013-06-28 16:24:48 -0700111import java.nio.charset.StandardCharsets;
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400112import java.util.ArrayList;
Chia-chi Yeh41d16852011-07-01 02:12:06 -0700113import java.util.Arrays;
Robin Lee4d03abc2016-05-09 12:32:27 +0100114import java.util.Collection;
115import java.util.Collections;
Chalard Jeanadbf1d02018-02-26 11:52:46 +0900116import java.util.Comparator;
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400117import java.util.List;
Lorenzo Colitti6fd62b32017-09-22 21:27:32 +0900118import java.util.Objects;
Robin Lee4d03abc2016-05-09 12:32:27 +0100119import java.util.Set;
Paul Jensen0784eea2014-08-19 16:00:24 -0400120import java.util.SortedSet;
121import java.util.TreeSet;
Robert Greenwalt1b0ca9d2013-04-22 11:13:02 -0700122import java.util.concurrent.atomic.AtomicInteger;
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -0700123
Bernie Innocenti00000fe2018-05-28 22:04:37 +0900124import libcore.io.IoUtils;
125
Chia-chi Yehff3bdca2011-05-23 17:26:46 -0700126/**
127 * @hide
128 */
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400129public class Vpn {
130 private static final String NETWORKTYPE = "VPN";
Jeff Sharkey899223b2012-08-04 15:24:58 -0700131 private static final String TAG = "Vpn";
132 private static final boolean LOGD = true;
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400133
Christopher Tatee0be7e82017-02-08 17:38:20 -0800134 // Length of time (in milliseconds) that an app hosting an always-on VPN is placed on
135 // the device idle whitelist during service launch and VPN bootstrap.
Chalard Jeandd59ece2017-12-20 13:23:32 +0900136 private static final long VPN_LAUNCH_IDLE_WHITELIST_DURATION_MS = 60 * 1000;
Christopher Tatee0be7e82017-02-08 17:38:20 -0800137
Chalard Jeanadbf1d02018-02-26 11:52:46 +0900138 // Settings for how much of the address space should be routed so that Vpn considers
139 // "most" of the address space is routed. This is used to determine whether this Vpn
140 // should be marked with the INTERNET capability.
141 private static final long MOST_IPV4_ADDRESSES_COUNT;
142 private static final BigInteger MOST_IPV6_ADDRESSES_COUNT;
143 static {
144 // 85% of the address space must be routed for Vpn to consider this VPN to provide
145 // INTERNET access.
146 final int howManyPercentIsMost = 85;
147
148 final long twoPower32 = 1L << 32;
149 MOST_IPV4_ADDRESSES_COUNT = twoPower32 * howManyPercentIsMost / 100;
150 final BigInteger twoPower128 = BigInteger.ONE.shiftLeft(128);
151 MOST_IPV6_ADDRESSES_COUNT = twoPower128
152 .multiply(BigInteger.valueOf(howManyPercentIsMost))
153 .divide(BigInteger.valueOf(100));
154 }
Chalard Jeane0d26f62018-03-29 14:10:44 +0900155 // How many routes to evaluate before bailing and declaring this Vpn should provide
156 // the INTERNET capability. This is necessary because computing the adress space is
157 // O(n²) and this is running in the system service, so a limit is needed to alleviate
158 // the risk of attack.
159 // This is taken as a total of IPv4 + IPV6 routes for simplicity, but the algorithm
160 // is actually O(n²)+O(n²).
161 private static final int MAX_ROUTES_TO_EVALUATE = 150;
Chalard Jeanadbf1d02018-02-26 11:52:46 +0900162
Jeff Sharkey899223b2012-08-04 15:24:58 -0700163 // TODO: create separate trackers for each unique VPN to support
164 // automated reconnection
Chia-chi Yehff3bdca2011-05-23 17:26:46 -0700165
Chalard Jean546ec6b2018-10-01 12:58:19 +0900166 private final Context mContext;
167 private final NetworkInfo mNetworkInfo;
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400168 private String mPackage;
169 private int mOwnerUID;
Chia-chi Yehc2b8aa02011-07-03 18:00:47 -0700170 private String mInterface;
Chia-chi Yeh199ed6e2011-08-03 17:38:49 -0700171 private Connection mConnection;
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -0700172 private LegacyVpnRunner mLegacyVpnRunner;
Jeff Davidson90b1b9f2014-08-22 13:05:43 -0700173 private PendingIntent mStatusIntent;
Jeff Sharkey57666932013-04-30 17:01:57 -0700174 private volatile boolean mEnableTeardown = true;
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400175 private final INetworkManagementService mNetd;
Chalard Jeanf666d0a2018-05-18 21:47:45 +0900176 @VisibleForTesting
177 protected VpnConfig mConfig;
178 @VisibleForTesting
179 protected NetworkAgent mNetworkAgent;
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400180 private final Looper mLooper;
Chalard Jeanf666d0a2018-05-18 21:47:45 +0900181 @VisibleForTesting
182 protected final NetworkCapabilities mNetworkCapabilities;
Robin Leeb8c2a2b2017-03-10 16:17:06 +0000183 private final SystemServices mSystemServices;
Chad Brubakerc2865192013-07-10 14:46:23 -0700184
Robin Lee4d03abc2016-05-09 12:32:27 +0100185 /**
Robin Lee17e61832016-05-09 13:46:28 +0100186 * Whether to keep the connection active after rebooting, or upgrading or reinstalling. This
187 * only applies to {@link VpnService} connections.
188 */
189 private boolean mAlwaysOn = false;
190
191 /**
192 * Whether to disable traffic outside of this VPN even when the VPN is not connected. System
193 * apps can still bypass by choosing explicit networks. Has no effect if {@link mAlwaysOn} is
194 * not set.
195 */
196 private boolean mLockdown = false;
197
198 /**
Robin Lee17e61832016-05-09 13:46:28 +0100199 * List of UIDs for which networking should be blocked until VPN is ready, during brief periods
200 * when VPN is not running. For example, during system startup or after a crash.
201 * @see mLockdown
202 */
203 @GuardedBy("this")
204 private Set<UidRange> mBlockedUsers = new ArraySet<>();
205
Chalard Jeandd59ece2017-12-20 13:23:32 +0900206 // Handle of the user initiating VPN.
Paul Jensen0784eea2014-08-19 16:00:24 -0400207 private final int mUserHandle;
Chia-chi Yehff3bdca2011-05-23 17:26:46 -0700208
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400209 public Vpn(Looper looper, Context context, INetworkManagementService netService,
Robin Leeb8c2a2b2017-03-10 16:17:06 +0000210 @UserIdInt int userHandle) {
211 this(looper, context, netService, userHandle, new SystemServices(context));
212 }
213
214 @VisibleForTesting
215 protected Vpn(Looper looper, Context context, INetworkManagementService netService,
216 int userHandle, SystemServices systemServices) {
Chia-chi Yehff3bdca2011-05-23 17:26:46 -0700217 mContext = context;
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400218 mNetd = netService;
Paul Jensen0784eea2014-08-19 16:00:24 -0400219 mUserHandle = userHandle;
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400220 mLooper = looper;
Robin Leeb8c2a2b2017-03-10 16:17:06 +0000221 mSystemServices = systemServices;
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400222
223 mPackage = VpnConfig.LEGACY_VPN;
Paul Jensen0784eea2014-08-19 16:00:24 -0400224 mOwnerUID = getAppUid(mPackage, mUserHandle);
Jeff Sharkey899223b2012-08-04 15:24:58 -0700225
226 try {
227 netService.registerObserver(mObserver);
228 } catch (RemoteException e) {
229 Log.wtf(TAG, "Problem registering observer", e);
230 }
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400231
Chalard Jeandd59ece2017-12-20 13:23:32 +0900232 mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_VPN, 0 /* subtype */, NETWORKTYPE,
233 "" /* subtypeName */);
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400234 mNetworkCapabilities = new NetworkCapabilities();
235 mNetworkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_VPN);
236 mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN);
Jeff Sharkey72f9c422017-10-27 17:22:59 -0600237 updateCapabilities();
Robin Leeb8c2a2b2017-03-10 16:17:06 +0000238
239 loadAlwaysOnPackage();
Jeff Sharkey899223b2012-08-04 15:24:58 -0700240 }
241
Jeff Sharkey57666932013-04-30 17:01:57 -0700242 /**
Chalard Jeandd59ece2017-12-20 13:23:32 +0900243 * Set whether this object is responsible for watching for {@link NetworkInfo}
Jeff Sharkey57666932013-04-30 17:01:57 -0700244 * teardown. When {@code false}, teardown is handled externally by someone
245 * else.
246 */
247 public void setEnableTeardown(boolean enableTeardown) {
248 mEnableTeardown = enableTeardown;
249 }
250
Jeff Sharkey899223b2012-08-04 15:24:58 -0700251 /**
252 * Update current state, dispaching event to listeners.
253 */
Tony Mak1a405fe2016-06-30 11:19:20 +0100254 @VisibleForTesting
255 protected void updateState(DetailedState detailedState, String reason) {
Jeff Sharkey899223b2012-08-04 15:24:58 -0700256 if (LOGD) Log.d(TAG, "setting state=" + detailedState + ", reason=" + reason);
257 mNetworkInfo.setDetailedState(detailedState, reason, null);
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400258 if (mNetworkAgent != null) {
259 mNetworkAgent.sendNetworkInfo(mNetworkInfo);
260 }
Tony Mak1a405fe2016-06-30 11:19:20 +0100261 updateAlwaysOnNotification(detailedState);
Chia-chi Yehff3bdca2011-05-23 17:26:46 -0700262 }
263
Jeff Sharkey72f9c422017-10-27 17:22:59 -0600264 public void updateCapabilities() {
265 final Network[] underlyingNetworks = (mConfig != null) ? mConfig.underlyingNetworks : null;
266 updateCapabilities(mContext.getSystemService(ConnectivityManager.class), underlyingNetworks,
267 mNetworkCapabilities);
268
269 if (mNetworkAgent != null) {
270 mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
271 }
272 }
273
274 @VisibleForTesting
275 public static void updateCapabilities(ConnectivityManager cm, Network[] underlyingNetworks,
276 NetworkCapabilities caps) {
277 int[] transportTypes = new int[] { NetworkCapabilities.TRANSPORT_VPN };
278 int downKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
279 int upKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
280 boolean metered = false;
281 boolean roaming = false;
Jeff Sharkey9b2a10f2018-01-17 13:27:03 +0900282 boolean congested = false;
Jeff Sharkey72f9c422017-10-27 17:22:59 -0600283
Chalard Jean3bd57052018-05-21 15:30:56 +0900284 boolean hadUnderlyingNetworks = false;
285 if (null != underlyingNetworks) {
Jeff Sharkey72f9c422017-10-27 17:22:59 -0600286 for (Network underlying : underlyingNetworks) {
287 final NetworkCapabilities underlyingCaps = cm.getNetworkCapabilities(underlying);
Jeff Sharkey4f5e6262018-01-02 11:46:32 -0700288 if (underlyingCaps == null) continue;
Chalard Jean3bd57052018-05-21 15:30:56 +0900289 hadUnderlyingNetworks = true;
Jeff Sharkey72f9c422017-10-27 17:22:59 -0600290 for (int underlyingType : underlyingCaps.getTransportTypes()) {
291 transportTypes = ArrayUtils.appendInt(transportTypes, underlyingType);
292 }
293
294 // When we have multiple networks, we have to assume the
295 // worst-case link speed and restrictions.
296 downKbps = NetworkCapabilities.minBandwidth(downKbps,
297 underlyingCaps.getLinkDownstreamBandwidthKbps());
298 upKbps = NetworkCapabilities.minBandwidth(upKbps,
299 underlyingCaps.getLinkUpstreamBandwidthKbps());
300 metered |= !underlyingCaps.hasCapability(NET_CAPABILITY_NOT_METERED);
301 roaming |= !underlyingCaps.hasCapability(NET_CAPABILITY_NOT_ROAMING);
Jeff Sharkey9b2a10f2018-01-17 13:27:03 +0900302 congested |= !underlyingCaps.hasCapability(NET_CAPABILITY_NOT_CONGESTED);
Jeff Sharkey72f9c422017-10-27 17:22:59 -0600303 }
304 }
Chalard Jean3bd57052018-05-21 15:30:56 +0900305 if (!hadUnderlyingNetworks) {
306 // No idea what the underlying networks are; assume sane defaults
307 metered = true;
308 roaming = false;
309 congested = false;
310 }
Jeff Sharkey72f9c422017-10-27 17:22:59 -0600311
312 caps.setTransportTypes(transportTypes);
313 caps.setLinkDownstreamBandwidthKbps(downKbps);
314 caps.setLinkUpstreamBandwidthKbps(upKbps);
Jeff Sharkey9b2a10f2018-01-17 13:27:03 +0900315 caps.setCapability(NET_CAPABILITY_NOT_METERED, !metered);
316 caps.setCapability(NET_CAPABILITY_NOT_ROAMING, !roaming);
317 caps.setCapability(NET_CAPABILITY_NOT_CONGESTED, !congested);
Jeff Sharkey72f9c422017-10-27 17:22:59 -0600318 }
319
Chia-chi Yehff3bdca2011-05-23 17:26:46 -0700320 /**
Robin Leec3736bc2017-03-10 16:19:54 +0000321 * Chooses whether to force all connections to go though VPN.
322 *
323 * Used to enable/disable legacy VPN lockdown.
324 *
325 * This uses the same ip rule mechanism as {@link #setAlwaysOnPackage(String, boolean)};
326 * previous settings from calling that function will be replaced and saved with the
327 * always-on state.
328 *
329 * @param lockdown whether to prevent all traffic outside of a VPN.
330 */
331 public synchronized void setLockdown(boolean lockdown) {
332 enforceControlPermissionOrInternalCaller();
333
334 setVpnForcedLocked(lockdown);
335 mLockdown = lockdown;
336
337 // Update app lockdown setting if it changed. Legacy VPN lockdown status is controlled by
338 // LockdownVpnTracker.isEnabled() which keeps track of its own state.
339 if (mAlwaysOn) {
340 saveAlwaysOnPackage();
341 }
342 }
343
344 /**
junyulai8ed89152018-10-25 10:56:17 +0800345 * Check whether to prevent all traffic outside of a VPN even when the VPN is not connected.
346 *
347 * @return {@code true} if VPN lockdown is enabled.
348 */
349 public boolean getLockdown() {
350 return mLockdown;
351 }
352
353 /**
Charles Hea0a87e82017-05-15 17:07:18 +0100354 * Checks if a VPN app supports always-on mode.
355 *
356 * In order to support the always-on feature, an app has to
357 * <ul>
358 * <li>target {@link VERSION_CODES#N API 24} or above, and
Charles He5da5ae32017-08-15 15:30:22 +0100359 * <li>not opt out through the {@link VpnService#SERVICE_META_DATA_SUPPORTS_ALWAYS_ON}
360 * meta-data field.
Charles Hea0a87e82017-05-15 17:07:18 +0100361 * </ul>
362 *
363 * @param packageName the canonical package name of the VPN app
364 * @return {@code true} if and only if the VPN app exists and supports always-on mode
365 */
366 public boolean isAlwaysOnPackageSupported(String packageName) {
367 enforceSettingsPermission();
368
369 if (packageName == null) {
370 return false;
371 }
372
373 PackageManager pm = mContext.getPackageManager();
374 ApplicationInfo appInfo = null;
375 try {
376 appInfo = pm.getApplicationInfoAsUser(packageName, 0 /*flags*/, mUserHandle);
377 } catch (NameNotFoundException unused) {
378 Log.w(TAG, "Can't find \"" + packageName + "\" when checking always-on support");
379 }
380 if (appInfo == null || appInfo.targetSdkVersion < VERSION_CODES.N) {
381 return false;
382 }
383
384 final Intent intent = new Intent(VpnConfig.SERVICE_INTERFACE);
385 intent.setPackage(packageName);
386 List<ResolveInfo> services =
387 pm.queryIntentServicesAsUser(intent, PackageManager.GET_META_DATA, mUserHandle);
388 if (services == null || services.size() == 0) {
389 return false;
390 }
391
392 for (ResolveInfo rInfo : services) {
393 final Bundle metaData = rInfo.serviceInfo.metaData;
Charles He5da5ae32017-08-15 15:30:22 +0100394 if (metaData != null &&
395 !metaData.getBoolean(VpnService.SERVICE_META_DATA_SUPPORTS_ALWAYS_ON, true)) {
Charles Hea0a87e82017-05-15 17:07:18 +0100396 return false;
397 }
398 }
399
400 return true;
401 }
402
403 /**
Robin Lee244ce8e2016-01-05 18:03:46 +0000404 * Configures an always-on VPN connection through a specific application.
405 * This connection is automatically granted and persisted after a reboot.
406 *
407 * <p>The designated package should exist and declare a {@link VpnService} in its
408 * manifest guarded by {@link android.Manifest.permission.BIND_VPN_SERVICE},
409 * otherwise the call will fail.
410 *
Charles Hea0a87e82017-05-15 17:07:18 +0100411 * <p>Note that this method does not check if the VPN app supports always-on mode. The check is
412 * delayed to {@link #startAlwaysOnVpn()}, which is always called immediately after this
413 * method in {@link android.net.IConnectivityManager#setAlwaysOnVpnPackage}.
414 *
Robin Lee17e61832016-05-09 13:46:28 +0100415 * @param packageName the package to designate as always-on VPN supplier.
416 * @param lockdown whether to prevent traffic outside of a VPN, for example while connecting.
Robin Lee9ff1a582016-06-10 16:41:10 +0100417 * @return {@code true} if the package has been set as always-on, {@code false} otherwise.
Robin Lee244ce8e2016-01-05 18:03:46 +0000418 */
Robin Lee17e61832016-05-09 13:46:28 +0100419 public synchronized boolean setAlwaysOnPackage(String packageName, boolean lockdown) {
Robin Lee244ce8e2016-01-05 18:03:46 +0000420 enforceControlPermissionOrInternalCaller();
Robin Leeb8c2a2b2017-03-10 16:17:06 +0000421
422 if (setAlwaysOnPackageInternal(packageName, lockdown)) {
423 saveAlwaysOnPackage();
424 return true;
425 }
426 return false;
427 }
428
429 /**
430 * Configures an always-on VPN connection through a specific application, the same as
431 * {@link #setAlwaysOnPackage}.
432 *
433 * Does not perform permission checks. Does not persist any of the changes to storage.
434 *
435 * @param packageName the package to designate as always-on VPN supplier.
436 * @param lockdown whether to prevent traffic outside of a VPN, for example while connecting.
437 * @return {@code true} if the package has been set as always-on, {@code false} otherwise.
438 */
439 @GuardedBy("this")
440 private boolean setAlwaysOnPackageInternal(String packageName, boolean lockdown) {
Robin Lee9ff1a582016-06-10 16:41:10 +0100441 if (VpnConfig.LEGACY_VPN.equals(packageName)) {
442 Log.w(TAG, "Not setting legacy VPN \"" + packageName + "\" as always-on.");
443 return false;
444 }
Robin Lee244ce8e2016-01-05 18:03:46 +0000445
Robin Lee244ce8e2016-01-05 18:03:46 +0000446 if (packageName != null) {
Robin Lee9ff1a582016-06-10 16:41:10 +0100447 // Pre-authorize new always-on VPN package.
Robin Lee244ce8e2016-01-05 18:03:46 +0000448 if (!setPackageAuthorization(packageName, true)) {
449 return false;
450 }
Robin Lee9ff1a582016-06-10 16:41:10 +0100451 mAlwaysOn = true;
452 } else {
453 packageName = VpnConfig.LEGACY_VPN;
454 mAlwaysOn = false;
Robin Lee244ce8e2016-01-05 18:03:46 +0000455 }
456
Robin Lee17e61832016-05-09 13:46:28 +0100457 mLockdown = (mAlwaysOn && lockdown);
Tony Mak1a405fe2016-06-30 11:19:20 +0100458 if (isCurrentPreparedPackage(packageName)) {
459 updateAlwaysOnNotification(mNetworkInfo.getDetailedState());
460 } else {
461 // Prepare this app. The notification will update as a side-effect of updateState().
Robin Lee9ff1a582016-06-10 16:41:10 +0100462 prepareInternal(packageName);
463 }
Robin Lee17e61832016-05-09 13:46:28 +0100464 setVpnForcedLocked(mLockdown);
Robin Lee244ce8e2016-01-05 18:03:46 +0000465 return true;
466 }
467
Robin Lee9ff1a582016-06-10 16:41:10 +0100468 private static boolean isNullOrLegacyVpn(String packageName) {
469 return packageName == null || VpnConfig.LEGACY_VPN.equals(packageName);
470 }
471
Robin Lee244ce8e2016-01-05 18:03:46 +0000472 /**
473 * @return the package name of the VPN controller responsible for always-on VPN,
474 * or {@code null} if none is set or always-on VPN is controlled through
475 * lockdown instead.
476 * @hide
477 */
478 public synchronized String getAlwaysOnPackage() {
479 enforceControlPermissionOrInternalCaller();
Robin Lee17e61832016-05-09 13:46:28 +0100480 return (mAlwaysOn ? mPackage : null);
Robin Lee244ce8e2016-01-05 18:03:46 +0000481 }
482
483 /**
Robin Lee812800c2016-05-13 15:38:08 +0100484 * Save the always-on package and lockdown config into Settings.Secure
485 */
Robin Leeb8c2a2b2017-03-10 16:17:06 +0000486 @GuardedBy("this")
487 private void saveAlwaysOnPackage() {
Robin Lee812800c2016-05-13 15:38:08 +0100488 final long token = Binder.clearCallingIdentity();
489 try {
Robin Leeb8c2a2b2017-03-10 16:17:06 +0000490 mSystemServices.settingsSecurePutStringForUser(Settings.Secure.ALWAYS_ON_VPN_APP,
Robin Lee812800c2016-05-13 15:38:08 +0100491 getAlwaysOnPackage(), mUserHandle);
Robin Leeb8c2a2b2017-03-10 16:17:06 +0000492 mSystemServices.settingsSecurePutIntForUser(Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN,
Robin Leec3736bc2017-03-10 16:19:54 +0000493 (mAlwaysOn && mLockdown ? 1 : 0), mUserHandle);
Robin Lee812800c2016-05-13 15:38:08 +0100494 } finally {
495 Binder.restoreCallingIdentity(token);
496 }
497 }
498
499 /**
Robin Leeb8c2a2b2017-03-10 16:17:06 +0000500 * Load the always-on package and lockdown config from Settings.Secure
Robin Lee812800c2016-05-13 15:38:08 +0100501 */
Robin Leeb8c2a2b2017-03-10 16:17:06 +0000502 @GuardedBy("this")
503 private void loadAlwaysOnPackage() {
504 final long token = Binder.clearCallingIdentity();
505 try {
506 final String alwaysOnPackage = mSystemServices.settingsSecureGetStringForUser(
507 Settings.Secure.ALWAYS_ON_VPN_APP, mUserHandle);
508 final boolean alwaysOnLockdown = mSystemServices.settingsSecureGetIntForUser(
509 Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN, 0 /*default*/, mUserHandle) != 0;
510 setAlwaysOnPackageInternal(alwaysOnPackage, alwaysOnLockdown);
511 } finally {
512 Binder.restoreCallingIdentity(token);
Robin Lee812800c2016-05-13 15:38:08 +0100513 }
514 }
515
516 /**
517 * @return {@code true} if the service was started, the service was already connected, or there
518 * was no always-on VPN to start. {@code false} otherwise.
519 */
520 public boolean startAlwaysOnVpn() {
521 final String alwaysOnPackage;
522 synchronized (this) {
523 alwaysOnPackage = getAlwaysOnPackage();
524 // Skip if there is no service to start.
525 if (alwaysOnPackage == null) {
526 return true;
527 }
Charles Hea0a87e82017-05-15 17:07:18 +0100528 // Remove always-on VPN if it's not supported.
529 if (!isAlwaysOnPackageSupported(alwaysOnPackage)) {
530 setAlwaysOnPackage(null, false);
531 return false;
532 }
Robin Lee812800c2016-05-13 15:38:08 +0100533 // Skip if the service is already established. This isn't bulletproof: it's not bound
534 // until after establish(), so if it's mid-setup onStartCommand will be sent twice,
535 // which may restart the connection.
536 if (getNetworkInfo().isConnected()) {
537 return true;
538 }
539 }
540
Christopher Tatee0be7e82017-02-08 17:38:20 -0800541 // Tell the OS that background services in this app need to be allowed for
542 // a short time, so we can bootstrap the VPN service.
543 final long oldId = Binder.clearCallingIdentity();
Robin Lee812800c2016-05-13 15:38:08 +0100544 try {
Christopher Tatee0be7e82017-02-08 17:38:20 -0800545 DeviceIdleController.LocalService idleController =
546 LocalServices.getService(DeviceIdleController.LocalService.class);
547 idleController.addPowerSaveTempWhitelistApp(Process.myUid(), alwaysOnPackage,
Chalard Jeandd59ece2017-12-20 13:23:32 +0900548 VPN_LAUNCH_IDLE_WHITELIST_DURATION_MS, mUserHandle, false, "vpn");
Christopher Tatee0be7e82017-02-08 17:38:20 -0800549
550 // Start the VPN service declared in the app's manifest.
551 Intent serviceIntent = new Intent(VpnConfig.SERVICE_INTERFACE);
552 serviceIntent.setPackage(alwaysOnPackage);
553 try {
554 return mContext.startServiceAsUser(serviceIntent, UserHandle.of(mUserHandle)) != null;
555 } catch (RuntimeException e) {
556 Log.e(TAG, "VpnService " + serviceIntent + " failed to start", e);
557 return false;
558 }
559 } finally {
560 Binder.restoreCallingIdentity(oldId);
Robin Lee812800c2016-05-13 15:38:08 +0100561 }
562 }
563
564 /**
Chia-chi Yeh100155a2011-07-03 16:52:38 -0700565 * Prepare for a VPN application. This method is designed to solve
566 * race conditions. It first compares the current prepared package
567 * with {@code oldPackage}. If they are the same, the prepared
568 * package is revoked and replaced with {@code newPackage}. If
569 * {@code oldPackage} is {@code null}, the comparison is omitted.
570 * If {@code newPackage} is the same package or {@code null}, the
571 * revocation is omitted. This method returns {@code true} if the
572 * operation is succeeded.
Chia-chi Yehff3bdca2011-05-23 17:26:46 -0700573 *
Chia-chi Yeh100155a2011-07-03 16:52:38 -0700574 * Legacy VPN is handled specially since it is not a real package.
575 * It uses {@link VpnConfig#LEGACY_VPN} as its package name, and
576 * it can be revoked by itself.
577 *
Chalard Jeandd59ece2017-12-20 13:23:32 +0900578 * Note: when we added VPN pre-consent in
579 * https://android.googlesource.com/platform/frameworks/base/+/0554260
580 * the names oldPackage and newPackage became misleading, because when
581 * an app is pre-consented, we actually prepare oldPackage, not newPackage.
Victor Chang98a633a2016-05-27 17:30:49 +0100582 *
583 * Their meanings actually are:
584 *
585 * - oldPackage non-null, newPackage null: App calling VpnService#prepare().
586 * - oldPackage null, newPackage non-null: ConfirmDialog calling prepareVpn().
Robin Lee812800c2016-05-13 15:38:08 +0100587 * - oldPackage null, newPackage=LEGACY_VPN: Used internally to disconnect
Victor Chang98a633a2016-05-27 17:30:49 +0100588 * and revoke any current app VPN and re-prepare legacy vpn.
589 *
Robin Lee812800c2016-05-13 15:38:08 +0100590 * TODO: Rename the variables - or split this method into two - and end this confusion.
591 * TODO: b/29032008 Migrate code from prepare(oldPackage=non-null, newPackage=LEGACY_VPN)
592 * to prepare(oldPackage=null, newPackage=LEGACY_VPN)
Victor Chang98a633a2016-05-27 17:30:49 +0100593 *
594 * @param oldPackage The package name of the old VPN application
595 * @param newPackage The package name of the new VPN application
596 *
Chalard Jeandd59ece2017-12-20 13:23:32 +0900597 * @return true if the operation succeeded.
Chia-chi Yehe9107902011-07-02 01:48:50 -0700598 */
Chia-chi Yeh100155a2011-07-03 16:52:38 -0700599 public synchronized boolean prepare(String oldPackage, String newPackage) {
Jeff Davidson0a775ce2015-04-27 15:02:48 -0700600 if (oldPackage != null) {
Victor Chang98a633a2016-05-27 17:30:49 +0100601 // Stop an existing always-on VPN from being dethroned by other apps.
Robin Lee812800c2016-05-13 15:38:08 +0100602 if (mAlwaysOn && !isCurrentPreparedPackage(oldPackage)) {
Victor Chang98a633a2016-05-27 17:30:49 +0100603 return false;
604 }
605
Chalard Jeandd59ece2017-12-20 13:23:32 +0900606 // Package is not the same or old package was reinstalled.
Victor Chang98a633a2016-05-27 17:30:49 +0100607 if (!isCurrentPreparedPackage(oldPackage)) {
Jeff Davidson0a775ce2015-04-27 15:02:48 -0700608 // The package doesn't match. We return false (to obtain user consent) unless the
609 // user has already consented to that VPN package.
610 if (!oldPackage.equals(VpnConfig.LEGACY_VPN) && isVpnUserPreConsented(oldPackage)) {
611 prepareInternal(oldPackage);
612 return true;
613 }
614 return false;
615 } else if (!oldPackage.equals(VpnConfig.LEGACY_VPN)
616 && !isVpnUserPreConsented(oldPackage)) {
617 // Currently prepared VPN is revoked, so unprepare it and return false.
618 prepareInternal(VpnConfig.LEGACY_VPN);
619 return false;
Jeff Davidson05542602014-08-11 14:07:27 -0700620 }
Chia-chi Yehe9107902011-07-02 01:48:50 -0700621 }
622
Chia-chi Yeh100155a2011-07-03 16:52:38 -0700623 // Return true if we do not need to revoke.
Jeff Davidsonbe085872014-10-24 10:35:53 -0700624 if (newPackage == null || (!newPackage.equals(VpnConfig.LEGACY_VPN) &&
Victor Chang98a633a2016-05-27 17:30:49 +0100625 isCurrentPreparedPackage(newPackage))) {
Chia-chi Yeh100155a2011-07-03 16:52:38 -0700626 return true;
627 }
628
Robin Lee1b1bcd72016-02-12 18:11:30 +0000629 // Check that the caller is authorized.
Chia-chi Yehdadc8572012-06-08 13:05:58 -0700630 enforceControlPermission();
Chia-chi Yehe9107902011-07-02 01:48:50 -0700631
Victor Chang98a633a2016-05-27 17:30:49 +0100632 // Stop an existing always-on VPN from being dethroned by other apps.
Robin Lee812800c2016-05-13 15:38:08 +0100633 if (mAlwaysOn && !isCurrentPreparedPackage(newPackage)) {
Victor Chang98a633a2016-05-27 17:30:49 +0100634 return false;
635 }
636
Jeff Davidson11008a72014-11-20 13:12:46 -0800637 prepareInternal(newPackage);
638 return true;
639 }
Chia-chi Yehe9107902011-07-02 01:48:50 -0700640
Victor Chang98a633a2016-05-27 17:30:49 +0100641 private boolean isCurrentPreparedPackage(String packageName) {
642 // We can't just check that packageName matches mPackage, because if the app was uninstalled
643 // and reinstalled it will no longer be prepared. Instead check the UID.
644 return getAppUid(packageName, mUserHandle) == mOwnerUID;
645 }
646
Jeff Davidson11008a72014-11-20 13:12:46 -0800647 /** Prepare the VPN for the given package. Does not perform permission checks. */
648 private void prepareInternal(String newPackage) {
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400649 long token = Binder.clearCallingIdentity();
650 try {
Jeff Davidson11008a72014-11-20 13:12:46 -0800651 // Reset the interface.
652 if (mInterface != null) {
653 mStatusIntent = null;
654 agentDisconnect();
655 jniReset(mInterface);
656 mInterface = null;
Chalard Jeanecacd5e2017-12-27 14:23:31 +0900657 mNetworkCapabilities.setUids(null);
Jeff Davidson11008a72014-11-20 13:12:46 -0800658 }
659
660 // Revoke the connection or stop LegacyVpnRunner.
661 if (mConnection != null) {
662 try {
663 mConnection.mService.transact(IBinder.LAST_CALL_TRANSACTION,
664 Parcel.obtain(), null, IBinder.FLAG_ONEWAY);
665 } catch (Exception e) {
666 // ignore
667 }
668 mContext.unbindService(mConnection);
669 mConnection = null;
670 } else if (mLegacyVpnRunner != null) {
671 mLegacyVpnRunner.exit();
672 mLegacyVpnRunner = null;
673 }
674
675 try {
676 mNetd.denyProtect(mOwnerUID);
677 } catch (Exception e) {
678 Log.wtf(TAG, "Failed to disallow UID " + mOwnerUID + " to call protect() " + e);
679 }
680
681 Log.i(TAG, "Switched from " + mPackage + " to " + newPackage);
682 mPackage = newPackage;
683 mOwnerUID = getAppUid(newPackage, mUserHandle);
684 try {
685 mNetd.allowProtect(mOwnerUID);
686 } catch (Exception e) {
687 Log.wtf(TAG, "Failed to allow UID " + mOwnerUID + " to call protect() " + e);
688 }
689 mConfig = null;
690
691 updateState(DetailedState.IDLE, "prepare");
Robin Leec3736bc2017-03-10 16:19:54 +0000692 setVpnForcedLocked(mLockdown);
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400693 } finally {
694 Binder.restoreCallingIdentity(token);
695 }
Chia-chi Yehe9107902011-07-02 01:48:50 -0700696 }
697
Jeff Davidson05542602014-08-11 14:07:27 -0700698 /**
Robin Lee3b3dd942015-05-12 18:14:58 +0100699 * Set whether a package has the ability to launch VPNs without user intervention.
Jeff Davidson05542602014-08-11 14:07:27 -0700700 */
Robin Lee244ce8e2016-01-05 18:03:46 +0000701 public boolean setPackageAuthorization(String packageName, boolean authorized) {
Jeff Davidson05542602014-08-11 14:07:27 -0700702 // Check if the caller is authorized.
Robin Lee244ce8e2016-01-05 18:03:46 +0000703 enforceControlPermissionOrInternalCaller();
Jeff Davidson05542602014-08-11 14:07:27 -0700704
Robin Lee3b3dd942015-05-12 18:14:58 +0100705 int uid = getAppUid(packageName, mUserHandle);
706 if (uid == -1 || VpnConfig.LEGACY_VPN.equals(packageName)) {
707 // Authorization for nonexistent packages (or fake ones) can't be updated.
Robin Lee244ce8e2016-01-05 18:03:46 +0000708 return false;
Jeff Davidson05542602014-08-11 14:07:27 -0700709 }
710
711 long token = Binder.clearCallingIdentity();
712 try {
713 AppOpsManager appOps =
714 (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
Robin Lee3b3dd942015-05-12 18:14:58 +0100715 appOps.setMode(AppOpsManager.OP_ACTIVATE_VPN, uid, packageName,
Jeff Davidson05542602014-08-11 14:07:27 -0700716 authorized ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
Robin Lee244ce8e2016-01-05 18:03:46 +0000717 return true;
Jeff Davidson05542602014-08-11 14:07:27 -0700718 } catch (Exception e) {
Robin Lee3b3dd942015-05-12 18:14:58 +0100719 Log.wtf(TAG, "Failed to set app ops for package " + packageName + ", uid " + uid, e);
Jeff Davidson05542602014-08-11 14:07:27 -0700720 } finally {
721 Binder.restoreCallingIdentity(token);
722 }
Robin Lee244ce8e2016-01-05 18:03:46 +0000723 return false;
Jeff Davidson05542602014-08-11 14:07:27 -0700724 }
725
726 private boolean isVpnUserPreConsented(String packageName) {
727 AppOpsManager appOps =
728 (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
729
730 // Verify that the caller matches the given package and has permission to activate VPNs.
731 return appOps.noteOpNoThrow(AppOpsManager.OP_ACTIVATE_VPN, Binder.getCallingUid(),
732 packageName) == AppOpsManager.MODE_ALLOWED;
733 }
734
Paul Jensen0784eea2014-08-19 16:00:24 -0400735 private int getAppUid(String app, int userHandle) {
Jeff Davidson05542602014-08-11 14:07:27 -0700736 if (VpnConfig.LEGACY_VPN.equals(app)) {
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400737 return Process.myUid();
Chia-chi Yehfcc1b412011-08-03 15:39:59 -0700738 }
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400739 PackageManager pm = mContext.getPackageManager();
740 int result;
Chad Brubaker4ca19e82013-06-14 11:16:51 -0700741 try {
Jeff Sharkeye06b4d12016-01-06 14:51:50 -0700742 result = pm.getPackageUidAsUser(app, userHandle);
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400743 } catch (NameNotFoundException e) {
744 result = -1;
745 }
746 return result;
747 }
748
749 public NetworkInfo getNetworkInfo() {
750 return mNetworkInfo;
751 }
752
Paul Jensen31a94f42015-02-13 14:18:39 -0500753 public int getNetId() {
754 return mNetworkAgent != null ? mNetworkAgent.netId : NETID_UNSET;
755 }
756
Lorenzo Colitti60446162014-09-20 00:14:31 +0900757 private LinkProperties makeLinkProperties() {
758 boolean allowIPv4 = mConfig.allowIPv4;
759 boolean allowIPv6 = mConfig.allowIPv6;
760
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400761 LinkProperties lp = new LinkProperties();
Lorenzo Colitti60446162014-09-20 00:14:31 +0900762
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400763 lp.setInterfaceName(mInterface);
Sreeram Ramachandran42065ac2014-07-27 00:37:35 -0700764
Lorenzo Colitti60446162014-09-20 00:14:31 +0900765 if (mConfig.addresses != null) {
766 for (LinkAddress address : mConfig.addresses) {
767 lp.addLinkAddress(address);
768 allowIPv4 |= address.getAddress() instanceof Inet4Address;
769 allowIPv6 |= address.getAddress() instanceof Inet6Address;
770 }
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400771 }
Lorenzo Colitti60446162014-09-20 00:14:31 +0900772
773 if (mConfig.routes != null) {
774 for (RouteInfo route : mConfig.routes) {
775 lp.addRoute(route);
776 InetAddress address = route.getDestination().getAddress();
777 allowIPv4 |= address instanceof Inet4Address;
778 allowIPv6 |= address instanceof Inet6Address;
779 }
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400780 }
Sreeram Ramachandran42065ac2014-07-27 00:37:35 -0700781
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400782 if (mConfig.dnsServers != null) {
783 for (String dnsServer : mConfig.dnsServers) {
Sreeram Ramachandran42065ac2014-07-27 00:37:35 -0700784 InetAddress address = InetAddress.parseNumericAddress(dnsServer);
785 lp.addDnsServer(address);
Lorenzo Colitti60446162014-09-20 00:14:31 +0900786 allowIPv4 |= address instanceof Inet4Address;
787 allowIPv6 |= address instanceof Inet6Address;
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400788 }
789 }
Sreeram Ramachandran42065ac2014-07-27 00:37:35 -0700790
Lorenzo Colitti60446162014-09-20 00:14:31 +0900791 if (!allowIPv4) {
792 lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE));
793 }
794 if (!allowIPv6) {
795 lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE));
796 }
797
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400798 // Concatenate search domains into a string.
799 StringBuilder buffer = new StringBuilder();
800 if (mConfig.searchDomains != null) {
801 for (String domain : mConfig.searchDomains) {
802 buffer.append(domain).append(' ');
803 }
804 }
805 lp.setDomains(buffer.toString().trim());
Sreeram Ramachandran42065ac2014-07-27 00:37:35 -0700806
Lorenzo Colitti60446162014-09-20 00:14:31 +0900807 // TODO: Stop setting the MTU in jniCreate and set it here.
808
809 return lp;
810 }
811
Chalard Jeanadbf1d02018-02-26 11:52:46 +0900812 /**
813 * Analyzes the passed LinkedProperties to figure out whether it routes to most of the IP space.
814 *
815 * This returns true if the passed LinkedProperties contains routes to either most of the IPv4
816 * space or to most of the IPv6 address space, where "most" is defined by the value of the
817 * MOST_IPV{4,6}_ADDRESSES_COUNT constants : if more than this number of addresses are matched
818 * by any of the routes, then it's decided that most of the space is routed.
819 * @hide
820 */
821 @VisibleForTesting
822 static boolean providesRoutesToMostDestinations(LinkProperties lp) {
Chalard Jeane0d26f62018-03-29 14:10:44 +0900823 final List<RouteInfo> routes = lp.getAllRoutes();
824 if (routes.size() > MAX_ROUTES_TO_EVALUATE) return true;
Chalard Jeanadbf1d02018-02-26 11:52:46 +0900825 final Comparator<IpPrefix> prefixLengthComparator = IpPrefix.lengthComparator();
826 TreeSet<IpPrefix> ipv4Prefixes = new TreeSet<>(prefixLengthComparator);
827 TreeSet<IpPrefix> ipv6Prefixes = new TreeSet<>(prefixLengthComparator);
Chalard Jeane0d26f62018-03-29 14:10:44 +0900828 for (final RouteInfo route : routes) {
Chalard Jeanadbf1d02018-02-26 11:52:46 +0900829 IpPrefix destination = route.getDestination();
830 if (destination.isIPv4()) {
831 ipv4Prefixes.add(destination);
832 } else {
833 ipv6Prefixes.add(destination);
834 }
835 }
836 if (NetworkUtils.routedIPv4AddressCount(ipv4Prefixes) > MOST_IPV4_ADDRESSES_COUNT) {
837 return true;
838 }
839 return NetworkUtils.routedIPv6AddressCount(ipv6Prefixes)
840 .compareTo(MOST_IPV6_ADDRESSES_COUNT) >= 0;
841 }
842
Lorenzo Colitti6fd62b32017-09-22 21:27:32 +0900843 /**
844 * Attempt to perform a seamless handover of VPNs by only updating LinkProperties without
845 * registering a new NetworkAgent. This is not always possible if the new VPN configuration
846 * has certain changes, in which case this method would just return {@code false}.
847 */
848 private boolean updateLinkPropertiesInPlaceIfPossible(NetworkAgent agent, VpnConfig oldConfig) {
849 // NetworkMisc cannot be updated without registering a new NetworkAgent.
850 if (oldConfig.allowBypass != mConfig.allowBypass) {
851 Log.i(TAG, "Handover not possible due to changes to allowBypass");
852 return false;
853 }
854
855 // TODO: we currently do not support seamless handover if the allowed or disallowed
856 // applications have changed. Consider diffing UID ranges and only applying the delta.
857 if (!Objects.equals(oldConfig.allowedApplications, mConfig.allowedApplications) ||
858 !Objects.equals(oldConfig.disallowedApplications, mConfig.disallowedApplications)) {
859 Log.i(TAG, "Handover not possible due to changes to whitelisted/blacklisted apps");
860 return false;
861 }
862
863 LinkProperties lp = makeLinkProperties();
864 final boolean hadInternetCapability = mNetworkCapabilities.hasCapability(
865 NetworkCapabilities.NET_CAPABILITY_INTERNET);
866 final boolean willHaveInternetCapability = providesRoutesToMostDestinations(lp);
867 if (hadInternetCapability != willHaveInternetCapability) {
868 // A seamless handover would have led to a change to INTERNET capability, which
869 // is supposed to be immutable for a given network. In this case bail out and do not
870 // perform handover.
871 Log.i(TAG, "Handover not possible due to changes to INTERNET capability");
872 return false;
873 }
874
875 agent.sendLinkProperties(lp);
876 return true;
877 }
878
Lorenzo Colitti60446162014-09-20 00:14:31 +0900879 private void agentConnect() {
880 LinkProperties lp = makeLinkProperties();
881
Chalard Jeanadbf1d02018-02-26 11:52:46 +0900882 if (providesRoutesToMostDestinations(lp)) {
Lorenzo Colitti60446162014-09-20 00:14:31 +0900883 mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
884 } else {
885 mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
886 }
887
Robin Lee323f29d2016-05-04 16:38:06 +0100888 mNetworkInfo.setDetailedState(DetailedState.CONNECTING, null, null);
Sreeram Ramachandran42065ac2014-07-27 00:37:35 -0700889
Sreeram Ramachandran8cd33ed2014-07-23 15:23:15 -0700890 NetworkMisc networkMisc = new NetworkMisc();
Robin Lee17e61832016-05-09 13:46:28 +0100891 networkMisc.allowBypass = mConfig.allowBypass && !mLockdown;
Sreeram Ramachandran42065ac2014-07-27 00:37:35 -0700892
Chalard Jeanf474fc32018-01-17 15:10:05 +0900893 mNetworkCapabilities.setEstablishingVpnAppUid(Binder.getCallingUid());
Chalard Jeanecacd5e2017-12-27 14:23:31 +0900894 mNetworkCapabilities.setUids(createUserAndRestrictedProfilesRanges(mUserHandle,
895 mConfig.allowedApplications, mConfig.disallowedApplications));
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400896 long token = Binder.clearCallingIdentity();
897 try {
Chalard Jeandd59ece2017-12-20 13:23:32 +0900898 mNetworkAgent = new NetworkAgent(mLooper, mContext, NETWORKTYPE /* logtag */,
Chalard Jeandda156a2018-01-10 21:19:32 +0900899 mNetworkInfo, mNetworkCapabilities, lp,
900 ConnectivityConstants.VPN_DEFAULT_SCORE, networkMisc) {
Jeff Davidson05542602014-08-11 14:07:27 -0700901 @Override
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400902 public void unwanted() {
903 // We are user controlled, not driven by NetworkRequest.
Jeff Davidson05542602014-08-11 14:07:27 -0700904 }
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400905 };
Chad Brubaker4ca19e82013-06-14 11:16:51 -0700906 } finally {
907 Binder.restoreCallingIdentity(token);
908 }
Robin Lee323f29d2016-05-04 16:38:06 +0100909 mNetworkInfo.setIsAvailable(true);
910 updateState(DetailedState.CONNECTED, "agentConnect");
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400911 }
Chad Brubaker4ca19e82013-06-14 11:16:51 -0700912
Fyodor Kupolov1c363152015-09-02 13:27:21 -0700913 private boolean canHaveRestrictedProfile(int userId) {
914 long token = Binder.clearCallingIdentity();
915 try {
916 return UserManager.get(mContext).canHaveRestrictedProfile(userId);
917 } finally {
918 Binder.restoreCallingIdentity(token);
919 }
920 }
921
Tony Mak1a405fe2016-06-30 11:19:20 +0100922 private void agentDisconnect(NetworkAgent networkAgent) {
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400923 if (networkAgent != null) {
Tony Mak1a405fe2016-06-30 11:19:20 +0100924 NetworkInfo networkInfo = new NetworkInfo(mNetworkInfo);
925 networkInfo.setIsAvailable(false);
926 networkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400927 networkAgent.sendNetworkInfo(networkInfo);
928 }
929 }
930
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400931 private void agentDisconnect() {
932 if (mNetworkInfo.isConnected()) {
Tony Mak1a405fe2016-06-30 11:19:20 +0100933 mNetworkInfo.setIsAvailable(false);
934 updateState(DetailedState.DISCONNECTED, "agentDisconnect");
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400935 mNetworkAgent = null;
936 }
Chia-chi Yehfcc1b412011-08-03 15:39:59 -0700937 }
938
939 /**
Chia-chi Yehe9107902011-07-02 01:48:50 -0700940 * Establish a VPN network and return the file descriptor of the VPN
941 * interface. This methods returns {@code null} if the application is
Chia-chi Yeh100155a2011-07-03 16:52:38 -0700942 * revoked or not prepared.
Chia-chi Yehe9107902011-07-02 01:48:50 -0700943 *
944 * @param config The parameters to configure the network.
945 * @return The file descriptor of the VPN interface.
Chia-chi Yehff3bdca2011-05-23 17:26:46 -0700946 */
Chia-chi Yeh04ba25c2011-06-15 17:07:27 -0700947 public synchronized ParcelFileDescriptor establish(VpnConfig config) {
Chia-chi Yehff3bdca2011-05-23 17:26:46 -0700948 // Check if the caller is already prepared.
Chad Brubakerc2865192013-07-10 14:46:23 -0700949 UserManager mgr = UserManager.get(mContext);
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400950 if (Binder.getCallingUid() != mOwnerUID) {
Chia-chi Yeh7b0b8342011-06-17 14:34:11 -0700951 return null;
Chia-chi Yehff3bdca2011-05-23 17:26:46 -0700952 }
Jeff Davidson0a775ce2015-04-27 15:02:48 -0700953 // Check to ensure consent hasn't been revoked since we were prepared.
954 if (!isVpnUserPreConsented(mPackage)) {
955 return null;
956 }
Chia-chi Yehfcc1b412011-08-03 15:39:59 -0700957 // Check if the service is properly declared.
Chia-chi Yeh199ed6e2011-08-03 17:38:49 -0700958 Intent intent = new Intent(VpnConfig.SERVICE_INTERFACE);
959 intent.setClassName(mPackage, config.user);
Chad Brubaker4ca19e82013-06-14 11:16:51 -0700960 long token = Binder.clearCallingIdentity();
961 try {
Chad Brubakerc2865192013-07-10 14:46:23 -0700962 // Restricted users are not allowed to create VPNs, they are tied to Owner
Paul Jensen0784eea2014-08-19 16:00:24 -0400963 UserInfo user = mgr.getUserInfo(mUserHandle);
Robin Lee628ae0d2016-05-20 14:53:48 +0100964 if (user.isRestricted()) {
Chad Brubakerc2865192013-07-10 14:46:23 -0700965 throw new SecurityException("Restricted users cannot establish VPNs");
966 }
967
Chad Brubaker4ca19e82013-06-14 11:16:51 -0700968 ResolveInfo info = AppGlobals.getPackageManager().resolveService(intent,
Chalard Jeandd59ece2017-12-20 13:23:32 +0900969 null, 0, mUserHandle);
Chad Brubaker4ca19e82013-06-14 11:16:51 -0700970 if (info == null) {
971 throw new SecurityException("Cannot find " + config.user);
972 }
973 if (!BIND_VPN_SERVICE.equals(info.serviceInfo.permission)) {
974 throw new SecurityException(config.user + " does not require " + BIND_VPN_SERVICE);
975 }
976 } catch (RemoteException e) {
Chalard Jeandd59ece2017-12-20 13:23:32 +0900977 throw new SecurityException("Cannot find " + config.user);
Chad Brubaker4ca19e82013-06-14 11:16:51 -0700978 } finally {
979 Binder.restoreCallingIdentity(token);
Chia-chi Yeh199ed6e2011-08-03 17:38:49 -0700980 }
Chia-chi Yehfcc1b412011-08-03 15:39:59 -0700981
Chad Brubaker850eb672014-03-21 21:02:47 +0000982 // Save the old config in case we need to go back.
983 VpnConfig oldConfig = mConfig;
984 String oldInterface = mInterface;
985 Connection oldConnection = mConnection;
Paul Jensen6bc2c2c2014-05-07 15:27:40 -0400986 NetworkAgent oldNetworkAgent = mNetworkAgent;
Chalard Jeanecacd5e2017-12-27 14:23:31 +0900987 Set<UidRange> oldUsers = mNetworkCapabilities.getUids();
Chad Brubaker850eb672014-03-21 21:02:47 +0000988
Chia-chi Yehe9107902011-07-02 01:48:50 -0700989 // Configure the interface. Abort if any of these steps fails.
Chia-chi Yeh97a61562011-07-14 15:05:05 -0700990 ParcelFileDescriptor tun = ParcelFileDescriptor.adoptFd(jniCreate(config.mtu));
Chia-chi Yehff3bdca2011-05-23 17:26:46 -0700991 try {
Chia-chi Yehc2b8aa02011-07-03 18:00:47 -0700992 String interfaze = jniGetName(tun.getFd());
Chad Brubaker4ca19e82013-06-14 11:16:51 -0700993
Chad Brubakerc2865192013-07-10 14:46:23 -0700994 // TEMP use the old jni calls until there is support for netd address setting
Chad Brubaker4ca19e82013-06-14 11:16:51 -0700995 StringBuilder builder = new StringBuilder();
996 for (LinkAddress address : config.addresses) {
997 builder.append(" " + address);
998 }
999 if (jniSetAddresses(interfaze, builder.toString()) < 1) {
Chia-chi Yeh97a61562011-07-14 15:05:05 -07001000 throw new IllegalArgumentException("At least one address must be specified");
1001 }
Chia-chi Yeh199ed6e2011-08-03 17:38:49 -07001002 Connection connection = new Connection();
Dianne Hackbornd69e4c12015-04-24 09:54:54 -07001003 if (!mContext.bindServiceAsUser(intent, connection,
1004 Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
1005 new UserHandle(mUserHandle))) {
Chia-chi Yeh199ed6e2011-08-03 17:38:49 -07001006 throw new IllegalStateException("Cannot bind " + config.user);
1007 }
Chad Brubaker850eb672014-03-21 21:02:47 +00001008
Chia-chi Yeh199ed6e2011-08-03 17:38:49 -07001009 mConnection = connection;
Chia-chi Yehc2b8aa02011-07-03 18:00:47 -07001010 mInterface = interfaze;
Chad Brubaker4ca19e82013-06-14 11:16:51 -07001011
1012 // Fill more values.
1013 config.user = mPackage;
1014 config.interfaze = mInterface;
Chad Brubakerc2865192013-07-10 14:46:23 -07001015 config.startTime = SystemClock.elapsedRealtime();
1016 mConfig = config;
Chad Brubaker850eb672014-03-21 21:02:47 +00001017
Chad Brubaker4ca19e82013-06-14 11:16:51 -07001018 // Set up forwarding and DNS rules.
Lorenzo Colitti6fd62b32017-09-22 21:27:32 +09001019 // First attempt to do a seamless handover that only changes the interface name and
1020 // parameters. If that fails, disconnect.
1021 if (oldConfig != null
1022 && updateLinkPropertiesInPlaceIfPossible(mNetworkAgent, oldConfig)) {
1023 // Keep mNetworkAgent unchanged
1024 } else {
1025 mNetworkAgent = null;
1026 updateState(DetailedState.CONNECTING, "establish");
1027 // Set up forwarding and DNS rules.
1028 agentConnect();
1029 // Remove the old tun's user forwarding rules
1030 // The new tun's user rules have already been added above so they will take over
1031 // as rules are deleted. This prevents data leakage as the rules are moved over.
1032 agentDisconnect(oldNetworkAgent);
1033 }
Chad Brubaker850eb672014-03-21 21:02:47 +00001034
1035 if (oldConnection != null) {
1036 mContext.unbindService(oldConnection);
1037 }
Lorenzo Colitti6fd62b32017-09-22 21:27:32 +09001038
Chad Brubaker850eb672014-03-21 21:02:47 +00001039 if (oldInterface != null && !oldInterface.equals(interfaze)) {
Chad Brubaker850eb672014-03-21 21:02:47 +00001040 jniReset(oldInterface);
1041 }
Jeff Davidson6bbf39c2014-07-23 10:14:53 -07001042
1043 try {
1044 IoUtils.setBlocking(tun.getFileDescriptor(), config.blocking);
1045 } catch (IOException e) {
1046 throw new IllegalStateException(
1047 "Cannot set tunnel's fd as blocking=" + config.blocking, e);
1048 }
Chad Brubaker850eb672014-03-21 21:02:47 +00001049 } catch (RuntimeException e) {
Chad Brubaker850eb672014-03-21 21:02:47 +00001050 IoUtils.closeQuietly(tun);
Paul Jensen6bc2c2c2014-05-07 15:27:40 -04001051 agentDisconnect();
Chad Brubaker850eb672014-03-21 21:02:47 +00001052 // restore old state
1053 mConfig = oldConfig;
1054 mConnection = oldConnection;
Chalard Jeanecacd5e2017-12-27 14:23:31 +09001055 mNetworkCapabilities.setUids(oldUsers);
Paul Jensen6bc2c2c2014-05-07 15:27:40 -04001056 mNetworkAgent = oldNetworkAgent;
Chad Brubaker850eb672014-03-21 21:02:47 +00001057 mInterface = oldInterface;
1058 throw e;
Chad Brubakerc2865192013-07-10 14:46:23 -07001059 }
Chad Brubaker850eb672014-03-21 21:02:47 +00001060 Log.i(TAG, "Established by " + config.user + " on " + mInterface);
Chia-chi Yehc2b8aa02011-07-03 18:00:47 -07001061 return tun;
Chia-chi Yehff3bdca2011-05-23 17:26:46 -07001062 }
1063
Chad Brubakerc2865192013-07-10 14:46:23 -07001064 private boolean isRunningLocked() {
Sreeram Ramachandranc2c0bea2014-11-11 16:09:21 -08001065 return mNetworkAgent != null && mInterface != null;
1066 }
1067
1068 // Returns true if the VPN has been established and the calling UID is its owner. Used to check
1069 // that a call to mutate VPN state is admissible.
Chalard Jeanf666d0a2018-05-18 21:47:45 +09001070 @VisibleForTesting
1071 protected boolean isCallerEstablishedOwnerLocked() {
Sreeram Ramachandranc2c0bea2014-11-11 16:09:21 -08001072 return isRunningLocked() && Binder.getCallingUid() == mOwnerUID;
Chad Brubakerc2865192013-07-10 14:46:23 -07001073 }
1074
Paul Jensen0784eea2014-08-19 16:00:24 -04001075 // Note: Return type guarantees results are deduped and sorted, which callers require.
1076 private SortedSet<Integer> getAppsUids(List<String> packageNames, int userHandle) {
1077 SortedSet<Integer> uids = new TreeSet<Integer>();
1078 for (String app : packageNames) {
1079 int uid = getAppUid(app, userHandle);
1080 if (uid != -1) uids.add(uid);
1081 }
1082 return uids;
1083 }
1084
Robin Lee4d03abc2016-05-09 12:32:27 +01001085 /**
1086 * Creates a {@link Set} of non-intersecting {@link UidRange} objects including all UIDs
1087 * associated with one user, and any restricted profiles attached to that user.
1088 *
1089 * <p>If one of {@param allowedApplications} or {@param disallowedApplications} is provided,
1090 * the UID ranges will match the app whitelist or blacklist specified there. Otherwise, all UIDs
1091 * in each user and profile will be included.
1092 *
1093 * @param userHandle The userId to create UID ranges for along with any of its restricted
1094 * profiles.
1095 * @param allowedApplications (optional) whitelist of applications to include.
1096 * @param disallowedApplications (optional) blacklist of applications to exclude.
1097 */
1098 @VisibleForTesting
1099 Set<UidRange> createUserAndRestrictedProfilesRanges(@UserIdInt int userHandle,
1100 @Nullable List<String> allowedApplications,
1101 @Nullable List<String> disallowedApplications) {
1102 final Set<UidRange> ranges = new ArraySet<>();
Robert Greenwalt69887e82013-09-24 11:05:57 -07001103
Robin Lee4d03abc2016-05-09 12:32:27 +01001104 // Assign the top-level user to the set of ranges
1105 addUserToRanges(ranges, userHandle, allowedApplications, disallowedApplications);
1106
1107 // If the user can have restricted profiles, assign all its restricted profiles too
1108 if (canHaveRestrictedProfile(userHandle)) {
1109 final long token = Binder.clearCallingIdentity();
1110 List<UserInfo> users;
1111 try {
Robin Lee17e61832016-05-09 13:46:28 +01001112 users = UserManager.get(mContext).getUsers(true);
Robin Lee4d03abc2016-05-09 12:32:27 +01001113 } finally {
1114 Binder.restoreCallingIdentity(token);
1115 }
1116 for (UserInfo user : users) {
1117 if (user.isRestricted() && (user.restrictedProfileParentId == userHandle)) {
1118 addUserToRanges(ranges, user.id, allowedApplications, disallowedApplications);
1119 }
1120 }
1121 }
1122 return ranges;
1123 }
1124
1125 /**
1126 * Updates a {@link Set} of non-intersecting {@link UidRange} objects to include all UIDs
1127 * associated with one user.
1128 *
1129 * <p>If one of {@param allowedApplications} or {@param disallowedApplications} is provided,
1130 * the UID ranges will match the app whitelist or blacklist specified there. Otherwise, all UIDs
1131 * in the user will be included.
1132 *
1133 * @param ranges {@link Set} of {@link UidRange}s to which to add.
1134 * @param userHandle The userId to add to {@param ranges}.
1135 * @param allowedApplications (optional) whitelist of applications to include.
1136 * @param disallowedApplications (optional) blacklist of applications to exclude.
1137 */
1138 @VisibleForTesting
1139 void addUserToRanges(@NonNull Set<UidRange> ranges, @UserIdInt int userHandle,
1140 @Nullable List<String> allowedApplications,
1141 @Nullable List<String> disallowedApplications) {
1142 if (allowedApplications != null) {
Paul Jensen0784eea2014-08-19 16:00:24 -04001143 // Add ranges covering all UIDs for allowedApplications.
1144 int start = -1, stop = -1;
Robin Lee4d03abc2016-05-09 12:32:27 +01001145 for (int uid : getAppsUids(allowedApplications, userHandle)) {
Paul Jensen0784eea2014-08-19 16:00:24 -04001146 if (start == -1) {
1147 start = uid;
1148 } else if (uid != stop + 1) {
Robin Lee4d03abc2016-05-09 12:32:27 +01001149 ranges.add(new UidRange(start, stop));
Paul Jensen0784eea2014-08-19 16:00:24 -04001150 start = uid;
1151 }
1152 stop = uid;
1153 }
Robin Lee4d03abc2016-05-09 12:32:27 +01001154 if (start != -1) ranges.add(new UidRange(start, stop));
1155 } else if (disallowedApplications != null) {
Paul Jensen0784eea2014-08-19 16:00:24 -04001156 // Add all ranges for user skipping UIDs for disallowedApplications.
1157 final UidRange userRange = UidRange.createForUser(userHandle);
1158 int start = userRange.start;
Robin Lee4d03abc2016-05-09 12:32:27 +01001159 for (int uid : getAppsUids(disallowedApplications, userHandle)) {
Paul Jensen0784eea2014-08-19 16:00:24 -04001160 if (uid == start) {
1161 start++;
1162 } else {
Robin Lee4d03abc2016-05-09 12:32:27 +01001163 ranges.add(new UidRange(start, uid - 1));
Paul Jensen0784eea2014-08-19 16:00:24 -04001164 start = uid + 1;
1165 }
1166 }
Robin Lee4d03abc2016-05-09 12:32:27 +01001167 if (start <= userRange.stop) ranges.add(new UidRange(start, userRange.stop));
Paul Jensen0784eea2014-08-19 16:00:24 -04001168 } else {
1169 // Add all UIDs for the user.
Robin Lee4d03abc2016-05-09 12:32:27 +01001170 ranges.add(UidRange.createForUser(userHandle));
Paul Jensen0784eea2014-08-19 16:00:24 -04001171 }
Chad Brubakerc2865192013-07-10 14:46:23 -07001172 }
1173
Paul Jensen0784eea2014-08-19 16:00:24 -04001174 // Returns the subset of the full list of active UID ranges the VPN applies to (mVpnUsers) that
1175 // apply to userHandle.
Chalard Jeanecacd5e2017-12-27 14:23:31 +09001176 static private List<UidRange> uidRangesForUser(int userHandle, Set<UidRange> existingRanges) {
1177 // UidRange#createForUser returns the entire range of UIDs available to a macro-user.
1178 // This is something like 0-99999 ; {@see UserHandle#PER_USER_RANGE}
Paul Jensen0784eea2014-08-19 16:00:24 -04001179 final UidRange userRange = UidRange.createForUser(userHandle);
1180 final List<UidRange> ranges = new ArrayList<UidRange>();
Chalard Jeanecacd5e2017-12-27 14:23:31 +09001181 for (UidRange range : existingRanges) {
Robin Lee4d03abc2016-05-09 12:32:27 +01001182 if (userRange.containsRange(range)) {
Paul Jensen0784eea2014-08-19 16:00:24 -04001183 ranges.add(range);
1184 }
1185 }
1186 return ranges;
1187 }
1188
Fyodor Kupolov1c363152015-09-02 13:27:21 -07001189 public void onUserAdded(int userHandle) {
1190 // If the user is restricted tie them to the parent user's VPN
1191 UserInfo user = UserManager.get(mContext).getUserInfo(userHandle);
Robin Lee17e61832016-05-09 13:46:28 +01001192 if (user.isRestricted() && user.restrictedProfileParentId == mUserHandle) {
Fyodor Kupolov1c363152015-09-02 13:27:21 -07001193 synchronized(Vpn.this) {
Chalard Jeanecacd5e2017-12-27 14:23:31 +09001194 final Set<UidRange> existingRanges = mNetworkCapabilities.getUids();
1195 if (existingRanges != null) {
Robin Lee17e61832016-05-09 13:46:28 +01001196 try {
Chalard Jeanecacd5e2017-12-27 14:23:31 +09001197 addUserToRanges(existingRanges, userHandle, mConfig.allowedApplications,
Robin Lee17e61832016-05-09 13:46:28 +01001198 mConfig.disallowedApplications);
Chalard Jeanecacd5e2017-12-27 14:23:31 +09001199 mNetworkCapabilities.setUids(existingRanges);
Chalard Jeanf213ca12018-01-16 18:43:05 +09001200 updateCapabilities();
Robin Lee17e61832016-05-09 13:46:28 +01001201 } catch (Exception e) {
1202 Log.wtf(TAG, "Failed to add restricted user to owner", e);
Paul Jensen6bc2c2c2014-05-07 15:27:40 -04001203 }
Robin Lee17e61832016-05-09 13:46:28 +01001204 }
Robin Leec3736bc2017-03-10 16:19:54 +00001205 setVpnForcedLocked(mLockdown);
Chad Brubakerc2865192013-07-10 14:46:23 -07001206 }
1207 }
1208 }
1209
Fyodor Kupolov1c363152015-09-02 13:27:21 -07001210 public void onUserRemoved(int userHandle) {
Chad Brubakerc2865192013-07-10 14:46:23 -07001211 // clean up if restricted
Fyodor Kupolov1c363152015-09-02 13:27:21 -07001212 UserInfo user = UserManager.get(mContext).getUserInfo(userHandle);
Robin Lee17e61832016-05-09 13:46:28 +01001213 if (user.isRestricted() && user.restrictedProfileParentId == mUserHandle) {
Fyodor Kupolov1c363152015-09-02 13:27:21 -07001214 synchronized(Vpn.this) {
Chalard Jeanecacd5e2017-12-27 14:23:31 +09001215 final Set<UidRange> existingRanges = mNetworkCapabilities.getUids();
1216 if (existingRanges != null) {
Robin Lee17e61832016-05-09 13:46:28 +01001217 try {
Chalard Jeanecacd5e2017-12-27 14:23:31 +09001218 final List<UidRange> removedRanges =
1219 uidRangesForUser(userHandle, existingRanges);
Chalard Jeanecacd5e2017-12-27 14:23:31 +09001220 existingRanges.removeAll(removedRanges);
1221 mNetworkCapabilities.setUids(existingRanges);
Chalard Jeanf213ca12018-01-16 18:43:05 +09001222 updateCapabilities();
Robin Lee17e61832016-05-09 13:46:28 +01001223 } catch (Exception e) {
1224 Log.wtf(TAG, "Failed to remove restricted user to owner", e);
1225 }
1226 }
Robin Leec3736bc2017-03-10 16:19:54 +00001227 setVpnForcedLocked(mLockdown);
Chad Brubakerc2865192013-07-10 14:46:23 -07001228 }
1229 }
1230 }
1231
Chad Brubakerbf6ff2c2013-07-16 18:59:12 -07001232 /**
Robin Lee17e61832016-05-09 13:46:28 +01001233 * Called when the user associated with this VPN has just been stopped.
1234 */
1235 public synchronized void onUserStopped() {
1236 // Switch off networking lockdown (if it was enabled)
Robin Leec3736bc2017-03-10 16:19:54 +00001237 setLockdown(false);
Robin Lee17e61832016-05-09 13:46:28 +01001238 mAlwaysOn = false;
1239
1240 // Quit any active connections
1241 agentDisconnect();
1242 }
1243
1244 /**
1245 * Restrict network access from all UIDs affected by this {@link Vpn}, apart from the VPN
1246 * service app itself, to only sockets that have had {@code protect()} called on them. All
1247 * non-VPN traffic is blocked via a {@code PROHIBIT} response from the kernel.
1248 *
1249 * The exception for the VPN UID isn't technically necessary -- setup should use protected
1250 * sockets -- but in practice it saves apps that don't protect their sockets from breaking.
1251 *
1252 * Calling multiple times with {@param enforce} = {@code true} will recreate the set of UIDs to
1253 * block every time, and if anything has changed update using {@link #setAllowOnlyVpnForUids}.
1254 *
1255 * @param enforce {@code true} to require that all traffic under the jurisdiction of this
1256 * {@link Vpn} goes through a VPN connection or is blocked until one is
1257 * available, {@code false} to lift the requirement.
1258 *
1259 * @see #mBlockedUsers
1260 */
1261 @GuardedBy("this")
1262 private void setVpnForcedLocked(boolean enforce) {
Robin Leec3736bc2017-03-10 16:19:54 +00001263 final List<String> exemptedPackages =
1264 isNullOrLegacyVpn(mPackage) ? null : Collections.singletonList(mPackage);
Robin Lee17e61832016-05-09 13:46:28 +01001265 final Set<UidRange> removedRanges = new ArraySet<>(mBlockedUsers);
Robin Leec3736bc2017-03-10 16:19:54 +00001266
1267 Set<UidRange> addedRanges = Collections.emptySet();
Robin Lee17e61832016-05-09 13:46:28 +01001268 if (enforce) {
Robin Leec3736bc2017-03-10 16:19:54 +00001269 addedRanges = createUserAndRestrictedProfilesRanges(mUserHandle,
Robin Lee17e61832016-05-09 13:46:28 +01001270 /* allowedApplications */ null,
Robin Leec3736bc2017-03-10 16:19:54 +00001271 /* disallowedApplications */ exemptedPackages);
Robin Lee17e61832016-05-09 13:46:28 +01001272
Bernie Innocenti00000fe2018-05-28 22:04:37 +09001273 // The UID range of the first user (0-99999) would block the IPSec traffic, which comes
1274 // directly from the kernel and is marked as uid=0. So we adjust the range to allow
1275 // it through (b/69873852).
1276 for (UidRange range : addedRanges) {
1277 if (range.start == 0) {
1278 addedRanges.remove(range);
1279 if (range.stop != 0) {
1280 addedRanges.add(new UidRange(1, range.stop));
1281 }
1282 }
1283 }
1284
Robin Lee17e61832016-05-09 13:46:28 +01001285 removedRanges.removeAll(addedRanges);
1286 addedRanges.removeAll(mBlockedUsers);
Robin Lee17e61832016-05-09 13:46:28 +01001287 }
Robin Leec3736bc2017-03-10 16:19:54 +00001288
1289 setAllowOnlyVpnForUids(false, removedRanges);
1290 setAllowOnlyVpnForUids(true, addedRanges);
Robin Lee17e61832016-05-09 13:46:28 +01001291 }
1292
1293 /**
1294 * Either add or remove a list of {@link UidRange}s to the list of UIDs that are only allowed
1295 * to make connections through sockets that have had {@code protect()} called on them.
1296 *
1297 * @param enforce {@code true} to add to the blacklist, {@code false} to remove.
1298 * @param ranges {@link Collection} of {@link UidRange}s to add (if {@param enforce} is
1299 * {@code true}) or to remove.
1300 * @return {@code true} if all of the UIDs were added/removed. {@code false} otherwise,
1301 * including added ranges that already existed or removed ones that didn't.
1302 */
1303 @GuardedBy("this")
1304 private boolean setAllowOnlyVpnForUids(boolean enforce, Collection<UidRange> ranges) {
1305 if (ranges.size() == 0) {
1306 return true;
1307 }
1308 final UidRange[] rangesArray = ranges.toArray(new UidRange[ranges.size()]);
1309 try {
1310 mNetd.setAllowOnlyVpnForUids(enforce, rangesArray);
1311 } catch (RemoteException | RuntimeException e) {
1312 Log.e(TAG, "Updating blocked=" + enforce
1313 + " for UIDs " + Arrays.toString(ranges.toArray()) + " failed", e);
1314 return false;
1315 }
1316 if (enforce) {
1317 mBlockedUsers.addAll(ranges);
1318 } else {
1319 mBlockedUsers.removeAll(ranges);
1320 }
1321 return true;
1322 }
1323
1324 /**
Chad Brubakerbf6ff2c2013-07-16 18:59:12 -07001325 * Return the configuration of the currently running VPN.
1326 */
1327 public VpnConfig getVpnConfig() {
1328 enforceControlPermission();
1329 return mConfig;
1330 }
1331
Jeff Sharkey899223b2012-08-04 15:24:58 -07001332 @Deprecated
1333 public synchronized void interfaceStatusChanged(String iface, boolean up) {
1334 try {
1335 mObserver.interfaceStatusChanged(iface, up);
1336 } catch (RemoteException e) {
1337 // ignored; target is local
Chia-chi Yehaa1727f2011-07-14 18:55:33 -07001338 }
1339 }
1340
Jeff Sharkey899223b2012-08-04 15:24:58 -07001341 private INetworkManagementEventObserver mObserver = new BaseNetworkObserver() {
1342 @Override
1343 public void interfaceStatusChanged(String interfaze, boolean up) {
1344 synchronized (Vpn.this) {
1345 if (!up && mLegacyVpnRunner != null) {
1346 mLegacyVpnRunner.check(interfaze);
1347 }
Chia-chi Yeh199ed6e2011-08-03 17:38:49 -07001348 }
Chia-chi Yehaa1727f2011-07-14 18:55:33 -07001349 }
Chia-chi Yehaa1727f2011-07-14 18:55:33 -07001350
Jeff Sharkey899223b2012-08-04 15:24:58 -07001351 @Override
1352 public void interfaceRemoved(String interfaze) {
1353 synchronized (Vpn.this) {
1354 if (interfaze.equals(mInterface) && jniCheck(interfaze) == 0) {
Jeff Davidson90b1b9f2014-08-22 13:05:43 -07001355 mStatusIntent = null;
Chalard Jeanecacd5e2017-12-27 14:23:31 +09001356 mNetworkCapabilities.setUids(null);
Paul Jensenc4c72312014-12-08 14:04:51 -05001357 mConfig = null;
Jeff Sharkey899223b2012-08-04 15:24:58 -07001358 mInterface = null;
1359 if (mConnection != null) {
1360 mContext.unbindService(mConnection);
1361 mConnection = null;
Paul Jensen6bc2c2c2014-05-07 15:27:40 -04001362 agentDisconnect();
Jeff Sharkey899223b2012-08-04 15:24:58 -07001363 } else if (mLegacyVpnRunner != null) {
1364 mLegacyVpnRunner.exit();
1365 mLegacyVpnRunner = null;
1366 }
1367 }
1368 }
1369 }
1370 };
Haoyu Baidb3c8672012-06-20 14:29:57 -07001371
Chia-chi Yehdadc8572012-06-08 13:05:58 -07001372 private void enforceControlPermission() {
Jeff Davidsonbc19c182014-11-11 13:20:01 -08001373 mContext.enforceCallingPermission(Manifest.permission.CONTROL_VPN, "Unauthorized Caller");
Chia-chi Yehdadc8572012-06-08 13:05:58 -07001374 }
1375
Robin Lee244ce8e2016-01-05 18:03:46 +00001376 private void enforceControlPermissionOrInternalCaller() {
Chalard Jeandd59ece2017-12-20 13:23:32 +09001377 // Require the caller to be either an application with CONTROL_VPN permission or a process
Robin Lee244ce8e2016-01-05 18:03:46 +00001378 // in the system server.
1379 mContext.enforceCallingOrSelfPermission(Manifest.permission.CONTROL_VPN,
1380 "Unauthorized Caller");
1381 }
1382
Charles Hea0a87e82017-05-15 17:07:18 +01001383 private void enforceSettingsPermission() {
1384 mContext.enforceCallingOrSelfPermission(Manifest.permission.NETWORK_SETTINGS,
1385 "Unauthorized Caller");
1386 }
1387
Chia-chi Yeh199ed6e2011-08-03 17:38:49 -07001388 private class Connection implements ServiceConnection {
1389 private IBinder mService;
1390
1391 @Override
1392 public void onServiceConnected(ComponentName name, IBinder service) {
1393 mService = service;
1394 }
1395
1396 @Override
1397 public void onServiceDisconnected(ComponentName name) {
1398 mService = null;
1399 }
1400 }
1401
Jeff Davidson90b1b9f2014-08-22 13:05:43 -07001402 private void prepareStatusIntent() {
1403 final long token = Binder.clearCallingIdentity();
1404 try {
1405 mStatusIntent = VpnConfig.getIntentForStatusPanel(mContext);
1406 } finally {
1407 Binder.restoreCallingIdentity(token);
1408 }
1409 }
1410
Sreeram Ramachandranf4e0c0c2014-07-27 14:18:26 -07001411 public synchronized boolean addAddress(String address, int prefixLength) {
Sreeram Ramachandranc2c0bea2014-11-11 16:09:21 -08001412 if (!isCallerEstablishedOwnerLocked()) {
Sreeram Ramachandranf4e0c0c2014-07-27 14:18:26 -07001413 return false;
1414 }
1415 boolean success = jniAddAddress(mInterface, address, prefixLength);
Sreeram Ramachandranc2c0bea2014-11-11 16:09:21 -08001416 mNetworkAgent.sendLinkProperties(makeLinkProperties());
Sreeram Ramachandranf4e0c0c2014-07-27 14:18:26 -07001417 return success;
1418 }
1419
1420 public synchronized boolean removeAddress(String address, int prefixLength) {
Sreeram Ramachandranc2c0bea2014-11-11 16:09:21 -08001421 if (!isCallerEstablishedOwnerLocked()) {
Sreeram Ramachandranf4e0c0c2014-07-27 14:18:26 -07001422 return false;
1423 }
1424 boolean success = jniDelAddress(mInterface, address, prefixLength);
Sreeram Ramachandranc2c0bea2014-11-11 16:09:21 -08001425 mNetworkAgent.sendLinkProperties(makeLinkProperties());
Sreeram Ramachandranf4e0c0c2014-07-27 14:18:26 -07001426 return success;
1427 }
1428
Sreeram Ramachandranc2c0bea2014-11-11 16:09:21 -08001429 public synchronized boolean setUnderlyingNetworks(Network[] networks) {
1430 if (!isCallerEstablishedOwnerLocked()) {
1431 return false;
1432 }
1433 if (networks == null) {
1434 mConfig.underlyingNetworks = null;
1435 } else {
1436 mConfig.underlyingNetworks = new Network[networks.length];
1437 for (int i = 0; i < networks.length; ++i) {
1438 if (networks[i] == null) {
1439 mConfig.underlyingNetworks[i] = null;
1440 } else {
1441 mConfig.underlyingNetworks[i] = new Network(networks[i].netId);
1442 }
1443 }
1444 }
Jeff Sharkey72f9c422017-10-27 17:22:59 -06001445 updateCapabilities();
Sreeram Ramachandranc2c0bea2014-11-11 16:09:21 -08001446 return true;
1447 }
1448
1449 public synchronized Network[] getUnderlyingNetworks() {
1450 if (!isRunningLocked()) {
1451 return null;
1452 }
1453 return mConfig.underlyingNetworks;
1454 }
1455
Wenchao Tongf5ea3402015-03-04 13:26:38 -08001456 /**
Chalard Jeandd59ece2017-12-20 13:23:32 +09001457 * This method should only be called by ConnectivityService because it doesn't
Wenchao Tongf5ea3402015-03-04 13:26:38 -08001458 * have enough data to fill VpnInfo.primaryUnderlyingIface field.
1459 */
1460 public synchronized VpnInfo getVpnInfo() {
1461 if (!isRunningLocked()) {
1462 return null;
1463 }
1464
1465 VpnInfo info = new VpnInfo();
1466 info.ownerUid = mOwnerUID;
1467 info.vpnIface = mInterface;
1468 return info;
1469 }
1470
Sreeram Ramachandranc2c0bea2014-11-11 16:09:21 -08001471 public synchronized boolean appliesToUid(int uid) {
1472 if (!isRunningLocked()) {
1473 return false;
1474 }
Chalard Jeanecacd5e2017-12-27 14:23:31 +09001475 return mNetworkCapabilities.appliesToUid(uid);
Sreeram Ramachandranc2c0bea2014-11-11 16:09:21 -08001476 }
1477
Robin Lee17e61832016-05-09 13:46:28 +01001478 /**
junyulai8ed89152018-10-25 10:56:17 +08001479 * @param uid The target uid.
Robin Lee17e61832016-05-09 13:46:28 +01001480 *
junyulai8ed89152018-10-25 10:56:17 +08001481 * @return {@code true} if {@code uid} is included in one of the mBlockedUsers ranges and the
1482 * VPN is not connected, or if the VPN is connected but does not apply to the {@code uid}.
1483 *
1484 * @apiNote This method don't check VPN lockdown status.
Robin Lee17e61832016-05-09 13:46:28 +01001485 * @see #mBlockedUsers
1486 */
1487 public synchronized boolean isBlockingUid(int uid) {
Robin Leeebbcb542016-05-24 16:35:10 +01001488 if (mNetworkInfo.isConnected()) {
1489 return !appliesToUid(uid);
1490 } else {
1491 for (UidRange uidRange : mBlockedUsers) {
1492 if (uidRange.contains(uid)) {
1493 return true;
1494 }
1495 }
1496 return false;
1497 }
Robin Lee17e61832016-05-09 13:46:28 +01001498 }
1499
Tony Mak1a405fe2016-06-30 11:19:20 +01001500 private void updateAlwaysOnNotification(DetailedState networkState) {
1501 final boolean visible = (mAlwaysOn && networkState != DetailedState.CONNECTED);
Tony Mak1a405fe2016-06-30 11:19:20 +01001502
Tony Mak1a405fe2016-06-30 11:19:20 +01001503 final UserHandle user = UserHandle.of(mUserHandle);
1504 final long token = Binder.clearCallingIdentity();
1505 try {
1506 final NotificationManager notificationManager = NotificationManager.from(mContext);
1507 if (!visible) {
Charles He15297a62017-04-08 22:03:42 +01001508 notificationManager.cancelAsUser(TAG, SystemMessage.NOTE_VPN_DISCONNECTED, user);
Tony Mak1a405fe2016-06-30 11:19:20 +01001509 return;
1510 }
Charles Heab6f2f62017-07-12 15:30:00 +01001511 final Intent intent = new Intent();
1512 intent.setComponent(ComponentName.unflattenFromString(mContext.getString(
1513 R.string.config_customVpnAlwaysOnDisconnectedDialogComponent)));
1514 intent.putExtra("lockdown", mLockdown);
1515 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Robin Leeb8c2a2b2017-03-10 16:17:06 +00001516 final PendingIntent configIntent = mSystemServices.pendingIntentGetActivityAsUser(
1517 intent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT, user);
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05001518 final Notification.Builder builder =
1519 new Notification.Builder(mContext, SystemNotificationChannels.VPN)
1520 .setSmallIcon(R.drawable.vpn_connected)
1521 .setContentTitle(mContext.getString(R.string.vpn_lockdown_disconnected))
1522 .setContentText(mContext.getString(R.string.vpn_lockdown_config))
1523 .setContentIntent(configIntent)
1524 .setCategory(Notification.CATEGORY_SYSTEM)
1525 .setVisibility(Notification.VISIBILITY_PUBLIC)
1526 .setOngoing(true)
1527 .setColor(mContext.getColor(R.color.system_notification_accent_color));
Chris Wren282cfef2017-03-27 15:01:44 -04001528 notificationManager.notifyAsUser(TAG, SystemMessage.NOTE_VPN_DISCONNECTED,
1529 builder.build(), user);
Tony Mak1a405fe2016-06-30 11:19:20 +01001530 } finally {
1531 Binder.restoreCallingIdentity(token);
1532 }
1533 }
1534
Robin Leeb8c2a2b2017-03-10 16:17:06 +00001535 /**
1536 * Facade for system service calls that change, or depend on, state outside of
1537 * {@link ConnectivityService} and have hard-to-mock interfaces.
1538 *
1539 * @see com.android.server.connectivity.VpnTest
1540 */
1541 @VisibleForTesting
1542 public static class SystemServices {
1543 private final Context mContext;
1544
1545 public SystemServices(@NonNull Context context) {
1546 mContext = context;
1547 }
1548
1549 /**
1550 * @see PendingIntent#getActivityAsUser()
1551 */
1552 public PendingIntent pendingIntentGetActivityAsUser(
1553 Intent intent, int flags, UserHandle user) {
1554 return PendingIntent.getActivityAsUser(mContext, 0 /*request*/, intent, flags,
1555 null /*options*/, user);
1556 }
1557
1558 /**
1559 * @see Settings.Secure#putStringForUser
1560 */
1561 public void settingsSecurePutStringForUser(String key, String value, int userId) {
1562 Settings.Secure.putStringForUser(mContext.getContentResolver(), key, value, userId);
1563 }
1564
1565 /**
1566 * @see Settings.Secure#putIntForUser
1567 */
1568 public void settingsSecurePutIntForUser(String key, int value, int userId) {
1569 Settings.Secure.putIntForUser(mContext.getContentResolver(), key, value, userId);
1570 }
1571
1572 /**
1573 * @see Settings.Secure#getStringForUser
1574 */
1575 public String settingsSecureGetStringForUser(String key, int userId) {
1576 return Settings.Secure.getStringForUser(mContext.getContentResolver(), key, userId);
1577 }
1578
1579 /**
1580 * @see Settings.Secure#getIntForUser
1581 */
1582 public int settingsSecureGetIntForUser(String key, int def, int userId) {
1583 return Settings.Secure.getIntForUser(mContext.getContentResolver(), key, def, userId);
1584 }
1585 }
1586
Chia-chi Yeh97a61562011-07-14 15:05:05 -07001587 private native int jniCreate(int mtu);
Chia-chi Yehc2b8aa02011-07-03 18:00:47 -07001588 private native String jniGetName(int tun);
Chia-chi Yeh97a61562011-07-14 15:05:05 -07001589 private native int jniSetAddresses(String interfaze, String addresses);
Chia-chi Yehc2b8aa02011-07-03 18:00:47 -07001590 private native void jniReset(String interfaze);
1591 private native int jniCheck(String interfaze);
Sreeram Ramachandranf4e0c0c2014-07-27 14:18:26 -07001592 private native boolean jniAddAddress(String interfaze, String address, int prefixLen);
1593 private native boolean jniDelAddress(String interfaze, String address, int prefixLen);
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001594
Lorenzo Colitti41fb98c2013-06-28 17:26:21 +09001595 private static RouteInfo findIPv4DefaultRoute(LinkProperties prop) {
1596 for (RouteInfo route : prop.getAllRoutes()) {
Jeff Sharkey82f85212012-08-24 11:17:25 -07001597 // Currently legacy VPN only works on IPv4.
1598 if (route.isDefaultRoute() && route.getGateway() instanceof Inet4Address) {
Lorenzo Colitti41fb98c2013-06-28 17:26:21 +09001599 return route;
Jeff Sharkey82f85212012-08-24 11:17:25 -07001600 }
1601 }
Jeff Sharkey899223b2012-08-04 15:24:58 -07001602
Lorenzo Colitti41fb98c2013-06-28 17:26:21 +09001603 throw new IllegalStateException("Unable to find IPv4 default gateway");
Jeff Sharkey82f85212012-08-24 11:17:25 -07001604 }
1605
1606 /**
1607 * Start legacy VPN, controlling native daemons as needed. Creates a
1608 * secondary thread to perform connection work, returning quickly.
Jeff Davidsonb21298a2015-02-10 10:02:11 -08001609 *
1610 * Should only be called to respond to Binder requests as this enforces caller permission. Use
1611 * {@link #startLegacyVpnPrivileged(VpnProfile, KeyStore, LinkProperties)} to skip the
1612 * permission check only when the caller is trusted (or the call is initiated by the system).
Jeff Sharkey82f85212012-08-24 11:17:25 -07001613 */
1614 public void startLegacyVpn(VpnProfile profile, KeyStore keyStore, LinkProperties egress) {
Robert Greenwalt5a6bdc42013-02-15 10:56:35 -08001615 enforceControlPermission();
Jeff Davidsonb21298a2015-02-10 10:02:11 -08001616 long token = Binder.clearCallingIdentity();
1617 try {
1618 startLegacyVpnPrivileged(profile, keyStore, egress);
1619 } finally {
1620 Binder.restoreCallingIdentity(token);
1621 }
1622 }
1623
1624 /**
1625 * Like {@link #startLegacyVpn(VpnProfile, KeyStore, LinkProperties)}, but does not check
1626 * permissions under the assumption that the caller is the system.
1627 *
1628 * Callers are responsible for checking permissions if needed.
1629 */
1630 public void startLegacyVpnPrivileged(VpnProfile profile, KeyStore keyStore,
1631 LinkProperties egress) {
Julia Reynoldsf5116d02014-07-01 11:10:41 -04001632 UserManager mgr = UserManager.get(mContext);
Paul Jensen0784eea2014-08-19 16:00:24 -04001633 UserInfo user = mgr.getUserInfo(mUserHandle);
Nicolas Prevot95778ff2015-01-06 15:43:05 +00001634 if (user.isRestricted() || mgr.hasUserRestriction(UserManager.DISALLOW_CONFIG_VPN,
1635 new UserHandle(mUserHandle))) {
Julia Reynoldsf5116d02014-07-01 11:10:41 -04001636 throw new SecurityException("Restricted users cannot establish VPNs");
1637 }
Jeff Sharkey82f85212012-08-24 11:17:25 -07001638
Lorenzo Colitti41fb98c2013-06-28 17:26:21 +09001639 final RouteInfo ipv4DefaultRoute = findIPv4DefaultRoute(egress);
1640 final String gateway = ipv4DefaultRoute.getGateway().getHostAddress();
1641 final String iface = ipv4DefaultRoute.getInterface();
Jeff Sharkey82f85212012-08-24 11:17:25 -07001642
1643 // Load certificates.
1644 String privateKey = "";
1645 String userCert = "";
1646 String caCert = "";
1647 String serverCert = "";
1648 if (!profile.ipsecUserCert.isEmpty()) {
1649 privateKey = Credentials.USER_PRIVATE_KEY + profile.ipsecUserCert;
1650 byte[] value = keyStore.get(Credentials.USER_CERTIFICATE + profile.ipsecUserCert);
Elliott Hughesd396a442013-06-28 16:24:48 -07001651 userCert = (value == null) ? null : new String(value, StandardCharsets.UTF_8);
Jeff Sharkey82f85212012-08-24 11:17:25 -07001652 }
1653 if (!profile.ipsecCaCert.isEmpty()) {
1654 byte[] value = keyStore.get(Credentials.CA_CERTIFICATE + profile.ipsecCaCert);
Elliott Hughesd396a442013-06-28 16:24:48 -07001655 caCert = (value == null) ? null : new String(value, StandardCharsets.UTF_8);
Jeff Sharkey82f85212012-08-24 11:17:25 -07001656 }
1657 if (!profile.ipsecServerCert.isEmpty()) {
1658 byte[] value = keyStore.get(Credentials.USER_CERTIFICATE + profile.ipsecServerCert);
Elliott Hughesd396a442013-06-28 16:24:48 -07001659 serverCert = (value == null) ? null : new String(value, StandardCharsets.UTF_8);
Jeff Sharkey82f85212012-08-24 11:17:25 -07001660 }
1661 if (privateKey == null || userCert == null || caCert == null || serverCert == null) {
1662 throw new IllegalStateException("Cannot load credentials");
1663 }
1664
1665 // Prepare arguments for racoon.
1666 String[] racoon = null;
1667 switch (profile.type) {
1668 case VpnProfile.TYPE_L2TP_IPSEC_PSK:
1669 racoon = new String[] {
1670 iface, profile.server, "udppsk", profile.ipsecIdentifier,
1671 profile.ipsecSecret, "1701",
1672 };
1673 break;
1674 case VpnProfile.TYPE_L2TP_IPSEC_RSA:
1675 racoon = new String[] {
1676 iface, profile.server, "udprsa", privateKey, userCert,
1677 caCert, serverCert, "1701",
1678 };
1679 break;
1680 case VpnProfile.TYPE_IPSEC_XAUTH_PSK:
1681 racoon = new String[] {
1682 iface, profile.server, "xauthpsk", profile.ipsecIdentifier,
1683 profile.ipsecSecret, profile.username, profile.password, "", gateway,
1684 };
1685 break;
1686 case VpnProfile.TYPE_IPSEC_XAUTH_RSA:
1687 racoon = new String[] {
1688 iface, profile.server, "xauthrsa", privateKey, userCert,
1689 caCert, serverCert, profile.username, profile.password, "", gateway,
1690 };
1691 break;
1692 case VpnProfile.TYPE_IPSEC_HYBRID_RSA:
1693 racoon = new String[] {
1694 iface, profile.server, "hybridrsa",
1695 caCert, serverCert, profile.username, profile.password, "", gateway,
1696 };
1697 break;
1698 }
1699
1700 // Prepare arguments for mtpd.
1701 String[] mtpd = null;
1702 switch (profile.type) {
1703 case VpnProfile.TYPE_PPTP:
1704 mtpd = new String[] {
1705 iface, "pptp", profile.server, "1723",
1706 "name", profile.username, "password", profile.password,
1707 "linkname", "vpn", "refuse-eap", "nodefaultroute",
1708 "usepeerdns", "idle", "1800", "mtu", "1400", "mru", "1400",
1709 (profile.mppe ? "+mppe" : "nomppe"),
1710 };
1711 break;
1712 case VpnProfile.TYPE_L2TP_IPSEC_PSK:
1713 case VpnProfile.TYPE_L2TP_IPSEC_RSA:
1714 mtpd = new String[] {
1715 iface, "l2tp", profile.server, "1701", profile.l2tpSecret,
1716 "name", profile.username, "password", profile.password,
1717 "linkname", "vpn", "refuse-eap", "nodefaultroute",
1718 "usepeerdns", "idle", "1800", "mtu", "1400", "mru", "1400",
1719 };
1720 break;
1721 }
1722
1723 VpnConfig config = new VpnConfig();
Jeff Sharkey899223b2012-08-04 15:24:58 -07001724 config.legacy = true;
Jeff Sharkey82f85212012-08-24 11:17:25 -07001725 config.user = profile.key;
1726 config.interfaze = iface;
1727 config.session = profile.name;
Chad Brubaker4ca19e82013-06-14 11:16:51 -07001728
1729 config.addLegacyRoutes(profile.routes);
Jeff Sharkey82f85212012-08-24 11:17:25 -07001730 if (!profile.dnsServers.isEmpty()) {
1731 config.dnsServers = Arrays.asList(profile.dnsServers.split(" +"));
1732 }
1733 if (!profile.searchDomains.isEmpty()) {
1734 config.searchDomains = Arrays.asList(profile.searchDomains.split(" +"));
1735 }
Jeff Sharkey82f85212012-08-24 11:17:25 -07001736 startLegacyVpn(config, racoon, mtpd);
1737 }
1738
1739 private synchronized void startLegacyVpn(VpnConfig config, String[] racoon, String[] mtpd) {
Jeff Davidsonb21298a2015-02-10 10:02:11 -08001740 stopLegacyVpnPrivileged();
Jeff Sharkey899223b2012-08-04 15:24:58 -07001741
Jeff Davidsonb21298a2015-02-10 10:02:11 -08001742 // Prepare for the new request.
1743 prepareInternal(VpnConfig.LEGACY_VPN);
Jeff Sharkey899223b2012-08-04 15:24:58 -07001744 updateState(DetailedState.CONNECTING, "startLegacyVpn");
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001745
Chia-chi Yeh2e467642011-07-04 03:23:12 -07001746 // Start a new LegacyVpnRunner and we are done!
Chia-chi Yeh100155a2011-07-03 16:52:38 -07001747 mLegacyVpnRunner = new LegacyVpnRunner(config, racoon, mtpd);
1748 mLegacyVpnRunner.start();
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001749 }
1750
Jeff Davidsonb21298a2015-02-10 10:02:11 -08001751 /** Stop legacy VPN. Permissions must be checked by callers. */
1752 public synchronized void stopLegacyVpnPrivileged() {
Jeff Sharkey899223b2012-08-04 15:24:58 -07001753 if (mLegacyVpnRunner != null) {
1754 mLegacyVpnRunner.exit();
1755 mLegacyVpnRunner = null;
1756
1757 synchronized (LegacyVpnRunner.TAG) {
1758 // wait for old thread to completely finish before spinning up
1759 // new instance, otherwise state updates can be out of order.
1760 }
1761 }
1762 }
1763
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001764 /**
Chia-chi Yeh2e467642011-07-04 03:23:12 -07001765 * Return the information of the current ongoing legacy VPN.
1766 */
1767 public synchronized LegacyVpnInfo getLegacyVpnInfo() {
Chia-chi Yehdadc8572012-06-08 13:05:58 -07001768 // Check if the caller is authorized.
1769 enforceControlPermission();
sj.cha08bbca02015-03-23 11:35:24 +09001770 return getLegacyVpnInfoPrivileged();
1771 }
1772
1773 /**
1774 * Return the information of the current ongoing legacy VPN.
1775 * Callers are responsible for checking permissions if needed.
1776 */
1777 public synchronized LegacyVpnInfo getLegacyVpnInfoPrivileged() {
Jeff Sharkey899223b2012-08-04 15:24:58 -07001778 if (mLegacyVpnRunner == null) return null;
1779
1780 final LegacyVpnInfo info = new LegacyVpnInfo();
Chad Brubakerc2865192013-07-10 14:46:23 -07001781 info.key = mConfig.user;
Jeff Sharkey899223b2012-08-04 15:24:58 -07001782 info.state = LegacyVpnInfo.stateFromNetworkInfo(mNetworkInfo);
Jeff Davidson90b1b9f2014-08-22 13:05:43 -07001783 if (mNetworkInfo.isConnected()) {
1784 info.intent = mStatusIntent;
1785 }
Jeff Sharkey899223b2012-08-04 15:24:58 -07001786 return info;
Chia-chi Yeh2e467642011-07-04 03:23:12 -07001787 }
1788
Jeff Sharkey69ddab42012-08-25 00:05:46 -07001789 public VpnConfig getLegacyVpnConfig() {
1790 if (mLegacyVpnRunner != null) {
Chad Brubakerc2865192013-07-10 14:46:23 -07001791 return mConfig;
Jeff Sharkey69ddab42012-08-25 00:05:46 -07001792 } else {
1793 return null;
1794 }
1795 }
1796
Chia-chi Yeh2e467642011-07-04 03:23:12 -07001797 /**
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001798 * Bringing up a VPN connection takes time, and that is all this thread
1799 * does. Here we have plenty of time. The only thing we need to take
1800 * care of is responding to interruptions as soon as possible. Otherwise
Chalard Jeandd59ece2017-12-20 13:23:32 +09001801 * requests will pile up. This could be done in a Handler as a state
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001802 * machine, but it is much easier to read in the current form.
1803 */
1804 private class LegacyVpnRunner extends Thread {
1805 private static final String TAG = "LegacyVpnRunner";
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001806
Chia-chi Yeh1f7746b2011-07-01 00:29:06 -07001807 private final String[] mDaemons;
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001808 private final String[][] mArguments;
Chia-chi Yeh5317f032011-08-22 13:09:49 -07001809 private final LocalSocket[] mSockets;
Robert Greenwalt53c04bd2012-10-12 17:02:45 -07001810 private final String mOuterInterface;
Robert Greenwalt1b0ca9d2013-04-22 11:13:02 -07001811 private final AtomicInteger mOuterConnection =
1812 new AtomicInteger(ConnectivityManager.TYPE_NONE);
Chia-chi Yeh2e467642011-07-04 03:23:12 -07001813
Chalard Jeandd59ece2017-12-20 13:23:32 +09001814 private long mBringupStartTime = -1;
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001815
Robert Greenwalt1b0ca9d2013-04-22 11:13:02 -07001816 /**
1817 * Watch for the outer connection (passing in the constructor) going away.
1818 */
1819 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
1820 @Override
1821 public void onReceive(Context context, Intent intent) {
Jeff Sharkey57666932013-04-30 17:01:57 -07001822 if (!mEnableTeardown) return;
1823
Robert Greenwalt1b0ca9d2013-04-22 11:13:02 -07001824 if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
1825 if (intent.getIntExtra(ConnectivityManager.EXTRA_NETWORK_TYPE,
1826 ConnectivityManager.TYPE_NONE) == mOuterConnection.get()) {
1827 NetworkInfo info = (NetworkInfo)intent.getExtra(
1828 ConnectivityManager.EXTRA_NETWORK_INFO);
1829 if (info != null && !info.isConnectedOrConnecting()) {
1830 try {
1831 mObserver.interfaceStatusChanged(mOuterInterface, false);
1832 } catch (RemoteException e) {}
1833 }
1834 }
1835 }
1836 }
1837 };
1838
Chia-chi Yeh41d16852011-07-01 02:12:06 -07001839 public LegacyVpnRunner(VpnConfig config, String[] racoon, String[] mtpd) {
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001840 super(TAG);
Chia-chi Yeh41d16852011-07-01 02:12:06 -07001841 mConfig = config;
1842 mDaemons = new String[] {"racoon", "mtpd"};
Jeff Sharkey899223b2012-08-04 15:24:58 -07001843 // TODO: clear arguments from memory once launched
Chia-chi Yeh41d16852011-07-01 02:12:06 -07001844 mArguments = new String[][] {racoon, mtpd};
Chia-chi Yeh5317f032011-08-22 13:09:49 -07001845 mSockets = new LocalSocket[mDaemons.length];
Robert Greenwalt53c04bd2012-10-12 17:02:45 -07001846
1847 // This is the interface which VPN is running on,
1848 // mConfig.interfaze will change to point to OUR
1849 // internal interface soon. TODO - add inner/outer to mconfig
Robert Greenwalt1b0ca9d2013-04-22 11:13:02 -07001850 // TODO - we have a race - if the outer iface goes away/disconnects before we hit this
Chad Brubaker4ca19e82013-06-14 11:16:51 -07001851 // we will leave the VPN up. We should check that it's still there/connected after
Robert Greenwalt1b0ca9d2013-04-22 11:13:02 -07001852 // registering
Robert Greenwalt53c04bd2012-10-12 17:02:45 -07001853 mOuterInterface = mConfig.interfaze;
Robert Greenwalt1b0ca9d2013-04-22 11:13:02 -07001854
Paul Jensene75b9e32015-04-06 11:54:53 -04001855 if (!TextUtils.isEmpty(mOuterInterface)) {
1856 final ConnectivityManager cm = ConnectivityManager.from(mContext);
1857 for (Network network : cm.getAllNetworks()) {
1858 final LinkProperties lp = cm.getLinkProperties(network);
Lorenzo Colitti1b60d112015-07-02 13:03:03 +09001859 if (lp != null && lp.getAllInterfaceNames().contains(mOuterInterface)) {
Paul Jensene75b9e32015-04-06 11:54:53 -04001860 final NetworkInfo networkInfo = cm.getNetworkInfo(network);
1861 if (networkInfo != null) mOuterConnection.set(networkInfo.getType());
1862 }
1863 }
Robert Greenwalt1b0ca9d2013-04-22 11:13:02 -07001864 }
1865
1866 IntentFilter filter = new IntentFilter();
1867 filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
1868 mContext.registerReceiver(mBroadcastReceiver, filter);
Chia-chi Yeh41d16852011-07-01 02:12:06 -07001869 }
1870
Chia-chi Yehaa1727f2011-07-14 18:55:33 -07001871 public void check(String interfaze) {
Robert Greenwalt53c04bd2012-10-12 17:02:45 -07001872 if (interfaze.equals(mOuterInterface)) {
Chia-chi Yehaa1727f2011-07-14 18:55:33 -07001873 Log.i(TAG, "Legacy VPN is going down with " + interfaze);
1874 exit();
1875 }
1876 }
1877
Chia-chi Yeh41d16852011-07-01 02:12:06 -07001878 public void exit() {
Chia-chi Yeh5317f032011-08-22 13:09:49 -07001879 // We assume that everything is reset after stopping the daemons.
Chia-chi Yeh97a61562011-07-14 15:05:05 -07001880 interrupt();
Paul Jensen6bc2c2c2014-05-07 15:27:40 -04001881 agentDisconnect();
Robert Greenwalt1b0ca9d2013-04-22 11:13:02 -07001882 try {
1883 mContext.unregisterReceiver(mBroadcastReceiver);
1884 } catch (IllegalArgumentException e) {}
Chia-chi Yeh2e467642011-07-04 03:23:12 -07001885 }
1886
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001887 @Override
1888 public void run() {
1889 // Wait for the previous thread since it has been interrupted.
Chia-chi Yeh2e467642011-07-04 03:23:12 -07001890 Log.v(TAG, "Waiting");
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001891 synchronized (TAG) {
Chia-chi Yeh2e467642011-07-04 03:23:12 -07001892 Log.v(TAG, "Executing");
Hisanobu Watanabe047454c2016-06-07 19:55:41 +09001893 try {
Chalard Jeandd59ece2017-12-20 13:23:32 +09001894 bringup();
1895 waitForDaemonsToStop();
Hisanobu Watanabe047454c2016-06-07 19:55:41 +09001896 interrupted(); // Clear interrupt flag if execute called exit.
1897 } catch (InterruptedException e) {
1898 } finally {
1899 for (LocalSocket socket : mSockets) {
1900 IoUtils.closeQuietly(socket);
1901 }
1902 // This sleep is necessary for racoon to successfully complete sending delete
1903 // message to server.
1904 try {
1905 Thread.sleep(50);
1906 } catch (InterruptedException e) {
1907 }
1908 for (String daemon : mDaemons) {
1909 SystemService.stop(daemon);
1910 }
1911 }
1912 agentDisconnect();
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001913 }
1914 }
1915
Chalard Jeandd59ece2017-12-20 13:23:32 +09001916 private void checkInterruptAndDelay(boolean sleepLonger) throws InterruptedException {
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001917 long now = SystemClock.elapsedRealtime();
Chalard Jeandd59ece2017-12-20 13:23:32 +09001918 if (now - mBringupStartTime <= 60000) {
1919 Thread.sleep(sleepLonger ? 200 : 1);
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001920 } else {
Jeff Sharkey899223b2012-08-04 15:24:58 -07001921 updateState(DetailedState.FAILED, "checkpoint");
Chalard Jeandd59ece2017-12-20 13:23:32 +09001922 throw new IllegalStateException("VPN bringup took too long");
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001923 }
1924 }
1925
Chalard Jeandd59ece2017-12-20 13:23:32 +09001926 private void bringup() {
1927 // Catch all exceptions so we can clean up a few things.
Jeff Sharkey899223b2012-08-04 15:24:58 -07001928 boolean initFinished = false;
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001929 try {
1930 // Initialize the timer.
Chalard Jeandd59ece2017-12-20 13:23:32 +09001931 mBringupStartTime = SystemClock.elapsedRealtime();
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001932
Chia-chi Yeh1f7746b2011-07-01 00:29:06 -07001933 // Wait for the daemons to stop.
1934 for (String daemon : mDaemons) {
Jeff Sharkey088f29f2012-08-05 14:55:04 -07001935 while (!SystemService.isStopped(daemon)) {
Chalard Jeandd59ece2017-12-20 13:23:32 +09001936 checkInterruptAndDelay(true);
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001937 }
1938 }
1939
Chia-chi Yeh97a61562011-07-14 15:05:05 -07001940 // Clear the previous state.
1941 File state = new File("/data/misc/vpn/state");
1942 state.delete();
1943 if (state.exists()) {
1944 throw new IllegalStateException("Cannot delete the state");
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001945 }
Chia-chi Yehc1872732011-12-08 16:51:41 -08001946 new File("/data/misc/vpn/abort").delete();
Jeff Sharkey899223b2012-08-04 15:24:58 -07001947 initFinished = true;
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001948
Chia-chi Yehe9107902011-07-02 01:48:50 -07001949 // Check if we need to restart any of the daemons.
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001950 boolean restart = false;
1951 for (String[] arguments : mArguments) {
1952 restart = restart || (arguments != null);
1953 }
1954 if (!restart) {
Paul Jensen6bc2c2c2014-05-07 15:27:40 -04001955 agentDisconnect();
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001956 return;
1957 }
Jeff Sharkey899223b2012-08-04 15:24:58 -07001958 updateState(DetailedState.CONNECTING, "execute");
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001959
Chia-chi Yeh1f7746b2011-07-01 00:29:06 -07001960 // Start the daemon with arguments.
1961 for (int i = 0; i < mDaemons.length; ++i) {
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001962 String[] arguments = mArguments[i];
1963 if (arguments == null) {
1964 continue;
1965 }
1966
Chia-chi Yeh1f7746b2011-07-01 00:29:06 -07001967 // Start the daemon.
1968 String daemon = mDaemons[i];
Jeff Sharkey088f29f2012-08-05 14:55:04 -07001969 SystemService.start(daemon);
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001970
Chia-chi Yeh1f7746b2011-07-01 00:29:06 -07001971 // Wait for the daemon to start.
Jeff Sharkey088f29f2012-08-05 14:55:04 -07001972 while (!SystemService.isRunning(daemon)) {
Chalard Jeandd59ece2017-12-20 13:23:32 +09001973 checkInterruptAndDelay(true);
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001974 }
1975
1976 // Create the control socket.
Chia-chi Yeh5317f032011-08-22 13:09:49 -07001977 mSockets[i] = new LocalSocket();
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001978 LocalSocketAddress address = new LocalSocketAddress(
Chia-chi Yeh1f7746b2011-07-01 00:29:06 -07001979 daemon, LocalSocketAddress.Namespace.RESERVED);
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001980
1981 // Wait for the socket to connect.
1982 while (true) {
1983 try {
Chia-chi Yeh5317f032011-08-22 13:09:49 -07001984 mSockets[i].connect(address);
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001985 break;
1986 } catch (Exception e) {
1987 // ignore
1988 }
Chalard Jeandd59ece2017-12-20 13:23:32 +09001989 checkInterruptAndDelay(true);
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001990 }
Chia-chi Yeh5317f032011-08-22 13:09:49 -07001991 mSockets[i].setSoTimeout(500);
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001992
1993 // Send over the arguments.
Chia-chi Yeh5317f032011-08-22 13:09:49 -07001994 OutputStream out = mSockets[i].getOutputStream();
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001995 for (String argument : arguments) {
Elliott Hughesd396a442013-06-28 16:24:48 -07001996 byte[] bytes = argument.getBytes(StandardCharsets.UTF_8);
Chia-chi Yeh5317f032011-08-22 13:09:49 -07001997 if (bytes.length >= 0xFFFF) {
Chia-chi Yeh97a61562011-07-14 15:05:05 -07001998 throw new IllegalArgumentException("Argument is too large");
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07001999 }
Chia-chi Yeh1f7746b2011-07-01 00:29:06 -07002000 out.write(bytes.length >> 8);
2001 out.write(bytes.length);
2002 out.write(bytes);
Chalard Jeandd59ece2017-12-20 13:23:32 +09002003 checkInterruptAndDelay(false);
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07002004 }
Chia-chi Yeh5317f032011-08-22 13:09:49 -07002005 out.write(0xFF);
2006 out.write(0xFF);
Chia-chi Yeh1f7746b2011-07-01 00:29:06 -07002007 out.flush();
Chia-chi Yeh97a61562011-07-14 15:05:05 -07002008
2009 // Wait for End-of-File.
Chia-chi Yeh5317f032011-08-22 13:09:49 -07002010 InputStream in = mSockets[i].getInputStream();
Chia-chi Yeh97a61562011-07-14 15:05:05 -07002011 while (true) {
2012 try {
2013 if (in.read() == -1) {
2014 break;
2015 }
2016 } catch (Exception e) {
2017 // ignore
2018 }
Chalard Jeandd59ece2017-12-20 13:23:32 +09002019 checkInterruptAndDelay(true);
Chia-chi Yeh97a61562011-07-14 15:05:05 -07002020 }
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07002021 }
2022
Chia-chi Yeh97a61562011-07-14 15:05:05 -07002023 // Wait for the daemons to create the new state.
2024 while (!state.exists()) {
Chia-chi Yeh1f7746b2011-07-01 00:29:06 -07002025 // Check if a running daemon is dead.
2026 for (int i = 0; i < mDaemons.length; ++i) {
2027 String daemon = mDaemons[i];
Jeff Sharkey088f29f2012-08-05 14:55:04 -07002028 if (mArguments[i] != null && !SystemService.isRunning(daemon)) {
Chia-chi Yeh2e467642011-07-04 03:23:12 -07002029 throw new IllegalStateException(daemon + " is dead");
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07002030 }
2031 }
Chalard Jeandd59ece2017-12-20 13:23:32 +09002032 checkInterruptAndDelay(true);
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07002033 }
2034
Chia-chi Yeh97a61562011-07-14 15:05:05 -07002035 // Now we are connected. Read and parse the new state.
Chia-chi Yehc1bac3a2011-12-16 15:00:31 -08002036 String[] parameters = FileUtils.readTextFile(state, 0, null).split("\n", -1);
Lorenzo Colitti50262792014-09-19 01:53:35 +09002037 if (parameters.length != 7) {
Chia-chi Yeh97a61562011-07-14 15:05:05 -07002038 throw new IllegalStateException("Cannot parse the state");
2039 }
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07002040
Chia-chi Yeh97a61562011-07-14 15:05:05 -07002041 // Set the interface and the addresses in the config.
2042 mConfig.interfaze = parameters[0].trim();
Chia-chi Yeh97a61562011-07-14 15:05:05 -07002043
Chad Brubaker4ca19e82013-06-14 11:16:51 -07002044 mConfig.addLegacyAddresses(parameters[1]);
Chia-chi Yeh97a61562011-07-14 15:05:05 -07002045 // Set the routes if they are not set in the config.
2046 if (mConfig.routes == null || mConfig.routes.isEmpty()) {
Chad Brubaker4ca19e82013-06-14 11:16:51 -07002047 mConfig.addLegacyRoutes(parameters[2]);
Chia-chi Yeh97a61562011-07-14 15:05:05 -07002048 }
2049
2050 // Set the DNS servers if they are not set in the config.
Chia-chi Yeh41d16852011-07-01 02:12:06 -07002051 if (mConfig.dnsServers == null || mConfig.dnsServers.size() == 0) {
Chia-chi Yeh97a61562011-07-14 15:05:05 -07002052 String dnsServers = parameters[3].trim();
Chia-chi Yeh41d16852011-07-01 02:12:06 -07002053 if (!dnsServers.isEmpty()) {
2054 mConfig.dnsServers = Arrays.asList(dnsServers.split(" "));
2055 }
2056 }
2057
Chia-chi Yeh97a61562011-07-14 15:05:05 -07002058 // Set the search domains if they are not set in the config.
2059 if (mConfig.searchDomains == null || mConfig.searchDomains.size() == 0) {
2060 String searchDomains = parameters[4].trim();
2061 if (!searchDomains.isEmpty()) {
2062 mConfig.searchDomains = Arrays.asList(searchDomains.split(" "));
2063 }
2064 }
Chia-chi Yehe9107902011-07-02 01:48:50 -07002065
Lorenzo Colitti50262792014-09-19 01:53:35 +09002066 // Add a throw route for the VPN server endpoint, if one was specified.
2067 String endpoint = parameters[5];
2068 if (!endpoint.isEmpty()) {
2069 try {
2070 InetAddress addr = InetAddress.parseNumericAddress(endpoint);
2071 if (addr instanceof Inet4Address) {
2072 mConfig.routes.add(new RouteInfo(new IpPrefix(addr, 32), RTN_THROW));
2073 } else if (addr instanceof Inet6Address) {
2074 mConfig.routes.add(new RouteInfo(new IpPrefix(addr, 128), RTN_THROW));
2075 } else {
2076 Log.e(TAG, "Unknown IP address family for VPN endpoint: " + endpoint);
2077 }
2078 } catch (IllegalArgumentException e) {
2079 Log.e(TAG, "Exception constructing throw route to " + endpoint + ": " + e);
2080 }
2081 }
2082
Chia-chi Yeh97a61562011-07-14 15:05:05 -07002083 // Here is the last step and it must be done synchronously.
Chia-chi Yeh41d16852011-07-01 02:12:06 -07002084 synchronized (Vpn.this) {
Vinit Deshapnde2b862e52013-10-02 11:50:39 -07002085 // Set the start time
2086 mConfig.startTime = SystemClock.elapsedRealtime();
2087
Chalard Jeandd59ece2017-12-20 13:23:32 +09002088 // Check if the thread was interrupted while we were waiting on the lock.
2089 checkInterruptAndDelay(false);
Chia-chi Yeh41d16852011-07-01 02:12:06 -07002090
Chia-chi Yehe9107902011-07-02 01:48:50 -07002091 // Check if the interface is gone while we are waiting.
Chia-chi Yehc2b8aa02011-07-03 18:00:47 -07002092 if (jniCheck(mConfig.interfaze) == 0) {
Chia-chi Yeh34e78132011-07-03 03:07:07 -07002093 throw new IllegalStateException(mConfig.interfaze + " is gone");
Chia-chi Yeh41d16852011-07-01 02:12:06 -07002094 }
Chia-chi Yehe9107902011-07-02 01:48:50 -07002095
2096 // Now INetworkManagementEventObserver is watching our back.
Chia-chi Yehc2b8aa02011-07-03 18:00:47 -07002097 mInterface = mConfig.interfaze;
Robin Lee4d03abc2016-05-09 12:32:27 +01002098 prepareStatusIntent();
Chad Brubaker4ca19e82013-06-14 11:16:51 -07002099
Paul Jensen6bc2c2c2014-05-07 15:27:40 -04002100 agentConnect();
Chia-chi Yeh2e467642011-07-04 03:23:12 -07002101
2102 Log.i(TAG, "Connected!");
Chia-chi Yeh41d16852011-07-01 02:12:06 -07002103 }
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07002104 } catch (Exception e) {
Chia-chi Yeh2e467642011-07-04 03:23:12 -07002105 Log.i(TAG, "Aborting", e);
Lorenzo Colitti43840602014-08-20 16:01:44 -07002106 updateState(DetailedState.FAILED, e.getMessage());
Chia-chi Yehe9107902011-07-02 01:48:50 -07002107 exit();
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07002108 }
2109 }
Jeff Sharkey899223b2012-08-04 15:24:58 -07002110
2111 /**
Chalard Jeandd59ece2017-12-20 13:23:32 +09002112 * Check all daemons every two seconds. Return when one of them is stopped.
2113 * The caller will move to the disconnected state when this function returns,
2114 * which can happen if a daemon failed or if the VPN was torn down.
Jeff Sharkey899223b2012-08-04 15:24:58 -07002115 */
Chalard Jeandd59ece2017-12-20 13:23:32 +09002116 private void waitForDaemonsToStop() throws InterruptedException {
Jeff Sharkey899223b2012-08-04 15:24:58 -07002117 if (!mNetworkInfo.isConnected()) {
2118 return;
2119 }
Hisanobu Watanabe047454c2016-06-07 19:55:41 +09002120 while (true) {
2121 Thread.sleep(2000);
2122 for (int i = 0; i < mDaemons.length; i++) {
2123 if (mArguments[i] != null && SystemService.isStopped(mDaemons[i])) {
2124 return;
Jeff Sharkey899223b2012-08-04 15:24:58 -07002125 }
2126 }
Jeff Sharkey899223b2012-08-04 15:24:58 -07002127 }
2128 }
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -07002129 }
Chia-chi Yehff3bdca2011-05-23 17:26:46 -07002130}