1330e1089da80cddcd68758512370d217b19f8890Nathan Harold/*
2330e1089da80cddcd68758512370d217b19f8890Nathan Harold * Copyright (C) 2017 The Android Open Source Project
3330e1089da80cddcd68758512370d217b19f8890Nathan Harold *
4330e1089da80cddcd68758512370d217b19f8890Nathan Harold * Licensed under the Apache License, Version 2.0 (the "License");
5330e1089da80cddcd68758512370d217b19f8890Nathan Harold * you may not use this file except in compliance with the License.
6330e1089da80cddcd68758512370d217b19f8890Nathan Harold * You may obtain a copy of the License at
7330e1089da80cddcd68758512370d217b19f8890Nathan Harold *
8330e1089da80cddcd68758512370d217b19f8890Nathan Harold *      http://www.apache.org/licenses/LICENSE-2.0
9330e1089da80cddcd68758512370d217b19f8890Nathan Harold *
10330e1089da80cddcd68758512370d217b19f8890Nathan Harold * Unless required by applicable law or agreed to in writing, software
11330e1089da80cddcd68758512370d217b19f8890Nathan Harold * distributed under the License is distributed on an "AS IS" BASIS,
12330e1089da80cddcd68758512370d217b19f8890Nathan Harold * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13330e1089da80cddcd68758512370d217b19f8890Nathan Harold * See the License for the specific language governing permissions and
14330e1089da80cddcd68758512370d217b19f8890Nathan Harold * limitations under the License.
15330e1089da80cddcd68758512370d217b19f8890Nathan Harold */
16330e1089da80cddcd68758512370d217b19f8890Nathan Haroldpackage android.net;
17330e1089da80cddcd68758512370d217b19f8890Nathan Harold
18330e1089da80cddcd68758512370d217b19f8890Nathan Haroldimport static com.android.internal.util.Preconditions.checkNotNull;
19330e1089da80cddcd68758512370d217b19f8890Nathan Harold
20a25233123b2d29fde83dd686f6313f0a232c5b2aNathan Haroldimport android.annotation.IntDef;
2193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Haroldimport android.annotation.NonNull;
225a920ca377efaaaaabf3fe6c77111d8158202055Nathan Haroldimport android.annotation.RequiresPermission;
23d86b8fea43ebb6e5c31691b44d8ceb0d8d3c9072Jeff Sharkeyimport android.annotation.SystemService;
24c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseriimport android.annotation.TestApi;
25d86b8fea43ebb6e5c31691b44d8ceb0d8d3c9072Jeff Sharkeyimport android.content.Context;
2693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Haroldimport android.os.Binder;
27330e1089da80cddcd68758512370d217b19f8890Nathan Haroldimport android.os.ParcelFileDescriptor;
2893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Haroldimport android.os.RemoteException;
29ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Haroldimport android.os.ServiceSpecificException;
30ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Haroldimport android.system.ErrnoException;
31ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Haroldimport android.system.OsConstants;
32330e1089da80cddcd68758512370d217b19f8890Nathan Haroldimport android.util.AndroidException;
338dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Haroldimport android.util.Log;
34b72821747cd8cfa9bcaff7f11247ebfce3255fbfNathan Harold
35a10003d5de52339f4d30fedd7294941378e5f13cNathan Haroldimport com.android.internal.annotations.VisibleForTesting;
36a10003d5de52339f4d30fedd7294941378e5f13cNathan Harold
37330e1089da80cddcd68758512370d217b19f8890Nathan Haroldimport dalvik.system.CloseGuard;
38b72821747cd8cfa9bcaff7f11247ebfce3255fbfNathan Harold
39330e1089da80cddcd68758512370d217b19f8890Nathan Haroldimport java.io.FileDescriptor;
40330e1089da80cddcd68758512370d217b19f8890Nathan Haroldimport java.io.IOException;
41a25233123b2d29fde83dd686f6313f0a232c5b2aNathan Haroldimport java.lang.annotation.Retention;
42a25233123b2d29fde83dd686f6313f0a232c5b2aNathan Haroldimport java.lang.annotation.RetentionPolicy;
43330e1089da80cddcd68758512370d217b19f8890Nathan Haroldimport java.net.DatagramSocket;
44330e1089da80cddcd68758512370d217b19f8890Nathan Haroldimport java.net.InetAddress;
45330e1089da80cddcd68758512370d217b19f8890Nathan Haroldimport java.net.Socket;
46330e1089da80cddcd68758512370d217b19f8890Nathan Harold
47330e1089da80cddcd68758512370d217b19f8890Nathan Harold/**
48c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri * This class contains methods for managing IPsec sessions. Once configured, the kernel will apply
49c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri * confidentiality (encryption) and integrity (authentication) to IP traffic.
50330e1089da80cddcd68758512370d217b19f8890Nathan Harold *
51c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri * <p>Note that not all aspects of IPsec are permitted by this API. Applications may create
52c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri * transport mode security associations and apply them to individual sockets. Applications looking
53c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri * to create a VPN should use {@link VpnService}.
54c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri *
55c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri * @see <a href="https://tools.ietf.org/html/rfc4301">RFC 4301, Security Architecture for the
565fb929032de14ca78163e1d0c42c34f6fb287da4Jonathan Basseri *     Internet Protocol</a>
57330e1089da80cddcd68758512370d217b19f8890Nathan Harold */
58d86b8fea43ebb6e5c31691b44d8ceb0d8d3c9072Jeff Sharkey@SystemService(Context.IPSEC_SERVICE)
59330e1089da80cddcd68758512370d217b19f8890Nathan Haroldpublic final class IpSecManager {
60330e1089da80cddcd68758512370d217b19f8890Nathan Harold    private static final String TAG = "IpSecManager";
61330e1089da80cddcd68758512370d217b19f8890Nathan Harold
62330e1089da80cddcd68758512370d217b19f8890Nathan Harold    /**
637b7bea048511a54a628a8c340a2890dc50e7b451Nathan Harold     * Used when applying a transform to direct traffic through an {@link IpSecTransform}
647b7bea048511a54a628a8c340a2890dc50e7b451Nathan Harold     * towards the host.
657b7bea048511a54a628a8c340a2890dc50e7b451Nathan Harold     *
667b7bea048511a54a628a8c340a2890dc50e7b451Nathan Harold     * <p>See {@link #applyTransportModeTransform(Socket, int, IpSecTransform)}.
67a25233123b2d29fde83dd686f6313f0a232c5b2aNathan Harold     */
68a25233123b2d29fde83dd686f6313f0a232c5b2aNathan Harold    public static final int DIRECTION_IN = 0;
69a25233123b2d29fde83dd686f6313f0a232c5b2aNathan Harold
70a25233123b2d29fde83dd686f6313f0a232c5b2aNathan Harold    /**
717b7bea048511a54a628a8c340a2890dc50e7b451Nathan Harold     * Used when applying a transform to direct traffic through an {@link IpSecTransform}
727b7bea048511a54a628a8c340a2890dc50e7b451Nathan Harold     * away from the host.
737b7bea048511a54a628a8c340a2890dc50e7b451Nathan Harold     *
747b7bea048511a54a628a8c340a2890dc50e7b451Nathan Harold     * <p>See {@link #applyTransportModeTransform(Socket, int, IpSecTransform)}.
75a25233123b2d29fde83dd686f6313f0a232c5b2aNathan Harold     */
76a25233123b2d29fde83dd686f6313f0a232c5b2aNathan Harold    public static final int DIRECTION_OUT = 1;
77a25233123b2d29fde83dd686f6313f0a232c5b2aNathan Harold
78a25233123b2d29fde83dd686f6313f0a232c5b2aNathan Harold    /** @hide */
79a25233123b2d29fde83dd686f6313f0a232c5b2aNathan Harold    @IntDef(value = {DIRECTION_IN, DIRECTION_OUT})
80a25233123b2d29fde83dd686f6313f0a232c5b2aNathan Harold    @Retention(RetentionPolicy.SOURCE)
81a25233123b2d29fde83dd686f6313f0a232c5b2aNathan Harold    public @interface PolicyDirection {}
82a25233123b2d29fde83dd686f6313f0a232c5b2aNathan Harold
83a25233123b2d29fde83dd686f6313f0a232c5b2aNathan Harold    /**
84c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * The Security Parameter Index (SPI) 0 indicates an unknown or invalid index.
8593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     *
8693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     * <p>No IPsec packet may contain an SPI of 0.
87c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     *
88c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * @hide
8993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     */
905fb929032de14ca78163e1d0c42c34f6fb287da4Jonathan Basseri    @TestApi public static final int INVALID_SECURITY_PARAMETER_INDEX = 0;
9193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
9293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    /** @hide */
9393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    public interface Status {
9493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        public static final int OK = 0;
9593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        public static final int RESOURCE_UNAVAILABLE = 1;
9693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        public static final int SPI_UNAVAILABLE = 2;
9793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    }
9893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
9993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    /** @hide */
1006119d8d1d0d89b0d4c4ac822e9e93bb47f1ebd9aNathan Harold    public static final int INVALID_RESOURCE_ID = -1;
10193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
10293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    /**
103c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * Thrown to indicate that a requested SPI is in use.
104c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     *
105c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * <p>The combination of remote {@code InetAddress} and SPI must be unique across all apps on
106c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * one device. If this error is encountered, a new SPI is required before a transform may be
107c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * created. This error can be avoided by calling {@link
1085fb929032de14ca78163e1d0c42c34f6fb287da4Jonathan Basseri     * IpSecManager#allocateSecurityParameterIndex}.
109330e1089da80cddcd68758512370d217b19f8890Nathan Harold     */
110330e1089da80cddcd68758512370d217b19f8890Nathan Harold    public static final class SpiUnavailableException extends AndroidException {
111330e1089da80cddcd68758512370d217b19f8890Nathan Harold        private final int mSpi;
112330e1089da80cddcd68758512370d217b19f8890Nathan Harold
113330e1089da80cddcd68758512370d217b19f8890Nathan Harold        /**
114330e1089da80cddcd68758512370d217b19f8890Nathan Harold         * Construct an exception indicating that a transform with the given SPI is already in use
115330e1089da80cddcd68758512370d217b19f8890Nathan Harold         * or otherwise unavailable.
116330e1089da80cddcd68758512370d217b19f8890Nathan Harold         *
117c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri         * @param msg description indicating the colliding SPI
118330e1089da80cddcd68758512370d217b19f8890Nathan Harold         * @param spi the SPI that could not be used due to a collision
119330e1089da80cddcd68758512370d217b19f8890Nathan Harold         */
120330e1089da80cddcd68758512370d217b19f8890Nathan Harold        SpiUnavailableException(String msg, int spi) {
121c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri            super(msg + " (spi: " + spi + ")");
122330e1089da80cddcd68758512370d217b19f8890Nathan Harold            mSpi = spi;
123330e1089da80cddcd68758512370d217b19f8890Nathan Harold        }
124330e1089da80cddcd68758512370d217b19f8890Nathan Harold
125c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri        /** Get the SPI that caused a collision. */
126330e1089da80cddcd68758512370d217b19f8890Nathan Harold        public int getSpi() {
127330e1089da80cddcd68758512370d217b19f8890Nathan Harold            return mSpi;
128330e1089da80cddcd68758512370d217b19f8890Nathan Harold        }
129330e1089da80cddcd68758512370d217b19f8890Nathan Harold    }
130330e1089da80cddcd68758512370d217b19f8890Nathan Harold
131330e1089da80cddcd68758512370d217b19f8890Nathan Harold    /**
132c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * Thrown to indicate that an IPsec resource is unavailable.
133c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     *
134c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * <p>This could apply to resources such as sockets, {@link SecurityParameterIndex}, {@link
135c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * IpSecTransform}, or other system resources. If this exception is thrown, users should release
136c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * allocated objects of the type requested.
137330e1089da80cddcd68758512370d217b19f8890Nathan Harold     */
138330e1089da80cddcd68758512370d217b19f8890Nathan Harold    public static final class ResourceUnavailableException extends AndroidException {
139330e1089da80cddcd68758512370d217b19f8890Nathan Harold
140330e1089da80cddcd68758512370d217b19f8890Nathan Harold        ResourceUnavailableException(String msg) {
141330e1089da80cddcd68758512370d217b19f8890Nathan Harold            super(msg);
142330e1089da80cddcd68758512370d217b19f8890Nathan Harold        }
143330e1089da80cddcd68758512370d217b19f8890Nathan Harold    }
144330e1089da80cddcd68758512370d217b19f8890Nathan Harold
145592dadbd43fcb7c5d67e737adb34d07923da90c4Nathan Harold    private final Context mContext;
1461afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold    private final IIpSecService mService;
147330e1089da80cddcd68758512370d217b19f8890Nathan Harold
148c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri    /**
149c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * This class represents a reserved SPI.
150c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     *
151c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * <p>Objects of this type are used to track reserved security parameter indices. They can be
1525fb929032de14ca78163e1d0c42c34f6fb287da4Jonathan Basseri     * obtained by calling {@link IpSecManager#allocateSecurityParameterIndex} and must be released
153c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * by calling {@link #close()} when they are no longer needed.
154c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     */
155330e1089da80cddcd68758512370d217b19f8890Nathan Harold    public static final class SecurityParameterIndex implements AutoCloseable {
1561afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold        private final IIpSecService mService;
157a25233123b2d29fde83dd686f6313f0a232c5b2aNathan Harold        private final InetAddress mDestinationAddress;
158330e1089da80cddcd68758512370d217b19f8890Nathan Harold        private final CloseGuard mCloseGuard = CloseGuard.get();
15993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        private int mSpi = INVALID_SECURITY_PARAMETER_INDEX;
1606119d8d1d0d89b0d4c4ac822e9e93bb47f1ebd9aNathan Harold        private int mResourceId = INVALID_RESOURCE_ID;
161330e1089da80cddcd68758512370d217b19f8890Nathan Harold
162c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri        /** Get the underlying SPI held by this object. */
163330e1089da80cddcd68758512370d217b19f8890Nathan Harold        public int getSpi() {
164330e1089da80cddcd68758512370d217b19f8890Nathan Harold            return mSpi;
165330e1089da80cddcd68758512370d217b19f8890Nathan Harold        }
166330e1089da80cddcd68758512370d217b19f8890Nathan Harold
167330e1089da80cddcd68758512370d217b19f8890Nathan Harold        /**
168330e1089da80cddcd68758512370d217b19f8890Nathan Harold         * Release an SPI that was previously reserved.
169330e1089da80cddcd68758512370d217b19f8890Nathan Harold         *
170c4f879925b58b1b5ca9a3cfdc898c20cbf56355aNathan Harold         * <p>Release an SPI for use by other users in the system. If a SecurityParameterIndex is
171c4f879925b58b1b5ca9a3cfdc898c20cbf56355aNathan Harold         * applied to an IpSecTransform, it will become unusable for future transforms but should
172c4f879925b58b1b5ca9a3cfdc898c20cbf56355aNathan Harold         * still be closed to ensure system resources are released.
173330e1089da80cddcd68758512370d217b19f8890Nathan Harold         */
174330e1089da80cddcd68758512370d217b19f8890Nathan Harold        @Override
175330e1089da80cddcd68758512370d217b19f8890Nathan Harold        public void close() {
1768dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            try {
1778dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                mService.releaseSecurityParameterIndex(mResourceId);
1788dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            } catch (RemoteException e) {
1798dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                throw e.rethrowFromSystemServer();
180ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold            } catch (Exception e) {
181ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold                // On close we swallow all random exceptions since failure to close is not
182ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold                // actionable by the user.
183ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold                Log.e(TAG, "Failed to close " + this + ", Exception=" + e);
184ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold            } finally {
185ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold                mResourceId = INVALID_RESOURCE_ID;
186ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold                mCloseGuard.close();
1878dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            }
188330e1089da80cddcd68758512370d217b19f8890Nathan Harold        }
189330e1089da80cddcd68758512370d217b19f8890Nathan Harold
190c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri        /** Check that the SPI was closed properly. */
191330e1089da80cddcd68758512370d217b19f8890Nathan Harold        @Override
192440824f7434e1e2c343b21a9ca3e6f405b8e0ea1Nathan Harold        protected void finalize() throws Throwable {
193330e1089da80cddcd68758512370d217b19f8890Nathan Harold            if (mCloseGuard != null) {
194330e1089da80cddcd68758512370d217b19f8890Nathan Harold                mCloseGuard.warnIfOpen();
195330e1089da80cddcd68758512370d217b19f8890Nathan Harold            }
196330e1089da80cddcd68758512370d217b19f8890Nathan Harold
197330e1089da80cddcd68758512370d217b19f8890Nathan Harold            close();
198330e1089da80cddcd68758512370d217b19f8890Nathan Harold        }
199330e1089da80cddcd68758512370d217b19f8890Nathan Harold
20093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        private SecurityParameterIndex(
201a25233123b2d29fde83dd686f6313f0a232c5b2aNathan Harold                @NonNull IIpSecService service, InetAddress destinationAddress, int spi)
20293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                throws ResourceUnavailableException, SpiUnavailableException {
20393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            mService = service;
204a25233123b2d29fde83dd686f6313f0a232c5b2aNathan Harold            mDestinationAddress = destinationAddress;
20593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            try {
2068dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                IpSecSpiResponse result =
2075fb929032de14ca78163e1d0c42c34f6fb287da4Jonathan Basseri                        mService.allocateSecurityParameterIndex(
208a25233123b2d29fde83dd686f6313f0a232c5b2aNathan Harold                                destinationAddress.getHostAddress(), spi, new Binder());
20993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
21093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                if (result == null) {
21193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                    throw new NullPointerException("Received null response from IpSecService");
21293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                }
21393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
2148dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                int status = result.status;
21593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                switch (status) {
21693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                    case Status.OK:
21793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                        break;
21893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                    case Status.RESOURCE_UNAVAILABLE:
21993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                        throw new ResourceUnavailableException(
22093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                "No more SPIs may be allocated by this requester.");
22193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                    case Status.SPI_UNAVAILABLE:
22293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                        throw new SpiUnavailableException("Requested SPI is unavailable", spi);
22393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                    default:
22493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                        throw new RuntimeException(
22593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                "Unknown status returned by IpSecService: " + status);
22693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                }
2278dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                mSpi = result.spi;
2288dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                mResourceId = result.resourceId;
22993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
23093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                if (mSpi == INVALID_SECURITY_PARAMETER_INDEX) {
23193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                    throw new RuntimeException("Invalid SPI returned by IpSecService: " + status);
23293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                }
23393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
23493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                if (mResourceId == INVALID_RESOURCE_ID) {
23593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                    throw new RuntimeException(
23693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                            "Invalid Resource ID returned by IpSecService: " + status);
23793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                }
23893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            } catch (RemoteException e) {
23993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                throw e.rethrowFromSystemServer();
24093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            }
24193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            mCloseGuard.open("open");
24293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        }
2438dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
2448dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        /** @hide */
245a10003d5de52339f4d30fedd7294941378e5f13cNathan Harold        @VisibleForTesting
246a10003d5de52339f4d30fedd7294941378e5f13cNathan Harold        public int getResourceId() {
2478dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            return mResourceId;
2488dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
249ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold
250ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold        @Override
251ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold        public String toString() {
252ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold            return new StringBuilder()
253ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold                .append("SecurityParameterIndex{spi=")
254ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold                .append(mSpi)
255ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold                .append(",resourceId=")
256ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold                .append(mResourceId)
257ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold                .append("}")
258ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold                .toString();
259ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold        }
26093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    }
261330e1089da80cddcd68758512370d217b19f8890Nathan Harold
262330e1089da80cddcd68758512370d217b19f8890Nathan Harold    /**
263a25233123b2d29fde83dd686f6313f0a232c5b2aNathan Harold     * Reserve a random SPI for traffic bound to or from the specified destination address.
264330e1089da80cddcd68758512370d217b19f8890Nathan Harold     *
265330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * <p>If successful, this SPI is guaranteed available until released by a call to {@link
266330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * SecurityParameterIndex#close()}.
267330e1089da80cddcd68758512370d217b19f8890Nathan Harold     *
268a25233123b2d29fde83dd686f6313f0a232c5b2aNathan Harold     * @param destinationAddress the destination address for traffic bearing the requested SPI.
269a25233123b2d29fde83dd686f6313f0a232c5b2aNathan Harold     *     For inbound traffic, the destination should be an address currently assigned on-device.
270330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * @return the reserved SecurityParameterIndex
271a25233123b2d29fde83dd686f6313f0a232c5b2aNathan Harold     * @throws {@link #ResourceUnavailableException} indicating that too many SPIs are
272a25233123b2d29fde83dd686f6313f0a232c5b2aNathan Harold     *     currently allocated for this user
273330e1089da80cddcd68758512370d217b19f8890Nathan Harold     */
2745cd64cc8012243c656875be6b84456caeabd60f5Nathan Harold    @NonNull
2755cd64cc8012243c656875be6b84456caeabd60f5Nathan Harold    public SecurityParameterIndex allocateSecurityParameterIndex(
2765cd64cc8012243c656875be6b84456caeabd60f5Nathan Harold                @NonNull InetAddress destinationAddress) throws ResourceUnavailableException {
2776045429b35ca4c1cbd920e5e0872dec9de493fdeNathan Harold        try {
2786045429b35ca4c1cbd920e5e0872dec9de493fdeNathan Harold            return new SecurityParameterIndex(
2796045429b35ca4c1cbd920e5e0872dec9de493fdeNathan Harold                    mService,
280a25233123b2d29fde83dd686f6313f0a232c5b2aNathan Harold                    destinationAddress,
2816045429b35ca4c1cbd920e5e0872dec9de493fdeNathan Harold                    IpSecManager.INVALID_SECURITY_PARAMETER_INDEX);
282ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold        } catch (ServiceSpecificException e) {
283ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold            throw rethrowUncheckedExceptionFromServiceSpecificException(e);
2846045429b35ca4c1cbd920e5e0872dec9de493fdeNathan Harold        } catch (SpiUnavailableException unlikely) {
285ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold            // Because this function allocates a totally random SPI, it really shouldn't ever
286ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold            // fail to allocate an SPI; we simply need this because the exception is checked.
2876045429b35ca4c1cbd920e5e0872dec9de493fdeNathan Harold            throw new ResourceUnavailableException("No SPIs available");
2886045429b35ca4c1cbd920e5e0872dec9de493fdeNathan Harold        }
2896045429b35ca4c1cbd920e5e0872dec9de493fdeNathan Harold    }
2906045429b35ca4c1cbd920e5e0872dec9de493fdeNathan Harold
2916045429b35ca4c1cbd920e5e0872dec9de493fdeNathan Harold    /**
292a25233123b2d29fde83dd686f6313f0a232c5b2aNathan Harold     * Reserve the requested SPI for traffic bound to or from the specified destination address.
2936045429b35ca4c1cbd920e5e0872dec9de493fdeNathan Harold     *
2946045429b35ca4c1cbd920e5e0872dec9de493fdeNathan Harold     * <p>If successful, this SPI is guaranteed available until released by a call to {@link
2956045429b35ca4c1cbd920e5e0872dec9de493fdeNathan Harold     * SecurityParameterIndex#close()}.
2966045429b35ca4c1cbd920e5e0872dec9de493fdeNathan Harold     *
297a25233123b2d29fde83dd686f6313f0a232c5b2aNathan Harold     * @param destinationAddress the destination address for traffic bearing the requested SPI.
298a25233123b2d29fde83dd686f6313f0a232c5b2aNathan Harold     *     For inbound traffic, the destination should be an address currently assigned on-device.
299ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold     * @param requestedSpi the requested SPI. The range 1-255 is reserved and may not be used. See
300ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold     *     RFC 4303 Section 2.1.
3016045429b35ca4c1cbd920e5e0872dec9de493fdeNathan Harold     * @return the reserved SecurityParameterIndex
302a25233123b2d29fde83dd686f6313f0a232c5b2aNathan Harold     * @throws {@link #ResourceUnavailableException} indicating that too many SPIs are
303a25233123b2d29fde83dd686f6313f0a232c5b2aNathan Harold     *     currently allocated for this user
304a25233123b2d29fde83dd686f6313f0a232c5b2aNathan Harold     * @throws {@link #SpiUnavailableException} indicating that the requested SPI could not be
305a25233123b2d29fde83dd686f6313f0a232c5b2aNathan Harold     *     reserved
3066045429b35ca4c1cbd920e5e0872dec9de493fdeNathan Harold     */
3075cd64cc8012243c656875be6b84456caeabd60f5Nathan Harold    @NonNull
3085fb929032de14ca78163e1d0c42c34f6fb287da4Jonathan Basseri    public SecurityParameterIndex allocateSecurityParameterIndex(
3095cd64cc8012243c656875be6b84456caeabd60f5Nathan Harold            @NonNull InetAddress destinationAddress, int requestedSpi)
310330e1089da80cddcd68758512370d217b19f8890Nathan Harold            throws SpiUnavailableException, ResourceUnavailableException {
3116045429b35ca4c1cbd920e5e0872dec9de493fdeNathan Harold        if (requestedSpi == IpSecManager.INVALID_SECURITY_PARAMETER_INDEX) {
3126045429b35ca4c1cbd920e5e0872dec9de493fdeNathan Harold            throw new IllegalArgumentException("Requested SPI must be a valid (non-zero) SPI");
3136045429b35ca4c1cbd920e5e0872dec9de493fdeNathan Harold        }
314ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold        try {
315ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold            return new SecurityParameterIndex(mService, destinationAddress, requestedSpi);
316ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold        } catch (ServiceSpecificException e) {
317ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold            throw rethrowUncheckedExceptionFromServiceSpecificException(e);
318ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold        }
319330e1089da80cddcd68758512370d217b19f8890Nathan Harold    }
320330e1089da80cddcd68758512370d217b19f8890Nathan Harold
321330e1089da80cddcd68758512370d217b19f8890Nathan Harold    /**
322c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * Apply an IPsec transform to a stream socket.
323c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     *
324c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * <p>This applies transport mode encapsulation to the given socket. Once applied, I/O on the
325c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When
326a25233123b2d29fde83dd686f6313f0a232c5b2aNathan Harold     * the transform is removed from the socket by calling {@link #removeTransportModeTransforms},
327c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * unprotected traffic can resume on that socket.
328c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     *
329c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * <p>For security reasons, the destination address of any traffic on the socket must match the
3305fb929032de14ca78163e1d0c42c34f6fb287da4Jonathan Basseri     * remote {@code InetAddress} of the {@code IpSecTransform}. Attempts to send traffic to any
331c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * other IP address will result in an IOException. In addition, reads and writes on the socket
332c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * will throw IOException if the user deactivates the transform (by calling {@link
333a25233123b2d29fde83dd686f6313f0a232c5b2aNathan Harold     * IpSecTransform#close()}) without calling {@link #removeTransportModeTransforms}.
334c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     *
335420fe002f1d35e870d519344a13de9f6501e4ddbBenedict Wong     * <p>Note that when applied to TCP sockets, calling {@link IpSecTransform#close()} on an
336420fe002f1d35e870d519344a13de9f6501e4ddbBenedict Wong     * applied transform before completion of graceful shutdown may result in the shutdown sequence
337420fe002f1d35e870d519344a13de9f6501e4ddbBenedict Wong     * failing to complete. As such, applications requiring graceful shutdown MUST close the socket
338420fe002f1d35e870d519344a13de9f6501e4ddbBenedict Wong     * prior to deactivating the applied transform. Socket closure may be performed asynchronously
339420fe002f1d35e870d519344a13de9f6501e4ddbBenedict Wong     * (in batches), so the returning of a close function does not guarantee shutdown of a socket.
340420fe002f1d35e870d519344a13de9f6501e4ddbBenedict Wong     * Setting an SO_LINGER timeout results in socket closure being performed synchronously, and is
341420fe002f1d35e870d519344a13de9f6501e4ddbBenedict Wong     * sufficient to ensure shutdown.
342420fe002f1d35e870d519344a13de9f6501e4ddbBenedict Wong     *
343420fe002f1d35e870d519344a13de9f6501e4ddbBenedict Wong     * Specifically, if the transform is deactivated (by calling {@link IpSecTransform#close()}),
344420fe002f1d35e870d519344a13de9f6501e4ddbBenedict Wong     * prior to the socket being closed, the standard [FIN - FIN/ACK - ACK], or the reset [RST]
345420fe002f1d35e870d519344a13de9f6501e4ddbBenedict Wong     * packets are dropped due to the lack of a valid Transform. Similarly, if a socket without the
346420fe002f1d35e870d519344a13de9f6501e4ddbBenedict Wong     * SO_LINGER option set is closed, the delayed/batched FIN packets may be dropped.
347420fe002f1d35e870d519344a13de9f6501e4ddbBenedict Wong     *
3485fb929032de14ca78163e1d0c42c34f6fb287da4Jonathan Basseri     * <h4>Rekey Procedure</h4>
3495fb929032de14ca78163e1d0c42c34f6fb287da4Jonathan Basseri     *
3507b7bea048511a54a628a8c340a2890dc50e7b451Nathan Harold     * <p>When applying a new tranform to a socket in the outbound direction, the previous transform
3517b7bea048511a54a628a8c340a2890dc50e7b451Nathan Harold     * will be removed and the new transform will take effect immediately, sending all traffic on
3527b7bea048511a54a628a8c340a2890dc50e7b451Nathan Harold     * the new transform; however, when applying a transform in the inbound direction, traffic
3537b7bea048511a54a628a8c340a2890dc50e7b451Nathan Harold     * on the old transform will continue to be decrypted and delivered until that transform is
3547b7bea048511a54a628a8c340a2890dc50e7b451Nathan Harold     * deallocated by calling {@link IpSecTransform#close()}. This overlap allows lossless rekey
3557b7bea048511a54a628a8c340a2890dc50e7b451Nathan Harold     * procedures where both transforms are valid until both endpoints are using the new transform
3567b7bea048511a54a628a8c340a2890dc50e7b451Nathan Harold     * and all in-flight packets have been received.
357330e1089da80cddcd68758512370d217b19f8890Nathan Harold     *
358330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * @param socket a stream socket
3597b7bea048511a54a628a8c340a2890dc50e7b451Nathan Harold     * @param direction the direction in which the transform should be applied
360c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * @param transform a transport mode {@code IpSecTransform}
361c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * @throws IOException indicating that the transform could not be applied
362330e1089da80cddcd68758512370d217b19f8890Nathan Harold     */
3635cd64cc8012243c656875be6b84456caeabd60f5Nathan Harold    public void applyTransportModeTransform(@NonNull Socket socket,
3645cd64cc8012243c656875be6b84456caeabd60f5Nathan Harold            @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException {
3655e9b4c7c338e31b9acc2e4d3fb877202e435a32eBenedict Wong        // Ensure creation of FD. See b/77548890 for more details.
3665e9b4c7c338e31b9acc2e4d3fb877202e435a32eBenedict Wong        socket.getSoLinger();
3675e9b4c7c338e31b9acc2e4d3fb877202e435a32eBenedict Wong
368b548d251b7995a5b76e495978b61ad6c3c4183d1Nathan Harold        applyTransportModeTransform(socket.getFileDescriptor$(), direction, transform);
369330e1089da80cddcd68758512370d217b19f8890Nathan Harold    }
370330e1089da80cddcd68758512370d217b19f8890Nathan Harold
371330e1089da80cddcd68758512370d217b19f8890Nathan Harold    /**
372c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * Apply an IPsec transform to a datagram socket.
373c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     *
374c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * <p>This applies transport mode encapsulation to the given socket. Once applied, I/O on the
375c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When
376a25233123b2d29fde83dd686f6313f0a232c5b2aNathan Harold     * the transform is removed from the socket by calling {@link #removeTransportModeTransforms},
377c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * unprotected traffic can resume on that socket.
378c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     *
379c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * <p>For security reasons, the destination address of any traffic on the socket must match the
380c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * remote {@code InetAddress} of the {@code IpSecTransform}. Attempts to send traffic to any
381c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * other IP address will result in an IOException. In addition, reads and writes on the socket
382c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * will throw IOException if the user deactivates the transform (by calling {@link
383a25233123b2d29fde83dd686f6313f0a232c5b2aNathan Harold     * IpSecTransform#close()}) without calling {@link #removeTransportModeTransforms}.
384c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     *
3855fb929032de14ca78163e1d0c42c34f6fb287da4Jonathan Basseri     * <h4>Rekey Procedure</h4>
3865fb929032de14ca78163e1d0c42c34f6fb287da4Jonathan Basseri     *
3877b7bea048511a54a628a8c340a2890dc50e7b451Nathan Harold     * <p>When applying a new tranform to a socket in the outbound direction, the previous transform
3887b7bea048511a54a628a8c340a2890dc50e7b451Nathan Harold     * will be removed and the new transform will take effect immediately, sending all traffic on
3897b7bea048511a54a628a8c340a2890dc50e7b451Nathan Harold     * the new transform; however, when applying a transform in the inbound direction, traffic
3907b7bea048511a54a628a8c340a2890dc50e7b451Nathan Harold     * on the old transform will continue to be decrypted and delivered until that transform is
3917b7bea048511a54a628a8c340a2890dc50e7b451Nathan Harold     * deallocated by calling {@link IpSecTransform#close()}. This overlap allows lossless rekey
3927b7bea048511a54a628a8c340a2890dc50e7b451Nathan Harold     * procedures where both transforms are valid until both endpoints are using the new transform
3937b7bea048511a54a628a8c340a2890dc50e7b451Nathan Harold     * and all in-flight packets have been received.
394330e1089da80cddcd68758512370d217b19f8890Nathan Harold     *
395330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * @param socket a datagram socket
3967b7bea048511a54a628a8c340a2890dc50e7b451Nathan Harold     * @param direction the direction in which the transform should be applied
397c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * @param transform a transport mode {@code IpSecTransform}
398c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * @throws IOException indicating that the transform could not be applied
399330e1089da80cddcd68758512370d217b19f8890Nathan Harold     */
4005cd64cc8012243c656875be6b84456caeabd60f5Nathan Harold    public void applyTransportModeTransform(@NonNull DatagramSocket socket,
4015cd64cc8012243c656875be6b84456caeabd60f5Nathan Harold            @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException {
402b548d251b7995a5b76e495978b61ad6c3c4183d1Nathan Harold        applyTransportModeTransform(socket.getFileDescriptor$(), direction, transform);
40393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    }
404330e1089da80cddcd68758512370d217b19f8890Nathan Harold
405330e1089da80cddcd68758512370d217b19f8890Nathan Harold    /**
406c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * Apply an IPsec transform to a socket.
407c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     *
408c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * <p>This applies transport mode encapsulation to the given socket. Once applied, I/O on the
409c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When
410a25233123b2d29fde83dd686f6313f0a232c5b2aNathan Harold     * the transform is removed from the socket by calling {@link #removeTransportModeTransforms},
411c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * unprotected traffic can resume on that socket.
412c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     *
413c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * <p>For security reasons, the destination address of any traffic on the socket must match the
414c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * remote {@code InetAddress} of the {@code IpSecTransform}. Attempts to send traffic to any
415c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * other IP address will result in an IOException. In addition, reads and writes on the socket
416c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * will throw IOException if the user deactivates the transform (by calling {@link
417a25233123b2d29fde83dd686f6313f0a232c5b2aNathan Harold     * IpSecTransform#close()}) without calling {@link #removeTransportModeTransforms}.
418c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     *
419420fe002f1d35e870d519344a13de9f6501e4ddbBenedict Wong     * <p>Note that when applied to TCP sockets, calling {@link IpSecTransform#close()} on an
420420fe002f1d35e870d519344a13de9f6501e4ddbBenedict Wong     * applied transform before completion of graceful shutdown may result in the shutdown sequence
421420fe002f1d35e870d519344a13de9f6501e4ddbBenedict Wong     * failing to complete. As such, applications requiring graceful shutdown MUST close the socket
422420fe002f1d35e870d519344a13de9f6501e4ddbBenedict Wong     * prior to deactivating the applied transform. Socket closure may be performed asynchronously
423420fe002f1d35e870d519344a13de9f6501e4ddbBenedict Wong     * (in batches), so the returning of a close function does not guarantee shutdown of a socket.
424420fe002f1d35e870d519344a13de9f6501e4ddbBenedict Wong     * Setting an SO_LINGER timeout results in socket closure being performed synchronously, and is
425420fe002f1d35e870d519344a13de9f6501e4ddbBenedict Wong     * sufficient to ensure shutdown.
426420fe002f1d35e870d519344a13de9f6501e4ddbBenedict Wong     *
427420fe002f1d35e870d519344a13de9f6501e4ddbBenedict Wong     * Specifically, if the transform is deactivated (by calling {@link IpSecTransform#close()}),
428420fe002f1d35e870d519344a13de9f6501e4ddbBenedict Wong     * prior to the socket being closed, the standard [FIN - FIN/ACK - ACK], or the reset [RST]
429420fe002f1d35e870d519344a13de9f6501e4ddbBenedict Wong     * packets are dropped due to the lack of a valid Transform. Similarly, if a socket without the
430420fe002f1d35e870d519344a13de9f6501e4ddbBenedict Wong     * SO_LINGER option set is closed, the delayed/batched FIN packets may be dropped.
431420fe002f1d35e870d519344a13de9f6501e4ddbBenedict Wong     *
4325fb929032de14ca78163e1d0c42c34f6fb287da4Jonathan Basseri     * <h4>Rekey Procedure</h4>
4335fb929032de14ca78163e1d0c42c34f6fb287da4Jonathan Basseri     *
4347b7bea048511a54a628a8c340a2890dc50e7b451Nathan Harold     * <p>When applying a new tranform to a socket in the outbound direction, the previous transform
4357b7bea048511a54a628a8c340a2890dc50e7b451Nathan Harold     * will be removed and the new transform will take effect immediately, sending all traffic on
4367b7bea048511a54a628a8c340a2890dc50e7b451Nathan Harold     * the new transform; however, when applying a transform in the inbound direction, traffic
4377b7bea048511a54a628a8c340a2890dc50e7b451Nathan Harold     * on the old transform will continue to be decrypted and delivered until that transform is
4387b7bea048511a54a628a8c340a2890dc50e7b451Nathan Harold     * deallocated by calling {@link IpSecTransform#close()}. This overlap allows lossless rekey
4397b7bea048511a54a628a8c340a2890dc50e7b451Nathan Harold     * procedures where both transforms are valid until both endpoints are using the new transform
4407b7bea048511a54a628a8c340a2890dc50e7b451Nathan Harold     * and all in-flight packets have been received.
441b64993559b049327365bb63e81e8046a892a1033Nathan Harold     *
442b64993559b049327365bb63e81e8046a892a1033Nathan Harold     * @param socket a socket file descriptor
4437b7bea048511a54a628a8c340a2890dc50e7b451Nathan Harold     * @param direction the direction in which the transform should be applied
444c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * @param transform a transport mode {@code IpSecTransform}
445c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * @throws IOException indicating that the transform could not be applied
446b64993559b049327365bb63e81e8046a892a1033Nathan Harold     */
4475cd64cc8012243c656875be6b84456caeabd60f5Nathan Harold    public void applyTransportModeTransform(@NonNull FileDescriptor socket,
4485cd64cc8012243c656875be6b84456caeabd60f5Nathan Harold            @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException {
4498dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        // We dup() the FileDescriptor here because if we don't, then the ParcelFileDescriptor()
450b548d251b7995a5b76e495978b61ad6c3c4183d1Nathan Harold        // constructor takes control and closes the user's FD when we exit the method.
4518dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) {
452a25233123b2d29fde83dd686f6313f0a232c5b2aNathan Harold            mService.applyTransportModeTransform(pfd, direction, transform.getResourceId());
453ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold        } catch (ServiceSpecificException e) {
454ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold            throw rethrowCheckedExceptionFromServiceSpecificException(e);
4558dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        } catch (RemoteException e) {
4568dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            throw e.rethrowFromSystemServer();
4578dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
458b64993559b049327365bb63e81e8046a892a1033Nathan Harold    }
459b64993559b049327365bb63e81e8046a892a1033Nathan Harold
460b64993559b049327365bb63e81e8046a892a1033Nathan Harold    /**
461c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * Remove an IPsec transform from a stream socket.
462c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     *
463f73d252c8f51936eec49313f4cc26f1da7727b6cNathan Harold     * <p>Once removed, traffic on the socket will not be encrypted. Removing transforms from a
464f73d252c8f51936eec49313f4cc26f1da7727b6cNathan Harold     * socket allows the socket to be reused for communication in the clear.
465c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     *
466c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * <p>If an {@code IpSecTransform} object applied to this socket was deallocated by calling
467c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * {@link IpSecTransform#close()}, then communication on the socket will fail until this method
468c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * is called.
469330e1089da80cddcd68758512370d217b19f8890Nathan Harold     *
470c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * @param socket a socket that previously had a transform applied to it
471c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * @throws IOException indicating that the transform could not be removed from the socket
472330e1089da80cddcd68758512370d217b19f8890Nathan Harold     */
4735cd64cc8012243c656875be6b84456caeabd60f5Nathan Harold    public void removeTransportModeTransforms(@NonNull Socket socket) throws IOException {
4745e9b4c7c338e31b9acc2e4d3fb877202e435a32eBenedict Wong        // Ensure creation of FD. See b/77548890 for more details.
4755e9b4c7c338e31b9acc2e4d3fb877202e435a32eBenedict Wong        socket.getSoLinger();
4765e9b4c7c338e31b9acc2e4d3fb877202e435a32eBenedict Wong
477f73d252c8f51936eec49313f4cc26f1da7727b6cNathan Harold        removeTransportModeTransforms(socket.getFileDescriptor$());
478330e1089da80cddcd68758512370d217b19f8890Nathan Harold    }
479330e1089da80cddcd68758512370d217b19f8890Nathan Harold
480330e1089da80cddcd68758512370d217b19f8890Nathan Harold    /**
481c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * Remove an IPsec transform from a datagram socket.
482330e1089da80cddcd68758512370d217b19f8890Nathan Harold     *
483f73d252c8f51936eec49313f4cc26f1da7727b6cNathan Harold     * <p>Once removed, traffic on the socket will not be encrypted. Removing transforms from a
484f73d252c8f51936eec49313f4cc26f1da7727b6cNathan Harold     * socket allows the socket to be reused for communication in the clear.
485c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     *
486c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * <p>If an {@code IpSecTransform} object applied to this socket was deallocated by calling
487c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * {@link IpSecTransform#close()}, then communication on the socket will fail until this method
488c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * is called.
489c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     *
490c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * @param socket a socket that previously had a transform applied to it
491c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * @throws IOException indicating that the transform could not be removed from the socket
492330e1089da80cddcd68758512370d217b19f8890Nathan Harold     */
4935cd64cc8012243c656875be6b84456caeabd60f5Nathan Harold    public void removeTransportModeTransforms(@NonNull DatagramSocket socket) throws IOException {
494f73d252c8f51936eec49313f4cc26f1da7727b6cNathan Harold        removeTransportModeTransforms(socket.getFileDescriptor$());
495330e1089da80cddcd68758512370d217b19f8890Nathan Harold    }
496330e1089da80cddcd68758512370d217b19f8890Nathan Harold
497b64993559b049327365bb63e81e8046a892a1033Nathan Harold    /**
498c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * Remove an IPsec transform from a socket.
499c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     *
500f73d252c8f51936eec49313f4cc26f1da7727b6cNathan Harold     * <p>Once removed, traffic on the socket will not be encrypted. Removing transforms from a
501f73d252c8f51936eec49313f4cc26f1da7727b6cNathan Harold     * socket allows the socket to be reused for communication in the clear.
502b64993559b049327365bb63e81e8046a892a1033Nathan Harold     *
503c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * <p>If an {@code IpSecTransform} object applied to this socket was deallocated by calling
504c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * {@link IpSecTransform#close()}, then communication on the socket will fail until this method
505c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * is called.
506c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     *
507c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * @param socket a socket that previously had a transform applied to it
508c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * @throws IOException indicating that the transform could not be removed from the socket
509b64993559b049327365bb63e81e8046a892a1033Nathan Harold     */
5105cd64cc8012243c656875be6b84456caeabd60f5Nathan Harold    public void removeTransportModeTransforms(@NonNull FileDescriptor socket) throws IOException {
5118dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) {
512f73d252c8f51936eec49313f4cc26f1da7727b6cNathan Harold            mService.removeTransportModeTransforms(pfd);
513ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold        } catch (ServiceSpecificException e) {
514ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold            throw rethrowCheckedExceptionFromServiceSpecificException(e);
51593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        } catch (RemoteException e) {
51693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            throw e.rethrowFromSystemServer();
51793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        }
51893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    }
519330e1089da80cddcd68758512370d217b19f8890Nathan Harold
520330e1089da80cddcd68758512370d217b19f8890Nathan Harold    /**
521330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * Remove a Tunnel Mode IPsec Transform from a {@link Network}. This must be used as part of
522330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * cleanup if a tunneled Network experiences a change in default route. The Network will drop
523330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * all traffic that cannot be routed to the Tunnel's outbound interface. If that interface is
524330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * lost, all traffic will drop.
525330e1089da80cddcd68758512370d217b19f8890Nathan Harold     *
5265fb929032de14ca78163e1d0c42c34f6fb287da4Jonathan Basseri     * <p>TODO: Update javadoc for tunnel mode APIs at the same time the APIs are re-worked.
5275fb929032de14ca78163e1d0c42c34f6fb287da4Jonathan Basseri     *
528330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * @param net a network that currently has transform applied to it.
529330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * @param transform a Tunnel Mode IPsec Transform that has been previously applied to the given
530330e1089da80cddcd68758512370d217b19f8890Nathan Harold     *     network
531330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * @hide
532330e1089da80cddcd68758512370d217b19f8890Nathan Harold     */
533330e1089da80cddcd68758512370d217b19f8890Nathan Harold    public void removeTunnelModeTransform(Network net, IpSecTransform transform) {}
534330e1089da80cddcd68758512370d217b19f8890Nathan Harold
535330e1089da80cddcd68758512370d217b19f8890Nathan Harold    /**
536c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * This class provides access to a UDP encapsulation Socket.
537330e1089da80cddcd68758512370d217b19f8890Nathan Harold     *
538c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * <p>{@code UdpEncapsulationSocket} wraps a system-provided datagram socket intended for IKEv2
539c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * signalling and UDP encapsulated IPsec traffic. Instances can be obtained by calling {@link
540c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * IpSecManager#openUdpEncapsulationSocket}. The provided socket cannot be re-bound by the
541c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * caller. The caller should not close the {@code FileDescriptor} returned by {@link
5426ea93c4bcaf5c2c8489695308e77b659b70b64d4Benedict Wong     * #getFileDescriptor}, but should use {@link #close} instead.
543c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     *
544c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * <p>Allowing the user to close or unbind a UDP encapsulation socket could impact the traffic
545c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * of the next user who binds to that port. To prevent this scenario, these sockets are held
546c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * open by the system so that they may only be closed by calling {@link #close} or when the user
547c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * process exits.
548330e1089da80cddcd68758512370d217b19f8890Nathan Harold     */
549330e1089da80cddcd68758512370d217b19f8890Nathan Harold    public static final class UdpEncapsulationSocket implements AutoCloseable {
5508dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        private final ParcelFileDescriptor mPfd;
5511afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold        private final IIpSecService mService;
5526119d8d1d0d89b0d4c4ac822e9e93bb47f1ebd9aNathan Harold        private int mResourceId = INVALID_RESOURCE_ID;
5538dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        private final int mPort;
554330e1089da80cddcd68758512370d217b19f8890Nathan Harold        private final CloseGuard mCloseGuard = CloseGuard.get();
555330e1089da80cddcd68758512370d217b19f8890Nathan Harold
55693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        private UdpEncapsulationSocket(@NonNull IIpSecService service, int port)
5578dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                throws ResourceUnavailableException, IOException {
5581afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold            mService = service;
5598dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            try {
5608dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                IpSecUdpEncapResponse result =
5618dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                        mService.openUdpEncapsulationSocket(port, new Binder());
5628dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                switch (result.status) {
5638dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                    case Status.OK:
5648dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                        break;
5658dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                    case Status.RESOURCE_UNAVAILABLE:
5668dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                        throw new ResourceUnavailableException(
5678dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                                "No more Sockets may be allocated by this requester.");
5688dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                    default:
5698dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                        throw new RuntimeException(
5708dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                                "Unknown status returned by IpSecService: " + result.status);
5718dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                }
5728dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                mResourceId = result.resourceId;
5738dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                mPort = result.port;
5748dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                mPfd = result.fileDescriptor;
5758dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            } catch (RemoteException e) {
5768dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                throw e.rethrowFromSystemServer();
5778dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            }
578330e1089da80cddcd68758512370d217b19f8890Nathan Harold            mCloseGuard.open("constructor");
579330e1089da80cddcd68758512370d217b19f8890Nathan Harold        }
580330e1089da80cddcd68758512370d217b19f8890Nathan Harold
5816ea93c4bcaf5c2c8489695308e77b659b70b64d4Benedict Wong        /** Get the encapsulation socket's file descriptor. */
5826ea93c4bcaf5c2c8489695308e77b659b70b64d4Benedict Wong        public FileDescriptor getFileDescriptor() {
5838dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            if (mPfd == null) {
5848dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                return null;
5858dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            }
5868dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            return mPfd.getFileDescriptor();
587330e1089da80cddcd68758512370d217b19f8890Nathan Harold        }
588330e1089da80cddcd68758512370d217b19f8890Nathan Harold
589c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri        /** Get the bound port of the wrapped socket. */
590330e1089da80cddcd68758512370d217b19f8890Nathan Harold        public int getPort() {
5918dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            return mPort;
592330e1089da80cddcd68758512370d217b19f8890Nathan Harold        }
593330e1089da80cddcd68758512370d217b19f8890Nathan Harold
594330e1089da80cddcd68758512370d217b19f8890Nathan Harold        /**
595c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri         * Close this socket.
596330e1089da80cddcd68758512370d217b19f8890Nathan Harold         *
597c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri         * <p>This closes the wrapped socket. Open encapsulation sockets count against a user's
598c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri         * resource limits, and forgetting to close them eventually will result in {@link
599c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri         * ResourceUnavailableException} being thrown.
600330e1089da80cddcd68758512370d217b19f8890Nathan Harold         */
601c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri        @Override
6020bfb2075320a9f648fc2b3fcdfc58f425c9a685aNathan Harold        public void close() throws IOException {
6038dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            try {
6048dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                mService.closeUdpEncapsulationSocket(mResourceId);
6056119d8d1d0d89b0d4c4ac822e9e93bb47f1ebd9aNathan Harold                mResourceId = INVALID_RESOURCE_ID;
6068dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            } catch (RemoteException e) {
6078dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                throw e.rethrowFromSystemServer();
608ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold            } catch (Exception e) {
609ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold                // On close we swallow all random exceptions since failure to close is not
610ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold                // actionable by the user.
611ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold                Log.e(TAG, "Failed to close " + this + ", Exception=" + e);
612ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold            } finally {
613ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold                mResourceId = INVALID_RESOURCE_ID;
614ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold                mCloseGuard.close();
6158dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            }
6168dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
6178dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            try {
6188dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                mPfd.close();
6198dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            } catch (IOException e) {
6208dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                Log.e(TAG, "Failed to close UDP Encapsulation Socket with Port= " + mPort);
6218dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                throw e;
6228dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            }
623330e1089da80cddcd68758512370d217b19f8890Nathan Harold        }
624330e1089da80cddcd68758512370d217b19f8890Nathan Harold
625c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri        /** Check that the socket was closed properly. */
626330e1089da80cddcd68758512370d217b19f8890Nathan Harold        @Override
627330e1089da80cddcd68758512370d217b19f8890Nathan Harold        protected void finalize() throws Throwable {
628330e1089da80cddcd68758512370d217b19f8890Nathan Harold            if (mCloseGuard != null) {
629330e1089da80cddcd68758512370d217b19f8890Nathan Harold                mCloseGuard.warnIfOpen();
630330e1089da80cddcd68758512370d217b19f8890Nathan Harold            }
631330e1089da80cddcd68758512370d217b19f8890Nathan Harold            close();
632330e1089da80cddcd68758512370d217b19f8890Nathan Harold        }
6338dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
6348dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        /** @hide */
635a10003d5de52339f4d30fedd7294941378e5f13cNathan Harold        @VisibleForTesting
636a10003d5de52339f4d30fedd7294941378e5f13cNathan Harold        public int getResourceId() {
6378dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            return mResourceId;
6388dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
639ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold
640ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold        @Override
641ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold        public String toString() {
642ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold            return new StringBuilder()
643ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold                .append("UdpEncapsulationSocket{port=")
644ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold                .append(mPort)
645ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold                .append(",resourceId=")
646ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold                .append(mResourceId)
647ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold                .append("}")
648ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold                .toString();
649ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold        }
650330e1089da80cddcd68758512370d217b19f8890Nathan Harold    };
651330e1089da80cddcd68758512370d217b19f8890Nathan Harold
652330e1089da80cddcd68758512370d217b19f8890Nathan Harold    /**
653c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * Open a socket for UDP encapsulation and bind to the given port.
654330e1089da80cddcd68758512370d217b19f8890Nathan Harold     *
655c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * <p>See {@link UdpEncapsulationSocket} for the proper way to close the returned socket.
656330e1089da80cddcd68758512370d217b19f8890Nathan Harold     *
657c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * @param port a local UDP port
658c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * @return a socket that is bound to the given port
659c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * @throws IOException indicating that the socket could not be opened or bound
660c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * @throws ResourceUnavailableException indicating that too many encapsulation sockets are open
661330e1089da80cddcd68758512370d217b19f8890Nathan Harold     */
662330e1089da80cddcd68758512370d217b19f8890Nathan Harold    // Returning a socket in this fashion that has been created and bound by the system
663330e1089da80cddcd68758512370d217b19f8890Nathan Harold    // is the only safe way to ensure that a socket is both accessible to the user and
664330e1089da80cddcd68758512370d217b19f8890Nathan Harold    // safely usable for Encapsulation without allowing a user to possibly unbind from/close
665330e1089da80cddcd68758512370d217b19f8890Nathan Harold    // the port, which could potentially impact the traffic of the next user who binds to that
666330e1089da80cddcd68758512370d217b19f8890Nathan Harold    // socket.
6675cd64cc8012243c656875be6b84456caeabd60f5Nathan Harold    @NonNull
668330e1089da80cddcd68758512370d217b19f8890Nathan Harold    public UdpEncapsulationSocket openUdpEncapsulationSocket(int port)
669330e1089da80cddcd68758512370d217b19f8890Nathan Harold            throws IOException, ResourceUnavailableException {
6708dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        /*
6718dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold         * Most range checking is done in the service, but this version of the constructor expects
6728dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold         * a valid port number, and zero cannot be checked after being passed to the service.
6738dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold         */
6748dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        if (port == 0) {
6758dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            throw new IllegalArgumentException("Specified port must be a valid port number!");
6768dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
677ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold        try {
678ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold            return new UdpEncapsulationSocket(mService, port);
679ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold        } catch (ServiceSpecificException e) {
680ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold            throw rethrowCheckedExceptionFromServiceSpecificException(e);
681ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold        }
682330e1089da80cddcd68758512370d217b19f8890Nathan Harold    }
683330e1089da80cddcd68758512370d217b19f8890Nathan Harold
684330e1089da80cddcd68758512370d217b19f8890Nathan Harold    /**
685c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * Open a socket for UDP encapsulation.
686330e1089da80cddcd68758512370d217b19f8890Nathan Harold     *
687c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * <p>See {@link UdpEncapsulationSocket} for the proper way to close the returned socket.
688330e1089da80cddcd68758512370d217b19f8890Nathan Harold     *
689c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * <p>The local port of the returned socket can be obtained by calling {@link
690c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * UdpEncapsulationSocket#getPort()}.
691330e1089da80cddcd68758512370d217b19f8890Nathan Harold     *
692c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * @return a socket that is bound to a local port
693c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * @throws IOException indicating that the socket could not be opened or bound
694c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * @throws ResourceUnavailableException indicating that too many encapsulation sockets are open
695330e1089da80cddcd68758512370d217b19f8890Nathan Harold     */
696330e1089da80cddcd68758512370d217b19f8890Nathan Harold    // Returning a socket in this fashion that has been created and bound by the system
697330e1089da80cddcd68758512370d217b19f8890Nathan Harold    // is the only safe way to ensure that a socket is both accessible to the user and
698330e1089da80cddcd68758512370d217b19f8890Nathan Harold    // safely usable for Encapsulation without allowing a user to possibly unbind from/close
699330e1089da80cddcd68758512370d217b19f8890Nathan Harold    // the port, which could potentially impact the traffic of the next user who binds to that
700330e1089da80cddcd68758512370d217b19f8890Nathan Harold    // socket.
7015cd64cc8012243c656875be6b84456caeabd60f5Nathan Harold    @NonNull
702330e1089da80cddcd68758512370d217b19f8890Nathan Harold    public UdpEncapsulationSocket openUdpEncapsulationSocket()
703330e1089da80cddcd68758512370d217b19f8890Nathan Harold            throws IOException, ResourceUnavailableException {
704ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold        try {
705ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold            return new UdpEncapsulationSocket(mService, 0);
706ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold        } catch (ServiceSpecificException e) {
707ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold            throw rethrowCheckedExceptionFromServiceSpecificException(e);
708ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold        }
709330e1089da80cddcd68758512370d217b19f8890Nathan Harold    }
710330e1089da80cddcd68758512370d217b19f8890Nathan Harold
711330e1089da80cddcd68758512370d217b19f8890Nathan Harold    /**
712c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold     * This class represents an IpSecTunnelInterface
713c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold     *
714c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold     * <p>IpSecTunnelInterface objects track tunnel interfaces that serve as
715c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold     * local endpoints for IPsec tunnels.
716c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold     *
717c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold     * <p>Creating an IpSecTunnelInterface creates a device to which IpSecTransforms may be
718c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold     * applied to provide IPsec security to packets sent through the tunnel. While a tunnel
719c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold     * cannot be used in standalone mode within Android, the higher layers may use the tunnel
720c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold     * to create Network objects which are accessible to the Android system.
721c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold     * @hide
722c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold     */
723c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold    public static final class IpSecTunnelInterface implements AutoCloseable {
724592dadbd43fcb7c5d67e737adb34d07923da90c4Nathan Harold        private final String mOpPackageName;
725c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold        private final IIpSecService mService;
726c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold        private final InetAddress mRemoteAddress;
727c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold        private final InetAddress mLocalAddress;
728c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold        private final Network mUnderlyingNetwork;
729c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold        private final CloseGuard mCloseGuard = CloseGuard.get();
730c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold        private String mInterfaceName;
731c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold        private int mResourceId = INVALID_RESOURCE_ID;
732c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold
733c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold        /** Get the underlying SPI held by this object. */
7345cd64cc8012243c656875be6b84456caeabd60f5Nathan Harold        @NonNull
735c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold        public String getInterfaceName() {
736c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold            return mInterfaceName;
737c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold        }
738c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold
739c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold        /**
740c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold         * Add an address to the IpSecTunnelInterface
741c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold         *
742c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold         * <p>Add an address which may be used as the local inner address for
743c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold         * tunneled traffic.
744c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold         *
745c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold         * @param address the local address for traffic inside the tunnel
7463f2c54b7820c3a568890700479230966fdbcf0a4Benedict Wong         * @param prefixLen length of the InetAddress prefix
747c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold         * @hide
748c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold         */
749159788455c79fa47847d0c40fcee7aceff2551aeNathan Harold        @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
7503f2c54b7820c3a568890700479230966fdbcf0a4Benedict Wong        public void addAddress(@NonNull InetAddress address, int prefixLen) throws IOException {
751da4b0c65a5cbebf6c5e66b869b75dd3a6625cd2eBenedict Wong            try {
752592dadbd43fcb7c5d67e737adb34d07923da90c4Nathan Harold                mService.addAddressToTunnelInterface(
7533f2c54b7820c3a568890700479230966fdbcf0a4Benedict Wong                        mResourceId, new LinkAddress(address, prefixLen), mOpPackageName);
754ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold            } catch (ServiceSpecificException e) {
755ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold                throw rethrowCheckedExceptionFromServiceSpecificException(e);
756da4b0c65a5cbebf6c5e66b869b75dd3a6625cd2eBenedict Wong            } catch (RemoteException e) {
757da4b0c65a5cbebf6c5e66b869b75dd3a6625cd2eBenedict Wong                throw e.rethrowFromSystemServer();
758da4b0c65a5cbebf6c5e66b869b75dd3a6625cd2eBenedict Wong            }
759c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold        }
760c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold
761c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold        /**
762c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold         * Remove an address from the IpSecTunnelInterface
763c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold         *
764c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold         * <p>Remove an address which was previously added to the IpSecTunnelInterface
765c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold         *
766c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold         * @param address to be removed
7673f2c54b7820c3a568890700479230966fdbcf0a4Benedict Wong         * @param prefixLen length of the InetAddress prefix
768c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold         * @hide
769c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold         */
770159788455c79fa47847d0c40fcee7aceff2551aeNathan Harold        @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
7713f2c54b7820c3a568890700479230966fdbcf0a4Benedict Wong        public void removeAddress(@NonNull InetAddress address, int prefixLen) throws IOException {
772da4b0c65a5cbebf6c5e66b869b75dd3a6625cd2eBenedict Wong            try {
773592dadbd43fcb7c5d67e737adb34d07923da90c4Nathan Harold                mService.removeAddressFromTunnelInterface(
7743f2c54b7820c3a568890700479230966fdbcf0a4Benedict Wong                        mResourceId, new LinkAddress(address, prefixLen), mOpPackageName);
775ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold            } catch (ServiceSpecificException e) {
776ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold                throw rethrowCheckedExceptionFromServiceSpecificException(e);
777da4b0c65a5cbebf6c5e66b869b75dd3a6625cd2eBenedict Wong            } catch (RemoteException e) {
778da4b0c65a5cbebf6c5e66b869b75dd3a6625cd2eBenedict Wong                throw e.rethrowFromSystemServer();
779da4b0c65a5cbebf6c5e66b869b75dd3a6625cd2eBenedict Wong            }
780c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold        }
781c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold
782592dadbd43fcb7c5d67e737adb34d07923da90c4Nathan Harold        private IpSecTunnelInterface(@NonNull Context ctx, @NonNull IIpSecService service,
783c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold                @NonNull InetAddress localAddress, @NonNull InetAddress remoteAddress,
784c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold                @NonNull Network underlyingNetwork)
785c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold                throws ResourceUnavailableException, IOException {
786592dadbd43fcb7c5d67e737adb34d07923da90c4Nathan Harold            mOpPackageName = ctx.getOpPackageName();
787c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold            mService = service;
788c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold            mLocalAddress = localAddress;
789c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold            mRemoteAddress = remoteAddress;
790c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold            mUnderlyingNetwork = underlyingNetwork;
7918149f6eb6c0280078dc41d72027d1241e875ea02Benedict Wong
7928149f6eb6c0280078dc41d72027d1241e875ea02Benedict Wong            try {
7938149f6eb6c0280078dc41d72027d1241e875ea02Benedict Wong                IpSecTunnelInterfaceResponse result =
7948149f6eb6c0280078dc41d72027d1241e875ea02Benedict Wong                        mService.createTunnelInterface(
7958149f6eb6c0280078dc41d72027d1241e875ea02Benedict Wong                                localAddress.getHostAddress(),
7968149f6eb6c0280078dc41d72027d1241e875ea02Benedict Wong                                remoteAddress.getHostAddress(),
7978149f6eb6c0280078dc41d72027d1241e875ea02Benedict Wong                                underlyingNetwork,
798592dadbd43fcb7c5d67e737adb34d07923da90c4Nathan Harold                                new Binder(),
799592dadbd43fcb7c5d67e737adb34d07923da90c4Nathan Harold                                mOpPackageName);
8008149f6eb6c0280078dc41d72027d1241e875ea02Benedict Wong                switch (result.status) {
8018149f6eb6c0280078dc41d72027d1241e875ea02Benedict Wong                    case Status.OK:
8028149f6eb6c0280078dc41d72027d1241e875ea02Benedict Wong                        break;
8038149f6eb6c0280078dc41d72027d1241e875ea02Benedict Wong                    case Status.RESOURCE_UNAVAILABLE:
8048149f6eb6c0280078dc41d72027d1241e875ea02Benedict Wong                        throw new ResourceUnavailableException(
8058149f6eb6c0280078dc41d72027d1241e875ea02Benedict Wong                                "No more tunnel interfaces may be allocated by this requester.");
8068149f6eb6c0280078dc41d72027d1241e875ea02Benedict Wong                    default:
8078149f6eb6c0280078dc41d72027d1241e875ea02Benedict Wong                        throw new RuntimeException(
8088149f6eb6c0280078dc41d72027d1241e875ea02Benedict Wong                                "Unknown status returned by IpSecService: " + result.status);
8098149f6eb6c0280078dc41d72027d1241e875ea02Benedict Wong                }
8108149f6eb6c0280078dc41d72027d1241e875ea02Benedict Wong                mResourceId = result.resourceId;
8118149f6eb6c0280078dc41d72027d1241e875ea02Benedict Wong                mInterfaceName = result.interfaceName;
8128149f6eb6c0280078dc41d72027d1241e875ea02Benedict Wong            } catch (RemoteException e) {
8138149f6eb6c0280078dc41d72027d1241e875ea02Benedict Wong                throw e.rethrowFromSystemServer();
8148149f6eb6c0280078dc41d72027d1241e875ea02Benedict Wong            }
8158149f6eb6c0280078dc41d72027d1241e875ea02Benedict Wong            mCloseGuard.open("constructor");
816c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold        }
817c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold
818c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold        /**
819c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold         * Delete an IpSecTunnelInterface
820c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold         *
821c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold         * <p>Calling close will deallocate the IpSecTunnelInterface and all of its system
822c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold         * resources. Any packets bound for this interface either inbound or outbound will
823c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold         * all be lost.
824c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold         */
825c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold        @Override
826c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold        public void close() {
8278149f6eb6c0280078dc41d72027d1241e875ea02Benedict Wong            try {
828592dadbd43fcb7c5d67e737adb34d07923da90c4Nathan Harold                mService.deleteTunnelInterface(mResourceId, mOpPackageName);
8298149f6eb6c0280078dc41d72027d1241e875ea02Benedict Wong            } catch (RemoteException e) {
8308149f6eb6c0280078dc41d72027d1241e875ea02Benedict Wong                throw e.rethrowFromSystemServer();
831ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold            } catch (Exception e) {
832ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold                // On close we swallow all random exceptions since failure to close is not
833ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold                // actionable by the user.
834ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold                Log.e(TAG, "Failed to close " + this + ", Exception=" + e);
835ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold            } finally {
836ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold                mResourceId = INVALID_RESOURCE_ID;
837ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold                mCloseGuard.close();
8388149f6eb6c0280078dc41d72027d1241e875ea02Benedict Wong            }
839c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold        }
840c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold
841c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold        /** Check that the Interface was closed properly. */
842c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold        @Override
843c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold        protected void finalize() throws Throwable {
844c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold            if (mCloseGuard != null) {
845c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold                mCloseGuard.warnIfOpen();
846c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold            }
847c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold            close();
848c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold        }
8498149f6eb6c0280078dc41d72027d1241e875ea02Benedict Wong
8508149f6eb6c0280078dc41d72027d1241e875ea02Benedict Wong        /** @hide */
8518149f6eb6c0280078dc41d72027d1241e875ea02Benedict Wong        @VisibleForTesting
8528149f6eb6c0280078dc41d72027d1241e875ea02Benedict Wong        public int getResourceId() {
8538149f6eb6c0280078dc41d72027d1241e875ea02Benedict Wong            return mResourceId;
8548149f6eb6c0280078dc41d72027d1241e875ea02Benedict Wong        }
855ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold
856ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold        @Override
857ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold        public String toString() {
858ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold            return new StringBuilder()
859ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold                .append("IpSecTunnelInterface{ifname=")
860ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold                .append(mInterfaceName)
861ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold                .append(",resourceId=")
862ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold                .append(mResourceId)
863ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold                .append("}")
864ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold                .toString();
865ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold        }
866c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold    }
867c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold
868c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold    /**
869c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold     * Create a new IpSecTunnelInterface as a local endpoint for tunneled IPsec traffic.
870c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold     *
8718149f6eb6c0280078dc41d72027d1241e875ea02Benedict Wong     * <p>An application that creates tunnels is responsible for cleaning up the tunnel when the
8728149f6eb6c0280078dc41d72027d1241e875ea02Benedict Wong     * underlying network goes away, and the onLost() callback is received.
8738149f6eb6c0280078dc41d72027d1241e875ea02Benedict Wong     *
874c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold     * @param localAddress The local addres of the tunnel
875c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold     * @param remoteAddress The local addres of the tunnel
876c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold     * @param underlyingNetwork the {@link Network} that will carry traffic for this tunnel.
877c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold     *        This network should almost certainly be a network such as WiFi with an L2 address.
878c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold     * @return a new {@link IpSecManager#IpSecTunnelInterface} with the specified properties
879c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold     * @throws IOException indicating that the socket could not be opened or bound
880c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold     * @throws ResourceUnavailableException indicating that too many encapsulation sockets are open
881c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold     * @hide
882c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold     */
8835cd64cc8012243c656875be6b84456caeabd60f5Nathan Harold    @NonNull
884159788455c79fa47847d0c40fcee7aceff2551aeNathan Harold    @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
885c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold    public IpSecTunnelInterface createIpSecTunnelInterface(@NonNull InetAddress localAddress,
886c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold            @NonNull InetAddress remoteAddress, @NonNull Network underlyingNetwork)
887c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold            throws ResourceUnavailableException, IOException {
888ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold        try {
889ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold            return new IpSecTunnelInterface(
890ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold                    mContext, mService, localAddress, remoteAddress, underlyingNetwork);
891ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold        } catch (ServiceSpecificException e) {
892ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold            throw rethrowCheckedExceptionFromServiceSpecificException(e);
893ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold        }
894c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold    }
895c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold
896c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold    /**
8977b7bea048511a54a628a8c340a2890dc50e7b451Nathan Harold     * Apply an active Tunnel Mode IPsec Transform to a {@link IpSecTunnelInterface}, which will
8987b7bea048511a54a628a8c340a2890dc50e7b451Nathan Harold     * tunnel all traffic for the given direction through the underlying network's interface with
8997b7bea048511a54a628a8c340a2890dc50e7b451Nathan Harold     * IPsec (applies an outer IP header and IPsec Header to all traffic, and expects an additional
9007b7bea048511a54a628a8c340a2890dc50e7b451Nathan Harold     * IP header and IPsec Header on all inbound traffic).
9017b7bea048511a54a628a8c340a2890dc50e7b451Nathan Harold     * <p>Applications should probably not use this API directly.
9027b7bea048511a54a628a8c340a2890dc50e7b451Nathan Harold     *
903c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold     *
904c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold     * @param tunnel The {@link IpSecManager#IpSecTunnelInterface} that will use the supplied
905c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold     *        transform.
906c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold     * @param direction the direction, {@link DIRECTION_OUT} or {@link #DIRECTION_IN} in which
907c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold     *        the transform will be used.
908c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold     * @param transform an {@link IpSecTransform} created in tunnel mode
909c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold     * @throws IOException indicating that the transform could not be applied due to a lower
910c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold     *         layer failure.
911c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold     * @hide
912c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold     */
913159788455c79fa47847d0c40fcee7aceff2551aeNathan Harold    @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
9145cd64cc8012243c656875be6b84456caeabd60f5Nathan Harold    public void applyTunnelModeTransform(@NonNull IpSecTunnelInterface tunnel,
9155cd64cc8012243c656875be6b84456caeabd60f5Nathan Harold            @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException {
9168149f6eb6c0280078dc41d72027d1241e875ea02Benedict Wong        try {
9178149f6eb6c0280078dc41d72027d1241e875ea02Benedict Wong            mService.applyTunnelModeTransform(
918592dadbd43fcb7c5d67e737adb34d07923da90c4Nathan Harold                    tunnel.getResourceId(), direction,
919592dadbd43fcb7c5d67e737adb34d07923da90c4Nathan Harold                    transform.getResourceId(), mContext.getOpPackageName());
920ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold        } catch (ServiceSpecificException e) {
921ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold            throw rethrowCheckedExceptionFromServiceSpecificException(e);
9228149f6eb6c0280078dc41d72027d1241e875ea02Benedict Wong        } catch (RemoteException e) {
9238149f6eb6c0280078dc41d72027d1241e875ea02Benedict Wong            throw e.rethrowFromSystemServer();
9248149f6eb6c0280078dc41d72027d1241e875ea02Benedict Wong        }
925c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold    }
9267b7bea048511a54a628a8c340a2890dc50e7b451Nathan Harold
927c47eaccf7c09541c6dd3d3ebedcb2e224346d903Nathan Harold    /**
928c61b70d12d23da97013ee5e44f101609215d1bffJonathan Basseri     * Construct an instance of IpSecManager within an application context.
929330e1089da80cddcd68758512370d217b19f8890Nathan Harold     *
930330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * @param context the application context for this manager
931330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * @hide
932330e1089da80cddcd68758512370d217b19f8890Nathan Harold     */
933592dadbd43fcb7c5d67e737adb34d07923da90c4Nathan Harold    public IpSecManager(Context ctx, IIpSecService service) {
934592dadbd43fcb7c5d67e737adb34d07923da90c4Nathan Harold        mContext = ctx;
935330e1089da80cddcd68758512370d217b19f8890Nathan Harold        mService = checkNotNull(service, "missing service");
936330e1089da80cddcd68758512370d217b19f8890Nathan Harold    }
937ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold
938ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold    private static void maybeHandleServiceSpecificException(ServiceSpecificException sse) {
939ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold        // OsConstants are late binding, so switch statements can't be used.
940ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold        if (sse.errorCode == OsConstants.EINVAL) {
941ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold            throw new IllegalArgumentException(sse);
942ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold        } else if (sse.errorCode == OsConstants.EAGAIN) {
943ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold            throw new IllegalStateException(sse);
944ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold        } else if (sse.errorCode == OsConstants.EOPNOTSUPP) {
945ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold            throw new UnsupportedOperationException(sse);
946ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold        }
947ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold    }
948ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold
949ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold    /**
950ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold     * Convert an Errno SSE to the correct Unchecked exception type.
951ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold     *
952ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold     * This method never actually returns.
953ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold     */
954ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold    // package
955ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold    static RuntimeException
956ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold            rethrowUncheckedExceptionFromServiceSpecificException(ServiceSpecificException sse) {
957ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold        maybeHandleServiceSpecificException(sse);
958ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold        throw new RuntimeException(sse);
959ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold    }
960ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold
961ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold    /**
962ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold     * Convert an Errno SSE to the correct Checked or Unchecked exception type.
963ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold     *
964ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold     * This method may throw IOException, or it may throw an unchecked exception; it will never
965ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold     * actually return.
966ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold     */
967ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold    // package
968ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold    static IOException rethrowCheckedExceptionFromServiceSpecificException(
969ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold            ServiceSpecificException sse) throws IOException {
970ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold        // First see if this is an unchecked exception of a type we know.
971ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold        // If so, then we prefer the unchecked (specific) type of exception.
972ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold        maybeHandleServiceSpecificException(sse);
973ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold        // If not, then all we can do is provide the SSE in the form of an IOException.
974ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold        throw new ErrnoException(
975ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold                "IpSec encountered errno=" + sse.errorCode, sse.errorCode).rethrowAsIOException();
976ddeb90aa9db108d4a2e5aadc778a726b65e5c921Nathan Harold    }
977330e1089da80cddcd68758512370d217b19f8890Nathan Harold}
978