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