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