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