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