blob: ff021d60ad69a915610cadb8ace1382d71a4782e [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;
Yan Yane114b382021-02-16 16:29:48 -080040import com.android.modules.utils.build.SdkLevel;
Nathan Harold19b99d92017-08-23 13:46:33 -070041
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;
Aaron Huangca9c1df2021-12-16 00:11:15 +080046import java.lang.annotation.Retention;
47import java.lang.annotation.RetentionPolicy;
Nathan Haroldb1f605f2017-01-12 18:38:57 -080048import java.net.DatagramSocket;
49import java.net.InetAddress;
50import java.net.Socket;
Aaron Huang49eef6f2021-12-22 16:35:13 +080051import java.util.Objects;
Nathan Haroldb1f605f2017-01-12 18:38:57 -080052
53/**
Jonathan Basseri2725a232017-04-21 15:53:51 -070054 * This class contains methods for managing IPsec sessions. Once configured, the kernel will apply
55 * confidentiality (encryption) and integrity (authentication) to IP traffic.
Nathan Haroldb1f605f2017-01-12 18:38:57 -080056 *
Jonathan Basseri2725a232017-04-21 15:53:51 -070057 * <p>Note that not all aspects of IPsec are permitted by this API. Applications may create
58 * transport mode security associations and apply them to individual sockets. Applications looking
Benedict Wongc85b7b02019-11-12 22:31:51 -080059 * to create an IPsec VPN should use {@link VpnManager} and {@link Ikev2VpnProfile}.
Jonathan Basseri2725a232017-04-21 15:53:51 -070060 *
61 * @see <a href="https://tools.ietf.org/html/rfc4301">RFC 4301, Security Architecture for the
Jonathan Basseri20e96c52017-11-16 10:58:01 -080062 * Internet Protocol</a>
Nathan Haroldb1f605f2017-01-12 18:38:57 -080063 */
Jeff Sharkeyad1cebe2017-06-02 17:36:26 -060064@SystemService(Context.IPSEC_SERVICE)
Yan Yan98a3a032022-02-02 16:39:45 -080065public class IpSecManager {
Nathan Haroldb1f605f2017-01-12 18:38:57 -080066 private static final String TAG = "IpSecManager";
67
68 /**
Yan Yana48dcd92022-10-18 00:03:20 +000069 * Feature flag to declare the kernel support of updating IPsec SAs.
70 *
71 * <p>Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device
72 * has the requisite kernel support for migrating IPsec tunnels to new source/destination
73 * addresses.
74 *
75 * <p>This feature implies that the device supports XFRM Migration (CONFIG_XFRM_MIGRATE) and has
76 * the kernel fixes to allow XFRM Migration correctly
77 *
78 * @see android.content.pm.PackageManager#FEATURE_IPSEC_TUNNEL_MIGRATION
79 * @hide
80 */
81 // Redefine this flag here so that IPsec code shipped in a mainline module can build on old
82 // platforms before FEATURE_IPSEC_TUNNEL_MIGRATION API is released.
83 public static final String FEATURE_IPSEC_TUNNEL_MIGRATION =
84 "android.software.ipsec_tunnel_migration";
85
86 /**
Nathan Harolde3536f02018-03-06 13:22:22 -080087 * Used when applying a transform to direct traffic through an {@link IpSecTransform}
88 * towards the host.
89 *
90 * <p>See {@link #applyTransportModeTransform(Socket, int, IpSecTransform)}.
Nathan Harold5a19b952018-01-05 19:25:13 -080091 */
92 public static final int DIRECTION_IN = 0;
93
94 /**
Nathan Harolde3536f02018-03-06 13:22:22 -080095 * Used when applying a transform to direct traffic through an {@link IpSecTransform}
96 * away from the host.
97 *
98 * <p>See {@link #applyTransportModeTransform(Socket, int, IpSecTransform)}.
Nathan Harold5a19b952018-01-05 19:25:13 -080099 */
100 public static final int DIRECTION_OUT = 1;
101
Nathan Harold5a19b952018-01-05 19:25:13 -0800102 /**
Benedict Wong908d34e2021-04-15 11:59:16 -0700103 * Used when applying a transform to direct traffic through an {@link IpSecTransform} for
104 * forwarding between interfaces.
105 *
106 * <p>See {@link #applyTransportModeTransform(Socket, int, IpSecTransform)}.
107 *
108 * @hide
109 */
Aaron Huang4989e952021-12-15 23:27:18 +0800110 @SystemApi(client = MODULE_LIBRARIES)
Benedict Wong908d34e2021-04-15 11:59:16 -0700111 public static final int DIRECTION_FWD = 2;
112
Aaron Huangca9c1df2021-12-16 00:11:15 +0800113 /** @hide */
114 @IntDef(value = {DIRECTION_IN, DIRECTION_OUT})
115 @Retention(RetentionPolicy.SOURCE)
116 public @interface PolicyDirection {}
117
Benedict Wong908d34e2021-04-15 11:59:16 -0700118 /**
Jonathan Basseri2725a232017-04-21 15:53:51 -0700119 * The Security Parameter Index (SPI) 0 indicates an unknown or invalid index.
Nathan Harold031acb82017-03-07 13:23:36 -0800120 *
121 * <p>No IPsec packet may contain an SPI of 0.
Jonathan Basseri2725a232017-04-21 15:53:51 -0700122 *
123 * @hide
Nathan Harold031acb82017-03-07 13:23:36 -0800124 */
Jonathan Basseri20e96c52017-11-16 10:58:01 -0800125 @TestApi public static final int INVALID_SECURITY_PARAMETER_INDEX = 0;
Nathan Harold031acb82017-03-07 13:23:36 -0800126
127 /** @hide */
128 public interface Status {
Aaron Huangfbae3082021-12-06 15:18:42 +0800129 int OK = 0;
130 int RESOURCE_UNAVAILABLE = 1;
131 int SPI_UNAVAILABLE = 2;
Nathan Harold031acb82017-03-07 13:23:36 -0800132 }
133
134 /** @hide */
Nathan Harold5e854462017-12-13 18:51:35 -0800135 public static final int INVALID_RESOURCE_ID = -1;
Nathan Harold031acb82017-03-07 13:23:36 -0800136
137 /**
Jonathan Basseri2725a232017-04-21 15:53:51 -0700138 * Thrown to indicate that a requested SPI is in use.
139 *
140 * <p>The combination of remote {@code InetAddress} and SPI must be unique across all apps on
141 * one device. If this error is encountered, a new SPI is required before a transform may be
142 * created. This error can be avoided by calling {@link
Jonathan Basseri20e96c52017-11-16 10:58:01 -0800143 * IpSecManager#allocateSecurityParameterIndex}.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800144 */
145 public static final class SpiUnavailableException extends AndroidException {
146 private final int mSpi;
147
148 /**
149 * Construct an exception indicating that a transform with the given SPI is already in use
150 * or otherwise unavailable.
151 *
Jonathan Basseri2725a232017-04-21 15:53:51 -0700152 * @param msg description indicating the colliding SPI
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800153 * @param spi the SPI that could not be used due to a collision
154 */
155 SpiUnavailableException(String msg, int spi) {
Jonathan Basseri2725a232017-04-21 15:53:51 -0700156 super(msg + " (spi: " + spi + ")");
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800157 mSpi = spi;
158 }
159
Jonathan Basseri2725a232017-04-21 15:53:51 -0700160 /** Get the SPI that caused a collision. */
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800161 public int getSpi() {
162 return mSpi;
163 }
164 }
165
166 /**
Jonathan Basseri2725a232017-04-21 15:53:51 -0700167 * Thrown to indicate that an IPsec resource is unavailable.
168 *
169 * <p>This could apply to resources such as sockets, {@link SecurityParameterIndex}, {@link
170 * IpSecTransform}, or other system resources. If this exception is thrown, users should release
171 * allocated objects of the type requested.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800172 */
173 public static final class ResourceUnavailableException extends AndroidException {
174
175 ResourceUnavailableException(String msg) {
176 super(msg);
177 }
178 }
179
Nathan Harold65ef8432018-03-15 18:06:06 -0700180 private final Context mContext;
Nathan Haroldd2a1dad2017-03-01 18:55:06 -0800181 private final IIpSecService mService;
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800182
Jonathan Basseri2725a232017-04-21 15:53:51 -0700183 /**
184 * This class represents a reserved SPI.
185 *
186 * <p>Objects of this type are used to track reserved security parameter indices. They can be
Jonathan Basseri20e96c52017-11-16 10:58:01 -0800187 * obtained by calling {@link IpSecManager#allocateSecurityParameterIndex} and must be released
Jonathan Basseri2725a232017-04-21 15:53:51 -0700188 * by calling {@link #close()} when they are no longer needed.
189 */
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800190 public static final class SecurityParameterIndex implements AutoCloseable {
Nathan Haroldd2a1dad2017-03-01 18:55:06 -0800191 private final IIpSecService mService;
Nathan Harold5a19b952018-01-05 19:25:13 -0800192 private final InetAddress mDestinationAddress;
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800193 private final CloseGuard mCloseGuard = CloseGuard.get();
Nathan Harold031acb82017-03-07 13:23:36 -0800194 private int mSpi = INVALID_SECURITY_PARAMETER_INDEX;
Nathan Harold5e854462017-12-13 18:51:35 -0800195 private int mResourceId = INVALID_RESOURCE_ID;
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800196
Jonathan Basseri2725a232017-04-21 15:53:51 -0700197 /** Get the underlying SPI held by this object. */
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800198 public int getSpi() {
199 return mSpi;
200 }
201
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800202 /**
203 * Release an SPI that was previously reserved.
204 *
Nathan Harold909d66e2017-03-29 10:47:59 -0700205 * <p>Release an SPI for use by other users in the system. If a SecurityParameterIndex is
206 * applied to an IpSecTransform, it will become unusable for future transforms but should
207 * still be closed to ensure system resources are released.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800208 */
209 @Override
210 public void close() {
Nathan Harold80865392017-04-04 19:37:48 -0700211 try {
212 mService.releaseSecurityParameterIndex(mResourceId);
213 } catch (RemoteException e) {
214 throw e.rethrowFromSystemServer();
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700215 } catch (Exception e) {
216 // On close we swallow all random exceptions since failure to close is not
217 // actionable by the user.
218 Log.e(TAG, "Failed to close " + this + ", Exception=" + e);
219 } finally {
220 mResourceId = INVALID_RESOURCE_ID;
221 mCloseGuard.close();
Nathan Harold80865392017-04-04 19:37:48 -0700222 }
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800223 }
224
Jonathan Basseri2725a232017-04-21 15:53:51 -0700225 /** Check that the SPI was closed properly. */
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800226 @Override
Nathan Harold2a30daf2017-11-07 17:17:45 -0800227 protected void finalize() throws Throwable {
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800228 if (mCloseGuard != null) {
229 mCloseGuard.warnIfOpen();
230 }
231
232 close();
233 }
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800234
Nathan Harold031acb82017-03-07 13:23:36 -0800235 private SecurityParameterIndex(
Nathan Harold5a19b952018-01-05 19:25:13 -0800236 @NonNull IIpSecService service, InetAddress destinationAddress, int spi)
Nathan Harold031acb82017-03-07 13:23:36 -0800237 throws ResourceUnavailableException, SpiUnavailableException {
238 mService = service;
Nathan Harold5a19b952018-01-05 19:25:13 -0800239 mDestinationAddress = destinationAddress;
Nathan Harold031acb82017-03-07 13:23:36 -0800240 try {
Nathan Harold80865392017-04-04 19:37:48 -0700241 IpSecSpiResponse result =
Jonathan Basseri20e96c52017-11-16 10:58:01 -0800242 mService.allocateSecurityParameterIndex(
Nathan Harold5a19b952018-01-05 19:25:13 -0800243 destinationAddress.getHostAddress(), spi, new Binder());
Nathan Harold031acb82017-03-07 13:23:36 -0800244
245 if (result == null) {
246 throw new NullPointerException("Received null response from IpSecService");
247 }
248
Nathan Harold80865392017-04-04 19:37:48 -0700249 int status = result.status;
Nathan Harold031acb82017-03-07 13:23:36 -0800250 switch (status) {
251 case Status.OK:
252 break;
253 case Status.RESOURCE_UNAVAILABLE:
254 throw new ResourceUnavailableException(
255 "No more SPIs may be allocated by this requester.");
256 case Status.SPI_UNAVAILABLE:
257 throw new SpiUnavailableException("Requested SPI is unavailable", spi);
258 default:
259 throw new RuntimeException(
260 "Unknown status returned by IpSecService: " + status);
261 }
Nathan Harold80865392017-04-04 19:37:48 -0700262 mSpi = result.spi;
263 mResourceId = result.resourceId;
Nathan Harold031acb82017-03-07 13:23:36 -0800264
265 if (mSpi == INVALID_SECURITY_PARAMETER_INDEX) {
266 throw new RuntimeException("Invalid SPI returned by IpSecService: " + status);
267 }
268
269 if (mResourceId == INVALID_RESOURCE_ID) {
270 throw new RuntimeException(
271 "Invalid Resource ID returned by IpSecService: " + status);
272 }
Nathan Harold031acb82017-03-07 13:23:36 -0800273 } catch (RemoteException e) {
274 throw e.rethrowFromSystemServer();
275 }
276 mCloseGuard.open("open");
277 }
Nathan Harold80865392017-04-04 19:37:48 -0700278
279 /** @hide */
Nathan Harold19b99d92017-08-23 13:46:33 -0700280 @VisibleForTesting
281 public int getResourceId() {
Nathan Harold80865392017-04-04 19:37:48 -0700282 return mResourceId;
283 }
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700284
285 @Override
286 public String toString() {
287 return new StringBuilder()
288 .append("SecurityParameterIndex{spi=")
289 .append(mSpi)
290 .append(",resourceId=")
291 .append(mResourceId)
292 .append("}")
293 .toString();
294 }
Nathan Harold031acb82017-03-07 13:23:36 -0800295 }
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800296
297 /**
Nathan Harold5a19b952018-01-05 19:25:13 -0800298 * Reserve a random SPI for traffic bound to or from the specified destination address.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800299 *
300 * <p>If successful, this SPI is guaranteed available until released by a call to {@link
301 * SecurityParameterIndex#close()}.
302 *
Nathan Harold5a19b952018-01-05 19:25:13 -0800303 * @param destinationAddress the destination address for traffic bearing the requested SPI.
304 * For inbound traffic, the destination should be an address currently assigned on-device.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800305 * @return the reserved SecurityParameterIndex
Aaron Huangfbae3082021-12-06 15:18:42 +0800306 * @throws ResourceUnavailableException indicating that too many SPIs are
Nathan Harold5a19b952018-01-05 19:25:13 -0800307 * currently allocated for this user
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800308 */
Nathan Harold6303d9e2018-03-16 17:27:30 -0700309 @NonNull
310 public SecurityParameterIndex allocateSecurityParameterIndex(
311 @NonNull InetAddress destinationAddress) throws ResourceUnavailableException {
Nathan Harold05406792017-04-06 18:16:28 -0700312 try {
313 return new SecurityParameterIndex(
314 mService,
Nathan Harold5a19b952018-01-05 19:25:13 -0800315 destinationAddress,
Nathan Harold05406792017-04-06 18:16:28 -0700316 IpSecManager.INVALID_SECURITY_PARAMETER_INDEX);
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700317 } catch (ServiceSpecificException e) {
318 throw rethrowUncheckedExceptionFromServiceSpecificException(e);
Nathan Harold05406792017-04-06 18:16:28 -0700319 } catch (SpiUnavailableException unlikely) {
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700320 // Because this function allocates a totally random SPI, it really shouldn't ever
321 // fail to allocate an SPI; we simply need this because the exception is checked.
Nathan Harold05406792017-04-06 18:16:28 -0700322 throw new ResourceUnavailableException("No SPIs available");
323 }
324 }
325
326 /**
Nathan Harold5a19b952018-01-05 19:25:13 -0800327 * Reserve the requested SPI for traffic bound to or from the specified destination address.
Nathan Harold05406792017-04-06 18:16:28 -0700328 *
329 * <p>If successful, this SPI is guaranteed available until released by a call to {@link
330 * SecurityParameterIndex#close()}.
331 *
Nathan Harold5a19b952018-01-05 19:25:13 -0800332 * @param destinationAddress the destination address for traffic bearing the requested SPI.
333 * For inbound traffic, the destination should be an address currently assigned on-device.
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700334 * @param requestedSpi the requested SPI. The range 1-255 is reserved and may not be used. See
335 * RFC 4303 Section 2.1.
Nathan Harold05406792017-04-06 18:16:28 -0700336 * @return the reserved SecurityParameterIndex
Aaron Huangfbae3082021-12-06 15:18:42 +0800337 * @throws ResourceUnavailableException indicating that too many SPIs are
Nathan Harold5a19b952018-01-05 19:25:13 -0800338 * currently allocated for this user
Aaron Huangfbae3082021-12-06 15:18:42 +0800339 * @throws SpiUnavailableException indicating that the requested SPI could not be
Nathan Harold5a19b952018-01-05 19:25:13 -0800340 * reserved
Nathan Harold05406792017-04-06 18:16:28 -0700341 */
Nathan Harold6303d9e2018-03-16 17:27:30 -0700342 @NonNull
Jonathan Basseri20e96c52017-11-16 10:58:01 -0800343 public SecurityParameterIndex allocateSecurityParameterIndex(
Nathan Harold6303d9e2018-03-16 17:27:30 -0700344 @NonNull InetAddress destinationAddress, int requestedSpi)
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800345 throws SpiUnavailableException, ResourceUnavailableException {
Nathan Harold05406792017-04-06 18:16:28 -0700346 if (requestedSpi == IpSecManager.INVALID_SECURITY_PARAMETER_INDEX) {
347 throw new IllegalArgumentException("Requested SPI must be a valid (non-zero) SPI");
348 }
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700349 try {
350 return new SecurityParameterIndex(mService, destinationAddress, requestedSpi);
351 } catch (ServiceSpecificException e) {
352 throw rethrowUncheckedExceptionFromServiceSpecificException(e);
353 }
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800354 }
355
356 /**
Jonathan Basseri2725a232017-04-21 15:53:51 -0700357 * Apply an IPsec transform to a stream socket.
358 *
359 * <p>This applies transport mode encapsulation to the given socket. Once applied, I/O on the
360 * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When
Nathan Harold5a19b952018-01-05 19:25:13 -0800361 * the transform is removed from the socket by calling {@link #removeTransportModeTransforms},
Jonathan Basseri2725a232017-04-21 15:53:51 -0700362 * unprotected traffic can resume on that socket.
363 *
364 * <p>For security reasons, the destination address of any traffic on the socket must match the
Jonathan Basseri20e96c52017-11-16 10:58:01 -0800365 * remote {@code InetAddress} of the {@code IpSecTransform}. Attempts to send traffic to any
Jonathan Basseri2725a232017-04-21 15:53:51 -0700366 * other IP address will result in an IOException. In addition, reads and writes on the socket
367 * will throw IOException if the user deactivates the transform (by calling {@link
Nathan Harold5a19b952018-01-05 19:25:13 -0800368 * IpSecTransform#close()}) without calling {@link #removeTransportModeTransforms}.
Jonathan Basseri2725a232017-04-21 15:53:51 -0700369 *
Benedict Wongc5106f32018-03-14 19:01:14 -0700370 * <p>Note that when applied to TCP sockets, calling {@link IpSecTransform#close()} on an
371 * applied transform before completion of graceful shutdown may result in the shutdown sequence
372 * failing to complete. As such, applications requiring graceful shutdown MUST close the socket
373 * prior to deactivating the applied transform. Socket closure may be performed asynchronously
374 * (in batches), so the returning of a close function does not guarantee shutdown of a socket.
375 * Setting an SO_LINGER timeout results in socket closure being performed synchronously, and is
376 * sufficient to ensure shutdown.
377 *
378 * Specifically, if the transform is deactivated (by calling {@link IpSecTransform#close()}),
379 * prior to the socket being closed, the standard [FIN - FIN/ACK - ACK], or the reset [RST]
380 * packets are dropped due to the lack of a valid Transform. Similarly, if a socket without the
381 * SO_LINGER option set is closed, the delayed/batched FIN packets may be dropped.
382 *
Jonathan Basseri20e96c52017-11-16 10:58:01 -0800383 * <h4>Rekey Procedure</h4>
384 *
Nathan Harolde3536f02018-03-06 13:22:22 -0800385 * <p>When applying a new tranform to a socket in the outbound direction, the previous transform
386 * will be removed and the new transform will take effect immediately, sending all traffic on
387 * the new transform; however, when applying a transform in the inbound direction, traffic
388 * on the old transform will continue to be decrypted and delivered until that transform is
389 * deallocated by calling {@link IpSecTransform#close()}. This overlap allows lossless rekey
390 * procedures where both transforms are valid until both endpoints are using the new transform
391 * and all in-flight packets have been received.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800392 *
393 * @param socket a stream socket
Nathan Harolde3536f02018-03-06 13:22:22 -0800394 * @param direction the direction in which the transform should be applied
Jonathan Basseri2725a232017-04-21 15:53:51 -0700395 * @param transform a transport mode {@code IpSecTransform}
396 * @throws IOException indicating that the transform could not be applied
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800397 */
Nathan Harold6303d9e2018-03-16 17:27:30 -0700398 public void applyTransportModeTransform(@NonNull Socket socket,
399 @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException {
Benedict Wong57ab3f62018-04-02 18:12:34 -0700400 // Ensure creation of FD. See b/77548890 for more details.
401 socket.getSoLinger();
402
Nathan Harold31676252018-01-16 12:08:43 -0800403 applyTransportModeTransform(socket.getFileDescriptor$(), direction, transform);
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800404 }
405
406 /**
Jonathan Basseri2725a232017-04-21 15:53:51 -0700407 * Apply an IPsec transform to a datagram socket.
408 *
409 * <p>This applies transport mode encapsulation to the given socket. Once applied, I/O on the
410 * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When
Nathan Harold5a19b952018-01-05 19:25:13 -0800411 * the transform is removed from the socket by calling {@link #removeTransportModeTransforms},
Jonathan Basseri2725a232017-04-21 15:53:51 -0700412 * unprotected traffic can resume on that socket.
413 *
414 * <p>For security reasons, the destination address of any traffic on the socket must match the
415 * remote {@code InetAddress} of the {@code IpSecTransform}. Attempts to send traffic to any
416 * other IP address will result in an IOException. In addition, reads and writes on the socket
417 * will throw IOException if the user deactivates the transform (by calling {@link
Nathan Harold5a19b952018-01-05 19:25:13 -0800418 * IpSecTransform#close()}) without calling {@link #removeTransportModeTransforms}.
Jonathan Basseri2725a232017-04-21 15:53:51 -0700419 *
Jonathan Basseri20e96c52017-11-16 10:58:01 -0800420 * <h4>Rekey Procedure</h4>
421 *
Nathan Harolde3536f02018-03-06 13:22:22 -0800422 * <p>When applying a new tranform to a socket in the outbound direction, the previous transform
423 * will be removed and the new transform will take effect immediately, sending all traffic on
424 * the new transform; however, when applying a transform in the inbound direction, traffic
425 * on the old transform will continue to be decrypted and delivered until that transform is
426 * deallocated by calling {@link IpSecTransform#close()}. This overlap allows lossless rekey
427 * procedures where both transforms are valid until both endpoints are using the new transform
428 * and all in-flight packets have been received.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800429 *
430 * @param socket a datagram socket
Nathan Harolde3536f02018-03-06 13:22:22 -0800431 * @param direction the direction in which the transform should be applied
Jonathan Basseri2725a232017-04-21 15:53:51 -0700432 * @param transform a transport mode {@code IpSecTransform}
433 * @throws IOException indicating that the transform could not be applied
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800434 */
Nathan Harold6303d9e2018-03-16 17:27:30 -0700435 public void applyTransportModeTransform(@NonNull DatagramSocket socket,
436 @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException {
Nathan Harold31676252018-01-16 12:08:43 -0800437 applyTransportModeTransform(socket.getFileDescriptor$(), direction, transform);
Nathan Harold031acb82017-03-07 13:23:36 -0800438 }
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800439
440 /**
Jonathan Basseri2725a232017-04-21 15:53:51 -0700441 * Apply an IPsec transform to a socket.
442 *
443 * <p>This applies transport mode encapsulation to the given socket. Once applied, I/O on the
444 * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When
Nathan Harold5a19b952018-01-05 19:25:13 -0800445 * the transform is removed from the socket by calling {@link #removeTransportModeTransforms},
Jonathan Basseri2725a232017-04-21 15:53:51 -0700446 * unprotected traffic can resume on that socket.
447 *
448 * <p>For security reasons, the destination address of any traffic on the socket must match the
449 * remote {@code InetAddress} of the {@code IpSecTransform}. Attempts to send traffic to any
450 * other IP address will result in an IOException. In addition, reads and writes on the socket
451 * will throw IOException if the user deactivates the transform (by calling {@link
Nathan Harold5a19b952018-01-05 19:25:13 -0800452 * IpSecTransform#close()}) without calling {@link #removeTransportModeTransforms}.
Jonathan Basseri2725a232017-04-21 15:53:51 -0700453 *
Benedict Wongc5106f32018-03-14 19:01:14 -0700454 * <p>Note that when applied to TCP sockets, calling {@link IpSecTransform#close()} on an
455 * applied transform before completion of graceful shutdown may result in the shutdown sequence
456 * failing to complete. As such, applications requiring graceful shutdown MUST close the socket
457 * prior to deactivating the applied transform. Socket closure may be performed asynchronously
458 * (in batches), so the returning of a close function does not guarantee shutdown of a socket.
459 * Setting an SO_LINGER timeout results in socket closure being performed synchronously, and is
460 * sufficient to ensure shutdown.
461 *
462 * Specifically, if the transform is deactivated (by calling {@link IpSecTransform#close()}),
463 * prior to the socket being closed, the standard [FIN - FIN/ACK - ACK], or the reset [RST]
464 * packets are dropped due to the lack of a valid Transform. Similarly, if a socket without the
465 * SO_LINGER option set is closed, the delayed/batched FIN packets may be dropped.
466 *
Jonathan Basseri20e96c52017-11-16 10:58:01 -0800467 * <h4>Rekey Procedure</h4>
468 *
Nathan Harolde3536f02018-03-06 13:22:22 -0800469 * <p>When applying a new tranform to a socket in the outbound direction, the previous transform
470 * will be removed and the new transform will take effect immediately, sending all traffic on
471 * the new transform; however, when applying a transform in the inbound direction, traffic
472 * on the old transform will continue to be decrypted and delivered until that transform is
473 * deallocated by calling {@link IpSecTransform#close()}. This overlap allows lossless rekey
474 * procedures where both transforms are valid until both endpoints are using the new transform
475 * and all in-flight packets have been received.
Nathan Harold0072e192017-04-06 17:46:00 -0700476 *
477 * @param socket a socket file descriptor
Nathan Harolde3536f02018-03-06 13:22:22 -0800478 * @param direction the direction in which the transform should be applied
Jonathan Basseri2725a232017-04-21 15:53:51 -0700479 * @param transform a transport mode {@code IpSecTransform}
480 * @throws IOException indicating that the transform could not be applied
Nathan Harold0072e192017-04-06 17:46:00 -0700481 */
Nathan Harold6303d9e2018-03-16 17:27:30 -0700482 public void applyTransportModeTransform(@NonNull FileDescriptor socket,
483 @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException {
Nathan Harold80865392017-04-04 19:37:48 -0700484 // We dup() the FileDescriptor here because if we don't, then the ParcelFileDescriptor()
Nathan Harold31676252018-01-16 12:08:43 -0800485 // constructor takes control and closes the user's FD when we exit the method.
Nathan Harold80865392017-04-04 19:37:48 -0700486 try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) {
Nathan Harold5a19b952018-01-05 19:25:13 -0800487 mService.applyTransportModeTransform(pfd, direction, transform.getResourceId());
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700488 } catch (ServiceSpecificException e) {
489 throw rethrowCheckedExceptionFromServiceSpecificException(e);
Nathan Harold80865392017-04-04 19:37:48 -0700490 } catch (RemoteException e) {
491 throw e.rethrowFromSystemServer();
492 }
Nathan Harold0072e192017-04-06 17:46:00 -0700493 }
494
495 /**
Jonathan Basseri2725a232017-04-21 15:53:51 -0700496 * Remove an IPsec transform from a stream socket.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800497 *
Nathan Harold0d483b72018-01-17 01:00:20 -0800498 * <p>Once removed, traffic on the socket will not be encrypted. Removing transforms from a
499 * socket allows the socket to be reused for communication in the clear.
Jonathan Basseri2725a232017-04-21 15:53:51 -0700500 *
501 * <p>If an {@code IpSecTransform} object applied to this socket was deallocated by calling
502 * {@link IpSecTransform#close()}, then communication on the socket will fail until this method
503 * is called.
504 *
505 * @param socket a socket that previously had a transform applied to it
Jonathan Basseri2725a232017-04-21 15:53:51 -0700506 * @throws IOException indicating that the transform could not be removed from the socket
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800507 */
Nathan Harold6303d9e2018-03-16 17:27:30 -0700508 public void removeTransportModeTransforms(@NonNull Socket socket) throws IOException {
Benedict Wong57ab3f62018-04-02 18:12:34 -0700509 // Ensure creation of FD. See b/77548890 for more details.
510 socket.getSoLinger();
511
Nathan Harold0d483b72018-01-17 01:00:20 -0800512 removeTransportModeTransforms(socket.getFileDescriptor$());
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800513 }
514
515 /**
Jonathan Basseri2725a232017-04-21 15:53:51 -0700516 * Remove an IPsec transform from a datagram socket.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800517 *
Nathan Harold0d483b72018-01-17 01:00:20 -0800518 * <p>Once removed, traffic on the socket will not be encrypted. Removing transforms from a
519 * socket allows the socket to be reused for communication in the clear.
Jonathan Basseri2725a232017-04-21 15:53:51 -0700520 *
521 * <p>If an {@code IpSecTransform} object applied to this socket was deallocated by calling
522 * {@link IpSecTransform#close()}, then communication on the socket will fail until this method
523 * is called.
524 *
525 * @param socket a socket that previously had a transform applied to it
Jonathan Basseri2725a232017-04-21 15:53:51 -0700526 * @throws IOException indicating that the transform could not be removed from the socket
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800527 */
Nathan Harold6303d9e2018-03-16 17:27:30 -0700528 public void removeTransportModeTransforms(@NonNull DatagramSocket socket) throws IOException {
Nathan Harold0d483b72018-01-17 01:00:20 -0800529 removeTransportModeTransforms(socket.getFileDescriptor$());
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800530 }
531
Nathan Harold0072e192017-04-06 17:46:00 -0700532 /**
Jonathan Basseri2725a232017-04-21 15:53:51 -0700533 * Remove an IPsec transform from a socket.
Nathan Harold0072e192017-04-06 17:46:00 -0700534 *
Nathan Harold0d483b72018-01-17 01:00:20 -0800535 * <p>Once removed, traffic on the socket will not be encrypted. Removing transforms from a
536 * socket allows the socket to be reused for communication in the clear.
Jonathan Basseri2725a232017-04-21 15:53:51 -0700537 *
538 * <p>If an {@code IpSecTransform} object applied to this socket was deallocated by calling
539 * {@link IpSecTransform#close()}, then communication on the socket will fail until this method
540 * is called.
541 *
542 * @param socket a socket that previously had a transform applied to it
Jonathan Basseri2725a232017-04-21 15:53:51 -0700543 * @throws IOException indicating that the transform could not be removed from the socket
Nathan Harold0072e192017-04-06 17:46:00 -0700544 */
Nathan Harold6303d9e2018-03-16 17:27:30 -0700545 public void removeTransportModeTransforms(@NonNull FileDescriptor socket) throws IOException {
Nathan Harold80865392017-04-04 19:37:48 -0700546 try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) {
Nathan Harold0d483b72018-01-17 01:00:20 -0800547 mService.removeTransportModeTransforms(pfd);
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700548 } catch (ServiceSpecificException e) {
549 throw rethrowCheckedExceptionFromServiceSpecificException(e);
Nathan Harold031acb82017-03-07 13:23:36 -0800550 } catch (RemoteException e) {
551 throw e.rethrowFromSystemServer();
552 }
553 }
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800554
555 /**
556 * Remove a Tunnel Mode IPsec Transform from a {@link Network}. This must be used as part of
557 * cleanup if a tunneled Network experiences a change in default route. The Network will drop
558 * all traffic that cannot be routed to the Tunnel's outbound interface. If that interface is
559 * lost, all traffic will drop.
560 *
Jonathan Basseri20e96c52017-11-16 10:58:01 -0800561 * <p>TODO: Update javadoc for tunnel mode APIs at the same time the APIs are re-worked.
562 *
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800563 * @param net a network that currently has transform applied to it.
564 * @param transform a Tunnel Mode IPsec Transform that has been previously applied to the given
565 * network
566 * @hide
567 */
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800568 public void removeTunnelModeTransform(Network net, IpSecTransform transform) {}
569
570 /**
Jonathan Basseri2725a232017-04-21 15:53:51 -0700571 * This class provides access to a UDP encapsulation Socket.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800572 *
Jonathan Basseri2725a232017-04-21 15:53:51 -0700573 * <p>{@code UdpEncapsulationSocket} wraps a system-provided datagram socket intended for IKEv2
574 * signalling and UDP encapsulated IPsec traffic. Instances can be obtained by calling {@link
575 * IpSecManager#openUdpEncapsulationSocket}. The provided socket cannot be re-bound by the
576 * caller. The caller should not close the {@code FileDescriptor} returned by {@link
Benedict Wonga386e372018-03-27 16:55:48 -0700577 * #getFileDescriptor}, but should use {@link #close} instead.
Jonathan Basseri2725a232017-04-21 15:53:51 -0700578 *
579 * <p>Allowing the user to close or unbind a UDP encapsulation socket could impact the traffic
580 * of the next user who binds to that port. To prevent this scenario, these sockets are held
581 * open by the system so that they may only be closed by calling {@link #close} or when the user
582 * process exits.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800583 */
584 public static final class UdpEncapsulationSocket implements AutoCloseable {
Nathan Harold80865392017-04-04 19:37:48 -0700585 private final ParcelFileDescriptor mPfd;
Nathan Haroldd2a1dad2017-03-01 18:55:06 -0800586 private final IIpSecService mService;
Nathan Harold5e854462017-12-13 18:51:35 -0800587 private int mResourceId = INVALID_RESOURCE_ID;
Nathan Harold80865392017-04-04 19:37:48 -0700588 private final int mPort;
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800589 private final CloseGuard mCloseGuard = CloseGuard.get();
590
Nathan Harold031acb82017-03-07 13:23:36 -0800591 private UdpEncapsulationSocket(@NonNull IIpSecService service, int port)
Nathan Harold80865392017-04-04 19:37:48 -0700592 throws ResourceUnavailableException, IOException {
Nathan Haroldd2a1dad2017-03-01 18:55:06 -0800593 mService = service;
Nathan Harold80865392017-04-04 19:37:48 -0700594 try {
595 IpSecUdpEncapResponse result =
596 mService.openUdpEncapsulationSocket(port, new Binder());
597 switch (result.status) {
598 case Status.OK:
599 break;
600 case Status.RESOURCE_UNAVAILABLE:
601 throw new ResourceUnavailableException(
602 "No more Sockets may be allocated by this requester.");
603 default:
604 throw new RuntimeException(
605 "Unknown status returned by IpSecService: " + result.status);
606 }
607 mResourceId = result.resourceId;
608 mPort = result.port;
609 mPfd = result.fileDescriptor;
610 } catch (RemoteException e) {
611 throw e.rethrowFromSystemServer();
612 }
Maciej Żenczykowski223b5cc2023-01-07 00:59:44 +0000613 mCloseGuard.open("close");
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800614 }
615
Benedict Wonga386e372018-03-27 16:55:48 -0700616 /** Get the encapsulation socket's file descriptor. */
617 public FileDescriptor getFileDescriptor() {
Nathan Harold80865392017-04-04 19:37:48 -0700618 if (mPfd == null) {
619 return null;
620 }
621 return mPfd.getFileDescriptor();
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800622 }
623
Jonathan Basseri2725a232017-04-21 15:53:51 -0700624 /** Get the bound port of the wrapped socket. */
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800625 public int getPort() {
Nathan Harold80865392017-04-04 19:37:48 -0700626 return mPort;
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800627 }
628
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800629 /**
Jonathan Basseri2725a232017-04-21 15:53:51 -0700630 * Close this socket.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800631 *
Jonathan Basseri2725a232017-04-21 15:53:51 -0700632 * <p>This closes the wrapped socket. Open encapsulation sockets count against a user's
633 * resource limits, and forgetting to close them eventually will result in {@link
634 * ResourceUnavailableException} being thrown.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800635 */
Jonathan Basseri2725a232017-04-21 15:53:51 -0700636 @Override
Nathan Harolda64b0192017-04-17 17:11:58 -0700637 public void close() throws IOException {
Nathan Harold80865392017-04-04 19:37:48 -0700638 try {
639 mService.closeUdpEncapsulationSocket(mResourceId);
Nathan Harold5e854462017-12-13 18:51:35 -0800640 mResourceId = INVALID_RESOURCE_ID;
Nathan Harold80865392017-04-04 19:37:48 -0700641 } catch (RemoteException e) {
642 throw e.rethrowFromSystemServer();
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700643 } catch (Exception e) {
644 // On close we swallow all random exceptions since failure to close is not
645 // actionable by the user.
646 Log.e(TAG, "Failed to close " + this + ", Exception=" + e);
647 } finally {
648 mResourceId = INVALID_RESOURCE_ID;
649 mCloseGuard.close();
Nathan Harold80865392017-04-04 19:37:48 -0700650 }
651
652 try {
653 mPfd.close();
654 } catch (IOException e) {
655 Log.e(TAG, "Failed to close UDP Encapsulation Socket with Port= " + mPort);
656 throw e;
657 }
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800658 }
659
Jonathan Basseri2725a232017-04-21 15:53:51 -0700660 /** Check that the socket was closed properly. */
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800661 @Override
662 protected void finalize() throws Throwable {
663 if (mCloseGuard != null) {
664 mCloseGuard.warnIfOpen();
665 }
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800666 close();
667 }
Nathan Harold80865392017-04-04 19:37:48 -0700668
669 /** @hide */
Chiachang Wanga0343312021-01-12 18:48:13 +0800670 @SystemApi(client = MODULE_LIBRARIES)
Nathan Harold19b99d92017-08-23 13:46:33 -0700671 public int getResourceId() {
Nathan Harold80865392017-04-04 19:37:48 -0700672 return mResourceId;
673 }
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700674
675 @Override
676 public String toString() {
677 return new StringBuilder()
678 .append("UdpEncapsulationSocket{port=")
679 .append(mPort)
680 .append(",resourceId=")
681 .append(mResourceId)
682 .append("}")
683 .toString();
684 }
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800685 };
686
687 /**
Jonathan Basseri2725a232017-04-21 15:53:51 -0700688 * Open a socket for UDP encapsulation and bind to the given port.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800689 *
Jonathan Basseri2725a232017-04-21 15:53:51 -0700690 * <p>See {@link UdpEncapsulationSocket} for the proper way to close the returned socket.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800691 *
Jonathan Basseri2725a232017-04-21 15:53:51 -0700692 * @param port a local UDP port
693 * @return a socket that is bound to the given port
694 * @throws IOException indicating that the socket could not be opened or bound
695 * @throws ResourceUnavailableException indicating that too many encapsulation sockets are open
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800696 */
697 // Returning a socket in this fashion that has been created and bound by the system
698 // is the only safe way to ensure that a socket is both accessible to the user and
699 // safely usable for Encapsulation without allowing a user to possibly unbind from/close
700 // the port, which could potentially impact the traffic of the next user who binds to that
701 // socket.
Nathan Harold6303d9e2018-03-16 17:27:30 -0700702 @NonNull
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800703 public UdpEncapsulationSocket openUdpEncapsulationSocket(int port)
704 throws IOException, ResourceUnavailableException {
Nathan Harold80865392017-04-04 19:37:48 -0700705 /*
706 * Most range checking is done in the service, but this version of the constructor expects
707 * a valid port number, and zero cannot be checked after being passed to the service.
708 */
709 if (port == 0) {
710 throw new IllegalArgumentException("Specified port must be a valid port number!");
711 }
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700712 try {
713 return new UdpEncapsulationSocket(mService, port);
714 } catch (ServiceSpecificException e) {
715 throw rethrowCheckedExceptionFromServiceSpecificException(e);
716 }
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800717 }
718
719 /**
Jonathan Basseri2725a232017-04-21 15:53:51 -0700720 * Open a socket for UDP encapsulation.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800721 *
Jonathan Basseri2725a232017-04-21 15:53:51 -0700722 * <p>See {@link UdpEncapsulationSocket} for the proper way to close the returned socket.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800723 *
Jonathan Basseri2725a232017-04-21 15:53:51 -0700724 * <p>The local port of the returned socket can be obtained by calling {@link
725 * UdpEncapsulationSocket#getPort()}.
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800726 *
Jonathan Basseri2725a232017-04-21 15:53:51 -0700727 * @return a socket that is bound to a local port
728 * @throws IOException indicating that the socket could not be opened or bound
729 * @throws ResourceUnavailableException indicating that too many encapsulation sockets are open
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800730 */
731 // Returning a socket in this fashion that has been created and bound by the system
732 // is the only safe way to ensure that a socket is both accessible to the user and
733 // safely usable for Encapsulation without allowing a user to possibly unbind from/close
734 // the port, which could potentially impact the traffic of the next user who binds to that
735 // socket.
Nathan Harold6303d9e2018-03-16 17:27:30 -0700736 @NonNull
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800737 public UdpEncapsulationSocket openUdpEncapsulationSocket()
738 throws IOException, ResourceUnavailableException {
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700739 try {
740 return new UdpEncapsulationSocket(mService, 0);
741 } catch (ServiceSpecificException e) {
742 throw rethrowCheckedExceptionFromServiceSpecificException(e);
743 }
Nathan Haroldb1f605f2017-01-12 18:38:57 -0800744 }
745
746 /**
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000747 * This class represents an IpSecTunnelInterface
Nathan Harold67e76732018-01-17 16:09:24 -0800748 *
749 * <p>IpSecTunnelInterface objects track tunnel interfaces that serve as
750 * local endpoints for IPsec tunnels.
751 *
752 * <p>Creating an IpSecTunnelInterface creates a device to which IpSecTransforms may be
753 * applied to provide IPsec security to packets sent through the tunnel. While a tunnel
754 * cannot be used in standalone mode within Android, the higher layers may use the tunnel
755 * to create Network objects which are accessible to the Android system.
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
Nathan Harold67e76732018-01-17 16:09:24 -0800759 public static final class IpSecTunnelInterface implements AutoCloseable {
Nathan Harold65ef8432018-03-15 18:06:06 -0700760 private final String mOpPackageName;
Nathan Harold67e76732018-01-17 16:09:24 -0800761 private final IIpSecService mService;
762 private final InetAddress mRemoteAddress;
763 private final InetAddress mLocalAddress;
764 private final Network mUnderlyingNetwork;
765 private final CloseGuard mCloseGuard = CloseGuard.get();
766 private String mInterfaceName;
767 private int mResourceId = INVALID_RESOURCE_ID;
768
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000769 /** Get the underlying SPI held by this object. */
Nathan Harold6303d9e2018-03-16 17:27:30 -0700770 @NonNull
Nathan Harold67e76732018-01-17 16:09:24 -0800771 public String getInterfaceName() {
772 return mInterfaceName;
773 }
774
775 /**
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000776 * Add an address to the IpSecTunnelInterface
Nathan Harold67e76732018-01-17 16:09:24 -0800777 *
778 * <p>Add an address which may be used as the local inner address for
779 * tunneled traffic.
780 *
781 * @param address the local address for traffic inside the tunnel
Benedict Wongd39837f2018-04-03 20:30:54 -0700782 * @param prefixLen length of the InetAddress prefix
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000783 * @hide
Nathan Harold67e76732018-01-17 16:09:24 -0800784 */
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000785 @SystemApi
Benedict Wonge9763752018-11-08 19:45:34 -0800786 @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
Nathan Harold00e77242018-03-21 15:32:42 -0700787 @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
Benedict Wongd39837f2018-04-03 20:30:54 -0700788 public void addAddress(@NonNull InetAddress address, int prefixLen) throws IOException {
Benedict Wong97c3c942018-03-01 18:53:07 -0800789 try {
Nathan Harold65ef8432018-03-15 18:06:06 -0700790 mService.addAddressToTunnelInterface(
Benedict Wongd39837f2018-04-03 20:30:54 -0700791 mResourceId, new LinkAddress(address, prefixLen), mOpPackageName);
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700792 } catch (ServiceSpecificException e) {
793 throw rethrowCheckedExceptionFromServiceSpecificException(e);
Benedict Wong97c3c942018-03-01 18:53:07 -0800794 } catch (RemoteException e) {
795 throw e.rethrowFromSystemServer();
796 }
Nathan Harold67e76732018-01-17 16:09:24 -0800797 }
798
799 /**
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000800 * Remove an address from the IpSecTunnelInterface
Nathan Harold67e76732018-01-17 16:09:24 -0800801 *
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000802 * <p>Remove an address which was previously added to the IpSecTunnelInterface
Nathan Harold67e76732018-01-17 16:09:24 -0800803 *
804 * @param address to be removed
Benedict Wongd39837f2018-04-03 20:30:54 -0700805 * @param prefixLen length of the InetAddress prefix
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000806 * @hide
Nathan Harold67e76732018-01-17 16:09:24 -0800807 */
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000808 @SystemApi
Benedict Wonge9763752018-11-08 19:45:34 -0800809 @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
Nathan Harold00e77242018-03-21 15:32:42 -0700810 @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
Benedict Wongd39837f2018-04-03 20:30:54 -0700811 public void removeAddress(@NonNull InetAddress address, int prefixLen) throws IOException {
Benedict Wong97c3c942018-03-01 18:53:07 -0800812 try {
Nathan Harold65ef8432018-03-15 18:06:06 -0700813 mService.removeAddressFromTunnelInterface(
Benedict Wongd39837f2018-04-03 20:30:54 -0700814 mResourceId, new LinkAddress(address, prefixLen), mOpPackageName);
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700815 } catch (ServiceSpecificException e) {
816 throw rethrowCheckedExceptionFromServiceSpecificException(e);
Benedict Wong97c3c942018-03-01 18:53:07 -0800817 } catch (RemoteException e) {
818 throw e.rethrowFromSystemServer();
819 }
Nathan Harold67e76732018-01-17 16:09:24 -0800820 }
821
Yan Yana2f3b492020-09-29 23:38:00 -0700822 /**
823 * Update the underlying network for this IpSecTunnelInterface.
824 *
825 * <p>This new underlying network will be used for all transforms applied AFTER this call is
826 * complete. Before new {@link IpSecTransform}(s) with matching addresses are applied to
827 * this tunnel interface, traffic will still use the old SA, and be routed on the old
828 * underlying network.
829 *
830 * <p>To migrate IPsec tunnel mode traffic, a caller should:
831 *
832 * <ol>
833 * <li>Update the IpSecTunnelInterface’s underlying network.
834 * <li>Apply {@link IpSecTransform}(s) with matching addresses to this
835 * IpSecTunnelInterface.
836 * </ol>
837 *
838 * @param underlyingNetwork the new {@link Network} that will carry traffic for this tunnel.
Yan Yanbe3eb3d2022-05-16 17:13:45 -0700839 * This network MUST be a functional {@link Network} with valid {@link LinkProperties},
840 * and MUST never be the network exposing this IpSecTunnelInterface, otherwise this
841 * method will throw an {@link IllegalArgumentException}. If the IpSecTunnelInterface is
842 * later added to this network, all outbound traffic will be blackholed.
Yan Yana2f3b492020-09-29 23:38:00 -0700843 */
844 // TODO: b/169171001 Update the documentation when transform migration is supported.
845 // The purpose of making updating network and applying transforms separate is to leave open
846 // the possibility to support lossless migration procedures. To do that, Android platform
847 // will need to support multiple inbound tunnel mode transforms, just like it can support
848 // multiple transport mode transforms.
849 @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
850 @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
851 public void setUnderlyingNetwork(@NonNull Network underlyingNetwork) throws IOException {
852 try {
853 mService.setNetworkForTunnelInterface(
854 mResourceId, underlyingNetwork, mOpPackageName);
855 } catch (RemoteException e) {
856 throw e.rethrowFromSystemServer();
857 }
858 }
859
Nathan Harold65ef8432018-03-15 18:06:06 -0700860 private IpSecTunnelInterface(@NonNull Context ctx, @NonNull IIpSecService service,
Nathan Harold67e76732018-01-17 16:09:24 -0800861 @NonNull InetAddress localAddress, @NonNull InetAddress remoteAddress,
862 @NonNull Network underlyingNetwork)
863 throws ResourceUnavailableException, IOException {
Nathan Harold65ef8432018-03-15 18:06:06 -0700864 mOpPackageName = ctx.getOpPackageName();
Nathan Harold67e76732018-01-17 16:09:24 -0800865 mService = service;
866 mLocalAddress = localAddress;
867 mRemoteAddress = remoteAddress;
868 mUnderlyingNetwork = underlyingNetwork;
Benedict Wong8bc90732018-01-18 18:31:45 -0800869
870 try {
871 IpSecTunnelInterfaceResponse result =
872 mService.createTunnelInterface(
873 localAddress.getHostAddress(),
874 remoteAddress.getHostAddress(),
875 underlyingNetwork,
Nathan Harold65ef8432018-03-15 18:06:06 -0700876 new Binder(),
877 mOpPackageName);
Benedict Wong8bc90732018-01-18 18:31:45 -0800878 switch (result.status) {
879 case Status.OK:
880 break;
881 case Status.RESOURCE_UNAVAILABLE:
882 throw new ResourceUnavailableException(
883 "No more tunnel interfaces may be allocated by this requester.");
884 default:
885 throw new RuntimeException(
886 "Unknown status returned by IpSecService: " + result.status);
887 }
888 mResourceId = result.resourceId;
889 mInterfaceName = result.interfaceName;
890 } catch (RemoteException e) {
891 throw e.rethrowFromSystemServer();
892 }
Maciej Żenczykowski223b5cc2023-01-07 00:59:44 +0000893 mCloseGuard.open("close");
Nathan Harold67e76732018-01-17 16:09:24 -0800894 }
895
896 /**
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000897 * Delete an IpSecTunnelInterface
Nathan Harold67e76732018-01-17 16:09:24 -0800898 *
899 * <p>Calling close will deallocate the IpSecTunnelInterface and all of its system
900 * resources. Any packets bound for this interface either inbound or outbound will
901 * all be lost.
902 */
903 @Override
904 public void close() {
Benedict Wong8bc90732018-01-18 18:31:45 -0800905 try {
Nathan Harold65ef8432018-03-15 18:06:06 -0700906 mService.deleteTunnelInterface(mResourceId, mOpPackageName);
Benedict Wong8bc90732018-01-18 18:31:45 -0800907 } catch (RemoteException e) {
908 throw e.rethrowFromSystemServer();
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700909 } catch (Exception e) {
910 // On close we swallow all random exceptions since failure to close is not
911 // actionable by the user.
912 Log.e(TAG, "Failed to close " + this + ", Exception=" + e);
913 } finally {
914 mResourceId = INVALID_RESOURCE_ID;
915 mCloseGuard.close();
Benedict Wong8bc90732018-01-18 18:31:45 -0800916 }
Nathan Harold67e76732018-01-17 16:09:24 -0800917 }
918
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000919 /** Check that the Interface was closed properly. */
Nathan Harold67e76732018-01-17 16:09:24 -0800920 @Override
921 protected void finalize() throws Throwable {
922 if (mCloseGuard != null) {
923 mCloseGuard.warnIfOpen();
924 }
925 close();
926 }
Benedict Wong8bc90732018-01-18 18:31:45 -0800927
928 /** @hide */
929 @VisibleForTesting
930 public int getResourceId() {
931 return mResourceId;
932 }
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700933
Aurimas Liutikas3a78d9d2019-08-28 13:01:05 -0700934 @NonNull
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700935 @Override
936 public String toString() {
937 return new StringBuilder()
938 .append("IpSecTunnelInterface{ifname=")
939 .append(mInterfaceName)
940 .append(",resourceId=")
941 .append(mResourceId)
942 .append("}")
943 .toString();
944 }
Nathan Harold67e76732018-01-17 16:09:24 -0800945 }
946
947 /**
948 * Create a new IpSecTunnelInterface as a local endpoint for tunneled IPsec traffic.
949 *
Benedict Wong8bc90732018-01-18 18:31:45 -0800950 * <p>An application that creates tunnels is responsible for cleaning up the tunnel when the
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000951 * underlying network goes away, and the onLost() callback is received.
Benedict Wong8bc90732018-01-18 18:31:45 -0800952 *
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000953 * @param localAddress The local addres of the tunnel
954 * @param remoteAddress The local addres of the tunnel
955 * @param underlyingNetwork the {@link Network} that will carry traffic for this tunnel.
956 * This network should almost certainly be a network such as WiFi with an L2 address.
957 * @return a new {@link IpSecManager#IpSecTunnelInterface} with the specified properties
958 * @throws IOException indicating that the socket could not be opened or bound
959 * @throws ResourceUnavailableException indicating that too many encapsulation sockets are open
Yan Yan160aac32020-12-03 17:08:29 -0800960 * @hide
Yan Yan160aac32020-12-03 17:08:29 -0800961 */
Nathan Harold3a287d52018-04-25 12:01:34 -0700962 @SystemApi
Nathan Harold6303d9e2018-03-16 17:27:30 -0700963 @NonNull
Benedict Wonge9763752018-11-08 19:45:34 -0800964 @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
Nathan Harold00e77242018-03-21 15:32:42 -0700965 @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
Nathan Harold67e76732018-01-17 16:09:24 -0800966 public IpSecTunnelInterface createIpSecTunnelInterface(@NonNull InetAddress localAddress,
967 @NonNull InetAddress remoteAddress, @NonNull Network underlyingNetwork)
968 throws ResourceUnavailableException, IOException {
Nathan Haroldbeed0b62018-04-03 16:13:19 -0700969 try {
970 return new IpSecTunnelInterface(
971 mContext, mService, localAddress, remoteAddress, underlyingNetwork);
972 } catch (ServiceSpecificException e) {
973 throw rethrowCheckedExceptionFromServiceSpecificException(e);
974 }
Nathan Harold67e76732018-01-17 16:09:24 -0800975 }
976
977 /**
Nathan Harolde3536f02018-03-06 13:22:22 -0800978 * Apply an active Tunnel Mode IPsec Transform to a {@link IpSecTunnelInterface}, which will
979 * tunnel all traffic for the given direction through the underlying network's interface with
980 * IPsec (applies an outer IP header and IPsec Header to all traffic, and expects an additional
981 * IP header and IPsec Header on all inbound traffic).
982 * <p>Applications should probably not use this API directly.
983 *
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000984 * @param tunnel The {@link IpSecManager#IpSecTunnelInterface} that will use the supplied
Nathan Harold67e76732018-01-17 16:09:24 -0800985 * transform.
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000986 * @param direction the direction, {@link DIRECTION_OUT} or {@link #DIRECTION_IN} in which
Nathan Harold67e76732018-01-17 16:09:24 -0800987 * the transform will be used.
988 * @param transform an {@link IpSecTransform} created in tunnel mode
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000989 * @throws IOException indicating that the transform could not be applied due to a lower
990 * layer failure.
991 * @hide
Nathan Harold67e76732018-01-17 16:09:24 -0800992 */
Lorenzo Colitti388f4162021-02-01 08:12:34 +0000993 @SystemApi
Benedict Wonge9763752018-11-08 19:45:34 -0800994 @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
Nathan Harold00e77242018-03-21 15:32:42 -0700995 @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
Nathan Harold6303d9e2018-03-16 17:27:30 -0700996 public void applyTunnelModeTransform(@NonNull IpSecTunnelInterface tunnel,
997 @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException {
Benedict Wong8bc90732018-01-18 18:31:45 -0800998 try {
999 mService.applyTunnelModeTransform(
Nathan Harold65ef8432018-03-15 18:06:06 -07001000 tunnel.getResourceId(), direction,
1001 transform.getResourceId(), mContext.getOpPackageName());
Nathan Haroldbeed0b62018-04-03 16:13:19 -07001002 } catch (ServiceSpecificException e) {
1003 throw rethrowCheckedExceptionFromServiceSpecificException(e);
Benedict Wong8bc90732018-01-18 18:31:45 -08001004 } catch (RemoteException e) {
1005 throw e.rethrowFromSystemServer();
1006 }
Nathan Harold67e76732018-01-17 16:09:24 -08001007 }
Nathan Harolde3536f02018-03-06 13:22:22 -08001008
Nathan Harold67e76732018-01-17 16:09:24 -08001009 /**
Yan Yane114b382021-02-16 16:29:48 -08001010 * Migrate an active Tunnel Mode IPsec Transform to new source/destination addresses.
1011 *
1012 * <p>Begins the process of migrating a transform and cache the new addresses. To complete the
1013 * migration once started, callers MUST apply the same transform to the appropriate tunnel using
1014 * {@link IpSecManager#applyTunnelModeTransform}. Otherwise, the address update will not be
1015 * committed and the transform will still only process traffic between the current source and
1016 * destination address. One common use case is that the control plane will start the migration
1017 * process and then hand off the transform to the IPsec caller to perform the actual migration
1018 * when the tunnel is ready.
1019 *
1020 * <p>If this method is called multiple times before {@link
1021 * IpSecManager#applyTunnelModeTransform} is called, when the transform is applied, it will be
1022 * migrated to the addresses from the last call.
1023 *
1024 * <p>The provided source and destination addresses MUST share the same address family, but they
1025 * can have a different family from the current addresses.
1026 *
1027 * <p>Transform migration is only supported for tunnel mode transforms. Calling this method on
1028 * other types of transforms will throw an {@code UnsupportedOperationException}.
1029 *
1030 * @see IpSecTunnelInterface#setUnderlyingNetwork
1031 * @param transform a tunnel mode {@link IpSecTransform}
1032 * @param newSourceAddress the new source address
1033 * @param newDestinationAddress the new destination address
1034 * @hide
1035 */
Yan Yana48dcd92022-10-18 00:03:20 +00001036 @RequiresFeature(FEATURE_IPSEC_TUNNEL_MIGRATION)
Yan Yane114b382021-02-16 16:29:48 -08001037 @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
1038 public void startMigration(
1039 @NonNull IpSecTransform transform,
1040 @NonNull InetAddress newSourceAddress,
1041 @NonNull InetAddress newDestinationAddress) {
1042 if (!SdkLevel.isAtLeastU()) {
1043 throw new UnsupportedOperationException(
1044 "Transform migration only supported for Android 14+");
1045 }
1046
1047 Objects.requireNonNull(transform, "transform was null");
1048 Objects.requireNonNull(newSourceAddress, "newSourceAddress was null");
1049 Objects.requireNonNull(newDestinationAddress, "newDestinationAddress was null");
1050
1051 try {
1052 mService.migrateTransform(
1053 transform.getResourceId(),
1054 newSourceAddress.getHostAddress(),
1055 newDestinationAddress.getHostAddress(),
1056 mContext.getOpPackageName());
1057 } catch (RemoteException e) {
1058 throw e.rethrowFromSystemServer();
1059 }
1060 }
1061
1062 /**
Aaron Huang80a73fd2021-12-28 02:33:53 +08001063 * @hide
1064 */
1065 public IpSecTransformResponse createTransform(IpSecConfig config, IBinder binder,
1066 String callingPackage) {
1067 try {
1068 return mService.createTransform(config, binder, callingPackage);
1069 } catch (RemoteException e) {
1070 throw e.rethrowFromSystemServer();
1071 }
1072 }
1073
1074 /**
1075 * @hide
1076 */
1077 public void deleteTransform(int resourceId) {
1078 try {
1079 mService.deleteTransform(resourceId);
1080 } catch (RemoteException e) {
1081 throw e.rethrowFromSystemServer();
1082 }
1083 }
1084
1085 /**
Jonathan Basseri2725a232017-04-21 15:53:51 -07001086 * Construct an instance of IpSecManager within an application context.
Nathan Haroldb1f605f2017-01-12 18:38:57 -08001087 *
1088 * @param context the application context for this manager
1089 * @hide
1090 */
Nathan Harold65ef8432018-03-15 18:06:06 -07001091 public IpSecManager(Context ctx, IIpSecService service) {
1092 mContext = ctx;
Aaron Huang49eef6f2021-12-22 16:35:13 +08001093 mService = Objects.requireNonNull(service, "missing service");
Nathan Haroldb1f605f2017-01-12 18:38:57 -08001094 }
Nathan Haroldbeed0b62018-04-03 16:13:19 -07001095
1096 private static void maybeHandleServiceSpecificException(ServiceSpecificException sse) {
1097 // OsConstants are late binding, so switch statements can't be used.
1098 if (sse.errorCode == OsConstants.EINVAL) {
1099 throw new IllegalArgumentException(sse);
1100 } else if (sse.errorCode == OsConstants.EAGAIN) {
1101 throw new IllegalStateException(sse);
Benedict Wongc45974b2018-07-16 14:56:20 -07001102 } else if (sse.errorCode == OsConstants.EOPNOTSUPP
1103 || sse.errorCode == OsConstants.EPROTONOSUPPORT) {
Nathan Haroldbeed0b62018-04-03 16:13:19 -07001104 throw new UnsupportedOperationException(sse);
1105 }
1106 }
1107
1108 /**
1109 * Convert an Errno SSE to the correct Unchecked exception type.
1110 *
1111 * This method never actually returns.
1112 */
1113 // package
1114 static RuntimeException
1115 rethrowUncheckedExceptionFromServiceSpecificException(ServiceSpecificException sse) {
1116 maybeHandleServiceSpecificException(sse);
1117 throw new RuntimeException(sse);
1118 }
1119
1120 /**
1121 * Convert an Errno SSE to the correct Checked or Unchecked exception type.
1122 *
1123 * This method may throw IOException, or it may throw an unchecked exception; it will never
1124 * actually return.
1125 */
1126 // package
1127 static IOException rethrowCheckedExceptionFromServiceSpecificException(
1128 ServiceSpecificException sse) throws IOException {
1129 // First see if this is an unchecked exception of a type we know.
1130 // If so, then we prefer the unchecked (specific) type of exception.
1131 maybeHandleServiceSpecificException(sse);
1132 // If not, then all we can do is provide the SSE in the form of an IOException.
1133 throw new ErrnoException(
1134 "IpSec encountered errno=" + sse.errorCode, sse.errorCode).rethrowAsIOException();
1135 }
Nathan Haroldb1f605f2017-01-12 18:38:57 -08001136}