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