IpSecManager.java revision ddeb90aa9db108d4a2e5aadc778a726b65e5c921
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 */
16package android.net;
17
18import static com.android.internal.util.Preconditions.checkNotNull;
19
20import android.annotation.IntDef;
21import android.annotation.NonNull;
22import android.annotation.RequiresPermission;
23import android.annotation.SystemService;
24import android.annotation.TestApi;
25import android.content.Context;
26import android.os.Binder;
27import android.os.ParcelFileDescriptor;
28import android.os.RemoteException;
29import android.os.ServiceSpecificException;
30import android.system.ErrnoException;
31import android.system.OsConstants;
32import android.util.AndroidException;
33import android.util.Log;
34
35import com.android.internal.annotations.VisibleForTesting;
36
37import dalvik.system.CloseGuard;
38
39import java.io.FileDescriptor;
40import java.io.IOException;
41import java.lang.annotation.Retention;
42import java.lang.annotation.RetentionPolicy;
43import java.net.DatagramSocket;
44import java.net.InetAddress;
45import 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)
59public 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         */
120        SpiUnavailableException(String msg, int spi) {
121            super(msg + " (spi: " + spi + ")");
122            mSpi = spi;
123        }
124
125        /** Get the SPI that caused a collision. */
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
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. */
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
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
192        protected void finalize() throws Throwable {
193            if (mCloseGuard != null) {
194                mCloseGuard.warnIfOpen();
195            }
196
197            close();
198        }
199
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
246        public int getResourceId() {
247            return mResourceId;
248        }
249
250        @Override
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
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
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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
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. */
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. */
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
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
627        protected void finalize() throws Throwable {
628            if (mCloseGuard != null) {
629                mCloseGuard.warnIfOpen();
630            }
631            close();
632        }
633
634        /** @hide */
635        @VisibleForTesting
636        public int getResourceId() {
637            return mResourceId;
638        }
639
640        @Override
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
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
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
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)
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)
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
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
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
843        protected void finalize() throws Throwable {
844            if (mCloseGuard != null) {
845                mCloseGuard.warnIfOpen();
846            }
847            close();
848        }
849
850        /** @hide */
851        @VisibleForTesting
852        public int getResourceId() {
853            return mResourceId;
854        }
855
856        @Override
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)
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)
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     */
933    public IpSecManager(Context ctx, IIpSecService service) {
934        mContext = ctx;
935        mService = checkNotNull(service, "missing service");
936    }
937
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
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
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