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