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