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