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