Vpn.java revision 90b1b9f985a91fb54254705515f822b09c68ac26
1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.connectivity;
18
19import static android.Manifest.permission.BIND_VPN_SERVICE;
20import static android.system.OsConstants.AF_INET;
21import static android.system.OsConstants.AF_INET6;
22
23import android.app.AppGlobals;
24import android.app.AppOpsManager;
25import android.app.PendingIntent;
26import android.content.BroadcastReceiver;
27import android.content.ComponentName;
28import android.content.Context;
29import android.content.Intent;
30import android.content.IntentFilter;
31import android.content.ServiceConnection;
32import android.content.pm.ApplicationInfo;
33import android.content.pm.PackageManager;
34import android.content.pm.PackageManager.NameNotFoundException;
35import android.content.pm.ResolveInfo;
36import android.content.pm.UserInfo;
37import android.net.ConnectivityManager;
38import android.net.IConnectivityManager;
39import android.net.INetworkManagementEventObserver;
40import android.net.LinkAddress;
41import android.net.LinkProperties;
42import android.net.LocalSocket;
43import android.net.LocalSocketAddress;
44import android.net.NetworkAgent;
45import android.net.NetworkCapabilities;
46import android.net.NetworkInfo;
47import android.net.NetworkInfo.DetailedState;
48import android.net.NetworkMisc;
49import android.net.RouteInfo;
50import android.net.UidRange;
51import android.os.Binder;
52import android.os.FileUtils;
53import android.os.IBinder;
54import android.os.INetworkManagementService;
55import android.os.Looper;
56import android.os.Parcel;
57import android.os.ParcelFileDescriptor;
58import android.os.Process;
59import android.os.RemoteException;
60import android.os.SystemClock;
61import android.os.SystemService;
62import android.os.UserHandle;
63import android.os.UserManager;
64import android.security.Credentials;
65import android.security.KeyStore;
66import android.util.Log;
67
68import com.android.internal.annotations.GuardedBy;
69import com.android.internal.net.LegacyVpnInfo;
70import com.android.internal.net.VpnConfig;
71import com.android.internal.net.VpnProfile;
72import com.android.server.net.BaseNetworkObserver;
73
74import libcore.io.IoUtils;
75
76import java.io.File;
77import java.io.IOException;
78import java.io.InputStream;
79import java.io.OutputStream;
80import java.net.Inet4Address;
81import java.net.Inet6Address;
82import java.net.InetAddress;
83import java.nio.charset.StandardCharsets;
84import java.util.ArrayList;
85import java.util.Arrays;
86import java.util.List;
87import java.util.concurrent.atomic.AtomicInteger;
88
89/**
90 * @hide
91 */
92public class Vpn {
93    private static final String NETWORKTYPE = "VPN";
94    private static final String TAG = "Vpn";
95    private static final boolean LOGD = true;
96
97    // TODO: create separate trackers for each unique VPN to support
98    // automated reconnection
99
100    private Context mContext;
101    private NetworkInfo mNetworkInfo;
102    private String mPackage;
103    private int mOwnerUID;
104    private String mInterface;
105    private boolean mAllowIPv4;
106    private boolean mAllowIPv6;
107    private Connection mConnection;
108    private LegacyVpnRunner mLegacyVpnRunner;
109    private PendingIntent mStatusIntent;
110    private volatile boolean mEnableTeardown = true;
111    private final IConnectivityManager mConnService;
112    private final INetworkManagementService mNetd;
113    private VpnConfig mConfig;
114    private NetworkAgent mNetworkAgent;
115    private final Looper mLooper;
116    private final NetworkCapabilities mNetworkCapabilities;
117
118    /* list of users using this VPN. */
119    @GuardedBy("this")
120    private List<UidRange> mVpnUsers = null;
121    private BroadcastReceiver mUserIntentReceiver = null;
122
123    private final int mUserId;
124
125    public Vpn(Looper looper, Context context, INetworkManagementService netService,
126            IConnectivityManager connService, int userId) {
127        mContext = context;
128        mNetd = netService;
129        mConnService = connService;
130        mUserId = userId;
131        mLooper = looper;
132
133        mPackage = VpnConfig.LEGACY_VPN;
134        mOwnerUID = getAppUid(mPackage);
135
136        try {
137            netService.registerObserver(mObserver);
138        } catch (RemoteException e) {
139            Log.wtf(TAG, "Problem registering observer", e);
140        }
141        if (userId == UserHandle.USER_OWNER) {
142            // Owner's VPN also needs to handle restricted users
143            mUserIntentReceiver = new BroadcastReceiver() {
144                @Override
145                public void onReceive(Context context, Intent intent) {
146                    final String action = intent.getAction();
147                    final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
148                            UserHandle.USER_NULL);
149                    if (userId == UserHandle.USER_NULL) return;
150
151                    if (Intent.ACTION_USER_ADDED.equals(action)) {
152                        onUserAdded(userId);
153                    } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
154                        onUserRemoved(userId);
155                    }
156                }
157            };
158
159            IntentFilter intentFilter = new IntentFilter();
160            intentFilter.addAction(Intent.ACTION_USER_ADDED);
161            intentFilter.addAction(Intent.ACTION_USER_REMOVED);
162            mContext.registerReceiverAsUser(
163                    mUserIntentReceiver, UserHandle.ALL, intentFilter, null, null);
164        }
165
166        mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_VPN, 0, NETWORKTYPE, "");
167        // TODO: Copy metered attribute and bandwidths from physical transport, b/16207332
168        mNetworkCapabilities = new NetworkCapabilities();
169        mNetworkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_VPN);
170        mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN);
171    }
172
173    /**
174     * Set if this object is responsible for watching for {@link NetworkInfo}
175     * teardown. When {@code false}, teardown is handled externally by someone
176     * else.
177     */
178    public void setEnableTeardown(boolean enableTeardown) {
179        mEnableTeardown = enableTeardown;
180    }
181
182    /**
183     * Update current state, dispaching event to listeners.
184     */
185    private void updateState(DetailedState detailedState, String reason) {
186        if (LOGD) Log.d(TAG, "setting state=" + detailedState + ", reason=" + reason);
187        mNetworkInfo.setDetailedState(detailedState, reason, null);
188        if (mNetworkAgent != null) {
189            mNetworkAgent.sendNetworkInfo(mNetworkInfo);
190        }
191    }
192
193    /**
194     * Prepare for a VPN application. This method is designed to solve
195     * race conditions. It first compares the current prepared package
196     * with {@code oldPackage}. If they are the same, the prepared
197     * package is revoked and replaced with {@code newPackage}. If
198     * {@code oldPackage} is {@code null}, the comparison is omitted.
199     * If {@code newPackage} is the same package or {@code null}, the
200     * revocation is omitted. This method returns {@code true} if the
201     * operation is succeeded.
202     *
203     * Legacy VPN is handled specially since it is not a real package.
204     * It uses {@link VpnConfig#LEGACY_VPN} as its package name, and
205     * it can be revoked by itself.
206     *
207     * @param oldPackage The package name of the old VPN application.
208     * @param newPackage The package name of the new VPN application.
209     * @return true if the operation is succeeded.
210     */
211    public synchronized boolean prepare(String oldPackage, String newPackage) {
212        // Return false if the package does not match.
213        if (oldPackage != null && !oldPackage.equals(mPackage)) {
214            // The package doesn't match. If this VPN was not previously authorized, return false
215            // to force user authorization. Otherwise, revoke the VPN anyway.
216            if (!oldPackage.equals(VpnConfig.LEGACY_VPN) && isVpnUserPreConsented(oldPackage)) {
217                long token = Binder.clearCallingIdentity();
218                try {
219                    // This looks bizarre, but it is what ConfirmDialog in VpnDialogs is doing when
220                    // the user clicks through to allow the VPN to consent. So we are emulating the
221                    // action of the dialog without actually showing it.
222                    prepare(null, oldPackage);
223                } finally {
224                    Binder.restoreCallingIdentity(token);
225                }
226                return true;
227            }
228            return false;
229        }
230
231        // Return true if we do not need to revoke.
232        if (newPackage == null ||
233                (newPackage.equals(mPackage) && !newPackage.equals(VpnConfig.LEGACY_VPN))) {
234            return true;
235        }
236
237        // Check if the caller is authorized.
238        enforceControlPermission();
239
240        // Reset the interface.
241        if (mInterface != null) {
242            mStatusIntent = null;
243            agentDisconnect();
244            jniReset(mInterface);
245            mInterface = null;
246            mVpnUsers = null;
247        }
248
249        // Revoke the connection or stop LegacyVpnRunner.
250        if (mConnection != null) {
251            try {
252                mConnection.mService.transact(IBinder.LAST_CALL_TRANSACTION,
253                        Parcel.obtain(), null, IBinder.FLAG_ONEWAY);
254            } catch (Exception e) {
255                // ignore
256            }
257            mContext.unbindService(mConnection);
258            mConnection = null;
259        } else if (mLegacyVpnRunner != null) {
260            mLegacyVpnRunner.exit();
261            mLegacyVpnRunner = null;
262        }
263
264        long token = Binder.clearCallingIdentity();
265        try {
266            mNetd.denyProtect(mOwnerUID);
267        } catch (Exception e) {
268            Log.wtf(TAG, "Failed to disallow UID " + mOwnerUID + " to call protect() " + e);
269        } finally {
270            Binder.restoreCallingIdentity(token);
271        }
272
273        Log.i(TAG, "Switched from " + mPackage + " to " + newPackage);
274        mPackage = newPackage;
275        mOwnerUID = getAppUid(newPackage);
276        token = Binder.clearCallingIdentity();
277        try {
278            mNetd.allowProtect(mOwnerUID);
279        } catch (Exception e) {
280            Log.wtf(TAG, "Failed to allow UID " + mOwnerUID + " to call protect() " + e);
281        } finally {
282            Binder.restoreCallingIdentity(token);
283        }
284        mConfig = null;
285
286        updateState(DetailedState.IDLE, "prepare");
287        return true;
288    }
289
290    /**
291     * Set whether the current package has the ability to launch VPNs without user intervention.
292     */
293    public void setPackageAuthorization(boolean authorized) {
294        // Check if the caller is authorized.
295        enforceControlPermission();
296
297        if (mPackage == null || VpnConfig.LEGACY_VPN.equals(mPackage)) {
298            return;
299        }
300
301        long token = Binder.clearCallingIdentity();
302        try {
303            AppOpsManager appOps =
304                    (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
305            appOps.setMode(AppOpsManager.OP_ACTIVATE_VPN, mOwnerUID, mPackage,
306                    authorized ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
307        } catch (Exception e) {
308            Log.wtf(TAG, "Failed to set app ops for package " + mPackage, e);
309        } finally {
310            Binder.restoreCallingIdentity(token);
311        }
312    }
313
314    private boolean isVpnUserPreConsented(String packageName) {
315        AppOpsManager appOps =
316                (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
317
318        // Verify that the caller matches the given package and has permission to activate VPNs.
319        return appOps.noteOpNoThrow(AppOpsManager.OP_ACTIVATE_VPN, Binder.getCallingUid(),
320                packageName) == AppOpsManager.MODE_ALLOWED;
321    }
322
323    private int getAppUid(String app) {
324        if (VpnConfig.LEGACY_VPN.equals(app)) {
325            return Process.myUid();
326        }
327        PackageManager pm = mContext.getPackageManager();
328        int result;
329        try {
330            result = pm.getPackageUid(app, mUserId);
331        } catch (NameNotFoundException e) {
332            result = -1;
333        }
334        return result;
335    }
336
337    public NetworkInfo getNetworkInfo() {
338        return mNetworkInfo;
339    }
340
341    private void agentConnect() {
342        LinkProperties lp = new LinkProperties();
343        lp.setInterfaceName(mInterface);
344
345        boolean hasDefaultRoute = false;
346        for (RouteInfo route : mConfig.routes) {
347            lp.addRoute(route);
348            if (route.isDefaultRoute()) hasDefaultRoute = true;
349        }
350        if (hasDefaultRoute) {
351            mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
352        } else {
353            mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
354        }
355
356        if (mConfig.dnsServers != null) {
357            for (String dnsServer : mConfig.dnsServers) {
358                InetAddress address = InetAddress.parseNumericAddress(dnsServer);
359                lp.addDnsServer(address);
360                if (address instanceof Inet4Address) {
361                    mAllowIPv4 = true;
362                } else {
363                    mAllowIPv6 = true;
364                }
365            }
366        }
367
368        // Concatenate search domains into a string.
369        StringBuilder buffer = new StringBuilder();
370        if (mConfig.searchDomains != null) {
371            for (String domain : mConfig.searchDomains) {
372                buffer.append(domain).append(' ');
373            }
374        }
375        lp.setDomains(buffer.toString().trim());
376
377        mNetworkInfo.setIsAvailable(true);
378        mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null);
379
380        NetworkMisc networkMisc = new NetworkMisc();
381        networkMisc.allowBypass = mConfig.allowBypass;
382
383        long token = Binder.clearCallingIdentity();
384        try {
385            mNetworkAgent = new NetworkAgent(mLooper, mContext, NETWORKTYPE,
386                    mNetworkInfo, mNetworkCapabilities, lp, 0, networkMisc) {
387                            @Override
388                            public void unwanted() {
389                                // We are user controlled, not driven by NetworkRequest.
390                            }
391                        };
392        } finally {
393            Binder.restoreCallingIdentity(token);
394        }
395
396        if (!mAllowIPv4) {
397            mNetworkAgent.blockAddressFamily(AF_INET);
398        }
399        if (!mAllowIPv6) {
400            mNetworkAgent.blockAddressFamily(AF_INET6);
401        }
402
403        addVpnUserLocked(mUserId);
404        // If we are owner assign all Restricted Users to this VPN
405        if (mUserId == UserHandle.USER_OWNER) {
406            token = Binder.clearCallingIdentity();
407            List<UserInfo> users;
408            try {
409                users = UserManager.get(mContext).getUsers();
410            } finally {
411                Binder.restoreCallingIdentity(token);
412            }
413            for (UserInfo user : users) {
414                if (user.isRestricted()) {
415                    addVpnUserLocked(user.id);
416                }
417            }
418        }
419        mNetworkAgent.addUidRanges(mVpnUsers.toArray(new UidRange[mVpnUsers.size()]));
420    }
421
422    private void agentDisconnect(NetworkInfo networkInfo, NetworkAgent networkAgent) {
423        networkInfo.setIsAvailable(false);
424        networkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
425        if (networkAgent != null) {
426            networkAgent.sendNetworkInfo(networkInfo);
427        }
428    }
429
430    private void agentDisconnect(NetworkAgent networkAgent) {
431        NetworkInfo networkInfo = new NetworkInfo(mNetworkInfo);
432        agentDisconnect(networkInfo, networkAgent);
433    }
434
435    private void agentDisconnect() {
436        if (mNetworkInfo.isConnected()) {
437            agentDisconnect(mNetworkInfo, mNetworkAgent);
438            mNetworkAgent = null;
439        }
440    }
441
442    /**
443     * Establish a VPN network and return the file descriptor of the VPN
444     * interface. This methods returns {@code null} if the application is
445     * revoked or not prepared.
446     *
447     * @param config The parameters to configure the network.
448     * @return The file descriptor of the VPN interface.
449     */
450    public synchronized ParcelFileDescriptor establish(VpnConfig config) {
451        // Check if the caller is already prepared.
452        UserManager mgr = UserManager.get(mContext);
453        if (Binder.getCallingUid() != mOwnerUID) {
454            return null;
455        }
456        // Check if the service is properly declared.
457        Intent intent = new Intent(VpnConfig.SERVICE_INTERFACE);
458        intent.setClassName(mPackage, config.user);
459        long token = Binder.clearCallingIdentity();
460        try {
461            // Restricted users are not allowed to create VPNs, they are tied to Owner
462            UserInfo user = mgr.getUserInfo(mUserId);
463            if (user.isRestricted() || mgr.hasUserRestriction(UserManager.DISALLOW_CONFIG_VPN)) {
464                throw new SecurityException("Restricted users cannot establish VPNs");
465            }
466
467            ResolveInfo info = AppGlobals.getPackageManager().resolveService(intent,
468                                                                        null, 0, mUserId);
469            if (info == null) {
470                throw new SecurityException("Cannot find " + config.user);
471            }
472            if (!BIND_VPN_SERVICE.equals(info.serviceInfo.permission)) {
473                throw new SecurityException(config.user + " does not require " + BIND_VPN_SERVICE);
474            }
475        } catch (RemoteException e) {
476                throw new SecurityException("Cannot find " + config.user);
477        } finally {
478            Binder.restoreCallingIdentity(token);
479        }
480
481        // Save the old config in case we need to go back.
482        VpnConfig oldConfig = mConfig;
483        String oldInterface = mInterface;
484        Connection oldConnection = mConnection;
485        NetworkAgent oldNetworkAgent = mNetworkAgent;
486        mNetworkAgent = null;
487        List<UidRange> oldUsers = mVpnUsers;
488        boolean oldAllowIPv4 = mAllowIPv4;
489        boolean oldAllowIPv6 = mAllowIPv6;
490
491        // Configure the interface. Abort if any of these steps fails.
492        ParcelFileDescriptor tun = ParcelFileDescriptor.adoptFd(jniCreate(config.mtu));
493        try {
494            updateState(DetailedState.CONNECTING, "establish");
495            String interfaze = jniGetName(tun.getFd());
496
497            // TEMP use the old jni calls until there is support for netd address setting
498            StringBuilder builder = new StringBuilder();
499            for (LinkAddress address : config.addresses) {
500                builder.append(" " + address);
501            }
502            if (jniSetAddresses(interfaze, builder.toString()) < 1) {
503                throw new IllegalArgumentException("At least one address must be specified");
504            }
505            Connection connection = new Connection();
506            if (!mContext.bindServiceAsUser(intent, connection, Context.BIND_AUTO_CREATE,
507                        new UserHandle(mUserId))) {
508                throw new IllegalStateException("Cannot bind " + config.user);
509            }
510
511            mConnection = connection;
512            mInterface = interfaze;
513
514            // Fill more values.
515            config.user = mPackage;
516            config.interfaze = mInterface;
517            config.startTime = SystemClock.elapsedRealtime();
518            mConfig = config;
519
520            // Set up forwarding and DNS rules.
521            mVpnUsers = new ArrayList<UidRange>();
522            mAllowIPv4 = mConfig.allowIPv4;
523            mAllowIPv6 = mConfig.allowIPv6;
524
525            agentConnect();
526
527            if (oldConnection != null) {
528                mContext.unbindService(oldConnection);
529            }
530            // Remove the old tun's user forwarding rules
531            // The new tun's user rules have already been added so they will take over
532            // as rules are deleted. This prevents data leakage as the rules are moved over.
533            agentDisconnect(oldNetworkAgent);
534            if (oldInterface != null && !oldInterface.equals(interfaze)) {
535                jniReset(oldInterface);
536            }
537
538            try {
539                IoUtils.setBlocking(tun.getFileDescriptor(), config.blocking);
540            } catch (IOException e) {
541                throw new IllegalStateException(
542                        "Cannot set tunnel's fd as blocking=" + config.blocking, e);
543            }
544        } catch (RuntimeException e) {
545            IoUtils.closeQuietly(tun);
546            agentDisconnect();
547            // restore old state
548            mConfig = oldConfig;
549            mConnection = oldConnection;
550            mVpnUsers = oldUsers;
551            mNetworkAgent = oldNetworkAgent;
552            mInterface = oldInterface;
553            mAllowIPv4 = oldAllowIPv4;
554            mAllowIPv6 = oldAllowIPv6;
555            throw e;
556        }
557        Log.i(TAG, "Established by " + config.user + " on " + mInterface);
558        return tun;
559    }
560
561    private boolean isRunningLocked() {
562        return mVpnUsers != null;
563    }
564
565    // Note: This function adds to mVpnUsers but does not publish list to NetworkAgent.
566    private void addVpnUserLocked(int user) {
567        if (!isRunningLocked()) {
568            throw new IllegalStateException("VPN is not active");
569        }
570
571        // add the user
572        mVpnUsers.add(UidRange.createForUser(user));
573
574        prepareStatusIntent();
575    }
576
577    private void removeVpnUserLocked(int user) {
578        if (!isRunningLocked()) {
579            throw new IllegalStateException("VPN is not active");
580        }
581        UidRange uidRange = UidRange.createForUser(user);
582        if (mNetworkAgent != null) {
583            mNetworkAgent.removeUidRanges(new UidRange[] { uidRange });
584        }
585        mVpnUsers.remove(uidRange);
586        mStatusIntent = null;
587    }
588
589    private void onUserAdded(int userId) {
590        // If the user is restricted tie them to the owner's VPN
591        synchronized(Vpn.this) {
592            UserManager mgr = UserManager.get(mContext);
593            UserInfo user = mgr.getUserInfo(userId);
594            if (user.isRestricted()) {
595                try {
596                    addVpnUserLocked(userId);
597                    if (mNetworkAgent != null) {
598                        UidRange uidRange = UidRange.createForUser(userId);
599                        mNetworkAgent.addUidRanges(new UidRange[] { uidRange });
600                    }
601                } catch (Exception e) {
602                    Log.wtf(TAG, "Failed to add restricted user to owner", e);
603                }
604            }
605        }
606    }
607
608    private void onUserRemoved(int userId) {
609        // clean up if restricted
610        synchronized(Vpn.this) {
611            UserManager mgr = UserManager.get(mContext);
612            UserInfo user = mgr.getUserInfo(userId);
613            if (user.isRestricted()) {
614                try {
615                    removeVpnUserLocked(userId);
616                } catch (Exception e) {
617                    Log.wtf(TAG, "Failed to remove restricted user to owner", e);
618                }
619            }
620        }
621    }
622
623    /**
624     * Return the configuration of the currently running VPN.
625     */
626    public VpnConfig getVpnConfig() {
627        enforceControlPermission();
628        return mConfig;
629    }
630
631    @Deprecated
632    public synchronized void interfaceStatusChanged(String iface, boolean up) {
633        try {
634            mObserver.interfaceStatusChanged(iface, up);
635        } catch (RemoteException e) {
636            // ignored; target is local
637        }
638    }
639
640    private INetworkManagementEventObserver mObserver = new BaseNetworkObserver() {
641        @Override
642        public void interfaceStatusChanged(String interfaze, boolean up) {
643            synchronized (Vpn.this) {
644                if (!up && mLegacyVpnRunner != null) {
645                    mLegacyVpnRunner.check(interfaze);
646                }
647            }
648        }
649
650        @Override
651        public void interfaceRemoved(String interfaze) {
652            synchronized (Vpn.this) {
653                if (interfaze.equals(mInterface) && jniCheck(interfaze) == 0) {
654                    mStatusIntent = null;
655                    mVpnUsers = null;
656                    mInterface = null;
657                    if (mConnection != null) {
658                        mContext.unbindService(mConnection);
659                        mConnection = null;
660                        agentDisconnect();
661                    } else if (mLegacyVpnRunner != null) {
662                        mLegacyVpnRunner.exit();
663                        mLegacyVpnRunner = null;
664                    }
665                }
666            }
667        }
668    };
669
670    private void enforceControlPermission() {
671        // System user is allowed to control VPN.
672        if (Binder.getCallingUid() == Process.SYSTEM_UID) {
673            return;
674        }
675        int appId = UserHandle.getAppId(Binder.getCallingUid());
676        final long token = Binder.clearCallingIdentity();
677        try {
678            // System VPN dialogs are also allowed to control VPN.
679            PackageManager pm = mContext.getPackageManager();
680            ApplicationInfo app = pm.getApplicationInfo(VpnConfig.DIALOGS_PACKAGE, 0);
681            if (((app.flags & ApplicationInfo.FLAG_SYSTEM) != 0) && (appId == app.uid)) {
682                return;
683            }
684            // SystemUI dialogs are also allowed to control VPN.
685            ApplicationInfo sysUiApp = pm.getApplicationInfo("com.android.systemui", 0);
686            if (((sysUiApp.flags & ApplicationInfo.FLAG_SYSTEM) != 0) && (appId == sysUiApp.uid)) {
687                return;
688            }
689        } catch (Exception e) {
690            // ignore
691        } finally {
692            Binder.restoreCallingIdentity(token);
693        }
694
695        throw new SecurityException("Unauthorized Caller");
696    }
697
698    private class Connection implements ServiceConnection {
699        private IBinder mService;
700
701        @Override
702        public void onServiceConnected(ComponentName name, IBinder service) {
703            mService = service;
704        }
705
706        @Override
707        public void onServiceDisconnected(ComponentName name) {
708            mService = null;
709        }
710    }
711
712    private void prepareStatusIntent() {
713        final long token = Binder.clearCallingIdentity();
714        try {
715            mStatusIntent = VpnConfig.getIntentForStatusPanel(mContext);
716        } finally {
717            Binder.restoreCallingIdentity(token);
718        }
719    }
720
721    public synchronized boolean addAddress(String address, int prefixLength) {
722        if (Binder.getCallingUid() != mOwnerUID || mInterface == null || mNetworkAgent == null) {
723            return false;
724        }
725        boolean success = jniAddAddress(mInterface, address, prefixLength);
726        if (success && (!mAllowIPv4 || !mAllowIPv6)) {
727            try {
728                InetAddress inetAddress = InetAddress.parseNumericAddress(address);
729                if ((inetAddress instanceof Inet4Address) && !mAllowIPv4) {
730                    mAllowIPv4 = true;
731                    mNetworkAgent.unblockAddressFamily(AF_INET);
732                } else if ((inetAddress instanceof Inet6Address) && !mAllowIPv6) {
733                    mAllowIPv6 = true;
734                    mNetworkAgent.unblockAddressFamily(AF_INET6);
735                }
736            } catch (IllegalArgumentException e) {
737                // ignore
738            }
739        }
740        // Ideally, we'd call mNetworkAgent.sendLinkProperties() here to notify ConnectivityService
741        // that the LinkAddress has changed. But we don't do so for two reasons: (1) We don't set
742        // LinkAddresses on the LinkProperties we establish in the first place (see agentConnect())
743        // and (2) CS doesn't do anything with LinkAddresses anyway (see updateLinkProperties()).
744        // TODO: Maybe fix this.
745        return success;
746    }
747
748    public synchronized boolean removeAddress(String address, int prefixLength) {
749        if (Binder.getCallingUid() != mOwnerUID || mInterface == null || mNetworkAgent == null) {
750            return false;
751        }
752        boolean success = jniDelAddress(mInterface, address, prefixLength);
753        // Ideally, we'd call mNetworkAgent.sendLinkProperties() here to notify ConnectivityService
754        // that the LinkAddress has changed. But we don't do so for two reasons: (1) We don't set
755        // LinkAddresses on the LinkProperties we establish in the first place (see agentConnect())
756        // and (2) CS doesn't do anything with LinkAddresses anyway (see updateLinkProperties()).
757        // TODO: Maybe fix this.
758        return success;
759    }
760
761    private native int jniCreate(int mtu);
762    private native String jniGetName(int tun);
763    private native int jniSetAddresses(String interfaze, String addresses);
764    private native void jniReset(String interfaze);
765    private native int jniCheck(String interfaze);
766    private native boolean jniAddAddress(String interfaze, String address, int prefixLen);
767    private native boolean jniDelAddress(String interfaze, String address, int prefixLen);
768
769    private static RouteInfo findIPv4DefaultRoute(LinkProperties prop) {
770        for (RouteInfo route : prop.getAllRoutes()) {
771            // Currently legacy VPN only works on IPv4.
772            if (route.isDefaultRoute() && route.getGateway() instanceof Inet4Address) {
773                return route;
774            }
775        }
776
777        throw new IllegalStateException("Unable to find IPv4 default gateway");
778    }
779
780    /**
781     * Start legacy VPN, controlling native daemons as needed. Creates a
782     * secondary thread to perform connection work, returning quickly.
783     */
784    public void startLegacyVpn(VpnProfile profile, KeyStore keyStore, LinkProperties egress) {
785        enforceControlPermission();
786        if (!keyStore.isUnlocked()) {
787            throw new IllegalStateException("KeyStore isn't unlocked");
788        }
789        UserManager mgr = UserManager.get(mContext);
790        UserInfo user = mgr.getUserInfo(mUserId);
791        if (user.isRestricted() || mgr.hasUserRestriction(UserManager.DISALLOW_CONFIG_VPN)) {
792            throw new SecurityException("Restricted users cannot establish VPNs");
793        }
794
795        final RouteInfo ipv4DefaultRoute = findIPv4DefaultRoute(egress);
796        final String gateway = ipv4DefaultRoute.getGateway().getHostAddress();
797        final String iface = ipv4DefaultRoute.getInterface();
798
799        // Load certificates.
800        String privateKey = "";
801        String userCert = "";
802        String caCert = "";
803        String serverCert = "";
804        if (!profile.ipsecUserCert.isEmpty()) {
805            privateKey = Credentials.USER_PRIVATE_KEY + profile.ipsecUserCert;
806            byte[] value = keyStore.get(Credentials.USER_CERTIFICATE + profile.ipsecUserCert);
807            userCert = (value == null) ? null : new String(value, StandardCharsets.UTF_8);
808        }
809        if (!profile.ipsecCaCert.isEmpty()) {
810            byte[] value = keyStore.get(Credentials.CA_CERTIFICATE + profile.ipsecCaCert);
811            caCert = (value == null) ? null : new String(value, StandardCharsets.UTF_8);
812        }
813        if (!profile.ipsecServerCert.isEmpty()) {
814            byte[] value = keyStore.get(Credentials.USER_CERTIFICATE + profile.ipsecServerCert);
815            serverCert = (value == null) ? null : new String(value, StandardCharsets.UTF_8);
816        }
817        if (privateKey == null || userCert == null || caCert == null || serverCert == null) {
818            throw new IllegalStateException("Cannot load credentials");
819        }
820
821        // Prepare arguments for racoon.
822        String[] racoon = null;
823        switch (profile.type) {
824            case VpnProfile.TYPE_L2TP_IPSEC_PSK:
825                racoon = new String[] {
826                    iface, profile.server, "udppsk", profile.ipsecIdentifier,
827                    profile.ipsecSecret, "1701",
828                };
829                break;
830            case VpnProfile.TYPE_L2TP_IPSEC_RSA:
831                racoon = new String[] {
832                    iface, profile.server, "udprsa", privateKey, userCert,
833                    caCert, serverCert, "1701",
834                };
835                break;
836            case VpnProfile.TYPE_IPSEC_XAUTH_PSK:
837                racoon = new String[] {
838                    iface, profile.server, "xauthpsk", profile.ipsecIdentifier,
839                    profile.ipsecSecret, profile.username, profile.password, "", gateway,
840                };
841                break;
842            case VpnProfile.TYPE_IPSEC_XAUTH_RSA:
843                racoon = new String[] {
844                    iface, profile.server, "xauthrsa", privateKey, userCert,
845                    caCert, serverCert, profile.username, profile.password, "", gateway,
846                };
847                break;
848            case VpnProfile.TYPE_IPSEC_HYBRID_RSA:
849                racoon = new String[] {
850                    iface, profile.server, "hybridrsa",
851                    caCert, serverCert, profile.username, profile.password, "", gateway,
852                };
853                break;
854        }
855
856        // Prepare arguments for mtpd.
857        String[] mtpd = null;
858        switch (profile.type) {
859            case VpnProfile.TYPE_PPTP:
860                mtpd = new String[] {
861                    iface, "pptp", profile.server, "1723",
862                    "name", profile.username, "password", profile.password,
863                    "linkname", "vpn", "refuse-eap", "nodefaultroute",
864                    "usepeerdns", "idle", "1800", "mtu", "1400", "mru", "1400",
865                    (profile.mppe ? "+mppe" : "nomppe"),
866                };
867                break;
868            case VpnProfile.TYPE_L2TP_IPSEC_PSK:
869            case VpnProfile.TYPE_L2TP_IPSEC_RSA:
870                mtpd = new String[] {
871                    iface, "l2tp", profile.server, "1701", profile.l2tpSecret,
872                    "name", profile.username, "password", profile.password,
873                    "linkname", "vpn", "refuse-eap", "nodefaultroute",
874                    "usepeerdns", "idle", "1800", "mtu", "1400", "mru", "1400",
875                };
876                break;
877        }
878
879        VpnConfig config = new VpnConfig();
880        config.legacy = true;
881        config.user = profile.key;
882        config.interfaze = iface;
883        config.session = profile.name;
884
885        config.addLegacyRoutes(profile.routes);
886        if (!profile.dnsServers.isEmpty()) {
887            config.dnsServers = Arrays.asList(profile.dnsServers.split(" +"));
888        }
889        if (!profile.searchDomains.isEmpty()) {
890            config.searchDomains = Arrays.asList(profile.searchDomains.split(" +"));
891        }
892        startLegacyVpn(config, racoon, mtpd);
893    }
894
895    private synchronized void startLegacyVpn(VpnConfig config, String[] racoon, String[] mtpd) {
896        stopLegacyVpn();
897
898        // Prepare for the new request. This also checks the caller.
899        prepare(null, VpnConfig.LEGACY_VPN);
900        updateState(DetailedState.CONNECTING, "startLegacyVpn");
901
902        // Start a new LegacyVpnRunner and we are done!
903        mLegacyVpnRunner = new LegacyVpnRunner(config, racoon, mtpd);
904        mLegacyVpnRunner.start();
905    }
906
907    public synchronized void stopLegacyVpn() {
908        if (mLegacyVpnRunner != null) {
909            mLegacyVpnRunner.exit();
910            mLegacyVpnRunner = null;
911
912            synchronized (LegacyVpnRunner.TAG) {
913                // wait for old thread to completely finish before spinning up
914                // new instance, otherwise state updates can be out of order.
915            }
916        }
917    }
918
919    /**
920     * Return the information of the current ongoing legacy VPN.
921     */
922    public synchronized LegacyVpnInfo getLegacyVpnInfo() {
923        // Check if the caller is authorized.
924        enforceControlPermission();
925        if (mLegacyVpnRunner == null) return null;
926
927        final LegacyVpnInfo info = new LegacyVpnInfo();
928        info.key = mConfig.user;
929        info.state = LegacyVpnInfo.stateFromNetworkInfo(mNetworkInfo);
930        if (mNetworkInfo.isConnected()) {
931            info.intent = mStatusIntent;
932        }
933        return info;
934    }
935
936    public VpnConfig getLegacyVpnConfig() {
937        if (mLegacyVpnRunner != null) {
938            return mConfig;
939        } else {
940            return null;
941        }
942    }
943
944    /**
945     * Bringing up a VPN connection takes time, and that is all this thread
946     * does. Here we have plenty of time. The only thing we need to take
947     * care of is responding to interruptions as soon as possible. Otherwise
948     * requests will be piled up. This can be done in a Handler as a state
949     * machine, but it is much easier to read in the current form.
950     */
951    private class LegacyVpnRunner extends Thread {
952        private static final String TAG = "LegacyVpnRunner";
953
954        private final String[] mDaemons;
955        private final String[][] mArguments;
956        private final LocalSocket[] mSockets;
957        private final String mOuterInterface;
958        private final AtomicInteger mOuterConnection =
959                new AtomicInteger(ConnectivityManager.TYPE_NONE);
960
961        private long mTimer = -1;
962
963        /**
964         * Watch for the outer connection (passing in the constructor) going away.
965         */
966        private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
967            @Override
968            public void onReceive(Context context, Intent intent) {
969                if (!mEnableTeardown) return;
970
971                if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
972                    if (intent.getIntExtra(ConnectivityManager.EXTRA_NETWORK_TYPE,
973                            ConnectivityManager.TYPE_NONE) == mOuterConnection.get()) {
974                        NetworkInfo info = (NetworkInfo)intent.getExtra(
975                                ConnectivityManager.EXTRA_NETWORK_INFO);
976                        if (info != null && !info.isConnectedOrConnecting()) {
977                            try {
978                                mObserver.interfaceStatusChanged(mOuterInterface, false);
979                            } catch (RemoteException e) {}
980                        }
981                    }
982                }
983            }
984        };
985
986        public LegacyVpnRunner(VpnConfig config, String[] racoon, String[] mtpd) {
987            super(TAG);
988            mConfig = config;
989            mDaemons = new String[] {"racoon", "mtpd"};
990            // TODO: clear arguments from memory once launched
991            mArguments = new String[][] {racoon, mtpd};
992            mSockets = new LocalSocket[mDaemons.length];
993
994            // This is the interface which VPN is running on,
995            // mConfig.interfaze will change to point to OUR
996            // internal interface soon. TODO - add inner/outer to mconfig
997            // TODO - we have a race - if the outer iface goes away/disconnects before we hit this
998            // we will leave the VPN up.  We should check that it's still there/connected after
999            // registering
1000            mOuterInterface = mConfig.interfaze;
1001
1002            try {
1003                mOuterConnection.set(
1004                        mConnService.findConnectionTypeForIface(mOuterInterface));
1005            } catch (Exception e) {
1006                mOuterConnection.set(ConnectivityManager.TYPE_NONE);
1007            }
1008
1009            IntentFilter filter = new IntentFilter();
1010            filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
1011            mContext.registerReceiver(mBroadcastReceiver, filter);
1012        }
1013
1014        public void check(String interfaze) {
1015            if (interfaze.equals(mOuterInterface)) {
1016                Log.i(TAG, "Legacy VPN is going down with " + interfaze);
1017                exit();
1018            }
1019        }
1020
1021        public void exit() {
1022            // We assume that everything is reset after stopping the daemons.
1023            interrupt();
1024            for (LocalSocket socket : mSockets) {
1025                IoUtils.closeQuietly(socket);
1026            }
1027            agentDisconnect();
1028            try {
1029                mContext.unregisterReceiver(mBroadcastReceiver);
1030            } catch (IllegalArgumentException e) {}
1031        }
1032
1033        @Override
1034        public void run() {
1035            // Wait for the previous thread since it has been interrupted.
1036            Log.v(TAG, "Waiting");
1037            synchronized (TAG) {
1038                Log.v(TAG, "Executing");
1039                execute();
1040                monitorDaemons();
1041            }
1042        }
1043
1044        private void checkpoint(boolean yield) throws InterruptedException {
1045            long now = SystemClock.elapsedRealtime();
1046            if (mTimer == -1) {
1047                mTimer = now;
1048                Thread.sleep(1);
1049            } else if (now - mTimer <= 60000) {
1050                Thread.sleep(yield ? 200 : 1);
1051            } else {
1052                updateState(DetailedState.FAILED, "checkpoint");
1053                throw new IllegalStateException("Time is up");
1054            }
1055        }
1056
1057        private void execute() {
1058            // Catch all exceptions so we can clean up few things.
1059            boolean initFinished = false;
1060            try {
1061                // Initialize the timer.
1062                checkpoint(false);
1063
1064                // Wait for the daemons to stop.
1065                for (String daemon : mDaemons) {
1066                    while (!SystemService.isStopped(daemon)) {
1067                        checkpoint(true);
1068                    }
1069                }
1070
1071                // Clear the previous state.
1072                File state = new File("/data/misc/vpn/state");
1073                state.delete();
1074                if (state.exists()) {
1075                    throw new IllegalStateException("Cannot delete the state");
1076                }
1077                new File("/data/misc/vpn/abort").delete();
1078                initFinished = true;
1079
1080                // Check if we need to restart any of the daemons.
1081                boolean restart = false;
1082                for (String[] arguments : mArguments) {
1083                    restart = restart || (arguments != null);
1084                }
1085                if (!restart) {
1086                    agentDisconnect();
1087                    return;
1088                }
1089                updateState(DetailedState.CONNECTING, "execute");
1090
1091                // Start the daemon with arguments.
1092                for (int i = 0; i < mDaemons.length; ++i) {
1093                    String[] arguments = mArguments[i];
1094                    if (arguments == null) {
1095                        continue;
1096                    }
1097
1098                    // Start the daemon.
1099                    String daemon = mDaemons[i];
1100                    SystemService.start(daemon);
1101
1102                    // Wait for the daemon to start.
1103                    while (!SystemService.isRunning(daemon)) {
1104                        checkpoint(true);
1105                    }
1106
1107                    // Create the control socket.
1108                    mSockets[i] = new LocalSocket();
1109                    LocalSocketAddress address = new LocalSocketAddress(
1110                            daemon, LocalSocketAddress.Namespace.RESERVED);
1111
1112                    // Wait for the socket to connect.
1113                    while (true) {
1114                        try {
1115                            mSockets[i].connect(address);
1116                            break;
1117                        } catch (Exception e) {
1118                            // ignore
1119                        }
1120                        checkpoint(true);
1121                    }
1122                    mSockets[i].setSoTimeout(500);
1123
1124                    // Send over the arguments.
1125                    OutputStream out = mSockets[i].getOutputStream();
1126                    for (String argument : arguments) {
1127                        byte[] bytes = argument.getBytes(StandardCharsets.UTF_8);
1128                        if (bytes.length >= 0xFFFF) {
1129                            throw new IllegalArgumentException("Argument is too large");
1130                        }
1131                        out.write(bytes.length >> 8);
1132                        out.write(bytes.length);
1133                        out.write(bytes);
1134                        checkpoint(false);
1135                    }
1136                    out.write(0xFF);
1137                    out.write(0xFF);
1138                    out.flush();
1139
1140                    // Wait for End-of-File.
1141                    InputStream in = mSockets[i].getInputStream();
1142                    while (true) {
1143                        try {
1144                            if (in.read() == -1) {
1145                                break;
1146                            }
1147                        } catch (Exception e) {
1148                            // ignore
1149                        }
1150                        checkpoint(true);
1151                    }
1152                }
1153
1154                // Wait for the daemons to create the new state.
1155                while (!state.exists()) {
1156                    // Check if a running daemon is dead.
1157                    for (int i = 0; i < mDaemons.length; ++i) {
1158                        String daemon = mDaemons[i];
1159                        if (mArguments[i] != null && !SystemService.isRunning(daemon)) {
1160                            throw new IllegalStateException(daemon + " is dead");
1161                        }
1162                    }
1163                    checkpoint(true);
1164                }
1165
1166                // Now we are connected. Read and parse the new state.
1167                String[] parameters = FileUtils.readTextFile(state, 0, null).split("\n", -1);
1168                if (parameters.length != 6) {
1169                    throw new IllegalStateException("Cannot parse the state");
1170                }
1171
1172                // Set the interface and the addresses in the config.
1173                mConfig.interfaze = parameters[0].trim();
1174
1175                mConfig.addLegacyAddresses(parameters[1]);
1176                // Set the routes if they are not set in the config.
1177                if (mConfig.routes == null || mConfig.routes.isEmpty()) {
1178                    mConfig.addLegacyRoutes(parameters[2]);
1179                }
1180
1181                // Set the DNS servers if they are not set in the config.
1182                if (mConfig.dnsServers == null || mConfig.dnsServers.size() == 0) {
1183                    String dnsServers = parameters[3].trim();
1184                    if (!dnsServers.isEmpty()) {
1185                        mConfig.dnsServers = Arrays.asList(dnsServers.split(" "));
1186                    }
1187                }
1188
1189                // Set the search domains if they are not set in the config.
1190                if (mConfig.searchDomains == null || mConfig.searchDomains.size() == 0) {
1191                    String searchDomains = parameters[4].trim();
1192                    if (!searchDomains.isEmpty()) {
1193                        mConfig.searchDomains = Arrays.asList(searchDomains.split(" "));
1194                    }
1195                }
1196
1197                // Here is the last step and it must be done synchronously.
1198                synchronized (Vpn.this) {
1199                    // Set the start time
1200                    mConfig.startTime = SystemClock.elapsedRealtime();
1201
1202                    // Check if the thread is interrupted while we are waiting.
1203                    checkpoint(false);
1204
1205                    // Check if the interface is gone while we are waiting.
1206                    if (jniCheck(mConfig.interfaze) == 0) {
1207                        throw new IllegalStateException(mConfig.interfaze + " is gone");
1208                    }
1209
1210                    // Now INetworkManagementEventObserver is watching our back.
1211                    mInterface = mConfig.interfaze;
1212                    mVpnUsers = new ArrayList<UidRange>();
1213                    mAllowIPv4 = mConfig.allowIPv4;
1214                    mAllowIPv6 = mConfig.allowIPv6;
1215
1216                    agentConnect();
1217
1218                    Log.i(TAG, "Connected!");
1219                }
1220            } catch (Exception e) {
1221                Log.i(TAG, "Aborting", e);
1222                updateState(DetailedState.FAILED, e.getMessage());
1223                exit();
1224            } finally {
1225                // Kill the daemons if they fail to stop.
1226                if (!initFinished) {
1227                    for (String daemon : mDaemons) {
1228                        SystemService.stop(daemon);
1229                    }
1230                }
1231
1232                // Do not leave an unstable state.
1233                if (!initFinished || mNetworkInfo.getDetailedState() == DetailedState.CONNECTING) {
1234                    agentDisconnect();
1235                }
1236            }
1237        }
1238
1239        /**
1240         * Monitor the daemons we started, moving to disconnected state if the
1241         * underlying services fail.
1242         */
1243        private void monitorDaemons() {
1244            if (!mNetworkInfo.isConnected()) {
1245                return;
1246            }
1247
1248            try {
1249                while (true) {
1250                    Thread.sleep(2000);
1251                    for (int i = 0; i < mDaemons.length; i++) {
1252                        if (mArguments[i] != null && SystemService.isStopped(mDaemons[i])) {
1253                            return;
1254                        }
1255                    }
1256                }
1257            } catch (InterruptedException e) {
1258                Log.d(TAG, "interrupted during monitorDaemons(); stopping services");
1259            } finally {
1260                for (String daemon : mDaemons) {
1261                    SystemService.stop(daemon);
1262                }
1263
1264                agentDisconnect();
1265            }
1266        }
1267    }
1268}
1269