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