IpSecManager.java revision da4b0c65a5cbebf6c5e66b869b75dd3a6625cd2e
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 public SecurityParameterIndex allocateSecurityParameterIndex(InetAddress destinationAddress) 257 throws ResourceUnavailableException { 258 try { 259 return new SecurityParameterIndex( 260 mService, 261 destinationAddress, 262 IpSecManager.INVALID_SECURITY_PARAMETER_INDEX); 263 } catch (SpiUnavailableException unlikely) { 264 throw new ResourceUnavailableException("No SPIs available"); 265 } 266 } 267 268 /** 269 * Reserve the requested SPI for traffic bound to or from the specified destination address. 270 * 271 * <p>If successful, this SPI is guaranteed available until released by a call to {@link 272 * SecurityParameterIndex#close()}. 273 * 274 * @param destinationAddress the destination address for traffic bearing the requested SPI. 275 * For inbound traffic, the destination should be an address currently assigned on-device. 276 * @param requestedSpi the requested SPI, or '0' to allocate a random SPI 277 * @return the reserved SecurityParameterIndex 278 * @throws {@link #ResourceUnavailableException} indicating that too many SPIs are 279 * currently allocated for this user 280 * @throws {@link #SpiUnavailableException} indicating that the requested SPI could not be 281 * reserved 282 */ 283 public SecurityParameterIndex allocateSecurityParameterIndex( 284 InetAddress destinationAddress, int requestedSpi) 285 throws SpiUnavailableException, ResourceUnavailableException { 286 if (requestedSpi == IpSecManager.INVALID_SECURITY_PARAMETER_INDEX) { 287 throw new IllegalArgumentException("Requested SPI must be a valid (non-zero) SPI"); 288 } 289 return new SecurityParameterIndex(mService, destinationAddress, requestedSpi); 290 } 291 292 /** 293 * Apply an IPsec transform to a stream socket. 294 * 295 * <p>This applies transport mode encapsulation to the given socket. Once applied, I/O on the 296 * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When 297 * the transform is removed from the socket by calling {@link #removeTransportModeTransforms}, 298 * unprotected traffic can resume on that socket. 299 * 300 * <p>For security reasons, the destination address of any traffic on the socket must match the 301 * remote {@code InetAddress} of the {@code IpSecTransform}. Attempts to send traffic to any 302 * other IP address will result in an IOException. In addition, reads and writes on the socket 303 * will throw IOException if the user deactivates the transform (by calling {@link 304 * IpSecTransform#close()}) without calling {@link #removeTransportModeTransforms}. 305 * 306 * <h4>Rekey Procedure</h4> 307 * 308 * <p>When applying a new tranform to a socket in the outbound direction, the previous transform 309 * will be removed and the new transform will take effect immediately, sending all traffic on 310 * the new transform; however, when applying a transform in the inbound direction, traffic 311 * on the old transform will continue to be decrypted and delivered until that transform is 312 * deallocated by calling {@link IpSecTransform#close()}. This overlap allows lossless rekey 313 * procedures where both transforms are valid until both endpoints are using the new transform 314 * and all in-flight packets have been received. 315 * 316 * @param socket a stream socket 317 * @param direction the direction in which the transform should be applied 318 * @param transform a transport mode {@code IpSecTransform} 319 * @throws IOException indicating that the transform could not be applied 320 */ 321 public void applyTransportModeTransform( 322 Socket socket, @PolicyDirection int direction, IpSecTransform transform) 323 throws IOException { 324 applyTransportModeTransform(socket.getFileDescriptor$(), direction, transform); 325 } 326 327 /** 328 * Apply an IPsec transform to a datagram socket. 329 * 330 * <p>This applies transport mode encapsulation to the given socket. Once applied, I/O on the 331 * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When 332 * the transform is removed from the socket by calling {@link #removeTransportModeTransforms}, 333 * unprotected traffic can resume on that socket. 334 * 335 * <p>For security reasons, the destination address of any traffic on the socket must match the 336 * remote {@code InetAddress} of the {@code IpSecTransform}. Attempts to send traffic to any 337 * other IP address will result in an IOException. In addition, reads and writes on the socket 338 * will throw IOException if the user deactivates the transform (by calling {@link 339 * IpSecTransform#close()}) without calling {@link #removeTransportModeTransforms}. 340 * 341 * <h4>Rekey Procedure</h4> 342 * 343 * <p>When applying a new tranform to a socket in the outbound direction, the previous transform 344 * will be removed and the new transform will take effect immediately, sending all traffic on 345 * the new transform; however, when applying a transform in the inbound direction, traffic 346 * on the old transform will continue to be decrypted and delivered until that transform is 347 * deallocated by calling {@link IpSecTransform#close()}. This overlap allows lossless rekey 348 * procedures where both transforms are valid until both endpoints are using the new transform 349 * and all in-flight packets have been received. 350 * 351 * @param socket a datagram socket 352 * @param direction the direction in which the transform should be applied 353 * @param transform a transport mode {@code IpSecTransform} 354 * @throws IOException indicating that the transform could not be applied 355 */ 356 public void applyTransportModeTransform( 357 DatagramSocket socket, @PolicyDirection int direction, IpSecTransform transform) 358 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( 392 FileDescriptor socket, @PolicyDirection int direction, IpSecTransform transform) 393 throws IOException { 394 // We dup() the FileDescriptor here because if we don't, then the ParcelFileDescriptor() 395 // constructor takes control and closes the user's FD when we exit the method. 396 try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) { 397 mService.applyTransportModeTransform(pfd, direction, transform.getResourceId()); 398 } catch (RemoteException e) { 399 throw e.rethrowFromSystemServer(); 400 } 401 } 402 403 /** 404 * Remove an IPsec transform from a stream socket. 405 * 406 * <p>Once removed, traffic on the socket will not be encrypted. Removing transforms from a 407 * socket allows the socket to be reused for communication in the clear. 408 * 409 * <p>If an {@code IpSecTransform} object applied to this socket was deallocated by calling 410 * {@link IpSecTransform#close()}, then communication on the socket will fail until this method 411 * is called. 412 * 413 * @param socket a socket that previously had a transform applied to it 414 * @throws IOException indicating that the transform could not be removed from the socket 415 */ 416 public void removeTransportModeTransforms(Socket socket) 417 throws IOException { 418 removeTransportModeTransforms(socket.getFileDescriptor$()); 419 } 420 421 /** 422 * Remove an IPsec transform from a datagram socket. 423 * 424 * <p>Once removed, traffic on the socket will not be encrypted. Removing transforms from a 425 * socket allows the socket to be reused for communication in the clear. 426 * 427 * <p>If an {@code IpSecTransform} object applied to this socket was deallocated by calling 428 * {@link IpSecTransform#close()}, then communication on the socket will fail until this method 429 * is called. 430 * 431 * @param socket a socket that previously had a transform applied to it 432 * @throws IOException indicating that the transform could not be removed from the socket 433 */ 434 public void removeTransportModeTransforms(DatagramSocket socket) 435 throws IOException { 436 removeTransportModeTransforms(socket.getFileDescriptor$()); 437 } 438 439 /** 440 * Remove an IPsec transform from a socket. 441 * 442 * <p>Once removed, traffic on the socket will not be encrypted. Removing transforms from a 443 * socket allows the socket to be reused for communication in the clear. 444 * 445 * <p>If an {@code IpSecTransform} object applied to this socket was deallocated by calling 446 * {@link IpSecTransform#close()}, then communication on the socket will fail until this method 447 * is called. 448 * 449 * @param socket a socket that previously had a transform applied to it 450 * @throws IOException indicating that the transform could not be removed from the socket 451 */ 452 public void removeTransportModeTransforms(FileDescriptor socket) 453 throws IOException { 454 try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) { 455 mService.removeTransportModeTransforms(pfd); 456 } catch (RemoteException e) { 457 throw e.rethrowFromSystemServer(); 458 } 459 } 460 461 /** 462 * Remove a Tunnel Mode IPsec Transform from a {@link Network}. This must be used as part of 463 * cleanup if a tunneled Network experiences a change in default route. The Network will drop 464 * all traffic that cannot be routed to the Tunnel's outbound interface. If that interface is 465 * lost, all traffic will drop. 466 * 467 * <p>TODO: Update javadoc for tunnel mode APIs at the same time the APIs are re-worked. 468 * 469 * @param net a network that currently has transform applied to it. 470 * @param transform a Tunnel Mode IPsec Transform that has been previously applied to the given 471 * network 472 * @hide 473 */ 474 public void removeTunnelModeTransform(Network net, IpSecTransform transform) {} 475 476 /** 477 * This class provides access to a UDP encapsulation Socket. 478 * 479 * <p>{@code UdpEncapsulationSocket} wraps a system-provided datagram socket intended for IKEv2 480 * signalling and UDP encapsulated IPsec traffic. Instances can be obtained by calling {@link 481 * IpSecManager#openUdpEncapsulationSocket}. The provided socket cannot be re-bound by the 482 * caller. The caller should not close the {@code FileDescriptor} returned by {@link 483 * #getSocket}, but should use {@link #close} instead. 484 * 485 * <p>Allowing the user to close or unbind a UDP encapsulation socket could impact the traffic 486 * of the next user who binds to that port. To prevent this scenario, these sockets are held 487 * open by the system so that they may only be closed by calling {@link #close} or when the user 488 * process exits. 489 */ 490 public static final class UdpEncapsulationSocket implements AutoCloseable { 491 private final ParcelFileDescriptor mPfd; 492 private final IIpSecService mService; 493 private int mResourceId = INVALID_RESOURCE_ID; 494 private final int mPort; 495 private final CloseGuard mCloseGuard = CloseGuard.get(); 496 497 private UdpEncapsulationSocket(@NonNull IIpSecService service, int port) 498 throws ResourceUnavailableException, IOException { 499 mService = service; 500 try { 501 IpSecUdpEncapResponse result = 502 mService.openUdpEncapsulationSocket(port, new Binder()); 503 switch (result.status) { 504 case Status.OK: 505 break; 506 case Status.RESOURCE_UNAVAILABLE: 507 throw new ResourceUnavailableException( 508 "No more Sockets may be allocated by this requester."); 509 default: 510 throw new RuntimeException( 511 "Unknown status returned by IpSecService: " + result.status); 512 } 513 mResourceId = result.resourceId; 514 mPort = result.port; 515 mPfd = result.fileDescriptor; 516 } catch (RemoteException e) { 517 throw e.rethrowFromSystemServer(); 518 } 519 mCloseGuard.open("constructor"); 520 } 521 522 /** Get the wrapped socket. */ 523 public FileDescriptor getSocket() { 524 if (mPfd == null) { 525 return null; 526 } 527 return mPfd.getFileDescriptor(); 528 } 529 530 /** Get the bound port of the wrapped socket. */ 531 public int getPort() { 532 return mPort; 533 } 534 535 /** 536 * Close this socket. 537 * 538 * <p>This closes the wrapped socket. Open encapsulation sockets count against a user's 539 * resource limits, and forgetting to close them eventually will result in {@link 540 * ResourceUnavailableException} being thrown. 541 */ 542 @Override 543 public void close() throws IOException { 544 try { 545 mService.closeUdpEncapsulationSocket(mResourceId); 546 mResourceId = INVALID_RESOURCE_ID; 547 } catch (RemoteException e) { 548 throw e.rethrowFromSystemServer(); 549 } 550 551 try { 552 mPfd.close(); 553 } catch (IOException e) { 554 Log.e(TAG, "Failed to close UDP Encapsulation Socket with Port= " + mPort); 555 throw e; 556 } 557 mCloseGuard.close(); 558 } 559 560 /** Check that the socket was closed properly. */ 561 @Override 562 protected void finalize() throws Throwable { 563 if (mCloseGuard != null) { 564 mCloseGuard.warnIfOpen(); 565 } 566 close(); 567 } 568 569 /** @hide */ 570 @VisibleForTesting 571 public int getResourceId() { 572 return mResourceId; 573 } 574 }; 575 576 /** 577 * Open a socket for UDP encapsulation and bind to the given port. 578 * 579 * <p>See {@link UdpEncapsulationSocket} for the proper way to close the returned socket. 580 * 581 * @param port a local UDP port 582 * @return a socket that is bound to the given port 583 * @throws IOException indicating that the socket could not be opened or bound 584 * @throws ResourceUnavailableException indicating that too many encapsulation sockets are open 585 */ 586 // Returning a socket in this fashion that has been created and bound by the system 587 // is the only safe way to ensure that a socket is both accessible to the user and 588 // safely usable for Encapsulation without allowing a user to possibly unbind from/close 589 // the port, which could potentially impact the traffic of the next user who binds to that 590 // socket. 591 public UdpEncapsulationSocket openUdpEncapsulationSocket(int port) 592 throws IOException, ResourceUnavailableException { 593 /* 594 * Most range checking is done in the service, but this version of the constructor expects 595 * a valid port number, and zero cannot be checked after being passed to the service. 596 */ 597 if (port == 0) { 598 throw new IllegalArgumentException("Specified port must be a valid port number!"); 599 } 600 return new UdpEncapsulationSocket(mService, port); 601 } 602 603 /** 604 * Open a socket for UDP encapsulation. 605 * 606 * <p>See {@link UdpEncapsulationSocket} for the proper way to close the returned socket. 607 * 608 * <p>The local port of the returned socket can be obtained by calling {@link 609 * UdpEncapsulationSocket#getPort()}. 610 * 611 * @return a socket that is bound to a local port 612 * @throws IOException indicating that the socket could not be opened or bound 613 * @throws ResourceUnavailableException indicating that too many encapsulation sockets are open 614 */ 615 // Returning a socket in this fashion that has been created and bound by the system 616 // is the only safe way to ensure that a socket is both accessible to the user and 617 // safely usable for Encapsulation without allowing a user to possibly unbind from/close 618 // the port, which could potentially impact the traffic of the next user who binds to that 619 // socket. 620 public UdpEncapsulationSocket openUdpEncapsulationSocket() 621 throws IOException, ResourceUnavailableException { 622 return new UdpEncapsulationSocket(mService, 0); 623 } 624 625 /** 626 * This class represents an IpSecTunnelInterface 627 * 628 * <p>IpSecTunnelInterface objects track tunnel interfaces that serve as 629 * local endpoints for IPsec tunnels. 630 * 631 * <p>Creating an IpSecTunnelInterface creates a device to which IpSecTransforms may be 632 * applied to provide IPsec security to packets sent through the tunnel. While a tunnel 633 * cannot be used in standalone mode within Android, the higher layers may use the tunnel 634 * to create Network objects which are accessible to the Android system. 635 * @hide 636 */ 637 @SystemApi 638 public static final class IpSecTunnelInterface implements AutoCloseable { 639 private final IIpSecService mService; 640 private final InetAddress mRemoteAddress; 641 private final InetAddress mLocalAddress; 642 private final Network mUnderlyingNetwork; 643 private final CloseGuard mCloseGuard = CloseGuard.get(); 644 private String mInterfaceName; 645 private int mResourceId = INVALID_RESOURCE_ID; 646 647 /** Get the underlying SPI held by this object. */ 648 public String getInterfaceName() { 649 return mInterfaceName; 650 } 651 652 /** 653 * Add an address to the IpSecTunnelInterface 654 * 655 * <p>Add an address which may be used as the local inner address for 656 * tunneled traffic. 657 * 658 * @param address the local address for traffic inside the tunnel 659 * @hide 660 */ 661 public void addAddress(LinkAddress address) { 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 public void removeAddress(LinkAddress address) { 678 try { 679 mService.removeAddressFromTunnelInterface(mResourceId, address); 680 } catch (RemoteException e) { 681 throw e.rethrowFromSystemServer(); 682 } 683 } 684 685 private IpSecTunnelInterface(@NonNull IIpSecService service, 686 @NonNull InetAddress localAddress, @NonNull InetAddress remoteAddress, 687 @NonNull Network underlyingNetwork) 688 throws ResourceUnavailableException, IOException { 689 mService = service; 690 mLocalAddress = localAddress; 691 mRemoteAddress = remoteAddress; 692 mUnderlyingNetwork = underlyingNetwork; 693 694 try { 695 IpSecTunnelInterfaceResponse result = 696 mService.createTunnelInterface( 697 localAddress.getHostAddress(), 698 remoteAddress.getHostAddress(), 699 underlyingNetwork, 700 new Binder()); 701 switch (result.status) { 702 case Status.OK: 703 break; 704 case Status.RESOURCE_UNAVAILABLE: 705 throw new ResourceUnavailableException( 706 "No more tunnel interfaces may be allocated by this requester."); 707 default: 708 throw new RuntimeException( 709 "Unknown status returned by IpSecService: " + result.status); 710 } 711 mResourceId = result.resourceId; 712 mInterfaceName = result.interfaceName; 713 } catch (RemoteException e) { 714 throw e.rethrowFromSystemServer(); 715 } 716 mCloseGuard.open("constructor"); 717 } 718 719 /** 720 * Delete an IpSecTunnelInterface 721 * 722 * <p>Calling close will deallocate the IpSecTunnelInterface and all of its system 723 * resources. Any packets bound for this interface either inbound or outbound will 724 * all be lost. 725 */ 726 @Override 727 public void close() { 728 try { 729 mService.deleteTunnelInterface(mResourceId); 730 mResourceId = INVALID_RESOURCE_ID; 731 } catch (RemoteException e) { 732 throw e.rethrowFromSystemServer(); 733 } 734 mCloseGuard.close(); 735 } 736 737 /** Check that the Interface was closed properly. */ 738 @Override 739 protected void finalize() throws Throwable { 740 if (mCloseGuard != null) { 741 mCloseGuard.warnIfOpen(); 742 } 743 close(); 744 } 745 746 /** @hide */ 747 @VisibleForTesting 748 public int getResourceId() { 749 return mResourceId; 750 } 751 } 752 753 /** 754 * Create a new IpSecTunnelInterface as a local endpoint for tunneled IPsec traffic. 755 * 756 * <p>An application that creates tunnels is responsible for cleaning up the tunnel when the 757 * underlying network goes away, and the onLost() callback is received. 758 * 759 * @param localAddress The local addres of the tunnel 760 * @param remoteAddress The local addres of the tunnel 761 * @param underlyingNetwork the {@link Network} that will carry traffic for this tunnel. 762 * This network should almost certainly be a network such as WiFi with an L2 address. 763 * @return a new {@link IpSecManager#IpSecTunnelInterface} with the specified properties 764 * @throws IOException indicating that the socket could not be opened or bound 765 * @throws ResourceUnavailableException indicating that too many encapsulation sockets are open 766 * @hide 767 */ 768 @SystemApi 769 @RequiresPermission(android.Manifest.permission.NETWORK_STACK) 770 public IpSecTunnelInterface createIpSecTunnelInterface(@NonNull InetAddress localAddress, 771 @NonNull InetAddress remoteAddress, @NonNull Network underlyingNetwork) 772 throws ResourceUnavailableException, IOException { 773 return new IpSecTunnelInterface(mService, localAddress, remoteAddress, underlyingNetwork); 774 } 775 776 /** 777 * Apply an active Tunnel Mode IPsec Transform to a {@link IpSecTunnelInterface}, which will 778 * tunnel all traffic for the given direction through the underlying network's interface with 779 * IPsec (applies an outer IP header and IPsec Header to all traffic, and expects an additional 780 * IP header and IPsec Header on all inbound traffic). 781 * <p>Applications should probably not use this API directly. 782 * 783 * 784 * @param tunnel The {@link IpSecManager#IpSecTunnelInterface} that will use the supplied 785 * transform. 786 * @param direction the direction, {@link DIRECTION_OUT} or {@link #DIRECTION_IN} in which 787 * the transform will be used. 788 * @param transform an {@link IpSecTransform} created in tunnel mode 789 * @throws IOException indicating that the transform could not be applied due to a lower 790 * layer failure. 791 * @hide 792 */ 793 @SystemApi 794 @RequiresPermission(android.Manifest.permission.NETWORK_STACK) 795 public void applyTunnelModeTransform(IpSecTunnelInterface tunnel, 796 @PolicyDirection int direction, IpSecTransform transform) throws IOException { 797 try { 798 mService.applyTunnelModeTransform( 799 tunnel.getResourceId(), direction, transform.getResourceId()); 800 } catch (RemoteException e) { 801 throw e.rethrowFromSystemServer(); 802 } 803 } 804 805 /** 806 * Construct an instance of IpSecManager within an application context. 807 * 808 * @param context the application context for this manager 809 * @hide 810 */ 811 public IpSecManager(IIpSecService service) { 812 mService = checkNotNull(service, "missing service"); 813 } 814} 815