blob: 9cceac2af34bd86ca60a35492552d5ba44edcecb [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
Aaron Huangca9c1df2021-12-16 00:11:15 +080020import android.annotation.IntDef;
Nathan Harold031acb82017-03-07 13:23:36 -080021import android.annotation.NonNull;
Benedict Wonge9763752018-11-08 19:45:34 -080022import android.annotation.RequiresFeature;
Nathan Harold025aae12018-02-02 18:34:25 -080023import android.annotation.RequiresPermission;
Nathan Harold3a287d52018-04-25 12:01:34 -070024import android.annotation.SystemApi;
Jeff Sharkeyad1cebe2017-06-02 17:36:26 -060025import android.annotation.SystemService;
Jonathan Basseri2725a232017-04-21 15:53:51 -070026import android.annotation.TestApi;
Jeff Sharkeyad1cebe2017-06-02 17:36:26 -060027import android.content.Context;
Benedict Wonge9763752018-11-08 19:45:34 -080028import android.content.pm.PackageManager;
Nathan Harold031acb82017-03-07 13:23:36 -080029import android.os.Binder;
Aaron Huang80a73fd2021-12-28 02:33:53 +080030import android.os.IBinder;
Nathan Haroldb1f605f2017-01-12 18:38:57 -080031import android.os.ParcelFileDescriptor;
Nathan Harold031acb82017-03-07 13:23:36 -080032import android.os.RemoteException;
Nathan Haroldbeed0b62018-04-03 16:13:19 -070033import android.os.ServiceSpecificException;
34import android.system.ErrnoException;
35import android.system.OsConstants;
Nathan Haroldb1f605f2017-01-12 18:38:57 -080036import android.util.AndroidException;
Nathan Harold80865392017-04-04 19:37:48 -070037import android.util.Log;
Nathan Harold81f54632017-09-11 19:50:19 -070038
Nathan Harold19b99d92017-08-23 13:46:33 -070039import com.android.internal.annotations.VisibleForTesting;
40
Nathan Haroldb1f605f2017-01-12 18:38:57 -080041import dalvik.system.CloseGuard;
Nathan Harold81f54632017-09-11 19:50:19 -070042
Nathan Haroldb1f605f2017-01-12 18:38:57 -080043import java.io.FileDescriptor;
44import java.io.IOException;
Aaron Huangca9c1df2021-12-16 00:11:15 +080045import java.lang.annotation.Retention;
46import java.lang.annotation.RetentionPolicy;
Nathan Haroldb1f605f2017-01-12 18:38:57 -080047import java.net.DatagramSocket;
48import java.net.InetAddress;
49import java.net.Socket;
Aaron Huang49eef6f2021-12-22 16:35:13 +080050import java.util.Objects;
Nathan Haroldb1f605f2017-01-12 18:38:57 -080051
52/**
Jonathan Basseri2725a232017-04-21 15:53:51 -070053 * This class contains methods for managing IPsec sessions. Once configured, the kernel will apply
54 * confidentiality (encryption) and integrity (authentication) to IP traffic.
Nathan Haroldb1f605f2017-01-12 18:38:57 -080055 *
Jonathan Basseri2725a232017-04-21 15:53:51 -070056 * <p>Note that not all aspects of IPsec are permitted by this API. Applications may create
57 * transport mode security associations and apply them to individual sockets. Applications looking
Benedict Wongc85b7b02019-11-12 22:31:51 -080058 * to create an IPsec VPN should use {@link VpnManager} and {@link Ikev2VpnProfile}.
Jonathan Basseri2725a232017-04-21 15:53:51 -070059 *
60 * @see <a href="https://tools.ietf.org/html/rfc4301">RFC 4301, Security Architecture for the
Jonathan Basseri20e96c52017-11-16 10:58:01 -080061 * Internet Protocol</a>
Nathan Haroldb1f605f2017-01-12 18:38:57 -080062 */
Jeff Sharkeyad1cebe2017-06-02 17:36:26 -060063@SystemService(Context.IPSEC_SERVICE)
Yan Yan98a3a032022-02-02 16:39:45 -080064public class IpSecManager {
Nathan Haroldb1f605f2017-01-12 18:38:57 -080065 private static final String TAG = "IpSecManager";
66
67 /**
Nathan Harolde3536f02018-03-06 13:22:22 -080068 * Used when applying a transform to direct traffic through an {@link IpSecTransform}
69 * towards the host.
70 *
71 * <p>See {@link #applyTransportModeTransform(Socket, int, IpSecTransform)}.
Nathan Harold5a19b952018-01-05 19:25:13 -080072 */
73 public static final int DIRECTION_IN = 0;
74
75 /**
Nathan Harolde3536f02018-03-06 13:22:22 -080076 * Used when applying a transform to direct traffic through an {@link IpSecTransform}
77 * away from the host.
78 *
79 * <p>See {@link #applyTransportModeTransform(Socket, int, IpSecTransform)}.
Nathan Harold5a19b952018-01-05 19:25:13 -080080 */
81 public static final int DIRECTION_OUT = 1;
82
Nathan Harold5a19b952018-01-05 19:25:13 -080083 /**
Benedict Wong908d34e2021-04-15 11:59:16 -070084 * Used when applying a transform to direct traffic through an {@link IpSecTransform} for
85 * forwarding between interfaces.
86 *
87 * <p>See {@link #applyTransportModeTransform(Socket, int, IpSecTransform)}.
88 *
89 * @hide
90 */
Aaron Huang4989e952021-12-15 23:27:18 +080091 @SystemApi(client = MODULE_LIBRARIES)
Benedict Wong908d34e2021-04-15 11:59:16 -070092 public static final int DIRECTION_FWD = 2;
93
Aaron Huangca9c1df2021-12-16 00:11:15 +080094 /** @hide */
95 @IntDef(value = {DIRECTION_IN, DIRECTION_OUT})
96 @Retention(RetentionPolicy.SOURCE)
97 public @interface PolicyDirection {}
98
Benedict Wong908d34e2021-04-15 11:59:16 -070099 /**
Jonathan Basseri2725a232017-04-21 15:53:51 -0700100 * The Security Parameter Index (SPI) 0 indicates an unknown or invalid index.
Nathan Harold031acb82017-03-07 13:23:36 -0800101 *
102 * <p>No IPsec packet may contain an SPI of 0.
Jonathan Basseri2725a232017-04-21 15:53:51 -0700103 *
104 * @hide
Nathan Harold031acb82017-03-07 13:23:36 -0800105 */
Jonathan Basseri20e96c52017-11-16 10:58:01 -0800106 @TestApi public static final int INVALID_SECURITY_PARAMETER_INDEX = 0;
Nathan Harold031acb82017-03-07 13:23:36 -0800107
108 /** @hide */
109 public interface Status {
Aaron Huangfbae3082021-12-06 15:18:42 +0800110 int OK = 0;
111 int RESOURCE_UNAVAILABLE = 1;
112 int SPI_UNAVAILABLE = 2;
Nathan Harold031acb82017-03-07 13:23:36 -0800113 }
114
115 /** @hide */
Nathan Harold5e854462017-12-13 18:51:35 -0800116 public static final int INVALID_RESOURCE_ID = -1;
Nathan Harold031acb82017-03-07 13:23:36 -0800117
118 /**
Jonathan Basseri2725a232017-04-21 15:53:51 -0700119 * Thrown to indicate that a requested SPI is in use.
120 *
121 * <p>The combination of remote {@code InetAddress} and SPI must be unique across all apps on
122 * one device. If this error is encountered, a new SPI is required before a transform may be
123 * created. This error can be avoided by calling {@link
Jonathan Basseri20e96c52017-11-16 10:58:01 -0800124 * IpSecManager#allocateSecurityParameterIndex}.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800125 */
126 public static final class SpiUnavailableException extends AndroidException {
127 private final int mSpi;
128
129 /**
130 * Construct an exception indicating that a transform with the given SPI is already in use
131 * or otherwise unavailable.
132 *
Jonathan Basseri2725a232017-04-21 15:53:51 -0700133 * @param msg description indicating the colliding SPI
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800134 * @param spi the SPI that could not be used due to a collision
135 */
136 SpiUnavailableException(String msg, int spi) {
Jonathan Basseri2725a232017-04-21 15:53:51 -0700137 super(msg + " (spi: " + spi + ")");
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800138 mSpi = spi;
139 }
140
Jonathan Basseri2725a232017-04-21 15:53:51 -0700141 /** Get the SPI that caused a collision. */
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800142 public int getSpi() {
143 return mSpi;
144 }
145 }
146
147 /**
Jonathan Basseri2725a232017-04-21 15:53:51 -0700148 * Thrown to indicate that an IPsec resource is unavailable.
149 *
150 * <p>This could apply to resources such as sockets, {@link SecurityParameterIndex}, {@link
151 * IpSecTransform}, or other system resources. If this exception is thrown, users should release
152 * allocated objects of the type requested.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800153 */
154 public static final class ResourceUnavailableException extends AndroidException {
155
156 ResourceUnavailableException(String msg) {
157 super(msg);
158 }
159 }
160
Nathan Harold65ef8432018-03-15 18:06:06 -0700161 private final Context mContext;
Nathan Haroldd2a1dad2017-03-01 18:55:06 -0800162 private final IIpSecService mService;
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800163
Jonathan Basseri2725a232017-04-21 15:53:51 -0700164 /**
165 * This class represents a reserved SPI.
166 *
167 * <p>Objects of this type are used to track reserved security parameter indices. They can be
Jonathan Basseri20e96c52017-11-16 10:58:01 -0800168 * obtained by calling {@link IpSecManager#allocateSecurityParameterIndex} and must be released
Jonathan Basseri2725a232017-04-21 15:53:51 -0700169 * by calling {@link #close()} when they are no longer needed.
170 */
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800171 public static final class SecurityParameterIndex implements AutoCloseable {
Nathan Haroldd2a1dad2017-03-01 18:55:06 -0800172 private final IIpSecService mService;
Nathan Harold5a19b952018-01-05 19:25:13 -0800173 private final InetAddress mDestinationAddress;
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800174 private final CloseGuard mCloseGuard = CloseGuard.get();
Nathan Harold031acb82017-03-07 13:23:36 -0800175 private int mSpi = INVALID_SECURITY_PARAMETER_INDEX;
Nathan Harold5e854462017-12-13 18:51:35 -0800176 private int mResourceId = INVALID_RESOURCE_ID;
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800177
Jonathan Basseri2725a232017-04-21 15:53:51 -0700178 /** Get the underlying SPI held by this object. */
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800179 public int getSpi() {
180 return mSpi;
181 }
182
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800183 /**
184 * Release an SPI that was previously reserved.
185 *
Nathan Harold909d66e2017-03-29 10:47:59 -0700186 * <p>Release an SPI for use by other users in the system. If a SecurityParameterIndex is
187 * applied to an IpSecTransform, it will become unusable for future transforms but should
188 * still be closed to ensure system resources are released.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800189 */
190 @Override
191 public void close() {
Nathan Harold80865392017-04-04 19:37:48 -0700192 try {
193 mService.releaseSecurityParameterIndex(mResourceId);
194 } catch (RemoteException e) {
195 throw e.rethrowFromSystemServer();
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700196 } catch (Exception e) {
197 // On close we swallow all random exceptions since failure to close is not
198 // actionable by the user.
199 Log.e(TAG, "Failed to close " + this + ", Exception=" + e);
200 } finally {
201 mResourceId = INVALID_RESOURCE_ID;
202 mCloseGuard.close();
Nathan Harold80865392017-04-04 19:37:48 -0700203 }
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800204 }
205
Jonathan Basseri2725a232017-04-21 15:53:51 -0700206 /** Check that the SPI was closed properly. */
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800207 @Override
Nathan Harold2a30daf2017-11-07 17:17:45 -0800208 protected void finalize() throws Throwable {
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800209 if (mCloseGuard != null) {
210 mCloseGuard.warnIfOpen();
211 }
212
213 close();
214 }
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800215
Nathan Harold031acb82017-03-07 13:23:36 -0800216 private SecurityParameterIndex(
Nathan Harold5a19b952018-01-05 19:25:13 -0800217 @NonNull IIpSecService service, InetAddress destinationAddress, int spi)
Nathan Harold031acb82017-03-07 13:23:36 -0800218 throws ResourceUnavailableException, SpiUnavailableException {
219 mService = service;
Nathan Harold5a19b952018-01-05 19:25:13 -0800220 mDestinationAddress = destinationAddress;
Nathan Harold031acb82017-03-07 13:23:36 -0800221 try {
Nathan Harold80865392017-04-04 19:37:48 -0700222 IpSecSpiResponse result =
Jonathan Basseri20e96c52017-11-16 10:58:01 -0800223 mService.allocateSecurityParameterIndex(
Nathan Harold5a19b952018-01-05 19:25:13 -0800224 destinationAddress.getHostAddress(), spi, new Binder());
Nathan Harold031acb82017-03-07 13:23:36 -0800225
226 if (result == null) {
227 throw new NullPointerException("Received null response from IpSecService");
228 }
229
Nathan Harold80865392017-04-04 19:37:48 -0700230 int status = result.status;
Nathan Harold031acb82017-03-07 13:23:36 -0800231 switch (status) {
232 case Status.OK:
233 break;
234 case Status.RESOURCE_UNAVAILABLE:
235 throw new ResourceUnavailableException(
236 "No more SPIs may be allocated by this requester.");
237 case Status.SPI_UNAVAILABLE:
238 throw new SpiUnavailableException("Requested SPI is unavailable", spi);
239 default:
240 throw new RuntimeException(
241 "Unknown status returned by IpSecService: " + status);
242 }
Nathan Harold80865392017-04-04 19:37:48 -0700243 mSpi = result.spi;
244 mResourceId = result.resourceId;
Nathan Harold031acb82017-03-07 13:23:36 -0800245
246 if (mSpi == INVALID_SECURITY_PARAMETER_INDEX) {
247 throw new RuntimeException("Invalid SPI returned by IpSecService: " + status);
248 }
249
250 if (mResourceId == INVALID_RESOURCE_ID) {
251 throw new RuntimeException(
252 "Invalid Resource ID returned by IpSecService: " + status);
253 }
Nathan Harold031acb82017-03-07 13:23:36 -0800254 } catch (RemoteException e) {
255 throw e.rethrowFromSystemServer();
256 }
257 mCloseGuard.open("open");
258 }
Nathan Harold80865392017-04-04 19:37:48 -0700259
260 /** @hide */
Nathan Harold19b99d92017-08-23 13:46:33 -0700261 @VisibleForTesting
262 public int getResourceId() {
Nathan Harold80865392017-04-04 19:37:48 -0700263 return mResourceId;
264 }
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700265
266 @Override
267 public String toString() {
268 return new StringBuilder()
269 .append("SecurityParameterIndex{spi=")
270 .append(mSpi)
271 .append(",resourceId=")
272 .append(mResourceId)
273 .append("}")
274 .toString();
275 }
Nathan Harold031acb82017-03-07 13:23:36 -0800276 }
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800277
278 /**
Nathan Harold5a19b952018-01-05 19:25:13 -0800279 * Reserve a random SPI for traffic bound to or from the specified destination address.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800280 *
281 * <p>If successful, this SPI is guaranteed available until released by a call to {@link
282 * SecurityParameterIndex#close()}.
283 *
Nathan Harold5a19b952018-01-05 19:25:13 -0800284 * @param destinationAddress the destination address for traffic bearing the requested SPI.
285 * For inbound traffic, the destination should be an address currently assigned on-device.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800286 * @return the reserved SecurityParameterIndex
Aaron Huangfbae3082021-12-06 15:18:42 +0800287 * @throws ResourceUnavailableException indicating that too many SPIs are
Nathan Harold5a19b952018-01-05 19:25:13 -0800288 * currently allocated for this user
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800289 */
Nathan Harold6303d9e2018-03-16 17:27:30 -0700290 @NonNull
291 public SecurityParameterIndex allocateSecurityParameterIndex(
292 @NonNull InetAddress destinationAddress) throws ResourceUnavailableException {
Nathan Harold05406792017-04-06 18:16:28 -0700293 try {
294 return new SecurityParameterIndex(
295 mService,
Nathan Harold5a19b952018-01-05 19:25:13 -0800296 destinationAddress,
Nathan Harold05406792017-04-06 18:16:28 -0700297 IpSecManager.INVALID_SECURITY_PARAMETER_INDEX);
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700298 } catch (ServiceSpecificException e) {
299 throw rethrowUncheckedExceptionFromServiceSpecificException(e);
Nathan Harold05406792017-04-06 18:16:28 -0700300 } catch (SpiUnavailableException unlikely) {
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700301 // Because this function allocates a totally random SPI, it really shouldn't ever
302 // fail to allocate an SPI; we simply need this because the exception is checked.
Nathan Harold05406792017-04-06 18:16:28 -0700303 throw new ResourceUnavailableException("No SPIs available");
304 }
305 }
306
307 /**
Nathan Harold5a19b952018-01-05 19:25:13 -0800308 * Reserve the requested SPI for traffic bound to or from the specified destination address.
Nathan Harold05406792017-04-06 18:16:28 -0700309 *
310 * <p>If successful, this SPI is guaranteed available until released by a call to {@link
311 * SecurityParameterIndex#close()}.
312 *
Nathan Harold5a19b952018-01-05 19:25:13 -0800313 * @param destinationAddress the destination address for traffic bearing the requested SPI.
314 * For inbound traffic, the destination should be an address currently assigned on-device.
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700315 * @param requestedSpi the requested SPI. The range 1-255 is reserved and may not be used. See
316 * RFC 4303 Section 2.1.
Nathan Harold05406792017-04-06 18:16:28 -0700317 * @return the reserved SecurityParameterIndex
Aaron Huangfbae3082021-12-06 15:18:42 +0800318 * @throws ResourceUnavailableException indicating that too many SPIs are
Nathan Harold5a19b952018-01-05 19:25:13 -0800319 * currently allocated for this user
Aaron Huangfbae3082021-12-06 15:18:42 +0800320 * @throws SpiUnavailableException indicating that the requested SPI could not be
Nathan Harold5a19b952018-01-05 19:25:13 -0800321 * reserved
Nathan Harold05406792017-04-06 18:16:28 -0700322 */
Nathan Harold6303d9e2018-03-16 17:27:30 -0700323 @NonNull
Jonathan Basseri20e96c52017-11-16 10:58:01 -0800324 public SecurityParameterIndex allocateSecurityParameterIndex(
Nathan Harold6303d9e2018-03-16 17:27:30 -0700325 @NonNull InetAddress destinationAddress, int requestedSpi)
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800326 throws SpiUnavailableException, ResourceUnavailableException {
Nathan Harold05406792017-04-06 18:16:28 -0700327 if (requestedSpi == IpSecManager.INVALID_SECURITY_PARAMETER_INDEX) {
328 throw new IllegalArgumentException("Requested SPI must be a valid (non-zero) SPI");
329 }
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700330 try {
331 return new SecurityParameterIndex(mService, destinationAddress, requestedSpi);
332 } catch (ServiceSpecificException e) {
333 throw rethrowUncheckedExceptionFromServiceSpecificException(e);
334 }
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800335 }
336
337 /**
Jonathan Basseri2725a232017-04-21 15:53:51 -0700338 * Apply an IPsec transform to a stream socket.
339 *
340 * <p>This applies transport mode encapsulation to the given socket. Once applied, I/O on the
341 * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When
Nathan Harold5a19b952018-01-05 19:25:13 -0800342 * the transform is removed from the socket by calling {@link #removeTransportModeTransforms},
Jonathan Basseri2725a232017-04-21 15:53:51 -0700343 * unprotected traffic can resume on that socket.
344 *
345 * <p>For security reasons, the destination address of any traffic on the socket must match the
Jonathan Basseri20e96c52017-11-16 10:58:01 -0800346 * remote {@code InetAddress} of the {@code IpSecTransform}. Attempts to send traffic to any
Jonathan Basseri2725a232017-04-21 15:53:51 -0700347 * other IP address will result in an IOException. In addition, reads and writes on the socket
348 * will throw IOException if the user deactivates the transform (by calling {@link
Nathan Harold5a19b952018-01-05 19:25:13 -0800349 * IpSecTransform#close()}) without calling {@link #removeTransportModeTransforms}.
Jonathan Basseri2725a232017-04-21 15:53:51 -0700350 *
Benedict Wongc5106f32018-03-14 19:01:14 -0700351 * <p>Note that when applied to TCP sockets, calling {@link IpSecTransform#close()} on an
352 * applied transform before completion of graceful shutdown may result in the shutdown sequence
353 * failing to complete. As such, applications requiring graceful shutdown MUST close the socket
354 * prior to deactivating the applied transform. Socket closure may be performed asynchronously
355 * (in batches), so the returning of a close function does not guarantee shutdown of a socket.
356 * Setting an SO_LINGER timeout results in socket closure being performed synchronously, and is
357 * sufficient to ensure shutdown.
358 *
359 * Specifically, if the transform is deactivated (by calling {@link IpSecTransform#close()}),
360 * prior to the socket being closed, the standard [FIN - FIN/ACK - ACK], or the reset [RST]
361 * packets are dropped due to the lack of a valid Transform. Similarly, if a socket without the
362 * SO_LINGER option set is closed, the delayed/batched FIN packets may be dropped.
363 *
Jonathan Basseri20e96c52017-11-16 10:58:01 -0800364 * <h4>Rekey Procedure</h4>
365 *
Nathan Harolde3536f02018-03-06 13:22:22 -0800366 * <p>When applying a new tranform to a socket in the outbound direction, the previous transform
367 * will be removed and the new transform will take effect immediately, sending all traffic on
368 * the new transform; however, when applying a transform in the inbound direction, traffic
369 * on the old transform will continue to be decrypted and delivered until that transform is
370 * deallocated by calling {@link IpSecTransform#close()}. This overlap allows lossless rekey
371 * procedures where both transforms are valid until both endpoints are using the new transform
372 * and all in-flight packets have been received.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800373 *
374 * @param socket a stream socket
Nathan Harolde3536f02018-03-06 13:22:22 -0800375 * @param direction the direction in which the transform should be applied
Jonathan Basseri2725a232017-04-21 15:53:51 -0700376 * @param transform a transport mode {@code IpSecTransform}
377 * @throws IOException indicating that the transform could not be applied
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800378 */
Nathan Harold6303d9e2018-03-16 17:27:30 -0700379 public void applyTransportModeTransform(@NonNull Socket socket,
380 @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException {
Benedict Wong57ab3f62018-04-02 18:12:34 -0700381 // Ensure creation of FD. See b/77548890 for more details.
382 socket.getSoLinger();
383
Nathan Harold31676252018-01-16 12:08:43 -0800384 applyTransportModeTransform(socket.getFileDescriptor$(), direction, transform);
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800385 }
386
387 /**
Jonathan Basseri2725a232017-04-21 15:53:51 -0700388 * Apply an IPsec transform to a datagram socket.
389 *
390 * <p>This applies transport mode encapsulation to the given socket. Once applied, I/O on the
391 * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When
Nathan Harold5a19b952018-01-05 19:25:13 -0800392 * the transform is removed from the socket by calling {@link #removeTransportModeTransforms},
Jonathan Basseri2725a232017-04-21 15:53:51 -0700393 * unprotected traffic can resume on that socket.
394 *
395 * <p>For security reasons, the destination address of any traffic on the socket must match the
396 * remote {@code InetAddress} of the {@code IpSecTransform}. Attempts to send traffic to any
397 * other IP address will result in an IOException. In addition, reads and writes on the socket
398 * will throw IOException if the user deactivates the transform (by calling {@link
Nathan Harold5a19b952018-01-05 19:25:13 -0800399 * IpSecTransform#close()}) without calling {@link #removeTransportModeTransforms}.
Jonathan Basseri2725a232017-04-21 15:53:51 -0700400 *
Jonathan Basseri20e96c52017-11-16 10:58:01 -0800401 * <h4>Rekey Procedure</h4>
402 *
Nathan Harolde3536f02018-03-06 13:22:22 -0800403 * <p>When applying a new tranform to a socket in the outbound direction, the previous transform
404 * will be removed and the new transform will take effect immediately, sending all traffic on
405 * the new transform; however, when applying a transform in the inbound direction, traffic
406 * on the old transform will continue to be decrypted and delivered until that transform is
407 * deallocated by calling {@link IpSecTransform#close()}. This overlap allows lossless rekey
408 * procedures where both transforms are valid until both endpoints are using the new transform
409 * and all in-flight packets have been received.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800410 *
411 * @param socket a datagram socket
Nathan Harolde3536f02018-03-06 13:22:22 -0800412 * @param direction the direction in which the transform should be applied
Jonathan Basseri2725a232017-04-21 15:53:51 -0700413 * @param transform a transport mode {@code IpSecTransform}
414 * @throws IOException indicating that the transform could not be applied
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800415 */
Nathan Harold6303d9e2018-03-16 17:27:30 -0700416 public void applyTransportModeTransform(@NonNull DatagramSocket socket,
417 @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException {
Nathan Harold31676252018-01-16 12:08:43 -0800418 applyTransportModeTransform(socket.getFileDescriptor$(), direction, transform);
Nathan Harold031acb82017-03-07 13:23:36 -0800419 }
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800420
421 /**
Jonathan Basseri2725a232017-04-21 15:53:51 -0700422 * Apply an IPsec transform to a socket.
423 *
424 * <p>This applies transport mode encapsulation to the given socket. Once applied, I/O on the
425 * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When
Nathan Harold5a19b952018-01-05 19:25:13 -0800426 * the transform is removed from the socket by calling {@link #removeTransportModeTransforms},
Jonathan Basseri2725a232017-04-21 15:53:51 -0700427 * unprotected traffic can resume on that socket.
428 *
429 * <p>For security reasons, the destination address of any traffic on the socket must match the
430 * remote {@code InetAddress} of the {@code IpSecTransform}. Attempts to send traffic to any
431 * other IP address will result in an IOException. In addition, reads and writes on the socket
432 * will throw IOException if the user deactivates the transform (by calling {@link
Nathan Harold5a19b952018-01-05 19:25:13 -0800433 * IpSecTransform#close()}) without calling {@link #removeTransportModeTransforms}.
Jonathan Basseri2725a232017-04-21 15:53:51 -0700434 *
Benedict Wongc5106f32018-03-14 19:01:14 -0700435 * <p>Note that when applied to TCP sockets, calling {@link IpSecTransform#close()} on an
436 * applied transform before completion of graceful shutdown may result in the shutdown sequence
437 * failing to complete. As such, applications requiring graceful shutdown MUST close the socket
438 * prior to deactivating the applied transform. Socket closure may be performed asynchronously
439 * (in batches), so the returning of a close function does not guarantee shutdown of a socket.
440 * Setting an SO_LINGER timeout results in socket closure being performed synchronously, and is
441 * sufficient to ensure shutdown.
442 *
443 * Specifically, if the transform is deactivated (by calling {@link IpSecTransform#close()}),
444 * prior to the socket being closed, the standard [FIN - FIN/ACK - ACK], or the reset [RST]
445 * packets are dropped due to the lack of a valid Transform. Similarly, if a socket without the
446 * SO_LINGER option set is closed, the delayed/batched FIN packets may be dropped.
447 *
Jonathan Basseri20e96c52017-11-16 10:58:01 -0800448 * <h4>Rekey Procedure</h4>
449 *
Nathan Harolde3536f02018-03-06 13:22:22 -0800450 * <p>When applying a new tranform to a socket in the outbound direction, the previous transform
451 * will be removed and the new transform will take effect immediately, sending all traffic on
452 * the new transform; however, when applying a transform in the inbound direction, traffic
453 * on the old transform will continue to be decrypted and delivered until that transform is
454 * deallocated by calling {@link IpSecTransform#close()}. This overlap allows lossless rekey
455 * procedures where both transforms are valid until both endpoints are using the new transform
456 * and all in-flight packets have been received.
Nathan Harold0072e192017-04-06 17:46:00 -0700457 *
458 * @param socket a socket file descriptor
Nathan Harolde3536f02018-03-06 13:22:22 -0800459 * @param direction the direction in which the transform should be applied
Jonathan Basseri2725a232017-04-21 15:53:51 -0700460 * @param transform a transport mode {@code IpSecTransform}
461 * @throws IOException indicating that the transform could not be applied
Nathan Harold0072e192017-04-06 17:46:00 -0700462 */
Nathan Harold6303d9e2018-03-16 17:27:30 -0700463 public void applyTransportModeTransform(@NonNull FileDescriptor socket,
464 @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException {
Nathan Harold80865392017-04-04 19:37:48 -0700465 // We dup() the FileDescriptor here because if we don't, then the ParcelFileDescriptor()
Nathan Harold31676252018-01-16 12:08:43 -0800466 // constructor takes control and closes the user's FD when we exit the method.
Nathan Harold80865392017-04-04 19:37:48 -0700467 try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) {
Nathan Harold5a19b952018-01-05 19:25:13 -0800468 mService.applyTransportModeTransform(pfd, direction, transform.getResourceId());
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700469 } catch (ServiceSpecificException e) {
470 throw rethrowCheckedExceptionFromServiceSpecificException(e);
Nathan Harold80865392017-04-04 19:37:48 -0700471 } catch (RemoteException e) {
472 throw e.rethrowFromSystemServer();
473 }
Nathan Harold0072e192017-04-06 17:46:00 -0700474 }
475
476 /**
Jonathan Basseri2725a232017-04-21 15:53:51 -0700477 * Remove an IPsec transform from a stream socket.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800478 *
Nathan Harold0d483b72018-01-17 01:00:20 -0800479 * <p>Once removed, traffic on the socket will not be encrypted. Removing transforms from a
480 * socket allows the socket to be reused for communication in the clear.
Jonathan Basseri2725a232017-04-21 15:53:51 -0700481 *
482 * <p>If an {@code IpSecTransform} object applied to this socket was deallocated by calling
483 * {@link IpSecTransform#close()}, then communication on the socket will fail until this method
484 * is called.
485 *
486 * @param socket a socket that previously had a transform applied to it
Jonathan Basseri2725a232017-04-21 15:53:51 -0700487 * @throws IOException indicating that the transform could not be removed from the socket
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800488 */
Nathan Harold6303d9e2018-03-16 17:27:30 -0700489 public void removeTransportModeTransforms(@NonNull Socket socket) throws IOException {
Benedict Wong57ab3f62018-04-02 18:12:34 -0700490 // Ensure creation of FD. See b/77548890 for more details.
491 socket.getSoLinger();
492
Nathan Harold0d483b72018-01-17 01:00:20 -0800493 removeTransportModeTransforms(socket.getFileDescriptor$());
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800494 }
495
496 /**
Jonathan Basseri2725a232017-04-21 15:53:51 -0700497 * Remove an IPsec transform from a datagram socket.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800498 *
Nathan Harold0d483b72018-01-17 01:00:20 -0800499 * <p>Once removed, traffic on the socket will not be encrypted. Removing transforms from a
500 * socket allows the socket to be reused for communication in the clear.
Jonathan Basseri2725a232017-04-21 15:53:51 -0700501 *
502 * <p>If an {@code IpSecTransform} object applied to this socket was deallocated by calling
503 * {@link IpSecTransform#close()}, then communication on the socket will fail until this method
504 * is called.
505 *
506 * @param socket a socket that previously had a transform applied to it
Jonathan Basseri2725a232017-04-21 15:53:51 -0700507 * @throws IOException indicating that the transform could not be removed from the socket
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800508 */
Nathan Harold6303d9e2018-03-16 17:27:30 -0700509 public void removeTransportModeTransforms(@NonNull DatagramSocket socket) throws IOException {
Nathan Harold0d483b72018-01-17 01:00:20 -0800510 removeTransportModeTransforms(socket.getFileDescriptor$());
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800511 }
512
Nathan Harold0072e192017-04-06 17:46:00 -0700513 /**
Jonathan Basseri2725a232017-04-21 15:53:51 -0700514 * Remove an IPsec transform from a socket.
Nathan Harold0072e192017-04-06 17:46:00 -0700515 *
Nathan Harold0d483b72018-01-17 01:00:20 -0800516 * <p>Once removed, traffic on the socket will not be encrypted. Removing transforms from a
517 * socket allows the socket to be reused for communication in the clear.
Jonathan Basseri2725a232017-04-21 15:53:51 -0700518 *
519 * <p>If an {@code IpSecTransform} object applied to this socket was deallocated by calling
520 * {@link IpSecTransform#close()}, then communication on the socket will fail until this method
521 * is called.
522 *
523 * @param socket a socket that previously had a transform applied to it
Jonathan Basseri2725a232017-04-21 15:53:51 -0700524 * @throws IOException indicating that the transform could not be removed from the socket
Nathan Harold0072e192017-04-06 17:46:00 -0700525 */
Nathan Harold6303d9e2018-03-16 17:27:30 -0700526 public void removeTransportModeTransforms(@NonNull FileDescriptor socket) throws IOException {
Nathan Harold80865392017-04-04 19:37:48 -0700527 try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) {
Nathan Harold0d483b72018-01-17 01:00:20 -0800528 mService.removeTransportModeTransforms(pfd);
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700529 } catch (ServiceSpecificException e) {
530 throw rethrowCheckedExceptionFromServiceSpecificException(e);
Nathan Harold031acb82017-03-07 13:23:36 -0800531 } catch (RemoteException e) {
532 throw e.rethrowFromSystemServer();
533 }
534 }
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800535
536 /**
537 * Remove a Tunnel Mode IPsec Transform from a {@link Network}. This must be used as part of
538 * cleanup if a tunneled Network experiences a change in default route. The Network will drop
539 * all traffic that cannot be routed to the Tunnel's outbound interface. If that interface is
540 * lost, all traffic will drop.
541 *
Jonathan Basseri20e96c52017-11-16 10:58:01 -0800542 * <p>TODO: Update javadoc for tunnel mode APIs at the same time the APIs are re-worked.
543 *
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800544 * @param net a network that currently has transform applied to it.
545 * @param transform a Tunnel Mode IPsec Transform that has been previously applied to the given
546 * network
547 * @hide
548 */
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800549 public void removeTunnelModeTransform(Network net, IpSecTransform transform) {}
550
551 /**
Jonathan Basseri2725a232017-04-21 15:53:51 -0700552 * This class provides access to a UDP encapsulation Socket.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800553 *
Jonathan Basseri2725a232017-04-21 15:53:51 -0700554 * <p>{@code UdpEncapsulationSocket} wraps a system-provided datagram socket intended for IKEv2
555 * signalling and UDP encapsulated IPsec traffic. Instances can be obtained by calling {@link
556 * IpSecManager#openUdpEncapsulationSocket}. The provided socket cannot be re-bound by the
557 * caller. The caller should not close the {@code FileDescriptor} returned by {@link
Benedict Wonga386e372018-03-27 16:55:48 -0700558 * #getFileDescriptor}, but should use {@link #close} instead.
Jonathan Basseri2725a232017-04-21 15:53:51 -0700559 *
560 * <p>Allowing the user to close or unbind a UDP encapsulation socket could impact the traffic
561 * of the next user who binds to that port. To prevent this scenario, these sockets are held
562 * open by the system so that they may only be closed by calling {@link #close} or when the user
563 * process exits.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800564 */
565 public static final class UdpEncapsulationSocket implements AutoCloseable {
Nathan Harold80865392017-04-04 19:37:48 -0700566 private final ParcelFileDescriptor mPfd;
Nathan Haroldd2a1dad2017-03-01 18:55:06 -0800567 private final IIpSecService mService;
Nathan Harold5e854462017-12-13 18:51:35 -0800568 private int mResourceId = INVALID_RESOURCE_ID;
Nathan Harold80865392017-04-04 19:37:48 -0700569 private final int mPort;
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800570 private final CloseGuard mCloseGuard = CloseGuard.get();
571
Nathan Harold031acb82017-03-07 13:23:36 -0800572 private UdpEncapsulationSocket(@NonNull IIpSecService service, int port)
Nathan Harold80865392017-04-04 19:37:48 -0700573 throws ResourceUnavailableException, IOException {
Nathan Haroldd2a1dad2017-03-01 18:55:06 -0800574 mService = service;
Nathan Harold80865392017-04-04 19:37:48 -0700575 try {
576 IpSecUdpEncapResponse result =
577 mService.openUdpEncapsulationSocket(port, new Binder());
578 switch (result.status) {
579 case Status.OK:
580 break;
581 case Status.RESOURCE_UNAVAILABLE:
582 throw new ResourceUnavailableException(
583 "No more Sockets may be allocated by this requester.");
584 default:
585 throw new RuntimeException(
586 "Unknown status returned by IpSecService: " + result.status);
587 }
588 mResourceId = result.resourceId;
589 mPort = result.port;
590 mPfd = result.fileDescriptor;
591 } catch (RemoteException e) {
592 throw e.rethrowFromSystemServer();
593 }
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800594 mCloseGuard.open("constructor");
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800595 }
596
Benedict Wonga386e372018-03-27 16:55:48 -0700597 /** Get the encapsulation socket's file descriptor. */
598 public FileDescriptor getFileDescriptor() {
Nathan Harold80865392017-04-04 19:37:48 -0700599 if (mPfd == null) {
600 return null;
601 }
602 return mPfd.getFileDescriptor();
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800603 }
604
Jonathan Basseri2725a232017-04-21 15:53:51 -0700605 /** Get the bound port of the wrapped socket. */
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800606 public int getPort() {
Nathan Harold80865392017-04-04 19:37:48 -0700607 return mPort;
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800608 }
609
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800610 /**
Jonathan Basseri2725a232017-04-21 15:53:51 -0700611 * Close this socket.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800612 *
Jonathan Basseri2725a232017-04-21 15:53:51 -0700613 * <p>This closes the wrapped socket. Open encapsulation sockets count against a user's
614 * resource limits, and forgetting to close them eventually will result in {@link
615 * ResourceUnavailableException} being thrown.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800616 */
Jonathan Basseri2725a232017-04-21 15:53:51 -0700617 @Override
Nathan Harolda64b0192017-04-17 17:11:58 -0700618 public void close() throws IOException {
Nathan Harold80865392017-04-04 19:37:48 -0700619 try {
620 mService.closeUdpEncapsulationSocket(mResourceId);
Nathan Harold5e854462017-12-13 18:51:35 -0800621 mResourceId = INVALID_RESOURCE_ID;
Nathan Harold80865392017-04-04 19:37:48 -0700622 } catch (RemoteException e) {
623 throw e.rethrowFromSystemServer();
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700624 } catch (Exception e) {
625 // On close we swallow all random exceptions since failure to close is not
626 // actionable by the user.
627 Log.e(TAG, "Failed to close " + this + ", Exception=" + e);
628 } finally {
629 mResourceId = INVALID_RESOURCE_ID;
630 mCloseGuard.close();
Nathan Harold80865392017-04-04 19:37:48 -0700631 }
632
633 try {
634 mPfd.close();
635 } catch (IOException e) {
636 Log.e(TAG, "Failed to close UDP Encapsulation Socket with Port= " + mPort);
637 throw e;
638 }
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800639 }
640
Jonathan Basseri2725a232017-04-21 15:53:51 -0700641 /** Check that the socket was closed properly. */
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800642 @Override
643 protected void finalize() throws Throwable {
644 if (mCloseGuard != null) {
645 mCloseGuard.warnIfOpen();
646 }
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800647 close();
648 }
Nathan Harold80865392017-04-04 19:37:48 -0700649
650 /** @hide */
Chiachang Wanga0343312021-01-12 18:48:13 +0800651 @SystemApi(client = MODULE_LIBRARIES)
Nathan Harold19b99d92017-08-23 13:46:33 -0700652 public int getResourceId() {
Nathan Harold80865392017-04-04 19:37:48 -0700653 return mResourceId;
654 }
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700655
656 @Override
657 public String toString() {
658 return new StringBuilder()
659 .append("UdpEncapsulationSocket{port=")
660 .append(mPort)
661 .append(",resourceId=")
662 .append(mResourceId)
663 .append("}")
664 .toString();
665 }
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800666 };
667
668 /**
Jonathan Basseri2725a232017-04-21 15:53:51 -0700669 * Open a socket for UDP encapsulation and bind to the given port.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800670 *
Jonathan Basseri2725a232017-04-21 15:53:51 -0700671 * <p>See {@link UdpEncapsulationSocket} for the proper way to close the returned socket.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800672 *
Jonathan Basseri2725a232017-04-21 15:53:51 -0700673 * @param port a local UDP port
674 * @return a socket that is bound to the given port
675 * @throws IOException indicating that the socket could not be opened or bound
676 * @throws ResourceUnavailableException indicating that too many encapsulation sockets are open
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800677 */
678 // Returning a socket in this fashion that has been created and bound by the system
679 // is the only safe way to ensure that a socket is both accessible to the user and
680 // safely usable for Encapsulation without allowing a user to possibly unbind from/close
681 // the port, which could potentially impact the traffic of the next user who binds to that
682 // socket.
Nathan Harold6303d9e2018-03-16 17:27:30 -0700683 @NonNull
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800684 public UdpEncapsulationSocket openUdpEncapsulationSocket(int port)
685 throws IOException, ResourceUnavailableException {
Nathan Harold80865392017-04-04 19:37:48 -0700686 /*
687 * Most range checking is done in the service, but this version of the constructor expects
688 * a valid port number, and zero cannot be checked after being passed to the service.
689 */
690 if (port == 0) {
691 throw new IllegalArgumentException("Specified port must be a valid port number!");
692 }
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700693 try {
694 return new UdpEncapsulationSocket(mService, port);
695 } catch (ServiceSpecificException e) {
696 throw rethrowCheckedExceptionFromServiceSpecificException(e);
697 }
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800698 }
699
700 /**
Jonathan Basseri2725a232017-04-21 15:53:51 -0700701 * Open a socket for UDP encapsulation.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800702 *
Jonathan Basseri2725a232017-04-21 15:53:51 -0700703 * <p>See {@link UdpEncapsulationSocket} for the proper way to close the returned socket.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800704 *
Jonathan Basseri2725a232017-04-21 15:53:51 -0700705 * <p>The local port of the returned socket can be obtained by calling {@link
706 * UdpEncapsulationSocket#getPort()}.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800707 *
Jonathan Basseri2725a232017-04-21 15:53:51 -0700708 * @return a socket that is bound to a local port
709 * @throws IOException indicating that the socket could not be opened or bound
710 * @throws ResourceUnavailableException indicating that too many encapsulation sockets are open
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800711 */
712 // Returning a socket in this fashion that has been created and bound by the system
713 // is the only safe way to ensure that a socket is both accessible to the user and
714 // safely usable for Encapsulation without allowing a user to possibly unbind from/close
715 // the port, which could potentially impact the traffic of the next user who binds to that
716 // socket.
Nathan Harold6303d9e2018-03-16 17:27:30 -0700717 @NonNull
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800718 public UdpEncapsulationSocket openUdpEncapsulationSocket()
719 throws IOException, ResourceUnavailableException {
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700720 try {
721 return new UdpEncapsulationSocket(mService, 0);
722 } catch (ServiceSpecificException e) {
723 throw rethrowCheckedExceptionFromServiceSpecificException(e);
724 }
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800725 }
726
727 /**
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000728 * This class represents an IpSecTunnelInterface
Nathan Harold67e76732018-01-17 16:09:24 -0800729 *
730 * <p>IpSecTunnelInterface objects track tunnel interfaces that serve as
731 * local endpoints for IPsec tunnels.
732 *
733 * <p>Creating an IpSecTunnelInterface creates a device to which IpSecTransforms may be
734 * applied to provide IPsec security to packets sent through the tunnel. While a tunnel
735 * cannot be used in standalone mode within Android, the higher layers may use the tunnel
736 * to create Network objects which are accessible to the Android system.
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000737 * @hide
Nathan Harold67e76732018-01-17 16:09:24 -0800738 */
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000739 @SystemApi
Nathan Harold67e76732018-01-17 16:09:24 -0800740 public static final class IpSecTunnelInterface implements AutoCloseable {
Nathan Harold65ef8432018-03-15 18:06:06 -0700741 private final String mOpPackageName;
Nathan Harold67e76732018-01-17 16:09:24 -0800742 private final IIpSecService mService;
743 private final InetAddress mRemoteAddress;
744 private final InetAddress mLocalAddress;
745 private final Network mUnderlyingNetwork;
746 private final CloseGuard mCloseGuard = CloseGuard.get();
747 private String mInterfaceName;
748 private int mResourceId = INVALID_RESOURCE_ID;
749
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000750 /** Get the underlying SPI held by this object. */
Nathan Harold6303d9e2018-03-16 17:27:30 -0700751 @NonNull
Nathan Harold67e76732018-01-17 16:09:24 -0800752 public String getInterfaceName() {
753 return mInterfaceName;
754 }
755
756 /**
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000757 * Add an address to the IpSecTunnelInterface
Nathan Harold67e76732018-01-17 16:09:24 -0800758 *
759 * <p>Add an address which may be used as the local inner address for
760 * tunneled traffic.
761 *
762 * @param address the local address for traffic inside the tunnel
Benedict Wongd39837f2018-04-03 20:30:54 -0700763 * @param prefixLen length of the InetAddress prefix
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000764 * @hide
Nathan Harold67e76732018-01-17 16:09:24 -0800765 */
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000766 @SystemApi
Benedict Wonge9763752018-11-08 19:45:34 -0800767 @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
Nathan Harold00e77242018-03-21 15:32:42 -0700768 @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
Benedict Wongd39837f2018-04-03 20:30:54 -0700769 public void addAddress(@NonNull InetAddress address, int prefixLen) throws IOException {
Benedict Wong97c3c942018-03-01 18:53:07 -0800770 try {
Nathan Harold65ef8432018-03-15 18:06:06 -0700771 mService.addAddressToTunnelInterface(
Benedict Wongd39837f2018-04-03 20:30:54 -0700772 mResourceId, new LinkAddress(address, prefixLen), mOpPackageName);
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700773 } catch (ServiceSpecificException e) {
774 throw rethrowCheckedExceptionFromServiceSpecificException(e);
Benedict Wong97c3c942018-03-01 18:53:07 -0800775 } catch (RemoteException e) {
776 throw e.rethrowFromSystemServer();
777 }
Nathan Harold67e76732018-01-17 16:09:24 -0800778 }
779
780 /**
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000781 * Remove an address from the IpSecTunnelInterface
Nathan Harold67e76732018-01-17 16:09:24 -0800782 *
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000783 * <p>Remove an address which was previously added to the IpSecTunnelInterface
Nathan Harold67e76732018-01-17 16:09:24 -0800784 *
785 * @param address to be removed
Benedict Wongd39837f2018-04-03 20:30:54 -0700786 * @param prefixLen length of the InetAddress prefix
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000787 * @hide
Nathan Harold67e76732018-01-17 16:09:24 -0800788 */
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000789 @SystemApi
Benedict Wonge9763752018-11-08 19:45:34 -0800790 @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
Nathan Harold00e77242018-03-21 15:32:42 -0700791 @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
Benedict Wongd39837f2018-04-03 20:30:54 -0700792 public void removeAddress(@NonNull InetAddress address, int prefixLen) throws IOException {
Benedict Wong97c3c942018-03-01 18:53:07 -0800793 try {
Nathan Harold65ef8432018-03-15 18:06:06 -0700794 mService.removeAddressFromTunnelInterface(
Benedict Wongd39837f2018-04-03 20:30:54 -0700795 mResourceId, new LinkAddress(address, prefixLen), mOpPackageName);
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700796 } catch (ServiceSpecificException e) {
797 throw rethrowCheckedExceptionFromServiceSpecificException(e);
Benedict Wong97c3c942018-03-01 18:53:07 -0800798 } catch (RemoteException e) {
799 throw e.rethrowFromSystemServer();
800 }
Nathan Harold67e76732018-01-17 16:09:24 -0800801 }
802
Yan Yana2f3b492020-09-29 23:38:00 -0700803 /**
804 * Update the underlying network for this IpSecTunnelInterface.
805 *
806 * <p>This new underlying network will be used for all transforms applied AFTER this call is
807 * complete. Before new {@link IpSecTransform}(s) with matching addresses are applied to
808 * this tunnel interface, traffic will still use the old SA, and be routed on the old
809 * underlying network.
810 *
811 * <p>To migrate IPsec tunnel mode traffic, a caller should:
812 *
813 * <ol>
814 * <li>Update the IpSecTunnelInterface’s underlying network.
815 * <li>Apply {@link IpSecTransform}(s) with matching addresses to this
816 * IpSecTunnelInterface.
817 * </ol>
818 *
819 * @param underlyingNetwork the new {@link Network} that will carry traffic for this tunnel.
Yan Yanbe3eb3d2022-05-16 17:13:45 -0700820 * This network MUST be a functional {@link Network} with valid {@link LinkProperties},
821 * and MUST never be the network exposing this IpSecTunnelInterface, otherwise this
822 * method will throw an {@link IllegalArgumentException}. If the IpSecTunnelInterface is
823 * later added to this network, all outbound traffic will be blackholed.
Yan Yana2f3b492020-09-29 23:38:00 -0700824 */
825 // TODO: b/169171001 Update the documentation when transform migration is supported.
826 // The purpose of making updating network and applying transforms separate is to leave open
827 // the possibility to support lossless migration procedures. To do that, Android platform
828 // will need to support multiple inbound tunnel mode transforms, just like it can support
829 // multiple transport mode transforms.
830 @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
831 @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
832 public void setUnderlyingNetwork(@NonNull Network underlyingNetwork) throws IOException {
833 try {
834 mService.setNetworkForTunnelInterface(
835 mResourceId, underlyingNetwork, mOpPackageName);
836 } catch (RemoteException e) {
837 throw e.rethrowFromSystemServer();
838 }
839 }
840
Nathan Harold65ef8432018-03-15 18:06:06 -0700841 private IpSecTunnelInterface(@NonNull Context ctx, @NonNull IIpSecService service,
Nathan Harold67e76732018-01-17 16:09:24 -0800842 @NonNull InetAddress localAddress, @NonNull InetAddress remoteAddress,
843 @NonNull Network underlyingNetwork)
844 throws ResourceUnavailableException, IOException {
Nathan Harold65ef8432018-03-15 18:06:06 -0700845 mOpPackageName = ctx.getOpPackageName();
Nathan Harold67e76732018-01-17 16:09:24 -0800846 mService = service;
847 mLocalAddress = localAddress;
848 mRemoteAddress = remoteAddress;
849 mUnderlyingNetwork = underlyingNetwork;
Benedict Wong8bc90732018-01-18 18:31:45 -0800850
851 try {
852 IpSecTunnelInterfaceResponse result =
853 mService.createTunnelInterface(
854 localAddress.getHostAddress(),
855 remoteAddress.getHostAddress(),
856 underlyingNetwork,
Nathan Harold65ef8432018-03-15 18:06:06 -0700857 new Binder(),
858 mOpPackageName);
Benedict Wong8bc90732018-01-18 18:31:45 -0800859 switch (result.status) {
860 case Status.OK:
861 break;
862 case Status.RESOURCE_UNAVAILABLE:
863 throw new ResourceUnavailableException(
864 "No more tunnel interfaces may be allocated by this requester.");
865 default:
866 throw new RuntimeException(
867 "Unknown status returned by IpSecService: " + result.status);
868 }
869 mResourceId = result.resourceId;
870 mInterfaceName = result.interfaceName;
871 } catch (RemoteException e) {
872 throw e.rethrowFromSystemServer();
873 }
874 mCloseGuard.open("constructor");
Nathan Harold67e76732018-01-17 16:09:24 -0800875 }
876
877 /**
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000878 * Delete an IpSecTunnelInterface
Nathan Harold67e76732018-01-17 16:09:24 -0800879 *
880 * <p>Calling close will deallocate the IpSecTunnelInterface and all of its system
881 * resources. Any packets bound for this interface either inbound or outbound will
882 * all be lost.
883 */
884 @Override
885 public void close() {
Benedict Wong8bc90732018-01-18 18:31:45 -0800886 try {
Nathan Harold65ef8432018-03-15 18:06:06 -0700887 mService.deleteTunnelInterface(mResourceId, mOpPackageName);
Benedict Wong8bc90732018-01-18 18:31:45 -0800888 } catch (RemoteException e) {
889 throw e.rethrowFromSystemServer();
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700890 } catch (Exception e) {
891 // On close we swallow all random exceptions since failure to close is not
892 // actionable by the user.
893 Log.e(TAG, "Failed to close " + this + ", Exception=" + e);
894 } finally {
895 mResourceId = INVALID_RESOURCE_ID;
896 mCloseGuard.close();
Benedict Wong8bc90732018-01-18 18:31:45 -0800897 }
Nathan Harold67e76732018-01-17 16:09:24 -0800898 }
899
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000900 /** Check that the Interface was closed properly. */
Nathan Harold67e76732018-01-17 16:09:24 -0800901 @Override
902 protected void finalize() throws Throwable {
903 if (mCloseGuard != null) {
904 mCloseGuard.warnIfOpen();
905 }
906 close();
907 }
Benedict Wong8bc90732018-01-18 18:31:45 -0800908
909 /** @hide */
910 @VisibleForTesting
911 public int getResourceId() {
912 return mResourceId;
913 }
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700914
Aurimas Liutikas3a78d9d2019-08-28 13:01:05 -0700915 @NonNull
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700916 @Override
917 public String toString() {
918 return new StringBuilder()
919 .append("IpSecTunnelInterface{ifname=")
920 .append(mInterfaceName)
921 .append(",resourceId=")
922 .append(mResourceId)
923 .append("}")
924 .toString();
925 }
Nathan Harold67e76732018-01-17 16:09:24 -0800926 }
927
928 /**
929 * Create a new IpSecTunnelInterface as a local endpoint for tunneled IPsec traffic.
930 *
Benedict Wong8bc90732018-01-18 18:31:45 -0800931 * <p>An application that creates tunnels is responsible for cleaning up the tunnel when the
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000932 * underlying network goes away, and the onLost() callback is received.
Benedict Wong8bc90732018-01-18 18:31:45 -0800933 *
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000934 * @param localAddress The local addres of the tunnel
935 * @param remoteAddress The local addres of the tunnel
936 * @param underlyingNetwork the {@link Network} that will carry traffic for this tunnel.
937 * This network should almost certainly be a network such as WiFi with an L2 address.
938 * @return a new {@link IpSecManager#IpSecTunnelInterface} with the specified properties
939 * @throws IOException indicating that the socket could not be opened or bound
940 * @throws ResourceUnavailableException indicating that too many encapsulation sockets are open
Yan Yan160aac32020-12-03 17:08:29 -0800941 * @hide
Yan Yan160aac32020-12-03 17:08:29 -0800942 */
Nathan Harold3a287d52018-04-25 12:01:34 -0700943 @SystemApi
Nathan Harold6303d9e2018-03-16 17:27:30 -0700944 @NonNull
Benedict Wonge9763752018-11-08 19:45:34 -0800945 @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
Nathan Harold00e77242018-03-21 15:32:42 -0700946 @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
Nathan Harold67e76732018-01-17 16:09:24 -0800947 public IpSecTunnelInterface createIpSecTunnelInterface(@NonNull InetAddress localAddress,
948 @NonNull InetAddress remoteAddress, @NonNull Network underlyingNetwork)
949 throws ResourceUnavailableException, IOException {
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700950 try {
951 return new IpSecTunnelInterface(
952 mContext, mService, localAddress, remoteAddress, underlyingNetwork);
953 } catch (ServiceSpecificException e) {
954 throw rethrowCheckedExceptionFromServiceSpecificException(e);
955 }
Nathan Harold67e76732018-01-17 16:09:24 -0800956 }
957
958 /**
Nathan Harolde3536f02018-03-06 13:22:22 -0800959 * Apply an active Tunnel Mode IPsec Transform to a {@link IpSecTunnelInterface}, which will
960 * tunnel all traffic for the given direction through the underlying network's interface with
961 * IPsec (applies an outer IP header and IPsec Header to all traffic, and expects an additional
962 * IP header and IPsec Header on all inbound traffic).
963 * <p>Applications should probably not use this API directly.
964 *
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000965 * @param tunnel The {@link IpSecManager#IpSecTunnelInterface} that will use the supplied
Nathan Harold67e76732018-01-17 16:09:24 -0800966 * transform.
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000967 * @param direction the direction, {@link DIRECTION_OUT} or {@link #DIRECTION_IN} in which
Nathan Harold67e76732018-01-17 16:09:24 -0800968 * the transform will be used.
969 * @param transform an {@link IpSecTransform} created in tunnel mode
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000970 * @throws IOException indicating that the transform could not be applied due to a lower
971 * layer failure.
972 * @hide
Nathan Harold67e76732018-01-17 16:09:24 -0800973 */
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000974 @SystemApi
Benedict Wonge9763752018-11-08 19:45:34 -0800975 @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
Nathan Harold00e77242018-03-21 15:32:42 -0700976 @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
Nathan Harold6303d9e2018-03-16 17:27:30 -0700977 public void applyTunnelModeTransform(@NonNull IpSecTunnelInterface tunnel,
978 @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException {
Benedict Wong8bc90732018-01-18 18:31:45 -0800979 try {
980 mService.applyTunnelModeTransform(
Nathan Harold65ef8432018-03-15 18:06:06 -0700981 tunnel.getResourceId(), direction,
982 transform.getResourceId(), mContext.getOpPackageName());
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700983 } catch (ServiceSpecificException e) {
984 throw rethrowCheckedExceptionFromServiceSpecificException(e);
Benedict Wong8bc90732018-01-18 18:31:45 -0800985 } catch (RemoteException e) {
986 throw e.rethrowFromSystemServer();
987 }
Nathan Harold67e76732018-01-17 16:09:24 -0800988 }
Nathan Harolde3536f02018-03-06 13:22:22 -0800989
Nathan Harold67e76732018-01-17 16:09:24 -0800990 /**
Aaron Huang80a73fd2021-12-28 02:33:53 +0800991 * @hide
992 */
993 public IpSecTransformResponse createTransform(IpSecConfig config, IBinder binder,
994 String callingPackage) {
995 try {
996 return mService.createTransform(config, binder, callingPackage);
997 } catch (RemoteException e) {
998 throw e.rethrowFromSystemServer();
999 }
1000 }
1001
1002 /**
1003 * @hide
1004 */
1005 public void deleteTransform(int resourceId) {
1006 try {
1007 mService.deleteTransform(resourceId);
1008 } catch (RemoteException e) {
1009 throw e.rethrowFromSystemServer();
1010 }
1011 }
1012
1013 /**
Jonathan Basseri2725a232017-04-21 15:53:51 -07001014 * Construct an instance of IpSecManager within an application context.
Nathan Haroldb1f605f2017-01-12 18:38:57 -08001015 *
1016 * @param context the application context for this manager
1017 * @hide
1018 */
Nathan Harold65ef8432018-03-15 18:06:06 -07001019 public IpSecManager(Context ctx, IIpSecService service) {
1020 mContext = ctx;
Aaron Huang49eef6f2021-12-22 16:35:13 +08001021 mService = Objects.requireNonNull(service, "missing service");
Nathan Haroldb1f605f2017-01-12 18:38:57 -08001022 }
Nathan Haroldbeed0b62018-04-03 16:13:19 -07001023
1024 private static void maybeHandleServiceSpecificException(ServiceSpecificException sse) {
1025 // OsConstants are late binding, so switch statements can't be used.
1026 if (sse.errorCode == OsConstants.EINVAL) {
1027 throw new IllegalArgumentException(sse);
1028 } else if (sse.errorCode == OsConstants.EAGAIN) {
1029 throw new IllegalStateException(sse);
Benedict Wongc45974b2018-07-16 14:56:20 -07001030 } else if (sse.errorCode == OsConstants.EOPNOTSUPP
1031 || sse.errorCode == OsConstants.EPROTONOSUPPORT) {
Nathan Haroldbeed0b62018-04-03 16:13:19 -07001032 throw new UnsupportedOperationException(sse);
1033 }
1034 }
1035
1036 /**
1037 * Convert an Errno SSE to the correct Unchecked exception type.
1038 *
1039 * This method never actually returns.
1040 */
1041 // package
1042 static RuntimeException
1043 rethrowUncheckedExceptionFromServiceSpecificException(ServiceSpecificException sse) {
1044 maybeHandleServiceSpecificException(sse);
1045 throw new RuntimeException(sse);
1046 }
1047
1048 /**
1049 * Convert an Errno SSE to the correct Checked or Unchecked exception type.
1050 *
1051 * This method may throw IOException, or it may throw an unchecked exception; it will never
1052 * actually return.
1053 */
1054 // package
1055 static IOException rethrowCheckedExceptionFromServiceSpecificException(
1056 ServiceSpecificException sse) throws IOException {
1057 // First see if this is an unchecked exception of a type we know.
1058 // If so, then we prefer the unchecked (specific) type of exception.
1059 maybeHandleServiceSpecificException(sse);
1060 // If not, then all we can do is provide the SSE in the form of an IOException.
1061 throw new ErrnoException(
1062 "IpSec encountered errno=" + sse.errorCode, sse.errorCode).rethrowAsIOException();
1063 }
Nathan Haroldb1f605f2017-01-12 18:38:57 -08001064}