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