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