blob: 0d04fe5a9172f8fdf3a9d89f2414d4ae5f386264 [file] [log] [blame]
Nathan Harold330e1082017-01-12 18:38:57 -08001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package android.net;
17
18import static com.android.internal.util.Preconditions.checkNotNull;
19
Nathan Harolda2523312018-01-05 19:25:13 -080020import android.annotation.IntDef;
Nathan Harold93962f32017-03-07 13:23:36 -080021import android.annotation.NonNull;
Nathan Harold5a920ca2018-02-02 18:34:25 -080022import android.annotation.RequiresPermission;
Nathan Haroldc47eacc2018-01-17 16:09:24 -080023import android.annotation.SystemApi;
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060024import android.annotation.SystemService;
Jonathan Basseric61b70d2017-04-21 15:53:51 -070025import android.annotation.TestApi;
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060026import android.content.Context;
Nathan Harold93962f32017-03-07 13:23:36 -080027import android.os.Binder;
Nathan Harold330e1082017-01-12 18:38:57 -080028import android.os.ParcelFileDescriptor;
Nathan Harold93962f32017-03-07 13:23:36 -080029import android.os.RemoteException;
Nathan Harold330e1082017-01-12 18:38:57 -080030import android.util.AndroidException;
Nathan Harold8dc1fd02017-04-04 19:37:48 -070031import android.util.Log;
Nathan Haroldb7282172017-09-11 19:50:19 -070032
Nathan Harolda10003d2017-08-23 13:46:33 -070033import com.android.internal.annotations.VisibleForTesting;
34
Nathan Harold330e1082017-01-12 18:38:57 -080035import dalvik.system.CloseGuard;
Nathan Haroldb7282172017-09-11 19:50:19 -070036
Nathan Harold330e1082017-01-12 18:38:57 -080037import java.io.FileDescriptor;
38import java.io.IOException;
Nathan Harolda2523312018-01-05 19:25:13 -080039import java.lang.annotation.Retention;
40import java.lang.annotation.RetentionPolicy;
Nathan Harold330e1082017-01-12 18:38:57 -080041import java.net.DatagramSocket;
42import java.net.InetAddress;
43import java.net.Socket;
44
45/**
Jonathan Basseric61b70d2017-04-21 15:53:51 -070046 * This class contains methods for managing IPsec sessions. Once configured, the kernel will apply
47 * confidentiality (encryption) and integrity (authentication) to IP traffic.
Nathan Harold330e1082017-01-12 18:38:57 -080048 *
Jonathan Basseric61b70d2017-04-21 15:53:51 -070049 * <p>Note that not all aspects of IPsec are permitted by this API. Applications may create
50 * transport mode security associations and apply them to individual sockets. Applications looking
51 * to create a VPN should use {@link VpnService}.
52 *
53 * @see <a href="https://tools.ietf.org/html/rfc4301">RFC 4301, Security Architecture for the
Jonathan Basseri5fb92902017-11-16 10:58:01 -080054 * Internet Protocol</a>
Nathan Harold330e1082017-01-12 18:38:57 -080055 */
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060056@SystemService(Context.IPSEC_SERVICE)
Nathan Harold330e1082017-01-12 18:38:57 -080057public final class IpSecManager {
58 private static final String TAG = "IpSecManager";
59
60 /**
Nathan Harold7b7bea02018-03-06 13:22:22 -080061 * Used when applying a transform to direct traffic through an {@link IpSecTransform}
62 * towards the host.
63 *
64 * <p>See {@link #applyTransportModeTransform(Socket, int, IpSecTransform)}.
Nathan Harolda2523312018-01-05 19:25:13 -080065 */
66 public static final int DIRECTION_IN = 0;
67
68 /**
Nathan Harold7b7bea02018-03-06 13:22:22 -080069 * Used when applying a transform to direct traffic through an {@link IpSecTransform}
70 * away from the host.
71 *
72 * <p>See {@link #applyTransportModeTransform(Socket, int, IpSecTransform)}.
Nathan Harolda2523312018-01-05 19:25:13 -080073 */
74 public static final int DIRECTION_OUT = 1;
75
76 /** @hide */
77 @IntDef(value = {DIRECTION_IN, DIRECTION_OUT})
78 @Retention(RetentionPolicy.SOURCE)
79 public @interface PolicyDirection {}
80
81 /**
Jonathan Basseric61b70d2017-04-21 15:53:51 -070082 * The Security Parameter Index (SPI) 0 indicates an unknown or invalid index.
Nathan Harold93962f32017-03-07 13:23:36 -080083 *
84 * <p>No IPsec packet may contain an SPI of 0.
Jonathan Basseric61b70d2017-04-21 15:53:51 -070085 *
86 * @hide
Nathan Harold93962f32017-03-07 13:23:36 -080087 */
Jonathan Basseri5fb92902017-11-16 10:58:01 -080088 @TestApi public static final int INVALID_SECURITY_PARAMETER_INDEX = 0;
Nathan Harold93962f32017-03-07 13:23:36 -080089
90 /** @hide */
91 public interface Status {
92 public static final int OK = 0;
93 public static final int RESOURCE_UNAVAILABLE = 1;
94 public static final int SPI_UNAVAILABLE = 2;
95 }
96
97 /** @hide */
Nathan Harold6119d8d2017-12-13 18:51:35 -080098 public static final int INVALID_RESOURCE_ID = -1;
Nathan Harold93962f32017-03-07 13:23:36 -080099
100 /**
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700101 * Thrown to indicate that a requested SPI is in use.
102 *
103 * <p>The combination of remote {@code InetAddress} and SPI must be unique across all apps on
104 * one device. If this error is encountered, a new SPI is required before a transform may be
105 * created. This error can be avoided by calling {@link
Jonathan Basseri5fb92902017-11-16 10:58:01 -0800106 * IpSecManager#allocateSecurityParameterIndex}.
Nathan Harold330e1082017-01-12 18:38:57 -0800107 */
108 public static final class SpiUnavailableException extends AndroidException {
109 private final int mSpi;
110
111 /**
112 * Construct an exception indicating that a transform with the given SPI is already in use
113 * or otherwise unavailable.
114 *
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700115 * @param msg description indicating the colliding SPI
Nathan Harold330e1082017-01-12 18:38:57 -0800116 * @param spi the SPI that could not be used due to a collision
117 */
118 SpiUnavailableException(String msg, int spi) {
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700119 super(msg + " (spi: " + spi + ")");
Nathan Harold330e1082017-01-12 18:38:57 -0800120 mSpi = spi;
121 }
122
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700123 /** Get the SPI that caused a collision. */
Nathan Harold330e1082017-01-12 18:38:57 -0800124 public int getSpi() {
125 return mSpi;
126 }
127 }
128
129 /**
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700130 * Thrown to indicate that an IPsec resource is unavailable.
131 *
132 * <p>This could apply to resources such as sockets, {@link SecurityParameterIndex}, {@link
133 * IpSecTransform}, or other system resources. If this exception is thrown, users should release
134 * allocated objects of the type requested.
Nathan Harold330e1082017-01-12 18:38:57 -0800135 */
136 public static final class ResourceUnavailableException extends AndroidException {
137
138 ResourceUnavailableException(String msg) {
139 super(msg);
140 }
141 }
142
Nathan Harold592dadb2018-03-15 18:06:06 -0700143 private final Context mContext;
Nathan Harold1afbef42017-03-01 18:55:06 -0800144 private final IIpSecService mService;
Nathan Harold330e1082017-01-12 18:38:57 -0800145
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700146 /**
147 * This class represents a reserved SPI.
148 *
149 * <p>Objects of this type are used to track reserved security parameter indices. They can be
Jonathan Basseri5fb92902017-11-16 10:58:01 -0800150 * obtained by calling {@link IpSecManager#allocateSecurityParameterIndex} and must be released
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700151 * by calling {@link #close()} when they are no longer needed.
152 */
Nathan Harold330e1082017-01-12 18:38:57 -0800153 public static final class SecurityParameterIndex implements AutoCloseable {
Nathan Harold1afbef42017-03-01 18:55:06 -0800154 private final IIpSecService mService;
Nathan Harolda2523312018-01-05 19:25:13 -0800155 private final InetAddress mDestinationAddress;
Nathan Harold330e1082017-01-12 18:38:57 -0800156 private final CloseGuard mCloseGuard = CloseGuard.get();
Nathan Harold93962f32017-03-07 13:23:36 -0800157 private int mSpi = INVALID_SECURITY_PARAMETER_INDEX;
Nathan Harold6119d8d2017-12-13 18:51:35 -0800158 private int mResourceId = INVALID_RESOURCE_ID;
Nathan Harold330e1082017-01-12 18:38:57 -0800159
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700160 /** Get the underlying SPI held by this object. */
Nathan Harold330e1082017-01-12 18:38:57 -0800161 public int getSpi() {
162 return mSpi;
163 }
164
Nathan Harold330e1082017-01-12 18:38:57 -0800165 /**
166 * Release an SPI that was previously reserved.
167 *
Nathan Haroldc4f87992017-03-29 10:47:59 -0700168 * <p>Release an SPI for use by other users in the system. If a SecurityParameterIndex is
169 * applied to an IpSecTransform, it will become unusable for future transforms but should
170 * still be closed to ensure system resources are released.
Nathan Harold330e1082017-01-12 18:38:57 -0800171 */
172 @Override
173 public void close() {
Nathan Harold8dc1fd02017-04-04 19:37:48 -0700174 try {
175 mService.releaseSecurityParameterIndex(mResourceId);
Nathan Harold6119d8d2017-12-13 18:51:35 -0800176 mResourceId = INVALID_RESOURCE_ID;
Nathan Harold8dc1fd02017-04-04 19:37:48 -0700177 } catch (RemoteException e) {
178 throw e.rethrowFromSystemServer();
179 }
Nathan Harold330e1082017-01-12 18:38:57 -0800180 mCloseGuard.close();
181 }
182
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700183 /** Check that the SPI was closed properly. */
Nathan Harold330e1082017-01-12 18:38:57 -0800184 @Override
Nathan Harold440824f2017-11-07 17:17:45 -0800185 protected void finalize() throws Throwable {
Nathan Harold330e1082017-01-12 18:38:57 -0800186 if (mCloseGuard != null) {
187 mCloseGuard.warnIfOpen();
188 }
189
190 close();
191 }
Nathan Harold330e1082017-01-12 18:38:57 -0800192
Nathan Harold93962f32017-03-07 13:23:36 -0800193 private SecurityParameterIndex(
Nathan Harolda2523312018-01-05 19:25:13 -0800194 @NonNull IIpSecService service, InetAddress destinationAddress, int spi)
Nathan Harold93962f32017-03-07 13:23:36 -0800195 throws ResourceUnavailableException, SpiUnavailableException {
196 mService = service;
Nathan Harolda2523312018-01-05 19:25:13 -0800197 mDestinationAddress = destinationAddress;
Nathan Harold93962f32017-03-07 13:23:36 -0800198 try {
Nathan Harold8dc1fd02017-04-04 19:37:48 -0700199 IpSecSpiResponse result =
Jonathan Basseri5fb92902017-11-16 10:58:01 -0800200 mService.allocateSecurityParameterIndex(
Nathan Harolda2523312018-01-05 19:25:13 -0800201 destinationAddress.getHostAddress(), spi, new Binder());
Nathan Harold93962f32017-03-07 13:23:36 -0800202
203 if (result == null) {
204 throw new NullPointerException("Received null response from IpSecService");
205 }
206
Nathan Harold8dc1fd02017-04-04 19:37:48 -0700207 int status = result.status;
Nathan Harold93962f32017-03-07 13:23:36 -0800208 switch (status) {
209 case Status.OK:
210 break;
211 case Status.RESOURCE_UNAVAILABLE:
212 throw new ResourceUnavailableException(
213 "No more SPIs may be allocated by this requester.");
214 case Status.SPI_UNAVAILABLE:
215 throw new SpiUnavailableException("Requested SPI is unavailable", spi);
216 default:
217 throw new RuntimeException(
218 "Unknown status returned by IpSecService: " + status);
219 }
Nathan Harold8dc1fd02017-04-04 19:37:48 -0700220 mSpi = result.spi;
221 mResourceId = result.resourceId;
Nathan Harold93962f32017-03-07 13:23:36 -0800222
223 if (mSpi == INVALID_SECURITY_PARAMETER_INDEX) {
224 throw new RuntimeException("Invalid SPI returned by IpSecService: " + status);
225 }
226
227 if (mResourceId == INVALID_RESOURCE_ID) {
228 throw new RuntimeException(
229 "Invalid Resource ID returned by IpSecService: " + status);
230 }
231
232 } catch (RemoteException e) {
233 throw e.rethrowFromSystemServer();
234 }
235 mCloseGuard.open("open");
236 }
Nathan Harold8dc1fd02017-04-04 19:37:48 -0700237
238 /** @hide */
Nathan Harolda10003d2017-08-23 13:46:33 -0700239 @VisibleForTesting
240 public int getResourceId() {
Nathan Harold8dc1fd02017-04-04 19:37:48 -0700241 return mResourceId;
242 }
Nathan Harold93962f32017-03-07 13:23:36 -0800243 }
Nathan Harold330e1082017-01-12 18:38:57 -0800244
245 /**
Nathan Harolda2523312018-01-05 19:25:13 -0800246 * Reserve a random SPI for traffic bound to or from the specified destination address.
Nathan Harold330e1082017-01-12 18:38:57 -0800247 *
248 * <p>If successful, this SPI is guaranteed available until released by a call to {@link
249 * SecurityParameterIndex#close()}.
250 *
Nathan Harolda2523312018-01-05 19:25:13 -0800251 * @param destinationAddress the destination address for traffic bearing the requested SPI.
252 * For inbound traffic, the destination should be an address currently assigned on-device.
Nathan Harold330e1082017-01-12 18:38:57 -0800253 * @return the reserved SecurityParameterIndex
Nathan Harolda2523312018-01-05 19:25:13 -0800254 * @throws {@link #ResourceUnavailableException} indicating that too many SPIs are
255 * currently allocated for this user
Nathan Harold330e1082017-01-12 18:38:57 -0800256 */
Nathan Harold5cd64cc2018-03-16 17:27:30 -0700257 @NonNull
258 public SecurityParameterIndex allocateSecurityParameterIndex(
259 @NonNull InetAddress destinationAddress) throws ResourceUnavailableException {
Nathan Harold60454292017-04-06 18:16:28 -0700260 try {
261 return new SecurityParameterIndex(
262 mService,
Nathan Harolda2523312018-01-05 19:25:13 -0800263 destinationAddress,
Nathan Harold60454292017-04-06 18:16:28 -0700264 IpSecManager.INVALID_SECURITY_PARAMETER_INDEX);
265 } catch (SpiUnavailableException unlikely) {
266 throw new ResourceUnavailableException("No SPIs available");
267 }
268 }
269
270 /**
Nathan Harolda2523312018-01-05 19:25:13 -0800271 * Reserve the requested SPI for traffic bound to or from the specified destination address.
Nathan Harold60454292017-04-06 18:16:28 -0700272 *
273 * <p>If successful, this SPI is guaranteed available until released by a call to {@link
274 * SecurityParameterIndex#close()}.
275 *
Nathan Harolda2523312018-01-05 19:25:13 -0800276 * @param destinationAddress the destination address for traffic bearing the requested SPI.
277 * For inbound traffic, the destination should be an address currently assigned on-device.
Nathan Harold0f8c8bb02018-03-28 08:52:51 -0700278 * @param requestedSpi the requested SPI, or '0' to allocate a random SPI. The range 1-255 is
279 * reserved and may not be used. See RFC 4303 Section 2.1.
Nathan Harold60454292017-04-06 18:16:28 -0700280 * @return the reserved SecurityParameterIndex
Nathan Harolda2523312018-01-05 19:25:13 -0800281 * @throws {@link #ResourceUnavailableException} indicating that too many SPIs are
282 * currently allocated for this user
283 * @throws {@link #SpiUnavailableException} indicating that the requested SPI could not be
284 * reserved
Nathan Harold60454292017-04-06 18:16:28 -0700285 */
Nathan Harold5cd64cc2018-03-16 17:27:30 -0700286 @NonNull
Jonathan Basseri5fb92902017-11-16 10:58:01 -0800287 public SecurityParameterIndex allocateSecurityParameterIndex(
Nathan Harold5cd64cc2018-03-16 17:27:30 -0700288 @NonNull InetAddress destinationAddress, int requestedSpi)
Nathan Harold330e1082017-01-12 18:38:57 -0800289 throws SpiUnavailableException, ResourceUnavailableException {
Nathan Harold60454292017-04-06 18:16:28 -0700290 if (requestedSpi == IpSecManager.INVALID_SECURITY_PARAMETER_INDEX) {
291 throw new IllegalArgumentException("Requested SPI must be a valid (non-zero) SPI");
292 }
Nathan Harolda2523312018-01-05 19:25:13 -0800293 return new SecurityParameterIndex(mService, destinationAddress, requestedSpi);
Nathan Harold330e1082017-01-12 18:38:57 -0800294 }
295
296 /**
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700297 * Apply an IPsec transform to a stream socket.
298 *
299 * <p>This applies transport mode encapsulation to the given socket. Once applied, I/O on the
300 * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When
Nathan Harolda2523312018-01-05 19:25:13 -0800301 * the transform is removed from the socket by calling {@link #removeTransportModeTransforms},
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700302 * unprotected traffic can resume on that socket.
303 *
304 * <p>For security reasons, the destination address of any traffic on the socket must match the
Jonathan Basseri5fb92902017-11-16 10:58:01 -0800305 * remote {@code InetAddress} of the {@code IpSecTransform}. Attempts to send traffic to any
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700306 * other IP address will result in an IOException. In addition, reads and writes on the socket
307 * will throw IOException if the user deactivates the transform (by calling {@link
Nathan Harolda2523312018-01-05 19:25:13 -0800308 * IpSecTransform#close()}) without calling {@link #removeTransportModeTransforms}.
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700309 *
Benedict Wong420fe002018-03-14 19:01:14 -0700310 * <p>Note that when applied to TCP sockets, calling {@link IpSecTransform#close()} on an
311 * applied transform before completion of graceful shutdown may result in the shutdown sequence
312 * failing to complete. As such, applications requiring graceful shutdown MUST close the socket
313 * prior to deactivating the applied transform. Socket closure may be performed asynchronously
314 * (in batches), so the returning of a close function does not guarantee shutdown of a socket.
315 * Setting an SO_LINGER timeout results in socket closure being performed synchronously, and is
316 * sufficient to ensure shutdown.
317 *
318 * Specifically, if the transform is deactivated (by calling {@link IpSecTransform#close()}),
319 * prior to the socket being closed, the standard [FIN - FIN/ACK - ACK], or the reset [RST]
320 * packets are dropped due to the lack of a valid Transform. Similarly, if a socket without the
321 * SO_LINGER option set is closed, the delayed/batched FIN packets may be dropped.
322 *
Jonathan Basseri5fb92902017-11-16 10:58:01 -0800323 * <h4>Rekey Procedure</h4>
324 *
Nathan Harold7b7bea02018-03-06 13:22:22 -0800325 * <p>When applying a new tranform to a socket in the outbound direction, the previous transform
326 * will be removed and the new transform will take effect immediately, sending all traffic on
327 * the new transform; however, when applying a transform in the inbound direction, traffic
328 * on the old transform will continue to be decrypted and delivered until that transform is
329 * deallocated by calling {@link IpSecTransform#close()}. This overlap allows lossless rekey
330 * procedures where both transforms are valid until both endpoints are using the new transform
331 * and all in-flight packets have been received.
Nathan Harold330e1082017-01-12 18:38:57 -0800332 *
333 * @param socket a stream socket
Nathan Harold7b7bea02018-03-06 13:22:22 -0800334 * @param direction the direction in which the transform should be applied
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700335 * @param transform a transport mode {@code IpSecTransform}
336 * @throws IOException indicating that the transform could not be applied
Nathan Harold330e1082017-01-12 18:38:57 -0800337 */
Nathan Harold5cd64cc2018-03-16 17:27:30 -0700338 public void applyTransportModeTransform(@NonNull Socket socket,
339 @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException {
Benedict Wongd175a3d2018-04-02 18:12:34 -0700340 // Ensure creation of FD. See b/77548890 for more details.
341 socket.getSoLinger();
342
Nathan Haroldb548d252018-01-16 12:08:43 -0800343 applyTransportModeTransform(socket.getFileDescriptor$(), direction, transform);
Nathan Harold330e1082017-01-12 18:38:57 -0800344 }
345
346 /**
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700347 * Apply an IPsec transform to a datagram socket.
348 *
349 * <p>This applies transport mode encapsulation to the given socket. Once applied, I/O on the
350 * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When
Nathan Harolda2523312018-01-05 19:25:13 -0800351 * the transform is removed from the socket by calling {@link #removeTransportModeTransforms},
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700352 * unprotected traffic can resume on that socket.
353 *
354 * <p>For security reasons, the destination address of any traffic on the socket must match the
355 * remote {@code InetAddress} of the {@code IpSecTransform}. Attempts to send traffic to any
356 * other IP address will result in an IOException. In addition, reads and writes on the socket
357 * will throw IOException if the user deactivates the transform (by calling {@link
Nathan Harolda2523312018-01-05 19:25:13 -0800358 * IpSecTransform#close()}) without calling {@link #removeTransportModeTransforms}.
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700359 *
Jonathan Basseri5fb92902017-11-16 10:58:01 -0800360 * <h4>Rekey Procedure</h4>
361 *
Nathan Harold7b7bea02018-03-06 13:22:22 -0800362 * <p>When applying a new tranform to a socket in the outbound direction, the previous transform
363 * will be removed and the new transform will take effect immediately, sending all traffic on
364 * the new transform; however, when applying a transform in the inbound direction, traffic
365 * on the old transform will continue to be decrypted and delivered until that transform is
366 * deallocated by calling {@link IpSecTransform#close()}. This overlap allows lossless rekey
367 * procedures where both transforms are valid until both endpoints are using the new transform
368 * and all in-flight packets have been received.
Nathan Harold330e1082017-01-12 18:38:57 -0800369 *
370 * @param socket a datagram socket
Nathan Harold7b7bea02018-03-06 13:22:22 -0800371 * @param direction the direction in which the transform should be applied
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700372 * @param transform a transport mode {@code IpSecTransform}
373 * @throws IOException indicating that the transform could not be applied
Nathan Harold330e1082017-01-12 18:38:57 -0800374 */
Nathan Harold5cd64cc2018-03-16 17:27:30 -0700375 public void applyTransportModeTransform(@NonNull DatagramSocket socket,
376 @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException {
Nathan Haroldb548d252018-01-16 12:08:43 -0800377 applyTransportModeTransform(socket.getFileDescriptor$(), direction, transform);
Nathan Harold93962f32017-03-07 13:23:36 -0800378 }
Nathan Harold330e1082017-01-12 18:38:57 -0800379
380 /**
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700381 * Apply an IPsec transform to a socket.
382 *
383 * <p>This applies transport mode encapsulation to the given socket. Once applied, I/O on the
384 * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When
Nathan Harolda2523312018-01-05 19:25:13 -0800385 * the transform is removed from the socket by calling {@link #removeTransportModeTransforms},
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700386 * unprotected traffic can resume on that socket.
387 *
388 * <p>For security reasons, the destination address of any traffic on the socket must match the
389 * remote {@code InetAddress} of the {@code IpSecTransform}. Attempts to send traffic to any
390 * other IP address will result in an IOException. In addition, reads and writes on the socket
391 * will throw IOException if the user deactivates the transform (by calling {@link
Nathan Harolda2523312018-01-05 19:25:13 -0800392 * IpSecTransform#close()}) without calling {@link #removeTransportModeTransforms}.
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700393 *
Benedict Wong420fe002018-03-14 19:01:14 -0700394 * <p>Note that when applied to TCP sockets, calling {@link IpSecTransform#close()} on an
395 * applied transform before completion of graceful shutdown may result in the shutdown sequence
396 * failing to complete. As such, applications requiring graceful shutdown MUST close the socket
397 * prior to deactivating the applied transform. Socket closure may be performed asynchronously
398 * (in batches), so the returning of a close function does not guarantee shutdown of a socket.
399 * Setting an SO_LINGER timeout results in socket closure being performed synchronously, and is
400 * sufficient to ensure shutdown.
401 *
402 * Specifically, if the transform is deactivated (by calling {@link IpSecTransform#close()}),
403 * prior to the socket being closed, the standard [FIN - FIN/ACK - ACK], or the reset [RST]
404 * packets are dropped due to the lack of a valid Transform. Similarly, if a socket without the
405 * SO_LINGER option set is closed, the delayed/batched FIN packets may be dropped.
406 *
Jonathan Basseri5fb92902017-11-16 10:58:01 -0800407 * <h4>Rekey Procedure</h4>
408 *
Nathan Harold7b7bea02018-03-06 13:22:22 -0800409 * <p>When applying a new tranform to a socket in the outbound direction, the previous transform
410 * will be removed and the new transform will take effect immediately, sending all traffic on
411 * the new transform; however, when applying a transform in the inbound direction, traffic
412 * on the old transform will continue to be decrypted and delivered until that transform is
413 * deallocated by calling {@link IpSecTransform#close()}. This overlap allows lossless rekey
414 * procedures where both transforms are valid until both endpoints are using the new transform
415 * and all in-flight packets have been received.
Nathan Haroldb6499352017-04-06 17:46:00 -0700416 *
417 * @param socket a socket file descriptor
Nathan Harold7b7bea02018-03-06 13:22:22 -0800418 * @param direction the direction in which the transform should be applied
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700419 * @param transform a transport mode {@code IpSecTransform}
420 * @throws IOException indicating that the transform could not be applied
Nathan Haroldb6499352017-04-06 17:46:00 -0700421 */
Nathan Harold5cd64cc2018-03-16 17:27:30 -0700422 public void applyTransportModeTransform(@NonNull FileDescriptor socket,
423 @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException {
Nathan Harold8dc1fd02017-04-04 19:37:48 -0700424 // We dup() the FileDescriptor here because if we don't, then the ParcelFileDescriptor()
Nathan Haroldb548d252018-01-16 12:08:43 -0800425 // constructor takes control and closes the user's FD when we exit the method.
Nathan Harold8dc1fd02017-04-04 19:37:48 -0700426 try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) {
Nathan Harolda2523312018-01-05 19:25:13 -0800427 mService.applyTransportModeTransform(pfd, direction, transform.getResourceId());
Nathan Harold8dc1fd02017-04-04 19:37:48 -0700428 } catch (RemoteException e) {
429 throw e.rethrowFromSystemServer();
430 }
Nathan Haroldb6499352017-04-06 17:46:00 -0700431 }
432
433 /**
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700434 * Remove an IPsec transform from a stream socket.
Nathan Harold330e1082017-01-12 18:38:57 -0800435 *
Nathan Haroldf73d2522018-01-17 01:00:20 -0800436 * <p>Once removed, traffic on the socket will not be encrypted. Removing transforms from a
437 * socket allows the socket to be reused for communication in the clear.
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700438 *
439 * <p>If an {@code IpSecTransform} object applied to this socket was deallocated by calling
440 * {@link IpSecTransform#close()}, then communication on the socket will fail until this method
441 * is called.
442 *
443 * @param socket a socket that previously had a transform applied to it
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700444 * @throws IOException indicating that the transform could not be removed from the socket
Nathan Harold330e1082017-01-12 18:38:57 -0800445 */
Nathan Harold5cd64cc2018-03-16 17:27:30 -0700446 public void removeTransportModeTransforms(@NonNull Socket socket) throws IOException {
Benedict Wongd175a3d2018-04-02 18:12:34 -0700447 // Ensure creation of FD. See b/77548890 for more details.
448 socket.getSoLinger();
449
Nathan Haroldf73d2522018-01-17 01:00:20 -0800450 removeTransportModeTransforms(socket.getFileDescriptor$());
Nathan Harold330e1082017-01-12 18:38:57 -0800451 }
452
453 /**
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700454 * Remove an IPsec transform from a datagram socket.
Nathan Harold330e1082017-01-12 18:38:57 -0800455 *
Nathan Haroldf73d2522018-01-17 01:00:20 -0800456 * <p>Once removed, traffic on the socket will not be encrypted. Removing transforms from a
457 * socket allows the socket to be reused for communication in the clear.
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700458 *
459 * <p>If an {@code IpSecTransform} object applied to this socket was deallocated by calling
460 * {@link IpSecTransform#close()}, then communication on the socket will fail until this method
461 * is called.
462 *
463 * @param socket a socket that previously had a transform applied to it
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700464 * @throws IOException indicating that the transform could not be removed from the socket
Nathan Harold330e1082017-01-12 18:38:57 -0800465 */
Nathan Harold5cd64cc2018-03-16 17:27:30 -0700466 public void removeTransportModeTransforms(@NonNull DatagramSocket socket) throws IOException {
Nathan Haroldf73d2522018-01-17 01:00:20 -0800467 removeTransportModeTransforms(socket.getFileDescriptor$());
Nathan Harold330e1082017-01-12 18:38:57 -0800468 }
469
Nathan Haroldb6499352017-04-06 17:46:00 -0700470 /**
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700471 * Remove an IPsec transform from a socket.
Nathan Haroldb6499352017-04-06 17:46:00 -0700472 *
Nathan Haroldf73d2522018-01-17 01:00:20 -0800473 * <p>Once removed, traffic on the socket will not be encrypted. Removing transforms from a
474 * socket allows the socket to be reused for communication in the clear.
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700475 *
476 * <p>If an {@code IpSecTransform} object applied to this socket was deallocated by calling
477 * {@link IpSecTransform#close()}, then communication on the socket will fail until this method
478 * is called.
479 *
480 * @param socket a socket that previously had a transform applied to it
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700481 * @throws IOException indicating that the transform could not be removed from the socket
Nathan Haroldb6499352017-04-06 17:46:00 -0700482 */
Nathan Harold5cd64cc2018-03-16 17:27:30 -0700483 public void removeTransportModeTransforms(@NonNull FileDescriptor socket) throws IOException {
Nathan Harold8dc1fd02017-04-04 19:37:48 -0700484 try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) {
Nathan Haroldf73d2522018-01-17 01:00:20 -0800485 mService.removeTransportModeTransforms(pfd);
Nathan Harold93962f32017-03-07 13:23:36 -0800486 } catch (RemoteException e) {
487 throw e.rethrowFromSystemServer();
488 }
489 }
Nathan Harold330e1082017-01-12 18:38:57 -0800490
491 /**
492 * Remove a Tunnel Mode IPsec Transform from a {@link Network}. This must be used as part of
493 * cleanup if a tunneled Network experiences a change in default route. The Network will drop
494 * all traffic that cannot be routed to the Tunnel's outbound interface. If that interface is
495 * lost, all traffic will drop.
496 *
Jonathan Basseri5fb92902017-11-16 10:58:01 -0800497 * <p>TODO: Update javadoc for tunnel mode APIs at the same time the APIs are re-worked.
498 *
Nathan Harold330e1082017-01-12 18:38:57 -0800499 * @param net a network that currently has transform applied to it.
500 * @param transform a Tunnel Mode IPsec Transform that has been previously applied to the given
501 * network
502 * @hide
503 */
Nathan Harold330e1082017-01-12 18:38:57 -0800504 public void removeTunnelModeTransform(Network net, IpSecTransform transform) {}
505
506 /**
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700507 * This class provides access to a UDP encapsulation Socket.
Nathan Harold330e1082017-01-12 18:38:57 -0800508 *
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700509 * <p>{@code UdpEncapsulationSocket} wraps a system-provided datagram socket intended for IKEv2
510 * signalling and UDP encapsulated IPsec traffic. Instances can be obtained by calling {@link
511 * IpSecManager#openUdpEncapsulationSocket}. The provided socket cannot be re-bound by the
512 * caller. The caller should not close the {@code FileDescriptor} returned by {@link
Benedict Wong6ea93c42018-03-27 16:55:48 -0700513 * #getFileDescriptor}, but should use {@link #close} instead.
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700514 *
515 * <p>Allowing the user to close or unbind a UDP encapsulation socket could impact the traffic
516 * of the next user who binds to that port. To prevent this scenario, these sockets are held
517 * open by the system so that they may only be closed by calling {@link #close} or when the user
518 * process exits.
Nathan Harold330e1082017-01-12 18:38:57 -0800519 */
520 public static final class UdpEncapsulationSocket implements AutoCloseable {
Nathan Harold8dc1fd02017-04-04 19:37:48 -0700521 private final ParcelFileDescriptor mPfd;
Nathan Harold1afbef42017-03-01 18:55:06 -0800522 private final IIpSecService mService;
Nathan Harold6119d8d2017-12-13 18:51:35 -0800523 private int mResourceId = INVALID_RESOURCE_ID;
Nathan Harold8dc1fd02017-04-04 19:37:48 -0700524 private final int mPort;
Nathan Harold330e1082017-01-12 18:38:57 -0800525 private final CloseGuard mCloseGuard = CloseGuard.get();
526
Nathan Harold93962f32017-03-07 13:23:36 -0800527 private UdpEncapsulationSocket(@NonNull IIpSecService service, int port)
Nathan Harold8dc1fd02017-04-04 19:37:48 -0700528 throws ResourceUnavailableException, IOException {
Nathan Harold1afbef42017-03-01 18:55:06 -0800529 mService = service;
Nathan Harold8dc1fd02017-04-04 19:37:48 -0700530 try {
531 IpSecUdpEncapResponse result =
532 mService.openUdpEncapsulationSocket(port, new Binder());
533 switch (result.status) {
534 case Status.OK:
535 break;
536 case Status.RESOURCE_UNAVAILABLE:
537 throw new ResourceUnavailableException(
538 "No more Sockets may be allocated by this requester.");
539 default:
540 throw new RuntimeException(
541 "Unknown status returned by IpSecService: " + result.status);
542 }
543 mResourceId = result.resourceId;
544 mPort = result.port;
545 mPfd = result.fileDescriptor;
546 } catch (RemoteException e) {
547 throw e.rethrowFromSystemServer();
548 }
Nathan Harold330e1082017-01-12 18:38:57 -0800549 mCloseGuard.open("constructor");
Nathan Harold330e1082017-01-12 18:38:57 -0800550 }
551
Benedict Wong6ea93c42018-03-27 16:55:48 -0700552 /** Get the encapsulation socket's file descriptor. */
553 public FileDescriptor getFileDescriptor() {
Nathan Harold8dc1fd02017-04-04 19:37:48 -0700554 if (mPfd == null) {
555 return null;
556 }
557 return mPfd.getFileDescriptor();
Nathan Harold330e1082017-01-12 18:38:57 -0800558 }
559
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700560 /** Get the bound port of the wrapped socket. */
Nathan Harold330e1082017-01-12 18:38:57 -0800561 public int getPort() {
Nathan Harold8dc1fd02017-04-04 19:37:48 -0700562 return mPort;
Nathan Harold330e1082017-01-12 18:38:57 -0800563 }
564
Nathan Harold330e1082017-01-12 18:38:57 -0800565 /**
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700566 * Close this socket.
Nathan Harold330e1082017-01-12 18:38:57 -0800567 *
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700568 * <p>This closes the wrapped socket. Open encapsulation sockets count against a user's
569 * resource limits, and forgetting to close them eventually will result in {@link
570 * ResourceUnavailableException} being thrown.
Nathan Harold330e1082017-01-12 18:38:57 -0800571 */
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700572 @Override
Nathan Harold0bfb2072017-04-17 17:11:58 -0700573 public void close() throws IOException {
Nathan Harold8dc1fd02017-04-04 19:37:48 -0700574 try {
575 mService.closeUdpEncapsulationSocket(mResourceId);
Nathan Harold6119d8d2017-12-13 18:51:35 -0800576 mResourceId = INVALID_RESOURCE_ID;
Nathan Harold8dc1fd02017-04-04 19:37:48 -0700577 } catch (RemoteException e) {
578 throw e.rethrowFromSystemServer();
579 }
580
581 try {
582 mPfd.close();
583 } catch (IOException e) {
584 Log.e(TAG, "Failed to close UDP Encapsulation Socket with Port= " + mPort);
585 throw e;
586 }
Nathan Harold330e1082017-01-12 18:38:57 -0800587 mCloseGuard.close();
588 }
589
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700590 /** Check that the socket was closed properly. */
Nathan Harold330e1082017-01-12 18:38:57 -0800591 @Override
592 protected void finalize() throws Throwable {
593 if (mCloseGuard != null) {
594 mCloseGuard.warnIfOpen();
595 }
Nathan Harold330e1082017-01-12 18:38:57 -0800596 close();
597 }
Nathan Harold8dc1fd02017-04-04 19:37:48 -0700598
599 /** @hide */
Nathan Harolda10003d2017-08-23 13:46:33 -0700600 @VisibleForTesting
601 public int getResourceId() {
Nathan Harold8dc1fd02017-04-04 19:37:48 -0700602 return mResourceId;
603 }
Nathan Harold330e1082017-01-12 18:38:57 -0800604 };
605
606 /**
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700607 * Open a socket for UDP encapsulation and bind to the given port.
Nathan Harold330e1082017-01-12 18:38:57 -0800608 *
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700609 * <p>See {@link UdpEncapsulationSocket} for the proper way to close the returned socket.
Nathan Harold330e1082017-01-12 18:38:57 -0800610 *
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700611 * @param port a local UDP port
612 * @return a socket that is bound to the given port
613 * @throws IOException indicating that the socket could not be opened or bound
614 * @throws ResourceUnavailableException indicating that too many encapsulation sockets are open
Nathan Harold330e1082017-01-12 18:38:57 -0800615 */
616 // Returning a socket in this fashion that has been created and bound by the system
617 // is the only safe way to ensure that a socket is both accessible to the user and
618 // safely usable for Encapsulation without allowing a user to possibly unbind from/close
619 // the port, which could potentially impact the traffic of the next user who binds to that
620 // socket.
Nathan Harold5cd64cc2018-03-16 17:27:30 -0700621 @NonNull
Nathan Harold330e1082017-01-12 18:38:57 -0800622 public UdpEncapsulationSocket openUdpEncapsulationSocket(int port)
623 throws IOException, ResourceUnavailableException {
Nathan Harold8dc1fd02017-04-04 19:37:48 -0700624 /*
625 * Most range checking is done in the service, but this version of the constructor expects
626 * a valid port number, and zero cannot be checked after being passed to the service.
627 */
628 if (port == 0) {
629 throw new IllegalArgumentException("Specified port must be a valid port number!");
630 }
Nathan Harold1afbef42017-03-01 18:55:06 -0800631 return new UdpEncapsulationSocket(mService, port);
Nathan Harold330e1082017-01-12 18:38:57 -0800632 }
633
634 /**
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700635 * Open a socket for UDP encapsulation.
Nathan Harold330e1082017-01-12 18:38:57 -0800636 *
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700637 * <p>See {@link UdpEncapsulationSocket} for the proper way to close the returned socket.
Nathan Harold330e1082017-01-12 18:38:57 -0800638 *
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700639 * <p>The local port of the returned socket can be obtained by calling {@link
640 * UdpEncapsulationSocket#getPort()}.
Nathan Harold330e1082017-01-12 18:38:57 -0800641 *
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700642 * @return a socket that is bound to a local port
643 * @throws IOException indicating that the socket could not be opened or bound
644 * @throws ResourceUnavailableException indicating that too many encapsulation sockets are open
Nathan Harold330e1082017-01-12 18:38:57 -0800645 */
646 // Returning a socket in this fashion that has been created and bound by the system
647 // is the only safe way to ensure that a socket is both accessible to the user and
648 // safely usable for Encapsulation without allowing a user to possibly unbind from/close
649 // the port, which could potentially impact the traffic of the next user who binds to that
650 // socket.
Nathan Harold5cd64cc2018-03-16 17:27:30 -0700651 @NonNull
Nathan Harold330e1082017-01-12 18:38:57 -0800652 public UdpEncapsulationSocket openUdpEncapsulationSocket()
653 throws IOException, ResourceUnavailableException {
Nathan Harold8dc1fd02017-04-04 19:37:48 -0700654 return new UdpEncapsulationSocket(mService, 0);
Nathan Harold330e1082017-01-12 18:38:57 -0800655 }
656
657 /**
Nathan Haroldc47eacc2018-01-17 16:09:24 -0800658 * This class represents an IpSecTunnelInterface
659 *
660 * <p>IpSecTunnelInterface objects track tunnel interfaces that serve as
661 * local endpoints for IPsec tunnels.
662 *
663 * <p>Creating an IpSecTunnelInterface creates a device to which IpSecTransforms may be
664 * applied to provide IPsec security to packets sent through the tunnel. While a tunnel
665 * cannot be used in standalone mode within Android, the higher layers may use the tunnel
666 * to create Network objects which are accessible to the Android system.
667 * @hide
668 */
669 @SystemApi
670 public static final class IpSecTunnelInterface implements AutoCloseable {
Nathan Harold592dadb2018-03-15 18:06:06 -0700671 private final String mOpPackageName;
Nathan Haroldc47eacc2018-01-17 16:09:24 -0800672 private final IIpSecService mService;
673 private final InetAddress mRemoteAddress;
674 private final InetAddress mLocalAddress;
675 private final Network mUnderlyingNetwork;
676 private final CloseGuard mCloseGuard = CloseGuard.get();
677 private String mInterfaceName;
678 private int mResourceId = INVALID_RESOURCE_ID;
679
680 /** Get the underlying SPI held by this object. */
Nathan Harold5cd64cc2018-03-16 17:27:30 -0700681 @NonNull
Nathan Haroldc47eacc2018-01-17 16:09:24 -0800682 public String getInterfaceName() {
683 return mInterfaceName;
684 }
685
686 /**
687 * Add an address to the IpSecTunnelInterface
688 *
689 * <p>Add an address which may be used as the local inner address for
690 * tunneled traffic.
691 *
692 * @param address the local address for traffic inside the tunnel
Nathan Haroldc47eacc2018-01-17 16:09:24 -0800693 * @hide
694 */
Nathan Haroldc8f63062018-03-20 12:26:10 -0700695 @SystemApi
Nathan Harold15978842018-03-21 15:32:42 -0700696 @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
Nathan Harold5cd64cc2018-03-16 17:27:30 -0700697 public void addAddress(@NonNull LinkAddress address) throws IOException {
Benedict Wongda4b0c62018-03-01 18:53:07 -0800698 try {
Nathan Harold592dadb2018-03-15 18:06:06 -0700699 mService.addAddressToTunnelInterface(
700 mResourceId, address, mOpPackageName);
Benedict Wongda4b0c62018-03-01 18:53:07 -0800701 } catch (RemoteException e) {
702 throw e.rethrowFromSystemServer();
703 }
Nathan Haroldc47eacc2018-01-17 16:09:24 -0800704 }
705
706 /**
707 * Remove an address from the IpSecTunnelInterface
708 *
709 * <p>Remove an address which was previously added to the IpSecTunnelInterface
710 *
711 * @param address to be removed
Nathan Haroldc47eacc2018-01-17 16:09:24 -0800712 * @hide
713 */
Nathan Haroldc8f63062018-03-20 12:26:10 -0700714 @SystemApi
Nathan Harold15978842018-03-21 15:32:42 -0700715 @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
Nathan Harold5cd64cc2018-03-16 17:27:30 -0700716 public void removeAddress(@NonNull LinkAddress address) throws IOException {
Benedict Wongda4b0c62018-03-01 18:53:07 -0800717 try {
Nathan Harold592dadb2018-03-15 18:06:06 -0700718 mService.removeAddressFromTunnelInterface(
719 mResourceId, address, mOpPackageName);
Benedict Wongda4b0c62018-03-01 18:53:07 -0800720 } catch (RemoteException e) {
721 throw e.rethrowFromSystemServer();
722 }
Nathan Haroldc47eacc2018-01-17 16:09:24 -0800723 }
724
Nathan Harold592dadb2018-03-15 18:06:06 -0700725 private IpSecTunnelInterface(@NonNull Context ctx, @NonNull IIpSecService service,
Nathan Haroldc47eacc2018-01-17 16:09:24 -0800726 @NonNull InetAddress localAddress, @NonNull InetAddress remoteAddress,
727 @NonNull Network underlyingNetwork)
728 throws ResourceUnavailableException, IOException {
Nathan Harold592dadb2018-03-15 18:06:06 -0700729 mOpPackageName = ctx.getOpPackageName();
Nathan Haroldc47eacc2018-01-17 16:09:24 -0800730 mService = service;
731 mLocalAddress = localAddress;
732 mRemoteAddress = remoteAddress;
733 mUnderlyingNetwork = underlyingNetwork;
Benedict Wong8149f6e2018-01-18 18:31:45 -0800734
735 try {
736 IpSecTunnelInterfaceResponse result =
737 mService.createTunnelInterface(
738 localAddress.getHostAddress(),
739 remoteAddress.getHostAddress(),
740 underlyingNetwork,
Nathan Harold592dadb2018-03-15 18:06:06 -0700741 new Binder(),
742 mOpPackageName);
Benedict Wong8149f6e2018-01-18 18:31:45 -0800743 switch (result.status) {
744 case Status.OK:
745 break;
746 case Status.RESOURCE_UNAVAILABLE:
747 throw new ResourceUnavailableException(
748 "No more tunnel interfaces may be allocated by this requester.");
749 default:
750 throw new RuntimeException(
751 "Unknown status returned by IpSecService: " + result.status);
752 }
753 mResourceId = result.resourceId;
754 mInterfaceName = result.interfaceName;
755 } catch (RemoteException e) {
756 throw e.rethrowFromSystemServer();
757 }
758 mCloseGuard.open("constructor");
Nathan Haroldc47eacc2018-01-17 16:09:24 -0800759 }
760
761 /**
762 * Delete an IpSecTunnelInterface
763 *
764 * <p>Calling close will deallocate the IpSecTunnelInterface and all of its system
765 * resources. Any packets bound for this interface either inbound or outbound will
766 * all be lost.
767 */
768 @Override
769 public void close() {
Benedict Wong8149f6e2018-01-18 18:31:45 -0800770 try {
Nathan Harold592dadb2018-03-15 18:06:06 -0700771 mService.deleteTunnelInterface(mResourceId, mOpPackageName);
Benedict Wong8149f6e2018-01-18 18:31:45 -0800772 mResourceId = INVALID_RESOURCE_ID;
773 } catch (RemoteException e) {
774 throw e.rethrowFromSystemServer();
775 }
Nathan Haroldc47eacc2018-01-17 16:09:24 -0800776 mCloseGuard.close();
777 }
778
779 /** Check that the Interface was closed properly. */
780 @Override
781 protected void finalize() throws Throwable {
782 if (mCloseGuard != null) {
783 mCloseGuard.warnIfOpen();
784 }
785 close();
786 }
Benedict Wong8149f6e2018-01-18 18:31:45 -0800787
788 /** @hide */
789 @VisibleForTesting
790 public int getResourceId() {
791 return mResourceId;
792 }
Nathan Haroldc47eacc2018-01-17 16:09:24 -0800793 }
794
795 /**
796 * Create a new IpSecTunnelInterface as a local endpoint for tunneled IPsec traffic.
797 *
Benedict Wong8149f6e2018-01-18 18:31:45 -0800798 * <p>An application that creates tunnels is responsible for cleaning up the tunnel when the
799 * underlying network goes away, and the onLost() callback is received.
800 *
Nathan Haroldc47eacc2018-01-17 16:09:24 -0800801 * @param localAddress The local addres of the tunnel
802 * @param remoteAddress The local addres of the tunnel
803 * @param underlyingNetwork the {@link Network} that will carry traffic for this tunnel.
804 * This network should almost certainly be a network such as WiFi with an L2 address.
805 * @return a new {@link IpSecManager#IpSecTunnelInterface} with the specified properties
806 * @throws IOException indicating that the socket could not be opened or bound
807 * @throws ResourceUnavailableException indicating that too many encapsulation sockets are open
808 * @hide
809 */
810 @SystemApi
Nathan Harold5cd64cc2018-03-16 17:27:30 -0700811 @NonNull
Nathan Harold15978842018-03-21 15:32:42 -0700812 @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
Nathan Haroldc47eacc2018-01-17 16:09:24 -0800813 public IpSecTunnelInterface createIpSecTunnelInterface(@NonNull InetAddress localAddress,
814 @NonNull InetAddress remoteAddress, @NonNull Network underlyingNetwork)
815 throws ResourceUnavailableException, IOException {
Nathan Harold592dadb2018-03-15 18:06:06 -0700816 return new IpSecTunnelInterface(
817 mContext, mService, localAddress, remoteAddress, underlyingNetwork);
Nathan Haroldc47eacc2018-01-17 16:09:24 -0800818 }
819
820 /**
Nathan Harold7b7bea02018-03-06 13:22:22 -0800821 * Apply an active Tunnel Mode IPsec Transform to a {@link IpSecTunnelInterface}, which will
822 * tunnel all traffic for the given direction through the underlying network's interface with
823 * IPsec (applies an outer IP header and IPsec Header to all traffic, and expects an additional
824 * IP header and IPsec Header on all inbound traffic).
825 * <p>Applications should probably not use this API directly.
826 *
Nathan Haroldc47eacc2018-01-17 16:09:24 -0800827 *
828 * @param tunnel The {@link IpSecManager#IpSecTunnelInterface} that will use the supplied
829 * transform.
830 * @param direction the direction, {@link DIRECTION_OUT} or {@link #DIRECTION_IN} in which
831 * the transform will be used.
832 * @param transform an {@link IpSecTransform} created in tunnel mode
833 * @throws IOException indicating that the transform could not be applied due to a lower
834 * layer failure.
835 * @hide
836 */
837 @SystemApi
Nathan Harold15978842018-03-21 15:32:42 -0700838 @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
Nathan Harold5cd64cc2018-03-16 17:27:30 -0700839 public void applyTunnelModeTransform(@NonNull IpSecTunnelInterface tunnel,
840 @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException {
Benedict Wong8149f6e2018-01-18 18:31:45 -0800841 try {
842 mService.applyTunnelModeTransform(
Nathan Harold592dadb2018-03-15 18:06:06 -0700843 tunnel.getResourceId(), direction,
844 transform.getResourceId(), mContext.getOpPackageName());
Benedict Wong8149f6e2018-01-18 18:31:45 -0800845 } catch (RemoteException e) {
846 throw e.rethrowFromSystemServer();
847 }
Nathan Haroldc47eacc2018-01-17 16:09:24 -0800848 }
Nathan Harold7b7bea02018-03-06 13:22:22 -0800849
Nathan Haroldc47eacc2018-01-17 16:09:24 -0800850 /**
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700851 * Construct an instance of IpSecManager within an application context.
Nathan Harold330e1082017-01-12 18:38:57 -0800852 *
853 * @param context the application context for this manager
854 * @hide
855 */
Nathan Harold592dadb2018-03-15 18:06:06 -0700856 public IpSecManager(Context ctx, IIpSecService service) {
857 mContext = ctx;
Nathan Harold330e1082017-01-12 18:38:57 -0800858 mService = checkNotNull(service, "missing service");
859 }
860}