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