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