IpSecManager.java revision 5cd64cc8012243c656875be6b84456caeabd60f5
1/* 2 * Copyright (C) 2017 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 */ 16package android.net; 17 18import static com.android.internal.util.Preconditions.checkNotNull; 19 20import android.annotation.IntDef; 21import android.annotation.NonNull; 22import android.annotation.RequiresPermission; 23import android.annotation.SystemApi; 24import android.annotation.SystemService; 25import android.annotation.TestApi; 26import android.content.Context; 27import android.os.Binder; 28import android.os.ParcelFileDescriptor; 29import android.os.RemoteException; 30import android.util.AndroidException; 31import android.util.Log; 32 33import com.android.internal.annotations.VisibleForTesting; 34 35import dalvik.system.CloseGuard; 36 37import java.io.FileDescriptor; 38import java.io.IOException; 39import java.lang.annotation.Retention; 40import java.lang.annotation.RetentionPolicy; 41import java.net.DatagramSocket; 42import java.net.InetAddress; 43import java.net.Socket; 44 45/** 46 * This class contains methods for managing IPsec sessions. Once configured, the kernel will apply 47 * confidentiality (encryption) and integrity (authentication) to IP traffic. 48 * 49 * <p>Note that not all aspects of IPsec are permitted by this API. Applications may create 50 * transport mode security associations and apply them to individual sockets. Applications looking 51 * to create a VPN should use {@link VpnService}. 52 * 53 * @see <a href="https://tools.ietf.org/html/rfc4301">RFC 4301, Security Architecture for the 54 * Internet Protocol</a> 55 */ 56@SystemService(Context.IPSEC_SERVICE) 57public final class IpSecManager { 58 private static final String TAG = "IpSecManager"; 59 60 /** 61 * Used when applying a transform to direct traffic through an {@link IpSecTransform} 62 * towards the host. 63 * 64 * <p>See {@link #applyTransportModeTransform(Socket, int, IpSecTransform)}. 65 */ 66 public static final int DIRECTION_IN = 0; 67 68 /** 69 * Used when applying a transform to direct traffic through an {@link IpSecTransform} 70 * away from the host. 71 * 72 * <p>See {@link #applyTransportModeTransform(Socket, int, IpSecTransform)}. 73 */ 74 public static final int DIRECTION_OUT = 1; 75 76 /** @hide */ 77 @IntDef(value = {DIRECTION_IN, DIRECTION_OUT}) 78 @Retention(RetentionPolicy.SOURCE) 79 public @interface PolicyDirection {} 80 81 /** 82 * The Security Parameter Index (SPI) 0 indicates an unknown or invalid index. 83 * 84 * <p>No IPsec packet may contain an SPI of 0. 85 * 86 * @hide 87 */ 88 @TestApi public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; 89 90 /** @hide */ 91 public interface Status { 92 public static final int OK = 0; 93 public static final int RESOURCE_UNAVAILABLE = 1; 94 public static final int SPI_UNAVAILABLE = 2; 95 } 96 97 /** @hide */ 98 public static final int INVALID_RESOURCE_ID = -1; 99 100 /** 101 * Thrown to indicate that a requested SPI is in use. 102 * 103 * <p>The combination of remote {@code InetAddress} and SPI must be unique across all apps on 104 * one device. If this error is encountered, a new SPI is required before a transform may be 105 * created. This error can be avoided by calling {@link 106 * IpSecManager#allocateSecurityParameterIndex}. 107 */ 108 public static final class SpiUnavailableException extends AndroidException { 109 private final int mSpi; 110 111 /** 112 * Construct an exception indicating that a transform with the given SPI is already in use 113 * or otherwise unavailable. 114 * 115 * @param msg description indicating the colliding SPI 116 * @param spi the SPI that could not be used due to a collision 117 */ 118 SpiUnavailableException(String msg, int spi) { 119 super(msg + " (spi: " + spi + ")"); 120 mSpi = spi; 121 } 122 123 /** Get the SPI that caused a collision. */ 124 public int getSpi() { 125 return mSpi; 126 } 127 } 128 129 /** 130 * Thrown to indicate that an IPsec resource is unavailable. 131 * 132 * <p>This could apply to resources such as sockets, {@link SecurityParameterIndex}, {@link 133 * IpSecTransform}, or other system resources. If this exception is thrown, users should release 134 * allocated objects of the type requested. 135 */ 136 public static final class ResourceUnavailableException extends AndroidException { 137 138 ResourceUnavailableException(String msg) { 139 super(msg); 140 } 141 } 142 143 private final IIpSecService mService; 144 145 /** 146 * This class represents a reserved SPI. 147 * 148 * <p>Objects of this type are used to track reserved security parameter indices. They can be 149 * obtained by calling {@link IpSecManager#allocateSecurityParameterIndex} and must be released 150 * by calling {@link #close()} when they are no longer needed. 151 */ 152 public static final class SecurityParameterIndex implements AutoCloseable { 153 private final IIpSecService mService; 154 private final InetAddress mDestinationAddress; 155 private final CloseGuard mCloseGuard = CloseGuard.get(); 156 private int mSpi = INVALID_SECURITY_PARAMETER_INDEX; 157 private int mResourceId = INVALID_RESOURCE_ID; 158 159 /** Get the underlying SPI held by this object. */ 160 public int getSpi() { 161 return mSpi; 162 } 163 164 /** 165 * Release an SPI that was previously reserved. 166 * 167 * <p>Release an SPI for use by other users in the system. If a SecurityParameterIndex is 168 * applied to an IpSecTransform, it will become unusable for future transforms but should 169 * still be closed to ensure system resources are released. 170 */ 171 @Override 172 public void close() { 173 try { 174 mService.releaseSecurityParameterIndex(mResourceId); 175 mResourceId = INVALID_RESOURCE_ID; 176 } catch (RemoteException e) { 177 throw e.rethrowFromSystemServer(); 178 } 179 mCloseGuard.close(); 180 } 181 182 /** Check that the SPI was closed properly. */ 183 @Override 184 protected void finalize() throws Throwable { 185 if (mCloseGuard != null) { 186 mCloseGuard.warnIfOpen(); 187 } 188 189 close(); 190 } 191 192 private SecurityParameterIndex( 193 @NonNull IIpSecService service, InetAddress destinationAddress, int spi) 194 throws ResourceUnavailableException, SpiUnavailableException { 195 mService = service; 196 mDestinationAddress = destinationAddress; 197 try { 198 IpSecSpiResponse result = 199 mService.allocateSecurityParameterIndex( 200 destinationAddress.getHostAddress(), spi, new Binder()); 201 202 if (result == null) { 203 throw new NullPointerException("Received null response from IpSecService"); 204 } 205 206 int status = result.status; 207 switch (status) { 208 case Status.OK: 209 break; 210 case Status.RESOURCE_UNAVAILABLE: 211 throw new ResourceUnavailableException( 212 "No more SPIs may be allocated by this requester."); 213 case Status.SPI_UNAVAILABLE: 214 throw new SpiUnavailableException("Requested SPI is unavailable", spi); 215 default: 216 throw new RuntimeException( 217 "Unknown status returned by IpSecService: " + status); 218 } 219 mSpi = result.spi; 220 mResourceId = result.resourceId; 221 222 if (mSpi == INVALID_SECURITY_PARAMETER_INDEX) { 223 throw new RuntimeException("Invalid SPI returned by IpSecService: " + status); 224 } 225 226 if (mResourceId == INVALID_RESOURCE_ID) { 227 throw new RuntimeException( 228 "Invalid Resource ID returned by IpSecService: " + status); 229 } 230 231 } catch (RemoteException e) { 232 throw e.rethrowFromSystemServer(); 233 } 234 mCloseGuard.open("open"); 235 } 236 237 /** @hide */ 238 @VisibleForTesting 239 public int getResourceId() { 240 return mResourceId; 241 } 242 } 243 244 /** 245 * Reserve a random SPI for traffic bound to or from the specified destination address. 246 * 247 * <p>If successful, this SPI is guaranteed available until released by a call to {@link 248 * SecurityParameterIndex#close()}. 249 * 250 * @param destinationAddress the destination address for traffic bearing the requested SPI. 251 * For inbound traffic, the destination should be an address currently assigned on-device. 252 * @return the reserved SecurityParameterIndex 253 * @throws {@link #ResourceUnavailableException} indicating that too many SPIs are 254 * currently allocated for this user 255 */ 256 @NonNull 257 public SecurityParameterIndex allocateSecurityParameterIndex( 258 @NonNull InetAddress destinationAddress) throws ResourceUnavailableException { 259 try { 260 return new SecurityParameterIndex( 261 mService, 262 destinationAddress, 263 IpSecManager.INVALID_SECURITY_PARAMETER_INDEX); 264 } catch (SpiUnavailableException unlikely) { 265 throw new ResourceUnavailableException("No SPIs available"); 266 } 267 } 268 269 /** 270 * Reserve the requested SPI for traffic bound to or from the specified destination address. 271 * 272 * <p>If successful, this SPI is guaranteed available until released by a call to {@link 273 * SecurityParameterIndex#close()}. 274 * 275 * @param destinationAddress the destination address for traffic bearing the requested SPI. 276 * For inbound traffic, the destination should be an address currently assigned on-device. 277 * @param requestedSpi the requested SPI, or '0' to allocate a random SPI 278 * @return the reserved SecurityParameterIndex 279 * @throws {@link #ResourceUnavailableException} indicating that too many SPIs are 280 * currently allocated for this user 281 * @throws {@link #SpiUnavailableException} indicating that the requested SPI could not be 282 * reserved 283 */ 284 @NonNull 285 public SecurityParameterIndex allocateSecurityParameterIndex( 286 @NonNull InetAddress destinationAddress, int requestedSpi) 287 throws SpiUnavailableException, ResourceUnavailableException { 288 if (requestedSpi == IpSecManager.INVALID_SECURITY_PARAMETER_INDEX) { 289 throw new IllegalArgumentException("Requested SPI must be a valid (non-zero) SPI"); 290 } 291 return new SecurityParameterIndex(mService, destinationAddress, requestedSpi); 292 } 293 294 /** 295 * Apply an IPsec transform to a stream socket. 296 * 297 * <p>This applies transport mode encapsulation to the given socket. Once applied, I/O on the 298 * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When 299 * the transform is removed from the socket by calling {@link #removeTransportModeTransforms}, 300 * unprotected traffic can resume on that socket. 301 * 302 * <p>For security reasons, the destination address of any traffic on the socket must match the 303 * remote {@code InetAddress} of the {@code IpSecTransform}. Attempts to send traffic to any 304 * other IP address will result in an IOException. In addition, reads and writes on the socket 305 * will throw IOException if the user deactivates the transform (by calling {@link 306 * IpSecTransform#close()}) without calling {@link #removeTransportModeTransforms}. 307 * 308 * <h4>Rekey Procedure</h4> 309 * 310 * <p>When applying a new tranform to a socket in the outbound direction, the previous transform 311 * will be removed and the new transform will take effect immediately, sending all traffic on 312 * the new transform; however, when applying a transform in the inbound direction, traffic 313 * on the old transform will continue to be decrypted and delivered until that transform is 314 * deallocated by calling {@link IpSecTransform#close()}. This overlap allows lossless rekey 315 * procedures where both transforms are valid until both endpoints are using the new transform 316 * and all in-flight packets have been received. 317 * 318 * @param socket a stream socket 319 * @param direction the direction in which the transform should be applied 320 * @param transform a transport mode {@code IpSecTransform} 321 * @throws IOException indicating that the transform could not be applied 322 */ 323 public void applyTransportModeTransform(@NonNull Socket socket, 324 @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException { 325 applyTransportModeTransform(socket.getFileDescriptor$(), direction, transform); 326 } 327 328 /** 329 * Apply an IPsec transform to a datagram socket. 330 * 331 * <p>This applies transport mode encapsulation to the given socket. Once applied, I/O on the 332 * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When 333 * the transform is removed from the socket by calling {@link #removeTransportModeTransforms}, 334 * unprotected traffic can resume on that socket. 335 * 336 * <p>For security reasons, the destination address of any traffic on the socket must match the 337 * remote {@code InetAddress} of the {@code IpSecTransform}. Attempts to send traffic to any 338 * other IP address will result in an IOException. In addition, reads and writes on the socket 339 * will throw IOException if the user deactivates the transform (by calling {@link 340 * IpSecTransform#close()}) without calling {@link #removeTransportModeTransforms}. 341 * 342 * <h4>Rekey Procedure</h4> 343 * 344 * <p>When applying a new tranform to a socket in the outbound direction, the previous transform 345 * will be removed and the new transform will take effect immediately, sending all traffic on 346 * the new transform; however, when applying a transform in the inbound direction, traffic 347 * on the old transform will continue to be decrypted and delivered until that transform is 348 * deallocated by calling {@link IpSecTransform#close()}. This overlap allows lossless rekey 349 * procedures where both transforms are valid until both endpoints are using the new transform 350 * and all in-flight packets have been received. 351 * 352 * @param socket a datagram socket 353 * @param direction the direction in which the transform should be applied 354 * @param transform a transport mode {@code IpSecTransform} 355 * @throws IOException indicating that the transform could not be applied 356 */ 357 public void applyTransportModeTransform(@NonNull DatagramSocket socket, 358 @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException { 359 applyTransportModeTransform(socket.getFileDescriptor$(), direction, transform); 360 } 361 362 /** 363 * Apply an IPsec transform to a socket. 364 * 365 * <p>This applies transport mode encapsulation to the given socket. Once applied, I/O on the 366 * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When 367 * the transform is removed from the socket by calling {@link #removeTransportModeTransforms}, 368 * unprotected traffic can resume on that socket. 369 * 370 * <p>For security reasons, the destination address of any traffic on the socket must match the 371 * remote {@code InetAddress} of the {@code IpSecTransform}. Attempts to send traffic to any 372 * other IP address will result in an IOException. In addition, reads and writes on the socket 373 * will throw IOException if the user deactivates the transform (by calling {@link 374 * IpSecTransform#close()}) without calling {@link #removeTransportModeTransforms}. 375 * 376 * <h4>Rekey Procedure</h4> 377 * 378 * <p>When applying a new tranform to a socket in the outbound direction, the previous transform 379 * will be removed and the new transform will take effect immediately, sending all traffic on 380 * the new transform; however, when applying a transform in the inbound direction, traffic 381 * on the old transform will continue to be decrypted and delivered until that transform is 382 * deallocated by calling {@link IpSecTransform#close()}. This overlap allows lossless rekey 383 * procedures where both transforms are valid until both endpoints are using the new transform 384 * and all in-flight packets have been received. 385 * 386 * @param socket a socket file descriptor 387 * @param direction the direction in which the transform should be applied 388 * @param transform a transport mode {@code IpSecTransform} 389 * @throws IOException indicating that the transform could not be applied 390 */ 391 public void applyTransportModeTransform(@NonNull FileDescriptor socket, 392 @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException { 393 // We dup() the FileDescriptor here because if we don't, then the ParcelFileDescriptor() 394 // constructor takes control and closes the user's FD when we exit the method. 395 try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) { 396 mService.applyTransportModeTransform(pfd, direction, transform.getResourceId()); 397 } catch (RemoteException e) { 398 throw e.rethrowFromSystemServer(); 399 } 400 } 401 402 /** 403 * Remove an IPsec transform from a stream socket. 404 * 405 * <p>Once removed, traffic on the socket will not be encrypted. Removing transforms from a 406 * socket allows the socket to be reused for communication in the clear. 407 * 408 * <p>If an {@code IpSecTransform} object applied to this socket was deallocated by calling 409 * {@link IpSecTransform#close()}, then communication on the socket will fail until this method 410 * is called. 411 * 412 * @param socket a socket that previously had a transform applied to it 413 * @throws IOException indicating that the transform could not be removed from the socket 414 */ 415 public void removeTransportModeTransforms(@NonNull Socket socket) throws IOException { 416 removeTransportModeTransforms(socket.getFileDescriptor$()); 417 } 418 419 /** 420 * Remove an IPsec transform from a datagram socket. 421 * 422 * <p>Once removed, traffic on the socket will not be encrypted. Removing transforms from a 423 * socket allows the socket to be reused for communication in the clear. 424 * 425 * <p>If an {@code IpSecTransform} object applied to this socket was deallocated by calling 426 * {@link IpSecTransform#close()}, then communication on the socket will fail until this method 427 * is called. 428 * 429 * @param socket a socket that previously had a transform applied to it 430 * @throws IOException indicating that the transform could not be removed from the socket 431 */ 432 public void removeTransportModeTransforms(@NonNull DatagramSocket socket) throws IOException { 433 removeTransportModeTransforms(socket.getFileDescriptor$()); 434 } 435 436 /** 437 * Remove an IPsec transform from a socket. 438 * 439 * <p>Once removed, traffic on the socket will not be encrypted. Removing transforms from a 440 * socket allows the socket to be reused for communication in the clear. 441 * 442 * <p>If an {@code IpSecTransform} object applied to this socket was deallocated by calling 443 * {@link IpSecTransform#close()}, then communication on the socket will fail until this method 444 * is called. 445 * 446 * @param socket a socket that previously had a transform applied to it 447 * @throws IOException indicating that the transform could not be removed from the socket 448 */ 449 public void removeTransportModeTransforms(@NonNull FileDescriptor socket) throws IOException { 450 try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) { 451 mService.removeTransportModeTransforms(pfd); 452 } catch (RemoteException e) { 453 throw e.rethrowFromSystemServer(); 454 } 455 } 456 457 /** 458 * Remove a Tunnel Mode IPsec Transform from a {@link Network}. This must be used as part of 459 * cleanup if a tunneled Network experiences a change in default route. The Network will drop 460 * all traffic that cannot be routed to the Tunnel's outbound interface. If that interface is 461 * lost, all traffic will drop. 462 * 463 * <p>TODO: Update javadoc for tunnel mode APIs at the same time the APIs are re-worked. 464 * 465 * @param net a network that currently has transform applied to it. 466 * @param transform a Tunnel Mode IPsec Transform that has been previously applied to the given 467 * network 468 * @hide 469 */ 470 public void removeTunnelModeTransform(Network net, IpSecTransform transform) {} 471 472 /** 473 * This class provides access to a UDP encapsulation Socket. 474 * 475 * <p>{@code UdpEncapsulationSocket} wraps a system-provided datagram socket intended for IKEv2 476 * signalling and UDP encapsulated IPsec traffic. Instances can be obtained by calling {@link 477 * IpSecManager#openUdpEncapsulationSocket}. The provided socket cannot be re-bound by the 478 * caller. The caller should not close the {@code FileDescriptor} returned by {@link 479 * #getSocket}, but should use {@link #close} instead. 480 * 481 * <p>Allowing the user to close or unbind a UDP encapsulation socket could impact the traffic 482 * of the next user who binds to that port. To prevent this scenario, these sockets are held 483 * open by the system so that they may only be closed by calling {@link #close} or when the user 484 * process exits. 485 */ 486 public static final class UdpEncapsulationSocket implements AutoCloseable { 487 private final ParcelFileDescriptor mPfd; 488 private final IIpSecService mService; 489 private int mResourceId = INVALID_RESOURCE_ID; 490 private final int mPort; 491 private final CloseGuard mCloseGuard = CloseGuard.get(); 492 493 private UdpEncapsulationSocket(@NonNull IIpSecService service, int port) 494 throws ResourceUnavailableException, IOException { 495 mService = service; 496 try { 497 IpSecUdpEncapResponse result = 498 mService.openUdpEncapsulationSocket(port, new Binder()); 499 switch (result.status) { 500 case Status.OK: 501 break; 502 case Status.RESOURCE_UNAVAILABLE: 503 throw new ResourceUnavailableException( 504 "No more Sockets may be allocated by this requester."); 505 default: 506 throw new RuntimeException( 507 "Unknown status returned by IpSecService: " + result.status); 508 } 509 mResourceId = result.resourceId; 510 mPort = result.port; 511 mPfd = result.fileDescriptor; 512 } catch (RemoteException e) { 513 throw e.rethrowFromSystemServer(); 514 } 515 mCloseGuard.open("constructor"); 516 } 517 518 /** Get the wrapped socket. */ 519 public FileDescriptor getSocket() { 520 if (mPfd == null) { 521 return null; 522 } 523 return mPfd.getFileDescriptor(); 524 } 525 526 /** Get the bound port of the wrapped socket. */ 527 public int getPort() { 528 return mPort; 529 } 530 531 /** 532 * Close this socket. 533 * 534 * <p>This closes the wrapped socket. Open encapsulation sockets count against a user's 535 * resource limits, and forgetting to close them eventually will result in {@link 536 * ResourceUnavailableException} being thrown. 537 */ 538 @Override 539 public void close() throws IOException { 540 try { 541 mService.closeUdpEncapsulationSocket(mResourceId); 542 mResourceId = INVALID_RESOURCE_ID; 543 } catch (RemoteException e) { 544 throw e.rethrowFromSystemServer(); 545 } 546 547 try { 548 mPfd.close(); 549 } catch (IOException e) { 550 Log.e(TAG, "Failed to close UDP Encapsulation Socket with Port= " + mPort); 551 throw e; 552 } 553 mCloseGuard.close(); 554 } 555 556 /** Check that the socket was closed properly. */ 557 @Override 558 protected void finalize() throws Throwable { 559 if (mCloseGuard != null) { 560 mCloseGuard.warnIfOpen(); 561 } 562 close(); 563 } 564 565 /** @hide */ 566 @VisibleForTesting 567 public int getResourceId() { 568 return mResourceId; 569 } 570 }; 571 572 /** 573 * Open a socket for UDP encapsulation and bind to the given port. 574 * 575 * <p>See {@link UdpEncapsulationSocket} for the proper way to close the returned socket. 576 * 577 * @param port a local UDP port 578 * @return a socket that is bound to the given port 579 * @throws IOException indicating that the socket could not be opened or bound 580 * @throws ResourceUnavailableException indicating that too many encapsulation sockets are open 581 */ 582 // Returning a socket in this fashion that has been created and bound by the system 583 // is the only safe way to ensure that a socket is both accessible to the user and 584 // safely usable for Encapsulation without allowing a user to possibly unbind from/close 585 // the port, which could potentially impact the traffic of the next user who binds to that 586 // socket. 587 @NonNull 588 public UdpEncapsulationSocket openUdpEncapsulationSocket(int port) 589 throws IOException, ResourceUnavailableException { 590 /* 591 * Most range checking is done in the service, but this version of the constructor expects 592 * a valid port number, and zero cannot be checked after being passed to the service. 593 */ 594 if (port == 0) { 595 throw new IllegalArgumentException("Specified port must be a valid port number!"); 596 } 597 return new UdpEncapsulationSocket(mService, port); 598 } 599 600 /** 601 * Open a socket for UDP encapsulation. 602 * 603 * <p>See {@link UdpEncapsulationSocket} for the proper way to close the returned socket. 604 * 605 * <p>The local port of the returned socket can be obtained by calling {@link 606 * UdpEncapsulationSocket#getPort()}. 607 * 608 * @return a socket that is bound to a local port 609 * @throws IOException indicating that the socket could not be opened or bound 610 * @throws ResourceUnavailableException indicating that too many encapsulation sockets are open 611 */ 612 // Returning a socket in this fashion that has been created and bound by the system 613 // is the only safe way to ensure that a socket is both accessible to the user and 614 // safely usable for Encapsulation without allowing a user to possibly unbind from/close 615 // the port, which could potentially impact the traffic of the next user who binds to that 616 // socket. 617 @NonNull 618 public UdpEncapsulationSocket openUdpEncapsulationSocket() 619 throws IOException, ResourceUnavailableException { 620 return new UdpEncapsulationSocket(mService, 0); 621 } 622 623 /** 624 * This class represents an IpSecTunnelInterface 625 * 626 * <p>IpSecTunnelInterface objects track tunnel interfaces that serve as 627 * local endpoints for IPsec tunnels. 628 * 629 * <p>Creating an IpSecTunnelInterface creates a device to which IpSecTransforms may be 630 * applied to provide IPsec security to packets sent through the tunnel. While a tunnel 631 * cannot be used in standalone mode within Android, the higher layers may use the tunnel 632 * to create Network objects which are accessible to the Android system. 633 * @hide 634 */ 635 @SystemApi 636 public static final class IpSecTunnelInterface implements AutoCloseable { 637 private final IIpSecService mService; 638 private final InetAddress mRemoteAddress; 639 private final InetAddress mLocalAddress; 640 private final Network mUnderlyingNetwork; 641 private final CloseGuard mCloseGuard = CloseGuard.get(); 642 private String mInterfaceName; 643 private int mResourceId = INVALID_RESOURCE_ID; 644 645 /** Get the underlying SPI held by this object. */ 646 @NonNull 647 public String getInterfaceName() { 648 return mInterfaceName; 649 } 650 651 /** 652 * Add an address to the IpSecTunnelInterface 653 * 654 * <p>Add an address which may be used as the local inner address for 655 * tunneled traffic. 656 * 657 * @param address the local address for traffic inside the tunnel 658 * @hide 659 */ 660 @SystemApi 661 public void addAddress(@NonNull LinkAddress address) throws IOException { 662 try { 663 mService.addAddressToTunnelInterface(mResourceId, address); 664 } catch (RemoteException e) { 665 throw e.rethrowFromSystemServer(); 666 } 667 } 668 669 /** 670 * Remove an address from the IpSecTunnelInterface 671 * 672 * <p>Remove an address which was previously added to the IpSecTunnelInterface 673 * 674 * @param address to be removed 675 * @hide 676 */ 677 @SystemApi 678 public void removeAddress(@NonNull LinkAddress address) throws IOException { 679 try { 680 mService.removeAddressFromTunnelInterface(mResourceId, address); 681 } catch (RemoteException e) { 682 throw e.rethrowFromSystemServer(); 683 } 684 } 685 686 private IpSecTunnelInterface(@NonNull IIpSecService service, 687 @NonNull InetAddress localAddress, @NonNull InetAddress remoteAddress, 688 @NonNull Network underlyingNetwork) 689 throws ResourceUnavailableException, IOException { 690 mService = service; 691 mLocalAddress = localAddress; 692 mRemoteAddress = remoteAddress; 693 mUnderlyingNetwork = underlyingNetwork; 694 695 try { 696 IpSecTunnelInterfaceResponse result = 697 mService.createTunnelInterface( 698 localAddress.getHostAddress(), 699 remoteAddress.getHostAddress(), 700 underlyingNetwork, 701 new Binder()); 702 switch (result.status) { 703 case Status.OK: 704 break; 705 case Status.RESOURCE_UNAVAILABLE: 706 throw new ResourceUnavailableException( 707 "No more tunnel interfaces may be allocated by this requester."); 708 default: 709 throw new RuntimeException( 710 "Unknown status returned by IpSecService: " + result.status); 711 } 712 mResourceId = result.resourceId; 713 mInterfaceName = result.interfaceName; 714 } catch (RemoteException e) { 715 throw e.rethrowFromSystemServer(); 716 } 717 mCloseGuard.open("constructor"); 718 } 719 720 /** 721 * Delete an IpSecTunnelInterface 722 * 723 * <p>Calling close will deallocate the IpSecTunnelInterface and all of its system 724 * resources. Any packets bound for this interface either inbound or outbound will 725 * all be lost. 726 */ 727 @Override 728 public void close() { 729 try { 730 mService.deleteTunnelInterface(mResourceId); 731 mResourceId = INVALID_RESOURCE_ID; 732 } catch (RemoteException e) { 733 throw e.rethrowFromSystemServer(); 734 } 735 mCloseGuard.close(); 736 } 737 738 /** Check that the Interface was closed properly. */ 739 @Override 740 protected void finalize() throws Throwable { 741 if (mCloseGuard != null) { 742 mCloseGuard.warnIfOpen(); 743 } 744 close(); 745 } 746 747 /** @hide */ 748 @VisibleForTesting 749 public int getResourceId() { 750 return mResourceId; 751 } 752 } 753 754 /** 755 * Create a new IpSecTunnelInterface as a local endpoint for tunneled IPsec traffic. 756 * 757 * <p>An application that creates tunnels is responsible for cleaning up the tunnel when the 758 * underlying network goes away, and the onLost() callback is received. 759 * 760 * @param localAddress The local addres of the tunnel 761 * @param remoteAddress The local addres of the tunnel 762 * @param underlyingNetwork the {@link Network} that will carry traffic for this tunnel. 763 * This network should almost certainly be a network such as WiFi with an L2 address. 764 * @return a new {@link IpSecManager#IpSecTunnelInterface} with the specified properties 765 * @throws IOException indicating that the socket could not be opened or bound 766 * @throws ResourceUnavailableException indicating that too many encapsulation sockets are open 767 * @hide 768 */ 769 @SystemApi 770 @NonNull 771 @RequiresPermission(android.Manifest.permission.NETWORK_STACK) 772 public IpSecTunnelInterface createIpSecTunnelInterface(@NonNull InetAddress localAddress, 773 @NonNull InetAddress remoteAddress, @NonNull Network underlyingNetwork) 774 throws ResourceUnavailableException, IOException { 775 return new IpSecTunnelInterface(mService, localAddress, remoteAddress, underlyingNetwork); 776 } 777 778 /** 779 * Apply an active Tunnel Mode IPsec Transform to a {@link IpSecTunnelInterface}, which will 780 * tunnel all traffic for the given direction through the underlying network's interface with 781 * IPsec (applies an outer IP header and IPsec Header to all traffic, and expects an additional 782 * IP header and IPsec Header on all inbound traffic). 783 * <p>Applications should probably not use this API directly. 784 * 785 * 786 * @param tunnel The {@link IpSecManager#IpSecTunnelInterface} that will use the supplied 787 * transform. 788 * @param direction the direction, {@link DIRECTION_OUT} or {@link #DIRECTION_IN} in which 789 * the transform will be used. 790 * @param transform an {@link IpSecTransform} created in tunnel mode 791 * @throws IOException indicating that the transform could not be applied due to a lower 792 * layer failure. 793 * @hide 794 */ 795 @SystemApi 796 @RequiresPermission(android.Manifest.permission.NETWORK_STACK) 797 public void applyTunnelModeTransform(@NonNull IpSecTunnelInterface tunnel, 798 @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException { 799 try { 800 mService.applyTunnelModeTransform( 801 tunnel.getResourceId(), direction, transform.getResourceId()); 802 } catch (RemoteException e) { 803 throw e.rethrowFromSystemServer(); 804 } 805 } 806 807 /** 808 * Construct an instance of IpSecManager within an application context. 809 * 810 * @param context the application context for this manager 811 * @hide 812 */ 813 public IpSecManager(IIpSecService service) { 814 mService = checkNotNull(service, "missing service"); 815 } 816} 817