IpSecManager.java revision 440824f7434e1e2c343b21a9ca3e6f405b8e0ea1
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
2093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Haroldimport android.annotation.NonNull;
21d86b8fea43ebb6e5c31691b44d8ceb0d8d3c9072Jeff Sharkeyimport android.annotation.SystemService;
22d86b8fea43ebb6e5c31691b44d8ceb0d8d3c9072Jeff Sharkeyimport android.content.Context;
2393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Haroldimport android.os.Binder;
24330e1089da80cddcd68758512370d217b19f8890Nathan Haroldimport android.os.ParcelFileDescriptor;
2593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Haroldimport android.os.RemoteException;
26330e1089da80cddcd68758512370d217b19f8890Nathan Haroldimport android.util.AndroidException;
278dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Haroldimport android.util.Log;
28b72821747cd8cfa9bcaff7f11247ebfce3255fbfNathan Harold
29a10003d5de52339f4d30fedd7294941378e5f13cNathan Haroldimport com.android.internal.annotations.VisibleForTesting;
30a10003d5de52339f4d30fedd7294941378e5f13cNathan Harold
31330e1089da80cddcd68758512370d217b19f8890Nathan Haroldimport dalvik.system.CloseGuard;
32b72821747cd8cfa9bcaff7f11247ebfce3255fbfNathan Harold
33330e1089da80cddcd68758512370d217b19f8890Nathan Haroldimport java.io.FileDescriptor;
34330e1089da80cddcd68758512370d217b19f8890Nathan Haroldimport java.io.IOException;
35330e1089da80cddcd68758512370d217b19f8890Nathan Haroldimport java.net.DatagramSocket;
36330e1089da80cddcd68758512370d217b19f8890Nathan Haroldimport java.net.InetAddress;
37330e1089da80cddcd68758512370d217b19f8890Nathan Haroldimport java.net.Socket;
38330e1089da80cddcd68758512370d217b19f8890Nathan Harold
39330e1089da80cddcd68758512370d217b19f8890Nathan Harold/**
40330e1089da80cddcd68758512370d217b19f8890Nathan Harold * This class contains methods for managing IPsec sessions, which will perform kernel-space
41330e1089da80cddcd68758512370d217b19f8890Nathan Harold * encryption and decryption of socket or Network traffic.
42330e1089da80cddcd68758512370d217b19f8890Nathan Harold *
43d999d225a8ebd5662b61d7f67bb402d8e5cb965bNathan Harold * <p>An IpSecManager may be obtained by calling {@link
44d999d225a8ebd5662b61d7f67bb402d8e5cb965bNathan Harold * android.content.Context#getSystemService(String) Context#getSystemService(String)} with {@link
45d999d225a8ebd5662b61d7f67bb402d8e5cb965bNathan Harold * android.content.Context#IPSEC_SERVICE Context#IPSEC_SERVICE}
46330e1089da80cddcd68758512370d217b19f8890Nathan Harold */
47d86b8fea43ebb6e5c31691b44d8ceb0d8d3c9072Jeff Sharkey@SystemService(Context.IPSEC_SERVICE)
48330e1089da80cddcd68758512370d217b19f8890Nathan Haroldpublic final class IpSecManager {
49330e1089da80cddcd68758512370d217b19f8890Nathan Harold    private static final String TAG = "IpSecManager";
50330e1089da80cddcd68758512370d217b19f8890Nathan Harold
51330e1089da80cddcd68758512370d217b19f8890Nathan Harold    /**
5293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     * The Security Parameter Index, SPI, 0 indicates an unknown or invalid index.
5393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     *
5493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     * <p>No IPsec packet may contain an SPI of 0.
5593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold     */
5693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    public static final int INVALID_SECURITY_PARAMETER_INDEX = 0;
5793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
5893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    /** @hide */
5993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    public interface Status {
6093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        public static final int OK = 0;
6193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        public static final int RESOURCE_UNAVAILABLE = 1;
6293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        public static final int SPI_UNAVAILABLE = 2;
6393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    }
6493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
6593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    /** @hide */
6693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    public static final int INVALID_RESOURCE_ID = 0;
6793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
6893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    /**
69330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * Indicates that the combination of remote InetAddress and SPI was non-unique for a given
70330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * request. If encountered, selection of a new SPI is required before a transform may be
71330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * created. Note, this should happen very rarely if the SPI is chosen to be sufficiently random
72330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * or reserved using reserveSecurityParameterIndex.
73330e1089da80cddcd68758512370d217b19f8890Nathan Harold     */
74330e1089da80cddcd68758512370d217b19f8890Nathan Harold    public static final class SpiUnavailableException extends AndroidException {
75330e1089da80cddcd68758512370d217b19f8890Nathan Harold        private final int mSpi;
76330e1089da80cddcd68758512370d217b19f8890Nathan Harold
77330e1089da80cddcd68758512370d217b19f8890Nathan Harold        /**
78330e1089da80cddcd68758512370d217b19f8890Nathan Harold         * Construct an exception indicating that a transform with the given SPI is already in use
79330e1089da80cddcd68758512370d217b19f8890Nathan Harold         * or otherwise unavailable.
80330e1089da80cddcd68758512370d217b19f8890Nathan Harold         *
81330e1089da80cddcd68758512370d217b19f8890Nathan Harold         * @param msg Description indicating the colliding SPI
82330e1089da80cddcd68758512370d217b19f8890Nathan Harold         * @param spi the SPI that could not be used due to a collision
83330e1089da80cddcd68758512370d217b19f8890Nathan Harold         */
84330e1089da80cddcd68758512370d217b19f8890Nathan Harold        SpiUnavailableException(String msg, int spi) {
85330e1089da80cddcd68758512370d217b19f8890Nathan Harold            super(msg + "(spi: " + spi + ")");
86330e1089da80cddcd68758512370d217b19f8890Nathan Harold            mSpi = spi;
87330e1089da80cddcd68758512370d217b19f8890Nathan Harold        }
88330e1089da80cddcd68758512370d217b19f8890Nathan Harold
89330e1089da80cddcd68758512370d217b19f8890Nathan Harold        /** Retrieve the SPI that caused a collision */
90330e1089da80cddcd68758512370d217b19f8890Nathan Harold        public int getSpi() {
91330e1089da80cddcd68758512370d217b19f8890Nathan Harold            return mSpi;
92330e1089da80cddcd68758512370d217b19f8890Nathan Harold        }
93330e1089da80cddcd68758512370d217b19f8890Nathan Harold    }
94330e1089da80cddcd68758512370d217b19f8890Nathan Harold
95330e1089da80cddcd68758512370d217b19f8890Nathan Harold    /**
96330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * Indicates that the requested system resource for IPsec, such as a socket or other system
97330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * resource is unavailable. If this exception is thrown, try releasing allocated objects of the
98330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * type requested.
99330e1089da80cddcd68758512370d217b19f8890Nathan Harold     */
100330e1089da80cddcd68758512370d217b19f8890Nathan Harold    public static final class ResourceUnavailableException extends AndroidException {
101330e1089da80cddcd68758512370d217b19f8890Nathan Harold
102330e1089da80cddcd68758512370d217b19f8890Nathan Harold        ResourceUnavailableException(String msg) {
103330e1089da80cddcd68758512370d217b19f8890Nathan Harold            super(msg);
104330e1089da80cddcd68758512370d217b19f8890Nathan Harold        }
105330e1089da80cddcd68758512370d217b19f8890Nathan Harold    }
106330e1089da80cddcd68758512370d217b19f8890Nathan Harold
1071afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold    private final IIpSecService mService;
108330e1089da80cddcd68758512370d217b19f8890Nathan Harold
109330e1089da80cddcd68758512370d217b19f8890Nathan Harold    public static final class SecurityParameterIndex implements AutoCloseable {
1101afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold        private final IIpSecService mService;
111c4f879925b58b1b5ca9a3cfdc898c20cbf56355aNathan Harold        private final InetAddress mRemoteAddress;
112330e1089da80cddcd68758512370d217b19f8890Nathan Harold        private final CloseGuard mCloseGuard = CloseGuard.get();
11393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        private int mSpi = INVALID_SECURITY_PARAMETER_INDEX;
11493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        private int mResourceId;
115330e1089da80cddcd68758512370d217b19f8890Nathan Harold
116330e1089da80cddcd68758512370d217b19f8890Nathan Harold        /** Return the underlying SPI held by this object */
117330e1089da80cddcd68758512370d217b19f8890Nathan Harold        public int getSpi() {
118330e1089da80cddcd68758512370d217b19f8890Nathan Harold            return mSpi;
119330e1089da80cddcd68758512370d217b19f8890Nathan Harold        }
120330e1089da80cddcd68758512370d217b19f8890Nathan Harold
121330e1089da80cddcd68758512370d217b19f8890Nathan Harold        /**
122330e1089da80cddcd68758512370d217b19f8890Nathan Harold         * Release an SPI that was previously reserved.
123330e1089da80cddcd68758512370d217b19f8890Nathan Harold         *
124c4f879925b58b1b5ca9a3cfdc898c20cbf56355aNathan Harold         * <p>Release an SPI for use by other users in the system. If a SecurityParameterIndex is
125c4f879925b58b1b5ca9a3cfdc898c20cbf56355aNathan Harold         * applied to an IpSecTransform, it will become unusable for future transforms but should
126c4f879925b58b1b5ca9a3cfdc898c20cbf56355aNathan Harold         * still be closed to ensure system resources are released.
127330e1089da80cddcd68758512370d217b19f8890Nathan Harold         */
128330e1089da80cddcd68758512370d217b19f8890Nathan Harold        @Override
129330e1089da80cddcd68758512370d217b19f8890Nathan Harold        public void close() {
1308dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            try {
1318dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                mService.releaseSecurityParameterIndex(mResourceId);
1328dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            } catch (RemoteException e) {
1338dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                throw e.rethrowFromSystemServer();
1348dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            }
135330e1089da80cddcd68758512370d217b19f8890Nathan Harold            mCloseGuard.close();
136330e1089da80cddcd68758512370d217b19f8890Nathan Harold        }
137330e1089da80cddcd68758512370d217b19f8890Nathan Harold
138330e1089da80cddcd68758512370d217b19f8890Nathan Harold        @Override
139440824f7434e1e2c343b21a9ca3e6f405b8e0ea1Nathan Harold        protected void finalize() throws Throwable {
140330e1089da80cddcd68758512370d217b19f8890Nathan Harold            if (mCloseGuard != null) {
141330e1089da80cddcd68758512370d217b19f8890Nathan Harold                mCloseGuard.warnIfOpen();
142330e1089da80cddcd68758512370d217b19f8890Nathan Harold            }
143330e1089da80cddcd68758512370d217b19f8890Nathan Harold
144330e1089da80cddcd68758512370d217b19f8890Nathan Harold            close();
145330e1089da80cddcd68758512370d217b19f8890Nathan Harold        }
146330e1089da80cddcd68758512370d217b19f8890Nathan Harold
14793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        private SecurityParameterIndex(
14893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                @NonNull IIpSecService service, int direction, InetAddress remoteAddress, int spi)
14993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                throws ResourceUnavailableException, SpiUnavailableException {
15093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            mService = service;
15193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            mRemoteAddress = remoteAddress;
15293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            try {
1538dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                IpSecSpiResponse result =
15493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                        mService.reserveSecurityParameterIndex(
15593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                direction, remoteAddress.getHostAddress(), spi, new Binder());
15693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
15793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                if (result == null) {
15893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                    throw new NullPointerException("Received null response from IpSecService");
15993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                }
16093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
1618dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                int status = result.status;
16293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                switch (status) {
16393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                    case Status.OK:
16493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                        break;
16593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                    case Status.RESOURCE_UNAVAILABLE:
16693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                        throw new ResourceUnavailableException(
16793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                "No more SPIs may be allocated by this requester.");
16893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                    case Status.SPI_UNAVAILABLE:
16993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                        throw new SpiUnavailableException("Requested SPI is unavailable", spi);
17093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                    default:
17193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                        throw new RuntimeException(
17293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                                "Unknown status returned by IpSecService: " + status);
17393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                }
1748dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                mSpi = result.spi;
1758dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                mResourceId = result.resourceId;
17693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
17793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                if (mSpi == INVALID_SECURITY_PARAMETER_INDEX) {
17893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                    throw new RuntimeException("Invalid SPI returned by IpSecService: " + status);
17993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                }
18093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
18193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                if (mResourceId == INVALID_RESOURCE_ID) {
18293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                    throw new RuntimeException(
18393962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                            "Invalid Resource ID returned by IpSecService: " + status);
18493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                }
18593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold
18693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            } catch (RemoteException e) {
18793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold                throw e.rethrowFromSystemServer();
18893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            }
18993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            mCloseGuard.open("open");
19093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        }
1918dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
1928dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        /** @hide */
193a10003d5de52339f4d30fedd7294941378e5f13cNathan Harold        @VisibleForTesting
194a10003d5de52339f4d30fedd7294941378e5f13cNathan Harold        public int getResourceId() {
1958dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            return mResourceId;
1968dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
19793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    }
198330e1089da80cddcd68758512370d217b19f8890Nathan Harold
199330e1089da80cddcd68758512370d217b19f8890Nathan Harold    /**
200c4f879925b58b1b5ca9a3cfdc898c20cbf56355aNathan Harold     * Reserve an SPI for traffic bound towards the specified remote address.
201330e1089da80cddcd68758512370d217b19f8890Nathan Harold     *
202330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * <p>If successful, this SPI is guaranteed available until released by a call to {@link
203330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * SecurityParameterIndex#close()}.
204330e1089da80cddcd68758512370d217b19f8890Nathan Harold     *
205c4f879925b58b1b5ca9a3cfdc898c20cbf56355aNathan Harold     * @param direction {@link IpSecTransform#DIRECTION_IN} or {@link IpSecTransform#DIRECTION_OUT}
206c4f879925b58b1b5ca9a3cfdc898c20cbf56355aNathan Harold     * @param remoteAddress address of the remote. SPIs must be unique for each remoteAddress.
207330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * @return the reserved SecurityParameterIndex
208330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * @throws ResourceUnavailableException indicating that too many SPIs are currently allocated
209330e1089da80cddcd68758512370d217b19f8890Nathan Harold     *     for this user
210330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * @throws SpiUnavailableException indicating that a particular SPI cannot be reserved
211330e1089da80cddcd68758512370d217b19f8890Nathan Harold     */
212330e1089da80cddcd68758512370d217b19f8890Nathan Harold    public SecurityParameterIndex reserveSecurityParameterIndex(
2138dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            int direction, InetAddress remoteAddress) throws ResourceUnavailableException {
2146045429b35ca4c1cbd920e5e0872dec9de493fdeNathan Harold        try {
2156045429b35ca4c1cbd920e5e0872dec9de493fdeNathan Harold            return new SecurityParameterIndex(
2166045429b35ca4c1cbd920e5e0872dec9de493fdeNathan Harold                    mService,
2176045429b35ca4c1cbd920e5e0872dec9de493fdeNathan Harold                    direction,
2186045429b35ca4c1cbd920e5e0872dec9de493fdeNathan Harold                    remoteAddress,
2196045429b35ca4c1cbd920e5e0872dec9de493fdeNathan Harold                    IpSecManager.INVALID_SECURITY_PARAMETER_INDEX);
2206045429b35ca4c1cbd920e5e0872dec9de493fdeNathan Harold        } catch (SpiUnavailableException unlikely) {
2216045429b35ca4c1cbd920e5e0872dec9de493fdeNathan Harold            throw new ResourceUnavailableException("No SPIs available");
2226045429b35ca4c1cbd920e5e0872dec9de493fdeNathan Harold        }
2236045429b35ca4c1cbd920e5e0872dec9de493fdeNathan Harold    }
2246045429b35ca4c1cbd920e5e0872dec9de493fdeNathan Harold
2256045429b35ca4c1cbd920e5e0872dec9de493fdeNathan Harold    /**
2266045429b35ca4c1cbd920e5e0872dec9de493fdeNathan Harold     * Reserve an SPI for traffic bound towards the specified remote address.
2276045429b35ca4c1cbd920e5e0872dec9de493fdeNathan Harold     *
2286045429b35ca4c1cbd920e5e0872dec9de493fdeNathan Harold     * <p>If successful, this SPI is guaranteed available until released by a call to {@link
2296045429b35ca4c1cbd920e5e0872dec9de493fdeNathan Harold     * SecurityParameterIndex#close()}.
2306045429b35ca4c1cbd920e5e0872dec9de493fdeNathan Harold     *
2316045429b35ca4c1cbd920e5e0872dec9de493fdeNathan Harold     * @param direction {@link IpSecTransform#DIRECTION_IN} or {@link IpSecTransform#DIRECTION_OUT}
2326045429b35ca4c1cbd920e5e0872dec9de493fdeNathan Harold     * @param remoteAddress address of the remote. SPIs must be unique for each remoteAddress.
2336045429b35ca4c1cbd920e5e0872dec9de493fdeNathan Harold     * @param requestedSpi the requested SPI, or '0' to allocate a random SPI.
2346045429b35ca4c1cbd920e5e0872dec9de493fdeNathan Harold     * @return the reserved SecurityParameterIndex
2356045429b35ca4c1cbd920e5e0872dec9de493fdeNathan Harold     * @throws ResourceUnavailableException indicating that too many SPIs are currently allocated
2366045429b35ca4c1cbd920e5e0872dec9de493fdeNathan Harold     *     for this user
2376045429b35ca4c1cbd920e5e0872dec9de493fdeNathan Harold     */
2386045429b35ca4c1cbd920e5e0872dec9de493fdeNathan Harold    public SecurityParameterIndex reserveSecurityParameterIndex(
239c4f879925b58b1b5ca9a3cfdc898c20cbf56355aNathan Harold            int direction, InetAddress remoteAddress, int requestedSpi)
240330e1089da80cddcd68758512370d217b19f8890Nathan Harold            throws SpiUnavailableException, ResourceUnavailableException {
2416045429b35ca4c1cbd920e5e0872dec9de493fdeNathan Harold        if (requestedSpi == IpSecManager.INVALID_SECURITY_PARAMETER_INDEX) {
2426045429b35ca4c1cbd920e5e0872dec9de493fdeNathan Harold            throw new IllegalArgumentException("Requested SPI must be a valid (non-zero) SPI");
2436045429b35ca4c1cbd920e5e0872dec9de493fdeNathan Harold        }
244c4f879925b58b1b5ca9a3cfdc898c20cbf56355aNathan Harold        return new SecurityParameterIndex(mService, direction, remoteAddress, requestedSpi);
245330e1089da80cddcd68758512370d217b19f8890Nathan Harold    }
246330e1089da80cddcd68758512370d217b19f8890Nathan Harold
247330e1089da80cddcd68758512370d217b19f8890Nathan Harold    /**
248330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * Apply an active Transport Mode IPsec Transform to a stream socket to perform IPsec
249330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * encapsulation of the traffic flowing between the socket and the remote InetAddress of that
250330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * transform. For security reasons, attempts to send traffic to any IP address other than the
251330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * address associated with that transform will throw an IOException. In addition, if the
252330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * IpSecTransform is later deactivated, the socket will throw an IOException on any calls to
253330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * send() or receive() until the transform is removed from the socket by calling {@link
254330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * #removeTransportModeTransform(Socket, IpSecTransform)};
255330e1089da80cddcd68758512370d217b19f8890Nathan Harold     *
256330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * @param socket a stream socket
257330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * @param transform an {@link IpSecTransform}, which must be an active Transport Mode transform.
258da18b028f85e9a2c969c636aea6abf7f4bac3922Nathan Harold     * @hide
259330e1089da80cddcd68758512370d217b19f8890Nathan Harold     */
260330e1089da80cddcd68758512370d217b19f8890Nathan Harold    public void applyTransportModeTransform(Socket socket, IpSecTransform transform)
261330e1089da80cddcd68758512370d217b19f8890Nathan Harold            throws IOException {
2628dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        try (ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket)) {
2638dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            applyTransportModeTransform(pfd, transform);
2648dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
265330e1089da80cddcd68758512370d217b19f8890Nathan Harold    }
266330e1089da80cddcd68758512370d217b19f8890Nathan Harold
267330e1089da80cddcd68758512370d217b19f8890Nathan Harold    /**
268330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * Apply an active Transport Mode IPsec Transform to a datagram socket to perform IPsec
269330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * encapsulation of the traffic flowing between the socket and the remote InetAddress of that
270330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * transform. For security reasons, attempts to send traffic to any IP address other than the
271330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * address associated with that transform will throw an IOException. In addition, if the
272330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * IpSecTransform is later deactivated, the socket will throw an IOException on any calls to
273330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * send() or receive() until the transform is removed from the socket by calling {@link
274330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * #removeTransportModeTransform(DatagramSocket, IpSecTransform)};
275330e1089da80cddcd68758512370d217b19f8890Nathan Harold     *
276330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * @param socket a datagram socket
277330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * @param transform an {@link IpSecTransform}, which must be an active Transport Mode transform.
278da18b028f85e9a2c969c636aea6abf7f4bac3922Nathan Harold     * @hide
279330e1089da80cddcd68758512370d217b19f8890Nathan Harold     */
280330e1089da80cddcd68758512370d217b19f8890Nathan Harold    public void applyTransportModeTransform(DatagramSocket socket, IpSecTransform transform)
281330e1089da80cddcd68758512370d217b19f8890Nathan Harold            throws IOException {
2828dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        try (ParcelFileDescriptor pfd = ParcelFileDescriptor.fromDatagramSocket(socket)) {
2838dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            applyTransportModeTransform(pfd, transform);
28493962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        }
28593962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    }
286330e1089da80cddcd68758512370d217b19f8890Nathan Harold
287330e1089da80cddcd68758512370d217b19f8890Nathan Harold    /**
288b64993559b049327365bb63e81e8046a892a1033Nathan Harold     * Apply an active Transport Mode IPsec Transform to a stream socket to perform IPsec
289b64993559b049327365bb63e81e8046a892a1033Nathan Harold     * encapsulation of the traffic flowing between the socket and the remote InetAddress of that
290b64993559b049327365bb63e81e8046a892a1033Nathan Harold     * transform. For security reasons, attempts to send traffic to any IP address other than the
291b64993559b049327365bb63e81e8046a892a1033Nathan Harold     * address associated with that transform will throw an IOException. In addition, if the
292b64993559b049327365bb63e81e8046a892a1033Nathan Harold     * IpSecTransform is later deactivated, the socket will throw an IOException on any calls to
293b64993559b049327365bb63e81e8046a892a1033Nathan Harold     * send() or receive() until the transform is removed from the socket by calling {@link
294da18b028f85e9a2c969c636aea6abf7f4bac3922Nathan Harold     * #removeTransportModeTransform(FileDescriptor, IpSecTransform)};
295b64993559b049327365bb63e81e8046a892a1033Nathan Harold     *
296b64993559b049327365bb63e81e8046a892a1033Nathan Harold     * @param socket a socket file descriptor
297b64993559b049327365bb63e81e8046a892a1033Nathan Harold     * @param transform an {@link IpSecTransform}, which must be an active Transport Mode transform.
298b64993559b049327365bb63e81e8046a892a1033Nathan Harold     */
299b64993559b049327365bb63e81e8046a892a1033Nathan Harold    public void applyTransportModeTransform(FileDescriptor socket, IpSecTransform transform)
300b64993559b049327365bb63e81e8046a892a1033Nathan Harold            throws IOException {
3018dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        // We dup() the FileDescriptor here because if we don't, then the ParcelFileDescriptor()
3028dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        // constructor takes control and closes the user's FD when we exit the method
3038dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        // This is behaviorally the same as the other versions, but the PFD constructor does not
3048dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        // dup() automatically, whereas PFD.fromSocket() and PDF.fromDatagramSocket() do dup().
3058dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) {
3068dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            applyTransportModeTransform(pfd, transform);
3078dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
3088dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    }
3098dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
3108dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    /* Call down to activate a transform */
3118dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold    private void applyTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) {
3128dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        try {
3138dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            mService.applyTransportModeTransform(pfd, transform.getResourceId());
3148dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        } catch (RemoteException e) {
3158dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            throw e.rethrowFromSystemServer();
3168dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
317b64993559b049327365bb63e81e8046a892a1033Nathan Harold    }
318b64993559b049327365bb63e81e8046a892a1033Nathan Harold
319b64993559b049327365bb63e81e8046a892a1033Nathan Harold    /**
320330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * Apply an active Tunnel Mode IPsec Transform to a network, which will tunnel all traffic to
321330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * and from that network's interface with IPsec (applies an outer IP header and IPsec Header to
322330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * all traffic, and expects an additional IP header and IPsec Header on all inbound traffic).
323330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * Applications should probably not use this API directly. Instead, they should use {@link
324330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * VpnService} to provide VPN capability in a more generic fashion.
325330e1089da80cddcd68758512370d217b19f8890Nathan Harold     *
326330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * @param net a {@link Network} that will be tunneled via IP Sec.
327330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * @param transform an {@link IpSecTransform}, which must be an active Tunnel Mode transform.
328330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * @hide
329330e1089da80cddcd68758512370d217b19f8890Nathan Harold     */
330330e1089da80cddcd68758512370d217b19f8890Nathan Harold    public void applyTunnelModeTransform(Network net, IpSecTransform transform) {}
331330e1089da80cddcd68758512370d217b19f8890Nathan Harold
332330e1089da80cddcd68758512370d217b19f8890Nathan Harold    /**
333330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * Remove a transform from a given stream socket. Once removed, traffic on the socket will not
334330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * be encypted. This allows sockets that have been used for IPsec to be reclaimed for
335330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * communication in the clear in the event socket reuse is desired. This operation will succeed
336330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * regardless of the underlying state of a transform. If a transform is removed, communication
337330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * on all sockets to which that transform was applied will fail until this method is called.
338330e1089da80cddcd68758512370d217b19f8890Nathan Harold     *
339330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * @param socket a socket that previously had a transform applied to it.
340330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * @param transform the IPsec Transform that was previously applied to the given socket
341da18b028f85e9a2c969c636aea6abf7f4bac3922Nathan Harold     * @hide
342330e1089da80cddcd68758512370d217b19f8890Nathan Harold     */
3430bfb2075320a9f648fc2b3fcdfc58f425c9a685aNathan Harold    public void removeTransportModeTransform(Socket socket, IpSecTransform transform)
3440bfb2075320a9f648fc2b3fcdfc58f425c9a685aNathan Harold            throws IOException {
3458dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        try (ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket)) {
3468dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            removeTransportModeTransform(pfd, transform);
3478dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
348330e1089da80cddcd68758512370d217b19f8890Nathan Harold    }
349330e1089da80cddcd68758512370d217b19f8890Nathan Harold
350330e1089da80cddcd68758512370d217b19f8890Nathan Harold    /**
351330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * Remove a transform from a given datagram socket. Once removed, traffic on the socket will not
352330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * be encypted. This allows sockets that have been used for IPsec to be reclaimed for
353330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * communication in the clear in the event socket reuse is desired. This operation will succeed
354330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * regardless of the underlying state of a transform. If a transform is removed, communication
355330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * on all sockets to which that transform was applied will fail until this method is called.
356330e1089da80cddcd68758512370d217b19f8890Nathan Harold     *
357330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * @param socket a socket that previously had a transform applied to it.
358330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * @param transform the IPsec Transform that was previously applied to the given socket
359da18b028f85e9a2c969c636aea6abf7f4bac3922Nathan Harold     * @hide
360330e1089da80cddcd68758512370d217b19f8890Nathan Harold     */
3610bfb2075320a9f648fc2b3fcdfc58f425c9a685aNathan Harold    public void removeTransportModeTransform(DatagramSocket socket, IpSecTransform transform)
3620bfb2075320a9f648fc2b3fcdfc58f425c9a685aNathan Harold            throws IOException {
3638dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        try (ParcelFileDescriptor pfd = ParcelFileDescriptor.fromDatagramSocket(socket)) {
3648dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            removeTransportModeTransform(pfd, transform);
3658dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
366330e1089da80cddcd68758512370d217b19f8890Nathan Harold    }
367330e1089da80cddcd68758512370d217b19f8890Nathan Harold
368b64993559b049327365bb63e81e8046a892a1033Nathan Harold    /**
369b64993559b049327365bb63e81e8046a892a1033Nathan Harold     * Remove a transform from a given stream socket. Once removed, traffic on the socket will not
370b64993559b049327365bb63e81e8046a892a1033Nathan Harold     * be encypted. This allows sockets that have been used for IPsec to be reclaimed for
371b64993559b049327365bb63e81e8046a892a1033Nathan Harold     * communication in the clear in the event socket reuse is desired. This operation will succeed
372b64993559b049327365bb63e81e8046a892a1033Nathan Harold     * regardless of the underlying state of a transform. If a transform is removed, communication
373b64993559b049327365bb63e81e8046a892a1033Nathan Harold     * on all sockets to which that transform was applied will fail until this method is called.
374b64993559b049327365bb63e81e8046a892a1033Nathan Harold     *
375b64993559b049327365bb63e81e8046a892a1033Nathan Harold     * @param socket a socket file descriptor that previously had a transform applied to it.
376b64993559b049327365bb63e81e8046a892a1033Nathan Harold     * @param transform the IPsec Transform that was previously applied to the given socket
377b64993559b049327365bb63e81e8046a892a1033Nathan Harold     */
3780bfb2075320a9f648fc2b3fcdfc58f425c9a685aNathan Harold    public void removeTransportModeTransform(FileDescriptor socket, IpSecTransform transform)
3790bfb2075320a9f648fc2b3fcdfc58f425c9a685aNathan Harold            throws IOException {
3808dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) {
3818dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            removeTransportModeTransform(pfd, transform);
3828dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
383b64993559b049327365bb63e81e8046a892a1033Nathan Harold    }
384b64993559b049327365bb63e81e8046a892a1033Nathan Harold
385330e1089da80cddcd68758512370d217b19f8890Nathan Harold    /* Call down to activate a transform */
38693962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    private void removeTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) {
38793962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        try {
38893962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            mService.removeTransportModeTransform(pfd, transform.getResourceId());
38993962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        } catch (RemoteException e) {
39093962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold            throw e.rethrowFromSystemServer();
39193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        }
39293962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold    }
393330e1089da80cddcd68758512370d217b19f8890Nathan Harold
394330e1089da80cddcd68758512370d217b19f8890Nathan Harold    /**
395330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * Remove a Tunnel Mode IPsec Transform from a {@link Network}. This must be used as part of
396330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * cleanup if a tunneled Network experiences a change in default route. The Network will drop
397330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * all traffic that cannot be routed to the Tunnel's outbound interface. If that interface is
398330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * lost, all traffic will drop.
399330e1089da80cddcd68758512370d217b19f8890Nathan Harold     *
400330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * @param net a network that currently has transform applied to it.
401330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * @param transform a Tunnel Mode IPsec Transform that has been previously applied to the given
402330e1089da80cddcd68758512370d217b19f8890Nathan Harold     *     network
403330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * @hide
404330e1089da80cddcd68758512370d217b19f8890Nathan Harold     */
405330e1089da80cddcd68758512370d217b19f8890Nathan Harold    public void removeTunnelModeTransform(Network net, IpSecTransform transform) {}
406330e1089da80cddcd68758512370d217b19f8890Nathan Harold
407330e1089da80cddcd68758512370d217b19f8890Nathan Harold    /**
408330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * Class providing access to a system-provided UDP Encapsulation Socket, which may be used for
409330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * IKE signalling as well as for inbound and outbound UDP encapsulated IPsec traffic.
410330e1089da80cddcd68758512370d217b19f8890Nathan Harold     *
411330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * <p>The socket provided by this class cannot be re-bound or closed via the inner
412330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * FileDescriptor. Instead, disposing of this socket requires a call to close().
413330e1089da80cddcd68758512370d217b19f8890Nathan Harold     */
414330e1089da80cddcd68758512370d217b19f8890Nathan Harold    public static final class UdpEncapsulationSocket implements AutoCloseable {
4158dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        private final ParcelFileDescriptor mPfd;
4161afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold        private final IIpSecService mService;
4178dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        private final int mResourceId;
4188dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        private final int mPort;
419330e1089da80cddcd68758512370d217b19f8890Nathan Harold        private final CloseGuard mCloseGuard = CloseGuard.get();
420330e1089da80cddcd68758512370d217b19f8890Nathan Harold
42193962f34ce21f5aac825afbcebf2f3e8c7a30910Nathan Harold        private UdpEncapsulationSocket(@NonNull IIpSecService service, int port)
4228dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                throws ResourceUnavailableException, IOException {
4231afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold            mService = service;
4248dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            try {
4258dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                IpSecUdpEncapResponse result =
4268dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                        mService.openUdpEncapsulationSocket(port, new Binder());
4278dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                switch (result.status) {
4288dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                    case Status.OK:
4298dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                        break;
4308dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                    case Status.RESOURCE_UNAVAILABLE:
4318dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                        throw new ResourceUnavailableException(
4328dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                                "No more Sockets may be allocated by this requester.");
4338dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                    default:
4348dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                        throw new RuntimeException(
4358dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                                "Unknown status returned by IpSecService: " + result.status);
4368dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                }
4378dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                mResourceId = result.resourceId;
4388dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                mPort = result.port;
4398dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                mPfd = result.fileDescriptor;
4408dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            } catch (RemoteException e) {
4418dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                throw e.rethrowFromSystemServer();
4428dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            }
443330e1089da80cddcd68758512370d217b19f8890Nathan Harold            mCloseGuard.open("constructor");
444330e1089da80cddcd68758512370d217b19f8890Nathan Harold        }
445330e1089da80cddcd68758512370d217b19f8890Nathan Harold
446330e1089da80cddcd68758512370d217b19f8890Nathan Harold        /** Access the inner UDP Encapsulation Socket */
447330e1089da80cddcd68758512370d217b19f8890Nathan Harold        public FileDescriptor getSocket() {
4488dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            if (mPfd == null) {
4498dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                return null;
4508dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            }
4518dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            return mPfd.getFileDescriptor();
452330e1089da80cddcd68758512370d217b19f8890Nathan Harold        }
453330e1089da80cddcd68758512370d217b19f8890Nathan Harold
454330e1089da80cddcd68758512370d217b19f8890Nathan Harold        /** Retrieve the port number of the inner encapsulation socket */
455330e1089da80cddcd68758512370d217b19f8890Nathan Harold        public int getPort() {
4568dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            return mPort;
457330e1089da80cddcd68758512370d217b19f8890Nathan Harold        }
458330e1089da80cddcd68758512370d217b19f8890Nathan Harold
459330e1089da80cddcd68758512370d217b19f8890Nathan Harold        @Override
460330e1089da80cddcd68758512370d217b19f8890Nathan Harold        /**
461330e1089da80cddcd68758512370d217b19f8890Nathan Harold         * Release the resources that have been reserved for this Socket.
462330e1089da80cddcd68758512370d217b19f8890Nathan Harold         *
463330e1089da80cddcd68758512370d217b19f8890Nathan Harold         * <p>This method closes the underlying socket, reducing a user's allocated sockets in the
464330e1089da80cddcd68758512370d217b19f8890Nathan Harold         * system. This must be done as part of cleanup following use of a socket. Failure to do so
465330e1089da80cddcd68758512370d217b19f8890Nathan Harold         * will cause the socket to count against a total allocation limit for IpSec and eventually
466330e1089da80cddcd68758512370d217b19f8890Nathan Harold         * fail due to resource limits.
467330e1089da80cddcd68758512370d217b19f8890Nathan Harold         *
468330e1089da80cddcd68758512370d217b19f8890Nathan Harold         * @param fd a file descriptor previously returned as a UDP Encapsulation socket.
469330e1089da80cddcd68758512370d217b19f8890Nathan Harold         */
4700bfb2075320a9f648fc2b3fcdfc58f425c9a685aNathan Harold        public void close() throws IOException {
4718dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            try {
4728dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                mService.closeUdpEncapsulationSocket(mResourceId);
4738dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            } catch (RemoteException e) {
4748dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                throw e.rethrowFromSystemServer();
4758dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            }
4768dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
4778dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            try {
4788dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                mPfd.close();
4798dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            } catch (IOException e) {
4808dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                Log.e(TAG, "Failed to close UDP Encapsulation Socket with Port= " + mPort);
4818dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold                throw e;
4828dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            }
483330e1089da80cddcd68758512370d217b19f8890Nathan Harold            mCloseGuard.close();
484330e1089da80cddcd68758512370d217b19f8890Nathan Harold        }
485330e1089da80cddcd68758512370d217b19f8890Nathan Harold
486330e1089da80cddcd68758512370d217b19f8890Nathan Harold        @Override
487330e1089da80cddcd68758512370d217b19f8890Nathan Harold        protected void finalize() throws Throwable {
488330e1089da80cddcd68758512370d217b19f8890Nathan Harold            if (mCloseGuard != null) {
489330e1089da80cddcd68758512370d217b19f8890Nathan Harold                mCloseGuard.warnIfOpen();
490330e1089da80cddcd68758512370d217b19f8890Nathan Harold            }
491330e1089da80cddcd68758512370d217b19f8890Nathan Harold            close();
492330e1089da80cddcd68758512370d217b19f8890Nathan Harold        }
4938dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold
4948dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        /** @hide */
495a10003d5de52339f4d30fedd7294941378e5f13cNathan Harold        @VisibleForTesting
496a10003d5de52339f4d30fedd7294941378e5f13cNathan Harold        public int getResourceId() {
4978dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            return mResourceId;
4988dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
499330e1089da80cddcd68758512370d217b19f8890Nathan Harold    };
500330e1089da80cddcd68758512370d217b19f8890Nathan Harold
501330e1089da80cddcd68758512370d217b19f8890Nathan Harold    /**
502330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * Open a socket that is bound to a free UDP port on the system.
503330e1089da80cddcd68758512370d217b19f8890Nathan Harold     *
504330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * <p>By binding in this manner and holding the FileDescriptor, the socket cannot be un-bound by
505330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * the caller. This provides safe access to a socket on a port that can later be used as a UDP
506330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * Encapsulation port.
507330e1089da80cddcd68758512370d217b19f8890Nathan Harold     *
508330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * <p>This socket reservation works in conjunction with IpSecTransforms, which may re-use the
509330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * socket port. Explicitly opening this port is only necessary if communication is desired on
510330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * that port.
511330e1089da80cddcd68758512370d217b19f8890Nathan Harold     *
512330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * @param port a local UDP port to be reserved for UDP Encapsulation. is provided, then this
513330e1089da80cddcd68758512370d217b19f8890Nathan Harold     *     method will bind to the specified port or fail. To retrieve the port number, call {@link
514330e1089da80cddcd68758512370d217b19f8890Nathan Harold     *     android.system.Os#getsockname(FileDescriptor)}.
515330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * @return a {@link UdpEncapsulationSocket} that is bound to the requested port for the lifetime
516330e1089da80cddcd68758512370d217b19f8890Nathan Harold     *     of the object.
517330e1089da80cddcd68758512370d217b19f8890Nathan Harold     */
518330e1089da80cddcd68758512370d217b19f8890Nathan Harold    // Returning a socket in this fashion that has been created and bound by the system
519330e1089da80cddcd68758512370d217b19f8890Nathan Harold    // is the only safe way to ensure that a socket is both accessible to the user and
520330e1089da80cddcd68758512370d217b19f8890Nathan Harold    // safely usable for Encapsulation without allowing a user to possibly unbind from/close
521330e1089da80cddcd68758512370d217b19f8890Nathan Harold    // the port, which could potentially impact the traffic of the next user who binds to that
522330e1089da80cddcd68758512370d217b19f8890Nathan Harold    // socket.
523330e1089da80cddcd68758512370d217b19f8890Nathan Harold    public UdpEncapsulationSocket openUdpEncapsulationSocket(int port)
524330e1089da80cddcd68758512370d217b19f8890Nathan Harold            throws IOException, ResourceUnavailableException {
5258dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        /*
5268dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold         * Most range checking is done in the service, but this version of the constructor expects
5278dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold         * a valid port number, and zero cannot be checked after being passed to the service.
5288dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold         */
5298dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        if (port == 0) {
5308dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold            throw new IllegalArgumentException("Specified port must be a valid port number!");
5318dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        }
5321afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold        return new UdpEncapsulationSocket(mService, port);
533330e1089da80cddcd68758512370d217b19f8890Nathan Harold    }
534330e1089da80cddcd68758512370d217b19f8890Nathan Harold
535330e1089da80cddcd68758512370d217b19f8890Nathan Harold    /**
536330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * Open a socket that is bound to a port selected by the system.
537330e1089da80cddcd68758512370d217b19f8890Nathan Harold     *
538330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * <p>By binding in this manner and holding the FileDescriptor, the socket cannot be un-bound by
539330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * the caller. This provides safe access to a socket on a port that can later be used as a UDP
540330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * Encapsulation port.
541330e1089da80cddcd68758512370d217b19f8890Nathan Harold     *
542330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * <p>This socket reservation works in conjunction with IpSecTransforms, which may re-use the
543330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * socket port. Explicitly opening this port is only necessary if communication is desired on
544330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * that port.
545330e1089da80cddcd68758512370d217b19f8890Nathan Harold     *
546330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * @return a {@link UdpEncapsulationSocket} that is bound to an arbitrarily selected port
547330e1089da80cddcd68758512370d217b19f8890Nathan Harold     */
548330e1089da80cddcd68758512370d217b19f8890Nathan Harold    // Returning a socket in this fashion that has been created and bound by the system
549330e1089da80cddcd68758512370d217b19f8890Nathan Harold    // is the only safe way to ensure that a socket is both accessible to the user and
550330e1089da80cddcd68758512370d217b19f8890Nathan Harold    // safely usable for Encapsulation without allowing a user to possibly unbind from/close
551330e1089da80cddcd68758512370d217b19f8890Nathan Harold    // the port, which could potentially impact the traffic of the next user who binds to that
552330e1089da80cddcd68758512370d217b19f8890Nathan Harold    // socket.
553330e1089da80cddcd68758512370d217b19f8890Nathan Harold    public UdpEncapsulationSocket openUdpEncapsulationSocket()
554330e1089da80cddcd68758512370d217b19f8890Nathan Harold            throws IOException, ResourceUnavailableException {
5558dc1fd0237992e1d693376b4f6eea45e7447e9dbNathan Harold        return new UdpEncapsulationSocket(mService, 0);
556330e1089da80cddcd68758512370d217b19f8890Nathan Harold    }
557330e1089da80cddcd68758512370d217b19f8890Nathan Harold
558330e1089da80cddcd68758512370d217b19f8890Nathan Harold    /**
559330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * Retrieve an instance of an IpSecManager within you application context
560330e1089da80cddcd68758512370d217b19f8890Nathan Harold     *
561330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * @param context the application context for this manager
562330e1089da80cddcd68758512370d217b19f8890Nathan Harold     * @hide
563330e1089da80cddcd68758512370d217b19f8890Nathan Harold     */
5641afbef40c68373f3871eed087c546cfe1911ee36Nathan Harold    public IpSecManager(IIpSecService service) {
565330e1089da80cddcd68758512370d217b19f8890Nathan Harold        mService = checkNotNull(service, "missing service");
566330e1089da80cddcd68758512370d217b19f8890Nathan Harold    }
567330e1089da80cddcd68758512370d217b19f8890Nathan Harold}
568