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