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