Vpn.java revision f5116d01b20f21ba32cd9eaa3412daf97f41c623
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.NetworkUtils; 48import android.net.RouteInfo; 49import android.net.NetworkInfo.DetailedState; 50import android.os.Binder; 51import android.os.FileUtils; 52import android.os.IBinder; 53import android.os.INetworkManagementService; 54import android.os.Parcel; 55import android.os.ParcelFileDescriptor; 56import android.os.Process; 57import android.os.RemoteException; 58import android.os.SystemClock; 59import android.os.SystemService; 60import android.os.UserHandle; 61import android.os.UserManager; 62import android.security.Credentials; 63import android.security.KeyStore; 64import android.util.Log; 65import android.util.SparseBooleanArray; 66 67import com.android.internal.annotations.GuardedBy; 68import com.android.internal.R; 69import com.android.internal.net.LegacyVpnInfo; 70import com.android.internal.net.VpnConfig; 71import com.android.internal.net.VpnProfile; 72import com.android.server.ConnectivityService.VpnCallback; 73import com.android.server.net.BaseNetworkObserver; 74 75import java.io.File; 76import java.io.InputStream; 77import java.io.OutputStream; 78import java.net.InetAddress; 79import java.net.Inet4Address; 80import java.nio.charset.StandardCharsets; 81import java.util.Arrays; 82import java.util.concurrent.atomic.AtomicInteger; 83 84import libcore.io.IoUtils; 85 86/** 87 * @hide 88 */ 89public class Vpn extends BaseNetworkStateTracker { 90 private static final String TAG = "Vpn"; 91 private static final boolean LOGD = true; 92 93 // TODO: create separate trackers for each unique VPN to support 94 // automated reconnection 95 96 private final VpnCallback mCallback; 97 98 private String mPackage = VpnConfig.LEGACY_VPN; 99 private String mInterface; 100 private Connection mConnection; 101 private LegacyVpnRunner mLegacyVpnRunner; 102 private PendingIntent mStatusIntent; 103 private volatile boolean mEnableNotif = true; 104 private volatile boolean mEnableTeardown = true; 105 private final IConnectivityManager mConnService; 106 private VpnConfig mConfig; 107 108 /* list of users using this VPN. */ 109 @GuardedBy("this") 110 private SparseBooleanArray mVpnUsers = null; 111 private BroadcastReceiver mUserIntentReceiver = null; 112 113 private final int mUserId; 114 115 public Vpn(Context context, VpnCallback callback, INetworkManagementService netService, 116 IConnectivityManager connService, int userId) { 117 // TODO: create dedicated TYPE_VPN network type 118 super(ConnectivityManager.TYPE_DUMMY); 119 mContext = context; 120 mCallback = callback; 121 mConnService = connService; 122 mUserId = userId; 123 124 try { 125 netService.registerObserver(mObserver); 126 } catch (RemoteException e) { 127 Log.wtf(TAG, "Problem registering observer", e); 128 } 129 if (userId == UserHandle.USER_OWNER) { 130 // Owner's VPN also needs to handle restricted users 131 mUserIntentReceiver = new BroadcastReceiver() { 132 @Override 133 public void onReceive(Context context, Intent intent) { 134 final String action = intent.getAction(); 135 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 136 UserHandle.USER_NULL); 137 if (userId == UserHandle.USER_NULL) return; 138 139 if (Intent.ACTION_USER_ADDED.equals(action)) { 140 onUserAdded(userId); 141 } else if (Intent.ACTION_USER_REMOVED.equals(action)) { 142 onUserRemoved(userId); 143 } 144 } 145 }; 146 147 IntentFilter intentFilter = new IntentFilter(); 148 intentFilter.addAction(Intent.ACTION_USER_ADDED); 149 intentFilter.addAction(Intent.ACTION_USER_REMOVED); 150 mContext.registerReceiverAsUser( 151 mUserIntentReceiver, UserHandle.ALL, intentFilter, null, null); 152 } 153 } 154 155 /** 156 * Set if this object is responsible for showing its own notifications. When 157 * {@code false}, notifications are handled externally by someone else. 158 */ 159 public void setEnableNotifications(boolean enableNotif) { 160 mEnableNotif = enableNotif; 161 } 162 163 /** 164 * Set if this object is responsible for watching for {@link NetworkInfo} 165 * teardown. When {@code false}, teardown is handled externally by someone 166 * else. 167 */ 168 public void setEnableTeardown(boolean enableTeardown) { 169 mEnableTeardown = enableTeardown; 170 } 171 172 @Override 173 protected void startMonitoringInternal() { 174 // Ignored; events are sent through callbacks for now 175 } 176 177 @Override 178 public boolean teardown() { 179 // TODO: finish migration to unique tracker for each VPN 180 throw new UnsupportedOperationException(); 181 } 182 183 @Override 184 public boolean reconnect() { 185 // TODO: finish migration to unique tracker for each VPN 186 throw new UnsupportedOperationException(); 187 } 188 189 @Override 190 public String getTcpBufferSizesPropName() { 191 return PROP_TCP_BUFFER_UNKNOWN; 192 } 193 194 /** 195 * Update current state, dispaching event to listeners. 196 */ 197 private void updateState(DetailedState detailedState, String reason) { 198 if (LOGD) Log.d(TAG, "setting state=" + detailedState + ", reason=" + reason); 199 mNetworkInfo.setDetailedState(detailedState, reason, null); 200 mCallback.onStateChanged(new NetworkInfo(mNetworkInfo)); 201 } 202 203 /** 204 * Prepare for a VPN application. This method is designed to solve 205 * race conditions. It first compares the current prepared package 206 * with {@code oldPackage}. If they are the same, the prepared 207 * package is revoked and replaced with {@code newPackage}. If 208 * {@code oldPackage} is {@code null}, the comparison is omitted. 209 * If {@code newPackage} is the same package or {@code null}, the 210 * revocation is omitted. This method returns {@code true} if the 211 * operation is succeeded. 212 * 213 * Legacy VPN is handled specially since it is not a real package. 214 * It uses {@link VpnConfig#LEGACY_VPN} as its package name, and 215 * it can be revoked by itself. 216 * 217 * @param oldPackage The package name of the old VPN application. 218 * @param newPackage The package name of the new VPN application. 219 * @return true if the operation is succeeded. 220 */ 221 public synchronized boolean prepare(String oldPackage, String newPackage) { 222 // Return false if the package does not match. 223 if (oldPackage != null && !oldPackage.equals(mPackage)) { 224 return false; 225 } 226 227 // Return true if we do not need to revoke. 228 if (newPackage == null || 229 (newPackage.equals(mPackage) && !newPackage.equals(VpnConfig.LEGACY_VPN))) { 230 return true; 231 } 232 233 // Check if the caller is authorized. 234 enforceControlPermission(); 235 236 // Reset the interface and hide the notification. 237 if (mInterface != null) { 238 final long token = Binder.clearCallingIdentity(); 239 try { 240 mCallback.restore(); 241 final int size = mVpnUsers.size(); 242 final boolean forwardDns = (mConfig.dnsServers != null && 243 mConfig.dnsServers.size() != 0); 244 for (int i = 0; i < size; i++) { 245 int user = mVpnUsers.keyAt(i); 246 mCallback.clearUserForwarding(mInterface, user, forwardDns); 247 hideNotification(user); 248 } 249 250 mCallback.clearMarkedForwarding(mInterface); 251 } finally { 252 Binder.restoreCallingIdentity(token); 253 } 254 jniReset(mInterface); 255 mInterface = null; 256 mVpnUsers = null; 257 } 258 259 // Revoke the connection or stop LegacyVpnRunner. 260 if (mConnection != null) { 261 try { 262 mConnection.mService.transact(IBinder.LAST_CALL_TRANSACTION, 263 Parcel.obtain(), null, IBinder.FLAG_ONEWAY); 264 } catch (Exception e) { 265 // ignore 266 } 267 mContext.unbindService(mConnection); 268 mConnection = null; 269 } else if (mLegacyVpnRunner != null) { 270 mLegacyVpnRunner.exit(); 271 mLegacyVpnRunner = null; 272 } 273 274 Log.i(TAG, "Switched from " + mPackage + " to " + newPackage); 275 mPackage = newPackage; 276 mConfig = null; 277 updateState(DetailedState.IDLE, "prepare"); 278 return true; 279 } 280 281 /** 282 * Protect a socket from VPN rules by binding it to the main routing table. 283 * The socket is NOT closed by this method. 284 * 285 * @param socket The socket to be bound. 286 */ 287 public void protect(ParcelFileDescriptor socket) throws Exception { 288 289 PackageManager pm = mContext.getPackageManager(); 290 int appUid = pm.getPackageUid(mPackage, mUserId); 291 if (Binder.getCallingUid() != appUid) { 292 throw new SecurityException("Unauthorized Caller"); 293 } 294 // protect the socket from routing rules 295 final long token = Binder.clearCallingIdentity(); 296 try { 297 mCallback.protect(socket); 298 } finally { 299 Binder.restoreCallingIdentity(token); 300 } 301 302 } 303 304 /** 305 * Establish a VPN network and return the file descriptor of the VPN 306 * interface. This methods returns {@code null} if the application is 307 * revoked or not prepared. 308 * 309 * @param config The parameters to configure the network. 310 * @return The file descriptor of the VPN interface. 311 */ 312 public synchronized ParcelFileDescriptor establish(VpnConfig config) { 313 // Check if the caller is already prepared. 314 UserManager mgr = UserManager.get(mContext); 315 PackageManager pm = mContext.getPackageManager(); 316 ApplicationInfo app = null; 317 try { 318 app = AppGlobals.getPackageManager().getApplicationInfo(mPackage, 0, mUserId); 319 if (Binder.getCallingUid() != app.uid) { 320 return null; 321 } 322 } catch (Exception e) { 323 return null; 324 } 325 // Check if the service is properly declared. 326 Intent intent = new Intent(VpnConfig.SERVICE_INTERFACE); 327 intent.setClassName(mPackage, config.user); 328 long token = Binder.clearCallingIdentity(); 329 try { 330 // Restricted users are not allowed to create VPNs, they are tied to Owner 331 UserInfo user = mgr.getUserInfo(mUserId); 332 if (user.isRestricted() || mgr.hasUserRestriction(UserManager.DISALLOW_CONFIG_VPN)) { 333 throw new SecurityException("Restricted users cannot establish VPNs"); 334 } 335 336 ResolveInfo info = AppGlobals.getPackageManager().resolveService(intent, 337 null, 0, mUserId); 338 if (info == null) { 339 throw new SecurityException("Cannot find " + config.user); 340 } 341 if (!BIND_VPN_SERVICE.equals(info.serviceInfo.permission)) { 342 throw new SecurityException(config.user + " does not require " + BIND_VPN_SERVICE); 343 } 344 } catch (RemoteException e) { 345 throw new SecurityException("Cannot find " + config.user); 346 } finally { 347 Binder.restoreCallingIdentity(token); 348 } 349 350 // Save the old config in case we need to go back. 351 VpnConfig oldConfig = mConfig; 352 String oldInterface = mInterface; 353 Connection oldConnection = mConnection; 354 SparseBooleanArray oldUsers = mVpnUsers; 355 356 // Configure the interface. Abort if any of these steps fails. 357 ParcelFileDescriptor tun = ParcelFileDescriptor.adoptFd(jniCreate(config.mtu)); 358 try { 359 updateState(DetailedState.CONNECTING, "establish"); 360 String interfaze = jniGetName(tun.getFd()); 361 362 // TEMP use the old jni calls until there is support for netd address setting 363 StringBuilder builder = new StringBuilder(); 364 for (LinkAddress address : config.addresses) { 365 builder.append(" " + address); 366 } 367 if (jniSetAddresses(interfaze, builder.toString()) < 1) { 368 throw new IllegalArgumentException("At least one address must be specified"); 369 } 370 Connection connection = new Connection(); 371 if (!mContext.bindServiceAsUser(intent, connection, Context.BIND_AUTO_CREATE, 372 new UserHandle(mUserId))) { 373 throw new IllegalStateException("Cannot bind " + config.user); 374 } 375 376 mConnection = connection; 377 mInterface = interfaze; 378 379 // Fill more values. 380 config.user = mPackage; 381 config.interfaze = mInterface; 382 config.startTime = SystemClock.elapsedRealtime(); 383 mConfig = config; 384 385 // Set up forwarding and DNS rules. 386 mVpnUsers = new SparseBooleanArray(); 387 token = Binder.clearCallingIdentity(); 388 try { 389 mCallback.setMarkedForwarding(mInterface); 390 mCallback.setRoutes(mInterface, config.routes); 391 mCallback.override(mInterface, config.dnsServers, config.searchDomains); 392 addVpnUserLocked(mUserId); 393 // If we are owner assign all Restricted Users to this VPN 394 if (mUserId == UserHandle.USER_OWNER) { 395 for (UserInfo user : mgr.getUsers()) { 396 if (user.isRestricted()) { 397 try { 398 addVpnUserLocked(user.id); 399 } catch (Exception e) { 400 Log.wtf(TAG, "Failed to add user " + user.id + " to owner's VPN"); 401 } 402 } 403 } 404 } 405 } finally { 406 Binder.restoreCallingIdentity(token); 407 } 408 409 if (oldConnection != null) { 410 mContext.unbindService(oldConnection); 411 } 412 if (oldInterface != null && !oldInterface.equals(interfaze)) { 413 // Remove the old tun's user forwarding rules 414 // The new tun's user rules have already been added so they will take over 415 // as rules are deleted. This prevents data leakage as the rules are moved over. 416 token = Binder.clearCallingIdentity(); 417 try { 418 final int size = oldUsers.size(); 419 final boolean forwardDns = (oldConfig.dnsServers != null && 420 oldConfig.dnsServers.size() != 0); 421 for (int i = 0; i < size; i++) { 422 int user = oldUsers.keyAt(i); 423 mCallback.clearUserForwarding(oldInterface, user, forwardDns); 424 } 425 mCallback.clearMarkedForwarding(oldInterface); 426 } finally { 427 Binder.restoreCallingIdentity(token); 428 } 429 jniReset(oldInterface); 430 } 431 } catch (RuntimeException e) { 432 updateState(DetailedState.FAILED, "establish"); 433 IoUtils.closeQuietly(tun); 434 // make sure marked forwarding is cleared if it was set 435 token = Binder.clearCallingIdentity(); 436 try { 437 mCallback.clearMarkedForwarding(mInterface); 438 } catch (Exception ingored) { 439 // ignored 440 } finally { 441 Binder.restoreCallingIdentity(token); 442 } 443 // restore old state 444 mConfig = oldConfig; 445 mConnection = oldConnection; 446 mVpnUsers = oldUsers; 447 mInterface = oldInterface; 448 throw e; 449 } 450 Log.i(TAG, "Established by " + config.user + " on " + mInterface); 451 452 // TODO: ensure that contract class eventually marks as connected 453 updateState(DetailedState.AUTHENTICATING, "establish"); 454 return tun; 455 } 456 457 /** 458 * Check if a given address is covered by the VPN's routing rules. 459 */ 460 public boolean isAddressCovered(InetAddress address) { 461 synchronized (Vpn.this) { 462 if (!isRunningLocked()) { 463 return false; 464 } 465 return RouteInfo.selectBestRoute(mConfig.routes, address) != null; 466 } 467 } 468 469 private boolean isRunningLocked() { 470 return mVpnUsers != null; 471 } 472 473 private void addVpnUserLocked(int user) { 474 enforceControlPermission(); 475 476 if (!isRunningLocked()) { 477 throw new IllegalStateException("VPN is not active"); 478 } 479 480 final boolean forwardDns = (mConfig.dnsServers != null && 481 mConfig.dnsServers.size() != 0); 482 483 // add the user 484 mCallback.addUserForwarding(mInterface, user, forwardDns); 485 mVpnUsers.put(user, true); 486 487 // show the notification 488 if (!mPackage.equals(VpnConfig.LEGACY_VPN)) { 489 // Load everything for the user's notification 490 PackageManager pm = mContext.getPackageManager(); 491 ApplicationInfo app = null; 492 try { 493 app = AppGlobals.getPackageManager().getApplicationInfo(mPackage, 0, mUserId); 494 } catch (RemoteException e) { 495 throw new IllegalStateException("Invalid application"); 496 } 497 String label = app.loadLabel(pm).toString(); 498 // Load the icon and convert it into a bitmap. 499 Drawable icon = app.loadIcon(pm); 500 Bitmap bitmap = null; 501 if (icon.getIntrinsicWidth() > 0 && icon.getIntrinsicHeight() > 0) { 502 int width = mContext.getResources().getDimensionPixelSize( 503 android.R.dimen.notification_large_icon_width); 504 int height = mContext.getResources().getDimensionPixelSize( 505 android.R.dimen.notification_large_icon_height); 506 icon.setBounds(0, 0, width, height); 507 bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 508 Canvas c = new Canvas(bitmap); 509 icon.draw(c); 510 c.setBitmap(null); 511 } 512 showNotification(label, bitmap, user); 513 } else { 514 showNotification(null, null, user); 515 } 516 } 517 518 private void removeVpnUserLocked(int user) { 519 enforceControlPermission(); 520 521 if (!isRunningLocked()) { 522 throw new IllegalStateException("VPN is not active"); 523 } 524 final boolean forwardDns = (mConfig.dnsServers != null && 525 mConfig.dnsServers.size() != 0); 526 mCallback.clearUserForwarding(mInterface, user, forwardDns); 527 mVpnUsers.delete(user); 528 hideNotification(user); 529 } 530 531 private void onUserAdded(int userId) { 532 // If the user is restricted tie them to the owner's VPN 533 synchronized(Vpn.this) { 534 UserManager mgr = UserManager.get(mContext); 535 UserInfo user = mgr.getUserInfo(userId); 536 if (user.isRestricted()) { 537 try { 538 addVpnUserLocked(userId); 539 } catch (Exception e) { 540 Log.wtf(TAG, "Failed to add restricted user to owner", e); 541 } 542 } 543 } 544 } 545 546 private void onUserRemoved(int userId) { 547 // clean up if restricted 548 synchronized(Vpn.this) { 549 UserManager mgr = UserManager.get(mContext); 550 UserInfo user = mgr.getUserInfo(userId); 551 if (user.isRestricted()) { 552 try { 553 removeVpnUserLocked(userId); 554 } catch (Exception e) { 555 Log.wtf(TAG, "Failed to remove restricted user to owner", e); 556 } 557 } 558 } 559 } 560 561 /** 562 * Return the configuration of the currently running VPN. 563 */ 564 public VpnConfig getVpnConfig() { 565 enforceControlPermission(); 566 return mConfig; 567 } 568 569 @Deprecated 570 public synchronized void interfaceStatusChanged(String iface, boolean up) { 571 try { 572 mObserver.interfaceStatusChanged(iface, up); 573 } catch (RemoteException e) { 574 // ignored; target is local 575 } 576 } 577 578 private INetworkManagementEventObserver mObserver = new BaseNetworkObserver() { 579 @Override 580 public void interfaceStatusChanged(String interfaze, boolean up) { 581 synchronized (Vpn.this) { 582 if (!up && mLegacyVpnRunner != null) { 583 mLegacyVpnRunner.check(interfaze); 584 } 585 } 586 } 587 588 @Override 589 public void interfaceRemoved(String interfaze) { 590 synchronized (Vpn.this) { 591 if (interfaze.equals(mInterface) && jniCheck(interfaze) == 0) { 592 final long token = Binder.clearCallingIdentity(); 593 try { 594 final int size = mVpnUsers.size(); 595 final boolean forwardDns = (mConfig.dnsServers != null && 596 mConfig.dnsServers.size() != 0); 597 for (int i = 0; i < size; i++) { 598 int user = mVpnUsers.keyAt(i); 599 mCallback.clearUserForwarding(mInterface, user, forwardDns); 600 hideNotification(user); 601 } 602 mVpnUsers = null; 603 mCallback.clearMarkedForwarding(mInterface); 604 605 mCallback.restore(); 606 } finally { 607 Binder.restoreCallingIdentity(token); 608 } 609 mInterface = null; 610 if (mConnection != null) { 611 mContext.unbindService(mConnection); 612 mConnection = null; 613 updateState(DetailedState.DISCONNECTED, "interfaceRemoved"); 614 } else if (mLegacyVpnRunner != null) { 615 mLegacyVpnRunner.exit(); 616 mLegacyVpnRunner = null; 617 } 618 } 619 } 620 } 621 }; 622 623 private void enforceControlPermission() { 624 // System user is allowed to control VPN. 625 if (Binder.getCallingUid() == Process.SYSTEM_UID) { 626 return; 627 } 628 int appId = UserHandle.getAppId(Binder.getCallingUid()); 629 final long token = Binder.clearCallingIdentity(); 630 try { 631 // System VPN dialogs are also allowed to control VPN. 632 PackageManager pm = mContext.getPackageManager(); 633 ApplicationInfo app = pm.getApplicationInfo(VpnConfig.DIALOGS_PACKAGE, 0); 634 if (((app.flags & ApplicationInfo.FLAG_SYSTEM) != 0) && (appId == app.uid)) { 635 return; 636 } 637 } catch (Exception e) { 638 // ignore 639 } finally { 640 Binder.restoreCallingIdentity(token); 641 } 642 643 throw new SecurityException("Unauthorized Caller"); 644 } 645 646 private class Connection implements ServiceConnection { 647 private IBinder mService; 648 649 @Override 650 public void onServiceConnected(ComponentName name, IBinder service) { 651 mService = service; 652 } 653 654 @Override 655 public void onServiceDisconnected(ComponentName name) { 656 mService = null; 657 } 658 } 659 660 private void showNotification(String label, Bitmap icon, int user) { 661 if (!mEnableNotif) return; 662 mStatusIntent = VpnConfig.getIntentForStatusPanel(mContext); 663 664 NotificationManager nm = (NotificationManager) 665 mContext.getSystemService(Context.NOTIFICATION_SERVICE); 666 667 if (nm != null) { 668 String title = (label == null) ? mContext.getString(R.string.vpn_title) : 669 mContext.getString(R.string.vpn_title_long, label); 670 String text = (mConfig.session == null) ? mContext.getString(R.string.vpn_text) : 671 mContext.getString(R.string.vpn_text_long, mConfig.session); 672 673 Notification notification = new Notification.Builder(mContext) 674 .setSmallIcon(R.drawable.vpn_connected) 675 .setLargeIcon(icon) 676 .setContentTitle(title) 677 .setContentText(text) 678 .setContentIntent(mStatusIntent) 679 .setDefaults(0) 680 .setOngoing(true) 681 .build(); 682 nm.notifyAsUser(null, R.drawable.vpn_connected, notification, new UserHandle(user)); 683 } 684 } 685 686 private void hideNotification(int user) { 687 if (!mEnableNotif) return; 688 mStatusIntent = null; 689 690 NotificationManager nm = (NotificationManager) 691 mContext.getSystemService(Context.NOTIFICATION_SERVICE); 692 693 if (nm != null) { 694 nm.cancelAsUser(null, R.drawable.vpn_connected, new UserHandle(user)); 695 } 696 } 697 698 private native int jniCreate(int mtu); 699 private native String jniGetName(int tun); 700 private native int jniSetAddresses(String interfaze, String addresses); 701 private native int jniSetRoutes(String interfaze, String routes); 702 private native void jniReset(String interfaze); 703 private native int jniCheck(String interfaze); 704 705 private static RouteInfo findIPv4DefaultRoute(LinkProperties prop) { 706 for (RouteInfo route : prop.getAllRoutes()) { 707 // Currently legacy VPN only works on IPv4. 708 if (route.isDefaultRoute() && route.getGateway() instanceof Inet4Address) { 709 return route; 710 } 711 } 712 713 throw new IllegalStateException("Unable to find IPv4 default gateway"); 714 } 715 716 /** 717 * Start legacy VPN, controlling native daemons as needed. Creates a 718 * secondary thread to perform connection work, returning quickly. 719 */ 720 public void startLegacyVpn(VpnProfile profile, KeyStore keyStore, LinkProperties egress) { 721 enforceControlPermission(); 722 if (!keyStore.isUnlocked()) { 723 throw new IllegalStateException("KeyStore isn't unlocked"); 724 } 725 UserManager mgr = UserManager.get(mContext); 726 UserInfo user = mgr.getUserInfo(mUserId); 727 if (user.isRestricted() || mgr.hasUserRestriction(UserManager.DISALLOW_CONFIG_VPN)) { 728 throw new SecurityException("Restricted users cannot establish VPNs"); 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 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 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 */ 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 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 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 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 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 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 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 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 */ 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