blob: 837629911ccdcb68d738da4941460e95b5906cff [file] [log] [blame]
Nathan Haroldb1f605f2017-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
Chiachang Wanga0343312021-01-12 18:48:13 +080018import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
19
Nathan Haroldb1f605f2017-01-12 18:38:57 -080020import static com.android.internal.util.Preconditions.checkNotNull;
21
Nathan Harold031acb82017-03-07 13:23:36 -080022import android.annotation.NonNull;
Benedict Wonge9763752018-11-08 19:45:34 -080023import android.annotation.RequiresFeature;
Nathan Harold025aae12018-02-02 18:34:25 -080024import android.annotation.RequiresPermission;
Nathan Harold3a287d52018-04-25 12:01:34 -070025import android.annotation.SystemApi;
Jeff Sharkeyad1cebe2017-06-02 17:36:26 -060026import android.annotation.SystemService;
Jonathan Basseri2725a232017-04-21 15:53:51 -070027import android.annotation.TestApi;
Jeff Sharkeyad1cebe2017-06-02 17:36:26 -060028import android.content.Context;
Benedict Wonge9763752018-11-08 19:45:34 -080029import android.content.pm.PackageManager;
evitayan30878b02019-12-30 16:05:38 -080030import android.net.annotations.PolicyDirection;
Nathan Harold031acb82017-03-07 13:23:36 -080031import android.os.Binder;
Nathan Haroldb1f605f2017-01-12 18:38:57 -080032import android.os.ParcelFileDescriptor;
Nathan Harold031acb82017-03-07 13:23:36 -080033import android.os.RemoteException;
Nathan Haroldbeed0b62018-04-03 16:13:19 -070034import android.os.ServiceSpecificException;
35import android.system.ErrnoException;
36import android.system.OsConstants;
Nathan Haroldb1f605f2017-01-12 18:38:57 -080037import android.util.AndroidException;
Nathan Harold80865392017-04-04 19:37:48 -070038import android.util.Log;
Nathan Harold81f54632017-09-11 19:50:19 -070039
Nathan Harold19b99d92017-08-23 13:46:33 -070040import com.android.internal.annotations.VisibleForTesting;
41
Nathan Haroldb1f605f2017-01-12 18:38:57 -080042import dalvik.system.CloseGuard;
Nathan Harold81f54632017-09-11 19:50:19 -070043
Nathan Haroldb1f605f2017-01-12 18:38:57 -080044import java.io.FileDescriptor;
45import java.io.IOException;
46import java.net.DatagramSocket;
47import java.net.InetAddress;
48import java.net.Socket;
49
50/**
Jonathan Basseri2725a232017-04-21 15:53:51 -070051 * This class contains methods for managing IPsec sessions. Once configured, the kernel will apply
52 * confidentiality (encryption) and integrity (authentication) to IP traffic.
Nathan Haroldb1f605f2017-01-12 18:38:57 -080053 *
Jonathan Basseri2725a232017-04-21 15:53:51 -070054 * <p>Note that not all aspects of IPsec are permitted by this API. Applications may create
55 * transport mode security associations and apply them to individual sockets. Applications looking
Benedict Wongc85b7b02019-11-12 22:31:51 -080056 * to create an IPsec VPN should use {@link VpnManager} and {@link Ikev2VpnProfile}.
Jonathan Basseri2725a232017-04-21 15:53:51 -070057 *
58 * @see <a href="https://tools.ietf.org/html/rfc4301">RFC 4301, Security Architecture for the
Jonathan Basseri20e96c52017-11-16 10:58:01 -080059 * Internet Protocol</a>
Nathan Haroldb1f605f2017-01-12 18:38:57 -080060 */
Jeff Sharkeyad1cebe2017-06-02 17:36:26 -060061@SystemService(Context.IPSEC_SERVICE)
Nathan Haroldb1f605f2017-01-12 18:38:57 -080062public final class IpSecManager {
63 private static final String TAG = "IpSecManager";
64
65 /**
Nathan Harolde3536f02018-03-06 13:22:22 -080066 * Used when applying a transform to direct traffic through an {@link IpSecTransform}
67 * towards the host.
68 *
69 * <p>See {@link #applyTransportModeTransform(Socket, int, IpSecTransform)}.
Nathan Harold5a19b952018-01-05 19:25:13 -080070 */
71 public static final int DIRECTION_IN = 0;
72
73 /**
Nathan Harolde3536f02018-03-06 13:22:22 -080074 * Used when applying a transform to direct traffic through an {@link IpSecTransform}
75 * away from the host.
76 *
77 * <p>See {@link #applyTransportModeTransform(Socket, int, IpSecTransform)}.
Nathan Harold5a19b952018-01-05 19:25:13 -080078 */
79 public static final int DIRECTION_OUT = 1;
80
Nathan Harold5a19b952018-01-05 19:25:13 -080081 /**
Benedict Wong908d34e2021-04-15 11:59:16 -070082 * Used when applying a transform to direct traffic through an {@link IpSecTransform} for
83 * forwarding between interfaces.
84 *
85 * <p>See {@link #applyTransportModeTransform(Socket, int, IpSecTransform)}.
86 *
87 * @hide
88 */
89 public static final int DIRECTION_FWD = 2;
90
91 /**
Jonathan Basseri2725a232017-04-21 15:53:51 -070092 * The Security Parameter Index (SPI) 0 indicates an unknown or invalid index.
Nathan Harold031acb82017-03-07 13:23:36 -080093 *
94 * <p>No IPsec packet may contain an SPI of 0.
Jonathan Basseri2725a232017-04-21 15:53:51 -070095 *
96 * @hide
Nathan Harold031acb82017-03-07 13:23:36 -080097 */
Jonathan Basseri20e96c52017-11-16 10:58:01 -080098 @TestApi public static final int INVALID_SECURITY_PARAMETER_INDEX = 0;
Nathan Harold031acb82017-03-07 13:23:36 -080099
100 /** @hide */
101 public interface Status {
Aaron Huangfbae3082021-12-06 15:18:42 +0800102 int OK = 0;
103 int RESOURCE_UNAVAILABLE = 1;
104 int SPI_UNAVAILABLE = 2;
Nathan Harold031acb82017-03-07 13:23:36 -0800105 }
106
107 /** @hide */
Nathan Harold5e854462017-12-13 18:51:35 -0800108 public static final int INVALID_RESOURCE_ID = -1;
Nathan Harold031acb82017-03-07 13:23:36 -0800109
110 /**
Jonathan Basseri2725a232017-04-21 15:53:51 -0700111 * Thrown to indicate that a requested SPI is in use.
112 *
113 * <p>The combination of remote {@code InetAddress} and SPI must be unique across all apps on
114 * one device. If this error is encountered, a new SPI is required before a transform may be
115 * created. This error can be avoided by calling {@link
Jonathan Basseri20e96c52017-11-16 10:58:01 -0800116 * IpSecManager#allocateSecurityParameterIndex}.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800117 */
118 public static final class SpiUnavailableException extends AndroidException {
119 private final int mSpi;
120
121 /**
122 * Construct an exception indicating that a transform with the given SPI is already in use
123 * or otherwise unavailable.
124 *
Jonathan Basseri2725a232017-04-21 15:53:51 -0700125 * @param msg description indicating the colliding SPI
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800126 * @param spi the SPI that could not be used due to a collision
127 */
128 SpiUnavailableException(String msg, int spi) {
Jonathan Basseri2725a232017-04-21 15:53:51 -0700129 super(msg + " (spi: " + spi + ")");
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800130 mSpi = spi;
131 }
132
Jonathan Basseri2725a232017-04-21 15:53:51 -0700133 /** Get the SPI that caused a collision. */
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800134 public int getSpi() {
135 return mSpi;
136 }
137 }
138
139 /**
Jonathan Basseri2725a232017-04-21 15:53:51 -0700140 * Thrown to indicate that an IPsec resource is unavailable.
141 *
142 * <p>This could apply to resources such as sockets, {@link SecurityParameterIndex}, {@link
143 * IpSecTransform}, or other system resources. If this exception is thrown, users should release
144 * allocated objects of the type requested.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800145 */
146 public static final class ResourceUnavailableException extends AndroidException {
147
148 ResourceUnavailableException(String msg) {
149 super(msg);
150 }
151 }
152
Nathan Harold65ef8432018-03-15 18:06:06 -0700153 private final Context mContext;
Nathan Haroldd2a1dad2017-03-01 18:55:06 -0800154 private final IIpSecService mService;
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800155
Jonathan Basseri2725a232017-04-21 15:53:51 -0700156 /**
157 * This class represents a reserved SPI.
158 *
159 * <p>Objects of this type are used to track reserved security parameter indices. They can be
Jonathan Basseri20e96c52017-11-16 10:58:01 -0800160 * obtained by calling {@link IpSecManager#allocateSecurityParameterIndex} and must be released
Jonathan Basseri2725a232017-04-21 15:53:51 -0700161 * by calling {@link #close()} when they are no longer needed.
162 */
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800163 public static final class SecurityParameterIndex implements AutoCloseable {
Nathan Haroldd2a1dad2017-03-01 18:55:06 -0800164 private final IIpSecService mService;
Nathan Harold5a19b952018-01-05 19:25:13 -0800165 private final InetAddress mDestinationAddress;
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800166 private final CloseGuard mCloseGuard = CloseGuard.get();
Nathan Harold031acb82017-03-07 13:23:36 -0800167 private int mSpi = INVALID_SECURITY_PARAMETER_INDEX;
Nathan Harold5e854462017-12-13 18:51:35 -0800168 private int mResourceId = INVALID_RESOURCE_ID;
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800169
Jonathan Basseri2725a232017-04-21 15:53:51 -0700170 /** Get the underlying SPI held by this object. */
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800171 public int getSpi() {
172 return mSpi;
173 }
174
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800175 /**
176 * Release an SPI that was previously reserved.
177 *
Nathan Harold909d66e2017-03-29 10:47:59 -0700178 * <p>Release an SPI for use by other users in the system. If a SecurityParameterIndex is
179 * applied to an IpSecTransform, it will become unusable for future transforms but should
180 * still be closed to ensure system resources are released.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800181 */
182 @Override
183 public void close() {
Nathan Harold80865392017-04-04 19:37:48 -0700184 try {
185 mService.releaseSecurityParameterIndex(mResourceId);
186 } catch (RemoteException e) {
187 throw e.rethrowFromSystemServer();
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700188 } catch (Exception e) {
189 // On close we swallow all random exceptions since failure to close is not
190 // actionable by the user.
191 Log.e(TAG, "Failed to close " + this + ", Exception=" + e);
192 } finally {
193 mResourceId = INVALID_RESOURCE_ID;
194 mCloseGuard.close();
Nathan Harold80865392017-04-04 19:37:48 -0700195 }
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800196 }
197
Jonathan Basseri2725a232017-04-21 15:53:51 -0700198 /** Check that the SPI was closed properly. */
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800199 @Override
Nathan Harold2a30daf2017-11-07 17:17:45 -0800200 protected void finalize() throws Throwable {
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800201 if (mCloseGuard != null) {
202 mCloseGuard.warnIfOpen();
203 }
204
205 close();
206 }
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800207
Nathan Harold031acb82017-03-07 13:23:36 -0800208 private SecurityParameterIndex(
Nathan Harold5a19b952018-01-05 19:25:13 -0800209 @NonNull IIpSecService service, InetAddress destinationAddress, int spi)
Nathan Harold031acb82017-03-07 13:23:36 -0800210 throws ResourceUnavailableException, SpiUnavailableException {
211 mService = service;
Nathan Harold5a19b952018-01-05 19:25:13 -0800212 mDestinationAddress = destinationAddress;
Nathan Harold031acb82017-03-07 13:23:36 -0800213 try {
Nathan Harold80865392017-04-04 19:37:48 -0700214 IpSecSpiResponse result =
Jonathan Basseri20e96c52017-11-16 10:58:01 -0800215 mService.allocateSecurityParameterIndex(
Nathan Harold5a19b952018-01-05 19:25:13 -0800216 destinationAddress.getHostAddress(), spi, new Binder());
Nathan Harold031acb82017-03-07 13:23:36 -0800217
218 if (result == null) {
219 throw new NullPointerException("Received null response from IpSecService");
220 }
221
Nathan Harold80865392017-04-04 19:37:48 -0700222 int status = result.status;
Nathan Harold031acb82017-03-07 13:23:36 -0800223 switch (status) {
224 case Status.OK:
225 break;
226 case Status.RESOURCE_UNAVAILABLE:
227 throw new ResourceUnavailableException(
228 "No more SPIs may be allocated by this requester.");
229 case Status.SPI_UNAVAILABLE:
230 throw new SpiUnavailableException("Requested SPI is unavailable", spi);
231 default:
232 throw new RuntimeException(
233 "Unknown status returned by IpSecService: " + status);
234 }
Nathan Harold80865392017-04-04 19:37:48 -0700235 mSpi = result.spi;
236 mResourceId = result.resourceId;
Nathan Harold031acb82017-03-07 13:23:36 -0800237
238 if (mSpi == INVALID_SECURITY_PARAMETER_INDEX) {
239 throw new RuntimeException("Invalid SPI returned by IpSecService: " + status);
240 }
241
242 if (mResourceId == INVALID_RESOURCE_ID) {
243 throw new RuntimeException(
244 "Invalid Resource ID returned by IpSecService: " + status);
245 }
Nathan Harold031acb82017-03-07 13:23:36 -0800246 } catch (RemoteException e) {
247 throw e.rethrowFromSystemServer();
248 }
249 mCloseGuard.open("open");
250 }
Nathan Harold80865392017-04-04 19:37:48 -0700251
252 /** @hide */
Nathan Harold19b99d92017-08-23 13:46:33 -0700253 @VisibleForTesting
254 public int getResourceId() {
Nathan Harold80865392017-04-04 19:37:48 -0700255 return mResourceId;
256 }
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700257
258 @Override
259 public String toString() {
260 return new StringBuilder()
261 .append("SecurityParameterIndex{spi=")
262 .append(mSpi)
263 .append(",resourceId=")
264 .append(mResourceId)
265 .append("}")
266 .toString();
267 }
Nathan Harold031acb82017-03-07 13:23:36 -0800268 }
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800269
270 /**
Nathan Harold5a19b952018-01-05 19:25:13 -0800271 * Reserve a random SPI for traffic bound to or from the specified destination address.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800272 *
273 * <p>If successful, this SPI is guaranteed available until released by a call to {@link
274 * SecurityParameterIndex#close()}.
275 *
Nathan Harold5a19b952018-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 Haroldb1f605f2017-01-12 18:38:57 -0800278 * @return the reserved SecurityParameterIndex
Aaron Huangfbae3082021-12-06 15:18:42 +0800279 * @throws ResourceUnavailableException indicating that too many SPIs are
Nathan Harold5a19b952018-01-05 19:25:13 -0800280 * currently allocated for this user
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800281 */
Nathan Harold6303d9e2018-03-16 17:27:30 -0700282 @NonNull
283 public SecurityParameterIndex allocateSecurityParameterIndex(
284 @NonNull InetAddress destinationAddress) throws ResourceUnavailableException {
Nathan Harold05406792017-04-06 18:16:28 -0700285 try {
286 return new SecurityParameterIndex(
287 mService,
Nathan Harold5a19b952018-01-05 19:25:13 -0800288 destinationAddress,
Nathan Harold05406792017-04-06 18:16:28 -0700289 IpSecManager.INVALID_SECURITY_PARAMETER_INDEX);
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700290 } catch (ServiceSpecificException e) {
291 throw rethrowUncheckedExceptionFromServiceSpecificException(e);
Nathan Harold05406792017-04-06 18:16:28 -0700292 } catch (SpiUnavailableException unlikely) {
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700293 // Because this function allocates a totally random SPI, it really shouldn't ever
294 // fail to allocate an SPI; we simply need this because the exception is checked.
Nathan Harold05406792017-04-06 18:16:28 -0700295 throw new ResourceUnavailableException("No SPIs available");
296 }
297 }
298
299 /**
Nathan Harold5a19b952018-01-05 19:25:13 -0800300 * Reserve the requested SPI for traffic bound to or from the specified destination address.
Nathan Harold05406792017-04-06 18:16:28 -0700301 *
302 * <p>If successful, this SPI is guaranteed available until released by a call to {@link
303 * SecurityParameterIndex#close()}.
304 *
Nathan Harold5a19b952018-01-05 19:25:13 -0800305 * @param destinationAddress the destination address for traffic bearing the requested SPI.
306 * For inbound traffic, the destination should be an address currently assigned on-device.
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700307 * @param requestedSpi the requested SPI. The range 1-255 is reserved and may not be used. See
308 * RFC 4303 Section 2.1.
Nathan Harold05406792017-04-06 18:16:28 -0700309 * @return the reserved SecurityParameterIndex
Aaron Huangfbae3082021-12-06 15:18:42 +0800310 * @throws ResourceUnavailableException indicating that too many SPIs are
Nathan Harold5a19b952018-01-05 19:25:13 -0800311 * currently allocated for this user
Aaron Huangfbae3082021-12-06 15:18:42 +0800312 * @throws SpiUnavailableException indicating that the requested SPI could not be
Nathan Harold5a19b952018-01-05 19:25:13 -0800313 * reserved
Nathan Harold05406792017-04-06 18:16:28 -0700314 */
Nathan Harold6303d9e2018-03-16 17:27:30 -0700315 @NonNull
Jonathan Basseri20e96c52017-11-16 10:58:01 -0800316 public SecurityParameterIndex allocateSecurityParameterIndex(
Nathan Harold6303d9e2018-03-16 17:27:30 -0700317 @NonNull InetAddress destinationAddress, int requestedSpi)
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800318 throws SpiUnavailableException, ResourceUnavailableException {
Nathan Harold05406792017-04-06 18:16:28 -0700319 if (requestedSpi == IpSecManager.INVALID_SECURITY_PARAMETER_INDEX) {
320 throw new IllegalArgumentException("Requested SPI must be a valid (non-zero) SPI");
321 }
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700322 try {
323 return new SecurityParameterIndex(mService, destinationAddress, requestedSpi);
324 } catch (ServiceSpecificException e) {
325 throw rethrowUncheckedExceptionFromServiceSpecificException(e);
326 }
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800327 }
328
329 /**
Jonathan Basseri2725a232017-04-21 15:53:51 -0700330 * Apply an IPsec transform to a stream socket.
331 *
332 * <p>This applies transport mode encapsulation to the given socket. Once applied, I/O on the
333 * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When
Nathan Harold5a19b952018-01-05 19:25:13 -0800334 * the transform is removed from the socket by calling {@link #removeTransportModeTransforms},
Jonathan Basseri2725a232017-04-21 15:53:51 -0700335 * unprotected traffic can resume on that socket.
336 *
337 * <p>For security reasons, the destination address of any traffic on the socket must match the
Jonathan Basseri20e96c52017-11-16 10:58:01 -0800338 * remote {@code InetAddress} of the {@code IpSecTransform}. Attempts to send traffic to any
Jonathan Basseri2725a232017-04-21 15:53:51 -0700339 * other IP address will result in an IOException. In addition, reads and writes on the socket
340 * will throw IOException if the user deactivates the transform (by calling {@link
Nathan Harold5a19b952018-01-05 19:25:13 -0800341 * IpSecTransform#close()}) without calling {@link #removeTransportModeTransforms}.
Jonathan Basseri2725a232017-04-21 15:53:51 -0700342 *
Benedict Wongc5106f32018-03-14 19:01:14 -0700343 * <p>Note that when applied to TCP sockets, calling {@link IpSecTransform#close()} on an
344 * applied transform before completion of graceful shutdown may result in the shutdown sequence
345 * failing to complete. As such, applications requiring graceful shutdown MUST close the socket
346 * prior to deactivating the applied transform. Socket closure may be performed asynchronously
347 * (in batches), so the returning of a close function does not guarantee shutdown of a socket.
348 * Setting an SO_LINGER timeout results in socket closure being performed synchronously, and is
349 * sufficient to ensure shutdown.
350 *
351 * Specifically, if the transform is deactivated (by calling {@link IpSecTransform#close()}),
352 * prior to the socket being closed, the standard [FIN - FIN/ACK - ACK], or the reset [RST]
353 * packets are dropped due to the lack of a valid Transform. Similarly, if a socket without the
354 * SO_LINGER option set is closed, the delayed/batched FIN packets may be dropped.
355 *
Jonathan Basseri20e96c52017-11-16 10:58:01 -0800356 * <h4>Rekey Procedure</h4>
357 *
Nathan Harolde3536f02018-03-06 13:22:22 -0800358 * <p>When applying a new tranform to a socket in the outbound direction, the previous transform
359 * will be removed and the new transform will take effect immediately, sending all traffic on
360 * the new transform; however, when applying a transform in the inbound direction, traffic
361 * on the old transform will continue to be decrypted and delivered until that transform is
362 * deallocated by calling {@link IpSecTransform#close()}. This overlap allows lossless rekey
363 * procedures where both transforms are valid until both endpoints are using the new transform
364 * and all in-flight packets have been received.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800365 *
366 * @param socket a stream socket
Nathan Harolde3536f02018-03-06 13:22:22 -0800367 * @param direction the direction in which the transform should be applied
Jonathan Basseri2725a232017-04-21 15:53:51 -0700368 * @param transform a transport mode {@code IpSecTransform}
369 * @throws IOException indicating that the transform could not be applied
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800370 */
Nathan Harold6303d9e2018-03-16 17:27:30 -0700371 public void applyTransportModeTransform(@NonNull Socket socket,
372 @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException {
Benedict Wong57ab3f62018-04-02 18:12:34 -0700373 // Ensure creation of FD. See b/77548890 for more details.
374 socket.getSoLinger();
375
Nathan Harold31676252018-01-16 12:08:43 -0800376 applyTransportModeTransform(socket.getFileDescriptor$(), direction, transform);
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800377 }
378
379 /**
Jonathan Basseri2725a232017-04-21 15:53:51 -0700380 * Apply an IPsec transform to a datagram socket.
381 *
382 * <p>This applies transport mode encapsulation to the given socket. Once applied, I/O on the
383 * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When
Nathan Harold5a19b952018-01-05 19:25:13 -0800384 * the transform is removed from the socket by calling {@link #removeTransportModeTransforms},
Jonathan Basseri2725a232017-04-21 15:53:51 -0700385 * unprotected traffic can resume on that socket.
386 *
387 * <p>For security reasons, the destination address of any traffic on the socket must match the
388 * remote {@code InetAddress} of the {@code IpSecTransform}. Attempts to send traffic to any
389 * other IP address will result in an IOException. In addition, reads and writes on the socket
390 * will throw IOException if the user deactivates the transform (by calling {@link
Nathan Harold5a19b952018-01-05 19:25:13 -0800391 * IpSecTransform#close()}) without calling {@link #removeTransportModeTransforms}.
Jonathan Basseri2725a232017-04-21 15:53:51 -0700392 *
Jonathan Basseri20e96c52017-11-16 10:58:01 -0800393 * <h4>Rekey Procedure</h4>
394 *
Nathan Harolde3536f02018-03-06 13:22:22 -0800395 * <p>When applying a new tranform to a socket in the outbound direction, the previous transform
396 * will be removed and the new transform will take effect immediately, sending all traffic on
397 * the new transform; however, when applying a transform in the inbound direction, traffic
398 * on the old transform will continue to be decrypted and delivered until that transform is
399 * deallocated by calling {@link IpSecTransform#close()}. This overlap allows lossless rekey
400 * procedures where both transforms are valid until both endpoints are using the new transform
401 * and all in-flight packets have been received.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800402 *
403 * @param socket a datagram socket
Nathan Harolde3536f02018-03-06 13:22:22 -0800404 * @param direction the direction in which the transform should be applied
Jonathan Basseri2725a232017-04-21 15:53:51 -0700405 * @param transform a transport mode {@code IpSecTransform}
406 * @throws IOException indicating that the transform could not be applied
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800407 */
Nathan Harold6303d9e2018-03-16 17:27:30 -0700408 public void applyTransportModeTransform(@NonNull DatagramSocket socket,
409 @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException {
Nathan Harold31676252018-01-16 12:08:43 -0800410 applyTransportModeTransform(socket.getFileDescriptor$(), direction, transform);
Nathan Harold031acb82017-03-07 13:23:36 -0800411 }
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800412
413 /**
Jonathan Basseri2725a232017-04-21 15:53:51 -0700414 * Apply an IPsec transform to a socket.
415 *
416 * <p>This applies transport mode encapsulation to the given socket. Once applied, I/O on the
417 * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When
Nathan Harold5a19b952018-01-05 19:25:13 -0800418 * the transform is removed from the socket by calling {@link #removeTransportModeTransforms},
Jonathan Basseri2725a232017-04-21 15:53:51 -0700419 * unprotected traffic can resume on that socket.
420 *
421 * <p>For security reasons, the destination address of any traffic on the socket must match the
422 * remote {@code InetAddress} of the {@code IpSecTransform}. Attempts to send traffic to any
423 * other IP address will result in an IOException. In addition, reads and writes on the socket
424 * will throw IOException if the user deactivates the transform (by calling {@link
Nathan Harold5a19b952018-01-05 19:25:13 -0800425 * IpSecTransform#close()}) without calling {@link #removeTransportModeTransforms}.
Jonathan Basseri2725a232017-04-21 15:53:51 -0700426 *
Benedict Wongc5106f32018-03-14 19:01:14 -0700427 * <p>Note that when applied to TCP sockets, calling {@link IpSecTransform#close()} on an
428 * applied transform before completion of graceful shutdown may result in the shutdown sequence
429 * failing to complete. As such, applications requiring graceful shutdown MUST close the socket
430 * prior to deactivating the applied transform. Socket closure may be performed asynchronously
431 * (in batches), so the returning of a close function does not guarantee shutdown of a socket.
432 * Setting an SO_LINGER timeout results in socket closure being performed synchronously, and is
433 * sufficient to ensure shutdown.
434 *
435 * Specifically, if the transform is deactivated (by calling {@link IpSecTransform#close()}),
436 * prior to the socket being closed, the standard [FIN - FIN/ACK - ACK], or the reset [RST]
437 * packets are dropped due to the lack of a valid Transform. Similarly, if a socket without the
438 * SO_LINGER option set is closed, the delayed/batched FIN packets may be dropped.
439 *
Jonathan Basseri20e96c52017-11-16 10:58:01 -0800440 * <h4>Rekey Procedure</h4>
441 *
Nathan Harolde3536f02018-03-06 13:22:22 -0800442 * <p>When applying a new tranform to a socket in the outbound direction, the previous transform
443 * will be removed and the new transform will take effect immediately, sending all traffic on
444 * the new transform; however, when applying a transform in the inbound direction, traffic
445 * on the old transform will continue to be decrypted and delivered until that transform is
446 * deallocated by calling {@link IpSecTransform#close()}. This overlap allows lossless rekey
447 * procedures where both transforms are valid until both endpoints are using the new transform
448 * and all in-flight packets have been received.
Nathan Harold0072e192017-04-06 17:46:00 -0700449 *
450 * @param socket a socket file descriptor
Nathan Harolde3536f02018-03-06 13:22:22 -0800451 * @param direction the direction in which the transform should be applied
Jonathan Basseri2725a232017-04-21 15:53:51 -0700452 * @param transform a transport mode {@code IpSecTransform}
453 * @throws IOException indicating that the transform could not be applied
Nathan Harold0072e192017-04-06 17:46:00 -0700454 */
Nathan Harold6303d9e2018-03-16 17:27:30 -0700455 public void applyTransportModeTransform(@NonNull FileDescriptor socket,
456 @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException {
Nathan Harold80865392017-04-04 19:37:48 -0700457 // We dup() the FileDescriptor here because if we don't, then the ParcelFileDescriptor()
Nathan Harold31676252018-01-16 12:08:43 -0800458 // constructor takes control and closes the user's FD when we exit the method.
Nathan Harold80865392017-04-04 19:37:48 -0700459 try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) {
Nathan Harold5a19b952018-01-05 19:25:13 -0800460 mService.applyTransportModeTransform(pfd, direction, transform.getResourceId());
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700461 } catch (ServiceSpecificException e) {
462 throw rethrowCheckedExceptionFromServiceSpecificException(e);
Nathan Harold80865392017-04-04 19:37:48 -0700463 } catch (RemoteException e) {
464 throw e.rethrowFromSystemServer();
465 }
Nathan Harold0072e192017-04-06 17:46:00 -0700466 }
467
468 /**
Jonathan Basseri2725a232017-04-21 15:53:51 -0700469 * Remove an IPsec transform from a stream socket.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800470 *
Nathan Harold0d483b72018-01-17 01:00:20 -0800471 * <p>Once removed, traffic on the socket will not be encrypted. Removing transforms from a
472 * socket allows the socket to be reused for communication in the clear.
Jonathan Basseri2725a232017-04-21 15:53:51 -0700473 *
474 * <p>If an {@code IpSecTransform} object applied to this socket was deallocated by calling
475 * {@link IpSecTransform#close()}, then communication on the socket will fail until this method
476 * is called.
477 *
478 * @param socket a socket that previously had a transform applied to it
Jonathan Basseri2725a232017-04-21 15:53:51 -0700479 * @throws IOException indicating that the transform could not be removed from the socket
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800480 */
Nathan Harold6303d9e2018-03-16 17:27:30 -0700481 public void removeTransportModeTransforms(@NonNull Socket socket) throws IOException {
Benedict Wong57ab3f62018-04-02 18:12:34 -0700482 // Ensure creation of FD. See b/77548890 for more details.
483 socket.getSoLinger();
484
Nathan Harold0d483b72018-01-17 01:00:20 -0800485 removeTransportModeTransforms(socket.getFileDescriptor$());
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800486 }
487
488 /**
Jonathan Basseri2725a232017-04-21 15:53:51 -0700489 * Remove an IPsec transform from a datagram socket.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800490 *
Nathan Harold0d483b72018-01-17 01:00:20 -0800491 * <p>Once removed, traffic on the socket will not be encrypted. Removing transforms from a
492 * socket allows the socket to be reused for communication in the clear.
Jonathan Basseri2725a232017-04-21 15:53:51 -0700493 *
494 * <p>If an {@code IpSecTransform} object applied to this socket was deallocated by calling
495 * {@link IpSecTransform#close()}, then communication on the socket will fail until this method
496 * is called.
497 *
498 * @param socket a socket that previously had a transform applied to it
Jonathan Basseri2725a232017-04-21 15:53:51 -0700499 * @throws IOException indicating that the transform could not be removed from the socket
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800500 */
Nathan Harold6303d9e2018-03-16 17:27:30 -0700501 public void removeTransportModeTransforms(@NonNull DatagramSocket socket) throws IOException {
Nathan Harold0d483b72018-01-17 01:00:20 -0800502 removeTransportModeTransforms(socket.getFileDescriptor$());
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800503 }
504
Nathan Harold0072e192017-04-06 17:46:00 -0700505 /**
Jonathan Basseri2725a232017-04-21 15:53:51 -0700506 * Remove an IPsec transform from a socket.
Nathan Harold0072e192017-04-06 17:46:00 -0700507 *
Nathan Harold0d483b72018-01-17 01:00:20 -0800508 * <p>Once removed, traffic on the socket will not be encrypted. Removing transforms from a
509 * socket allows the socket to be reused for communication in the clear.
Jonathan Basseri2725a232017-04-21 15:53:51 -0700510 *
511 * <p>If an {@code IpSecTransform} object applied to this socket was deallocated by calling
512 * {@link IpSecTransform#close()}, then communication on the socket will fail until this method
513 * is called.
514 *
515 * @param socket a socket that previously had a transform applied to it
Jonathan Basseri2725a232017-04-21 15:53:51 -0700516 * @throws IOException indicating that the transform could not be removed from the socket
Nathan Harold0072e192017-04-06 17:46:00 -0700517 */
Nathan Harold6303d9e2018-03-16 17:27:30 -0700518 public void removeTransportModeTransforms(@NonNull FileDescriptor socket) throws IOException {
Nathan Harold80865392017-04-04 19:37:48 -0700519 try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) {
Nathan Harold0d483b72018-01-17 01:00:20 -0800520 mService.removeTransportModeTransforms(pfd);
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700521 } catch (ServiceSpecificException e) {
522 throw rethrowCheckedExceptionFromServiceSpecificException(e);
Nathan Harold031acb82017-03-07 13:23:36 -0800523 } catch (RemoteException e) {
524 throw e.rethrowFromSystemServer();
525 }
526 }
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800527
528 /**
529 * Remove a Tunnel Mode IPsec Transform from a {@link Network}. This must be used as part of
530 * cleanup if a tunneled Network experiences a change in default route. The Network will drop
531 * all traffic that cannot be routed to the Tunnel's outbound interface. If that interface is
532 * lost, all traffic will drop.
533 *
Jonathan Basseri20e96c52017-11-16 10:58:01 -0800534 * <p>TODO: Update javadoc for tunnel mode APIs at the same time the APIs are re-worked.
535 *
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800536 * @param net a network that currently has transform applied to it.
537 * @param transform a Tunnel Mode IPsec Transform that has been previously applied to the given
538 * network
539 * @hide
540 */
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800541 public void removeTunnelModeTransform(Network net, IpSecTransform transform) {}
542
543 /**
Jonathan Basseri2725a232017-04-21 15:53:51 -0700544 * This class provides access to a UDP encapsulation Socket.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800545 *
Jonathan Basseri2725a232017-04-21 15:53:51 -0700546 * <p>{@code UdpEncapsulationSocket} wraps a system-provided datagram socket intended for IKEv2
547 * signalling and UDP encapsulated IPsec traffic. Instances can be obtained by calling {@link
548 * IpSecManager#openUdpEncapsulationSocket}. The provided socket cannot be re-bound by the
549 * caller. The caller should not close the {@code FileDescriptor} returned by {@link
Benedict Wonga386e372018-03-27 16:55:48 -0700550 * #getFileDescriptor}, but should use {@link #close} instead.
Jonathan Basseri2725a232017-04-21 15:53:51 -0700551 *
552 * <p>Allowing the user to close or unbind a UDP encapsulation socket could impact the traffic
553 * of the next user who binds to that port. To prevent this scenario, these sockets are held
554 * open by the system so that they may only be closed by calling {@link #close} or when the user
555 * process exits.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800556 */
557 public static final class UdpEncapsulationSocket implements AutoCloseable {
Nathan Harold80865392017-04-04 19:37:48 -0700558 private final ParcelFileDescriptor mPfd;
Nathan Haroldd2a1dad2017-03-01 18:55:06 -0800559 private final IIpSecService mService;
Nathan Harold5e854462017-12-13 18:51:35 -0800560 private int mResourceId = INVALID_RESOURCE_ID;
Nathan Harold80865392017-04-04 19:37:48 -0700561 private final int mPort;
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800562 private final CloseGuard mCloseGuard = CloseGuard.get();
563
Nathan Harold031acb82017-03-07 13:23:36 -0800564 private UdpEncapsulationSocket(@NonNull IIpSecService service, int port)
Nathan Harold80865392017-04-04 19:37:48 -0700565 throws ResourceUnavailableException, IOException {
Nathan Haroldd2a1dad2017-03-01 18:55:06 -0800566 mService = service;
Nathan Harold80865392017-04-04 19:37:48 -0700567 try {
568 IpSecUdpEncapResponse result =
569 mService.openUdpEncapsulationSocket(port, new Binder());
570 switch (result.status) {
571 case Status.OK:
572 break;
573 case Status.RESOURCE_UNAVAILABLE:
574 throw new ResourceUnavailableException(
575 "No more Sockets may be allocated by this requester.");
576 default:
577 throw new RuntimeException(
578 "Unknown status returned by IpSecService: " + result.status);
579 }
580 mResourceId = result.resourceId;
581 mPort = result.port;
582 mPfd = result.fileDescriptor;
583 } catch (RemoteException e) {
584 throw e.rethrowFromSystemServer();
585 }
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800586 mCloseGuard.open("constructor");
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800587 }
588
Benedict Wonga386e372018-03-27 16:55:48 -0700589 /** Get the encapsulation socket's file descriptor. */
590 public FileDescriptor getFileDescriptor() {
Nathan Harold80865392017-04-04 19:37:48 -0700591 if (mPfd == null) {
592 return null;
593 }
594 return mPfd.getFileDescriptor();
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800595 }
596
Jonathan Basseri2725a232017-04-21 15:53:51 -0700597 /** Get the bound port of the wrapped socket. */
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800598 public int getPort() {
Nathan Harold80865392017-04-04 19:37:48 -0700599 return mPort;
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800600 }
601
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800602 /**
Jonathan Basseri2725a232017-04-21 15:53:51 -0700603 * Close this socket.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800604 *
Jonathan Basseri2725a232017-04-21 15:53:51 -0700605 * <p>This closes the wrapped socket. Open encapsulation sockets count against a user's
606 * resource limits, and forgetting to close them eventually will result in {@link
607 * ResourceUnavailableException} being thrown.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800608 */
Jonathan Basseri2725a232017-04-21 15:53:51 -0700609 @Override
Nathan Harolda64b0192017-04-17 17:11:58 -0700610 public void close() throws IOException {
Nathan Harold80865392017-04-04 19:37:48 -0700611 try {
612 mService.closeUdpEncapsulationSocket(mResourceId);
Nathan Harold5e854462017-12-13 18:51:35 -0800613 mResourceId = INVALID_RESOURCE_ID;
Nathan Harold80865392017-04-04 19:37:48 -0700614 } catch (RemoteException e) {
615 throw e.rethrowFromSystemServer();
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700616 } catch (Exception e) {
617 // On close we swallow all random exceptions since failure to close is not
618 // actionable by the user.
619 Log.e(TAG, "Failed to close " + this + ", Exception=" + e);
620 } finally {
621 mResourceId = INVALID_RESOURCE_ID;
622 mCloseGuard.close();
Nathan Harold80865392017-04-04 19:37:48 -0700623 }
624
625 try {
626 mPfd.close();
627 } catch (IOException e) {
628 Log.e(TAG, "Failed to close UDP Encapsulation Socket with Port= " + mPort);
629 throw e;
630 }
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800631 }
632
Jonathan Basseri2725a232017-04-21 15:53:51 -0700633 /** Check that the socket was closed properly. */
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800634 @Override
635 protected void finalize() throws Throwable {
636 if (mCloseGuard != null) {
637 mCloseGuard.warnIfOpen();
638 }
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800639 close();
640 }
Nathan Harold80865392017-04-04 19:37:48 -0700641
642 /** @hide */
Chiachang Wanga0343312021-01-12 18:48:13 +0800643 @SystemApi(client = MODULE_LIBRARIES)
Nathan Harold19b99d92017-08-23 13:46:33 -0700644 public int getResourceId() {
Nathan Harold80865392017-04-04 19:37:48 -0700645 return mResourceId;
646 }
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700647
648 @Override
649 public String toString() {
650 return new StringBuilder()
651 .append("UdpEncapsulationSocket{port=")
652 .append(mPort)
653 .append(",resourceId=")
654 .append(mResourceId)
655 .append("}")
656 .toString();
657 }
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800658 };
659
660 /**
Jonathan Basseri2725a232017-04-21 15:53:51 -0700661 * Open a socket for UDP encapsulation and bind to the given port.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800662 *
Jonathan Basseri2725a232017-04-21 15:53:51 -0700663 * <p>See {@link UdpEncapsulationSocket} for the proper way to close the returned socket.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800664 *
Jonathan Basseri2725a232017-04-21 15:53:51 -0700665 * @param port a local UDP port
666 * @return a socket that is bound to the given port
667 * @throws IOException indicating that the socket could not be opened or bound
668 * @throws ResourceUnavailableException indicating that too many encapsulation sockets are open
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800669 */
670 // Returning a socket in this fashion that has been created and bound by the system
671 // is the only safe way to ensure that a socket is both accessible to the user and
672 // safely usable for Encapsulation without allowing a user to possibly unbind from/close
673 // the port, which could potentially impact the traffic of the next user who binds to that
674 // socket.
Nathan Harold6303d9e2018-03-16 17:27:30 -0700675 @NonNull
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800676 public UdpEncapsulationSocket openUdpEncapsulationSocket(int port)
677 throws IOException, ResourceUnavailableException {
Nathan Harold80865392017-04-04 19:37:48 -0700678 /*
679 * Most range checking is done in the service, but this version of the constructor expects
680 * a valid port number, and zero cannot be checked after being passed to the service.
681 */
682 if (port == 0) {
683 throw new IllegalArgumentException("Specified port must be a valid port number!");
684 }
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700685 try {
686 return new UdpEncapsulationSocket(mService, port);
687 } catch (ServiceSpecificException e) {
688 throw rethrowCheckedExceptionFromServiceSpecificException(e);
689 }
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800690 }
691
692 /**
Jonathan Basseri2725a232017-04-21 15:53:51 -0700693 * Open a socket for UDP encapsulation.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800694 *
Jonathan Basseri2725a232017-04-21 15:53:51 -0700695 * <p>See {@link UdpEncapsulationSocket} for the proper way to close the returned socket.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800696 *
Jonathan Basseri2725a232017-04-21 15:53:51 -0700697 * <p>The local port of the returned socket can be obtained by calling {@link
698 * UdpEncapsulationSocket#getPort()}.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800699 *
Jonathan Basseri2725a232017-04-21 15:53:51 -0700700 * @return a socket that is bound to a local port
701 * @throws IOException indicating that the socket could not be opened or bound
702 * @throws ResourceUnavailableException indicating that too many encapsulation sockets are open
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800703 */
704 // Returning a socket in this fashion that has been created and bound by the system
705 // is the only safe way to ensure that a socket is both accessible to the user and
706 // safely usable for Encapsulation without allowing a user to possibly unbind from/close
707 // the port, which could potentially impact the traffic of the next user who binds to that
708 // socket.
Nathan Harold6303d9e2018-03-16 17:27:30 -0700709 @NonNull
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800710 public UdpEncapsulationSocket openUdpEncapsulationSocket()
711 throws IOException, ResourceUnavailableException {
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700712 try {
713 return new UdpEncapsulationSocket(mService, 0);
714 } catch (ServiceSpecificException e) {
715 throw rethrowCheckedExceptionFromServiceSpecificException(e);
716 }
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800717 }
718
719 /**
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000720 * This class represents an IpSecTunnelInterface
Nathan Harold67e76732018-01-17 16:09:24 -0800721 *
722 * <p>IpSecTunnelInterface objects track tunnel interfaces that serve as
723 * local endpoints for IPsec tunnels.
724 *
725 * <p>Creating an IpSecTunnelInterface creates a device to which IpSecTransforms may be
726 * applied to provide IPsec security to packets sent through the tunnel. While a tunnel
727 * cannot be used in standalone mode within Android, the higher layers may use the tunnel
728 * to create Network objects which are accessible to the Android system.
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000729 * @hide
Nathan Harold67e76732018-01-17 16:09:24 -0800730 */
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000731 @SystemApi
Nathan Harold67e76732018-01-17 16:09:24 -0800732 public static final class IpSecTunnelInterface implements AutoCloseable {
Nathan Harold65ef8432018-03-15 18:06:06 -0700733 private final String mOpPackageName;
Nathan Harold67e76732018-01-17 16:09:24 -0800734 private final IIpSecService mService;
735 private final InetAddress mRemoteAddress;
736 private final InetAddress mLocalAddress;
737 private final Network mUnderlyingNetwork;
738 private final CloseGuard mCloseGuard = CloseGuard.get();
739 private String mInterfaceName;
740 private int mResourceId = INVALID_RESOURCE_ID;
741
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000742 /** Get the underlying SPI held by this object. */
Nathan Harold6303d9e2018-03-16 17:27:30 -0700743 @NonNull
Nathan Harold67e76732018-01-17 16:09:24 -0800744 public String getInterfaceName() {
745 return mInterfaceName;
746 }
747
748 /**
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000749 * Add an address to the IpSecTunnelInterface
Nathan Harold67e76732018-01-17 16:09:24 -0800750 *
751 * <p>Add an address which may be used as the local inner address for
752 * tunneled traffic.
753 *
754 * @param address the local address for traffic inside the tunnel
Benedict Wongd39837f2018-04-03 20:30:54 -0700755 * @param prefixLen length of the InetAddress prefix
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000756 * @hide
Nathan Harold67e76732018-01-17 16:09:24 -0800757 */
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000758 @SystemApi
Benedict Wonge9763752018-11-08 19:45:34 -0800759 @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
Nathan Harold00e77242018-03-21 15:32:42 -0700760 @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
Benedict Wongd39837f2018-04-03 20:30:54 -0700761 public void addAddress(@NonNull InetAddress address, int prefixLen) throws IOException {
Benedict Wong97c3c942018-03-01 18:53:07 -0800762 try {
Nathan Harold65ef8432018-03-15 18:06:06 -0700763 mService.addAddressToTunnelInterface(
Benedict Wongd39837f2018-04-03 20:30:54 -0700764 mResourceId, new LinkAddress(address, prefixLen), mOpPackageName);
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700765 } catch (ServiceSpecificException e) {
766 throw rethrowCheckedExceptionFromServiceSpecificException(e);
Benedict Wong97c3c942018-03-01 18:53:07 -0800767 } catch (RemoteException e) {
768 throw e.rethrowFromSystemServer();
769 }
Nathan Harold67e76732018-01-17 16:09:24 -0800770 }
771
772 /**
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000773 * Remove an address from the IpSecTunnelInterface
Nathan Harold67e76732018-01-17 16:09:24 -0800774 *
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000775 * <p>Remove an address which was previously added to the IpSecTunnelInterface
Nathan Harold67e76732018-01-17 16:09:24 -0800776 *
777 * @param address to be removed
Benedict Wongd39837f2018-04-03 20:30:54 -0700778 * @param prefixLen length of the InetAddress prefix
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000779 * @hide
Nathan Harold67e76732018-01-17 16:09:24 -0800780 */
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000781 @SystemApi
Benedict Wonge9763752018-11-08 19:45:34 -0800782 @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
Nathan Harold00e77242018-03-21 15:32:42 -0700783 @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
Benedict Wongd39837f2018-04-03 20:30:54 -0700784 public void removeAddress(@NonNull InetAddress address, int prefixLen) throws IOException {
Benedict Wong97c3c942018-03-01 18:53:07 -0800785 try {
Nathan Harold65ef8432018-03-15 18:06:06 -0700786 mService.removeAddressFromTunnelInterface(
Benedict Wongd39837f2018-04-03 20:30:54 -0700787 mResourceId, new LinkAddress(address, prefixLen), mOpPackageName);
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700788 } catch (ServiceSpecificException e) {
789 throw rethrowCheckedExceptionFromServiceSpecificException(e);
Benedict Wong97c3c942018-03-01 18:53:07 -0800790 } catch (RemoteException e) {
791 throw e.rethrowFromSystemServer();
792 }
Nathan Harold67e76732018-01-17 16:09:24 -0800793 }
794
Yan Yana2f3b492020-09-29 23:38:00 -0700795 /**
796 * Update the underlying network for this IpSecTunnelInterface.
797 *
798 * <p>This new underlying network will be used for all transforms applied AFTER this call is
799 * complete. Before new {@link IpSecTransform}(s) with matching addresses are applied to
800 * this tunnel interface, traffic will still use the old SA, and be routed on the old
801 * underlying network.
802 *
803 * <p>To migrate IPsec tunnel mode traffic, a caller should:
804 *
805 * <ol>
806 * <li>Update the IpSecTunnelInterface’s underlying network.
807 * <li>Apply {@link IpSecTransform}(s) with matching addresses to this
808 * IpSecTunnelInterface.
809 * </ol>
810 *
811 * @param underlyingNetwork the new {@link Network} that will carry traffic for this tunnel.
812 * This network MUST never be the network exposing this IpSecTunnelInterface, otherwise
Yan Yancf4d2eb2021-02-16 11:48:55 -0800813 * this method will throw an {@link IllegalArgumentException}. If the
814 * IpSecTunnelInterface is later added to this network, all outbound traffic will be
815 * blackholed.
Yan Yana2f3b492020-09-29 23:38:00 -0700816 */
817 // TODO: b/169171001 Update the documentation when transform migration is supported.
818 // The purpose of making updating network and applying transforms separate is to leave open
819 // the possibility to support lossless migration procedures. To do that, Android platform
820 // will need to support multiple inbound tunnel mode transforms, just like it can support
821 // multiple transport mode transforms.
822 @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
823 @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
824 public void setUnderlyingNetwork(@NonNull Network underlyingNetwork) throws IOException {
825 try {
826 mService.setNetworkForTunnelInterface(
827 mResourceId, underlyingNetwork, mOpPackageName);
828 } catch (RemoteException e) {
829 throw e.rethrowFromSystemServer();
830 }
831 }
832
Nathan Harold65ef8432018-03-15 18:06:06 -0700833 private IpSecTunnelInterface(@NonNull Context ctx, @NonNull IIpSecService service,
Nathan Harold67e76732018-01-17 16:09:24 -0800834 @NonNull InetAddress localAddress, @NonNull InetAddress remoteAddress,
835 @NonNull Network underlyingNetwork)
836 throws ResourceUnavailableException, IOException {
Nathan Harold65ef8432018-03-15 18:06:06 -0700837 mOpPackageName = ctx.getOpPackageName();
Nathan Harold67e76732018-01-17 16:09:24 -0800838 mService = service;
839 mLocalAddress = localAddress;
840 mRemoteAddress = remoteAddress;
841 mUnderlyingNetwork = underlyingNetwork;
Benedict Wong8bc90732018-01-18 18:31:45 -0800842
843 try {
844 IpSecTunnelInterfaceResponse result =
845 mService.createTunnelInterface(
846 localAddress.getHostAddress(),
847 remoteAddress.getHostAddress(),
848 underlyingNetwork,
Nathan Harold65ef8432018-03-15 18:06:06 -0700849 new Binder(),
850 mOpPackageName);
Benedict Wong8bc90732018-01-18 18:31:45 -0800851 switch (result.status) {
852 case Status.OK:
853 break;
854 case Status.RESOURCE_UNAVAILABLE:
855 throw new ResourceUnavailableException(
856 "No more tunnel interfaces may be allocated by this requester.");
857 default:
858 throw new RuntimeException(
859 "Unknown status returned by IpSecService: " + result.status);
860 }
861 mResourceId = result.resourceId;
862 mInterfaceName = result.interfaceName;
863 } catch (RemoteException e) {
864 throw e.rethrowFromSystemServer();
865 }
866 mCloseGuard.open("constructor");
Nathan Harold67e76732018-01-17 16:09:24 -0800867 }
868
869 /**
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000870 * Delete an IpSecTunnelInterface
Nathan Harold67e76732018-01-17 16:09:24 -0800871 *
872 * <p>Calling close will deallocate the IpSecTunnelInterface and all of its system
873 * resources. Any packets bound for this interface either inbound or outbound will
874 * all be lost.
875 */
876 @Override
877 public void close() {
Benedict Wong8bc90732018-01-18 18:31:45 -0800878 try {
Nathan Harold65ef8432018-03-15 18:06:06 -0700879 mService.deleteTunnelInterface(mResourceId, mOpPackageName);
Benedict Wong8bc90732018-01-18 18:31:45 -0800880 } catch (RemoteException e) {
881 throw e.rethrowFromSystemServer();
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700882 } catch (Exception e) {
883 // On close we swallow all random exceptions since failure to close is not
884 // actionable by the user.
885 Log.e(TAG, "Failed to close " + this + ", Exception=" + e);
886 } finally {
887 mResourceId = INVALID_RESOURCE_ID;
888 mCloseGuard.close();
Benedict Wong8bc90732018-01-18 18:31:45 -0800889 }
Nathan Harold67e76732018-01-17 16:09:24 -0800890 }
891
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000892 /** Check that the Interface was closed properly. */
Nathan Harold67e76732018-01-17 16:09:24 -0800893 @Override
894 protected void finalize() throws Throwable {
895 if (mCloseGuard != null) {
896 mCloseGuard.warnIfOpen();
897 }
898 close();
899 }
Benedict Wong8bc90732018-01-18 18:31:45 -0800900
901 /** @hide */
902 @VisibleForTesting
903 public int getResourceId() {
904 return mResourceId;
905 }
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700906
Aurimas Liutikas3a78d9d2019-08-28 13:01:05 -0700907 @NonNull
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700908 @Override
909 public String toString() {
910 return new StringBuilder()
911 .append("IpSecTunnelInterface{ifname=")
912 .append(mInterfaceName)
913 .append(",resourceId=")
914 .append(mResourceId)
915 .append("}")
916 .toString();
917 }
Nathan Harold67e76732018-01-17 16:09:24 -0800918 }
919
920 /**
921 * Create a new IpSecTunnelInterface as a local endpoint for tunneled IPsec traffic.
922 *
Benedict Wong8bc90732018-01-18 18:31:45 -0800923 * <p>An application that creates tunnels is responsible for cleaning up the tunnel when the
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000924 * underlying network goes away, and the onLost() callback is received.
Benedict Wong8bc90732018-01-18 18:31:45 -0800925 *
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000926 * @param localAddress The local addres of the tunnel
927 * @param remoteAddress The local addres of the tunnel
928 * @param underlyingNetwork the {@link Network} that will carry traffic for this tunnel.
929 * This network should almost certainly be a network such as WiFi with an L2 address.
930 * @return a new {@link IpSecManager#IpSecTunnelInterface} with the specified properties
931 * @throws IOException indicating that the socket could not be opened or bound
932 * @throws ResourceUnavailableException indicating that too many encapsulation sockets are open
Yan Yan160aac32020-12-03 17:08:29 -0800933 * @hide
Yan Yan160aac32020-12-03 17:08:29 -0800934 */
Nathan Harold3a287d52018-04-25 12:01:34 -0700935 @SystemApi
Nathan Harold6303d9e2018-03-16 17:27:30 -0700936 @NonNull
Benedict Wonge9763752018-11-08 19:45:34 -0800937 @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
Nathan Harold00e77242018-03-21 15:32:42 -0700938 @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
Nathan Harold67e76732018-01-17 16:09:24 -0800939 public IpSecTunnelInterface createIpSecTunnelInterface(@NonNull InetAddress localAddress,
940 @NonNull InetAddress remoteAddress, @NonNull Network underlyingNetwork)
941 throws ResourceUnavailableException, IOException {
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700942 try {
943 return new IpSecTunnelInterface(
944 mContext, mService, localAddress, remoteAddress, underlyingNetwork);
945 } catch (ServiceSpecificException e) {
946 throw rethrowCheckedExceptionFromServiceSpecificException(e);
947 }
Nathan Harold67e76732018-01-17 16:09:24 -0800948 }
949
950 /**
Nathan Harolde3536f02018-03-06 13:22:22 -0800951 * Apply an active Tunnel Mode IPsec Transform to a {@link IpSecTunnelInterface}, which will
952 * tunnel all traffic for the given direction through the underlying network's interface with
953 * IPsec (applies an outer IP header and IPsec Header to all traffic, and expects an additional
954 * IP header and IPsec Header on all inbound traffic).
955 * <p>Applications should probably not use this API directly.
956 *
Nathan Harold67e76732018-01-17 16:09:24 -0800957 *
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000958 * @param tunnel The {@link IpSecManager#IpSecTunnelInterface} that will use the supplied
Nathan Harold67e76732018-01-17 16:09:24 -0800959 * transform.
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000960 * @param direction the direction, {@link DIRECTION_OUT} or {@link #DIRECTION_IN} in which
Nathan Harold67e76732018-01-17 16:09:24 -0800961 * the transform will be used.
962 * @param transform an {@link IpSecTransform} created in tunnel mode
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000963 * @throws IOException indicating that the transform could not be applied due to a lower
964 * layer failure.
965 * @hide
Nathan Harold67e76732018-01-17 16:09:24 -0800966 */
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000967 @SystemApi
Benedict Wonge9763752018-11-08 19:45:34 -0800968 @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
Nathan Harold00e77242018-03-21 15:32:42 -0700969 @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
Nathan Harold6303d9e2018-03-16 17:27:30 -0700970 public void applyTunnelModeTransform(@NonNull IpSecTunnelInterface tunnel,
971 @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException {
Benedict Wong8bc90732018-01-18 18:31:45 -0800972 try {
973 mService.applyTunnelModeTransform(
Nathan Harold65ef8432018-03-15 18:06:06 -0700974 tunnel.getResourceId(), direction,
975 transform.getResourceId(), mContext.getOpPackageName());
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700976 } catch (ServiceSpecificException e) {
977 throw rethrowCheckedExceptionFromServiceSpecificException(e);
Benedict Wong8bc90732018-01-18 18:31:45 -0800978 } catch (RemoteException e) {
979 throw e.rethrowFromSystemServer();
980 }
Nathan Harold67e76732018-01-17 16:09:24 -0800981 }
Nathan Harolde3536f02018-03-06 13:22:22 -0800982
Nathan Harold67e76732018-01-17 16:09:24 -0800983 /**
Jonathan Basseri2725a232017-04-21 15:53:51 -0700984 * Construct an instance of IpSecManager within an application context.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800985 *
986 * @param context the application context for this manager
987 * @hide
988 */
Nathan Harold65ef8432018-03-15 18:06:06 -0700989 public IpSecManager(Context ctx, IIpSecService service) {
990 mContext = ctx;
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800991 mService = checkNotNull(service, "missing service");
992 }
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700993
994 private static void maybeHandleServiceSpecificException(ServiceSpecificException sse) {
995 // OsConstants are late binding, so switch statements can't be used.
996 if (sse.errorCode == OsConstants.EINVAL) {
997 throw new IllegalArgumentException(sse);
998 } else if (sse.errorCode == OsConstants.EAGAIN) {
999 throw new IllegalStateException(sse);
Benedict Wongc45974b2018-07-16 14:56:20 -07001000 } else if (sse.errorCode == OsConstants.EOPNOTSUPP
1001 || sse.errorCode == OsConstants.EPROTONOSUPPORT) {
Nathan Haroldbeed0b62018-04-03 16:13:19 -07001002 throw new UnsupportedOperationException(sse);
1003 }
1004 }
1005
1006 /**
1007 * Convert an Errno SSE to the correct Unchecked exception type.
1008 *
1009 * This method never actually returns.
1010 */
1011 // package
1012 static RuntimeException
1013 rethrowUncheckedExceptionFromServiceSpecificException(ServiceSpecificException sse) {
1014 maybeHandleServiceSpecificException(sse);
1015 throw new RuntimeException(sse);
1016 }
1017
1018 /**
1019 * Convert an Errno SSE to the correct Checked or Unchecked exception type.
1020 *
1021 * This method may throw IOException, or it may throw an unchecked exception; it will never
1022 * actually return.
1023 */
1024 // package
1025 static IOException rethrowCheckedExceptionFromServiceSpecificException(
1026 ServiceSpecificException sse) throws IOException {
1027 // First see if this is an unchecked exception of a type we know.
1028 // If so, then we prefer the unchecked (specific) type of exception.
1029 maybeHandleServiceSpecificException(sse);
1030 // If not, then all we can do is provide the SSE in the form of an IOException.
1031 throw new ErrnoException(
1032 "IpSec encountered errno=" + sse.errorCode, sse.errorCode).rethrowAsIOException();
1033 }
Nathan Haroldb1f605f2017-01-12 18:38:57 -08001034}