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