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