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