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