blob: 44a0a4f3e18ea40e025b0fb30691c56357dc947b [file] [log] [blame]
Nathan Harold330e1082017-01-12 18:38:57 -08001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package android.net;
17
Nathan Harold93962f32017-03-07 13:23:36 -080018import static android.net.IpSecManager.INVALID_RESOURCE_ID;
Nathan Harold93962f32017-03-07 13:23:36 -080019
Nathan Haroldc43e89f2017-12-06 19:12:28 -080020import static com.android.internal.util.Preconditions.checkNotNull;
21
Nathan Harold330e1082017-01-12 18:38:57 -080022import android.annotation.IntDef;
Nathan Harold93962f32017-03-07 13:23:36 -080023import android.annotation.NonNull;
Benedict Wonge265d5f2018-11-08 19:45:34 -080024import android.annotation.RequiresFeature;
Nathan Harold5a920ca2018-02-02 18:34:25 -080025import android.annotation.RequiresPermission;
Nathan Harold330e1082017-01-12 18:38:57 -080026import android.annotation.SystemApi;
27import android.content.Context;
Benedict Wonge265d5f2018-11-08 19:45:34 -080028import android.content.pm.PackageManager;
Nathan Harold93962f32017-03-07 13:23:36 -080029import android.os.Binder;
Nathan Haroldc43e89f2017-12-06 19:12:28 -080030import android.os.Handler;
Nathan Harold93962f32017-03-07 13:23:36 -080031import android.os.IBinder;
32import android.os.RemoteException;
33import android.os.ServiceManager;
Nathan Haroldddeb90a2018-04-03 16:13:19 -070034import android.os.ServiceSpecificException;
Nathan Harold330e1082017-01-12 18:38:57 -080035import android.util.Log;
Nathan Haroldd999d222017-09-11 19:53:33 -070036
ludi1a06aa72017-05-12 09:15:00 -070037import com.android.internal.annotations.VisibleForTesting;
Nathan Harold93962f32017-03-07 13:23:36 -080038import com.android.internal.util.Preconditions;
Nathan Haroldd999d222017-09-11 19:53:33 -070039
Nathan Harold330e1082017-01-12 18:38:57 -080040import dalvik.system.CloseGuard;
Nathan Haroldd999d222017-09-11 19:53:33 -070041
Nathan Harold330e1082017-01-12 18:38:57 -080042import java.io.IOException;
43import java.lang.annotation.Retention;
44import java.lang.annotation.RetentionPolicy;
45import java.net.InetAddress;
46
47/**
Nathan Harolda2523312018-01-05 19:25:13 -080048 * This class represents a transform, which roughly corresponds to an IPsec Security Association.
Nathan Harold330e1082017-01-12 18:38:57 -080049 *
Jonathan Basseric61b70d2017-04-21 15:53:51 -070050 * <p>Transforms are created using {@link IpSecTransform.Builder}. Each {@code IpSecTransform}
Nathan Harolda2523312018-01-05 19:25:13 -080051 * object encapsulates the properties and state of an IPsec security association. That includes,
52 * but is not limited to, algorithm choice, key material, and allocated system resources.
Nathan Harold330e1082017-01-12 18:38:57 -080053 *
Jonathan Basseric61b70d2017-04-21 15:53:51 -070054 * @see <a href="https://tools.ietf.org/html/rfc4301">RFC 4301, Security Architecture for the
Jonathan Basseri5fb92902017-11-16 10:58:01 -080055 * Internet Protocol</a>
Nathan Harold330e1082017-01-12 18:38:57 -080056 */
57public final class IpSecTransform implements AutoCloseable {
58 private static final String TAG = "IpSecTransform";
59
Nathan Harold330e1082017-01-12 18:38:57 -080060 /** @hide */
Nathan Harolda10003d2017-08-23 13:46:33 -070061 public static final int MODE_TRANSPORT = 0;
Nathan Harold330e1082017-01-12 18:38:57 -080062
63 /** @hide */
Nathan Harolda10003d2017-08-23 13:46:33 -070064 public static final int MODE_TUNNEL = 1;
Nathan Harold330e1082017-01-12 18:38:57 -080065
66 /** @hide */
67 public static final int ENCAP_NONE = 0;
68
69 /**
Jonathan Basseric61b70d2017-04-21 15:53:51 -070070 * IPsec traffic will be encapsulated within UDP, but with 8 zero-value bytes between the UDP
71 * header and payload. This prevents traffic from being interpreted as ESP or IKEv2.
Nathan Harold330e1082017-01-12 18:38:57 -080072 *
73 * @hide
74 */
Nathan Harold8dc1fd02017-04-04 19:37:48 -070075 public static final int ENCAP_ESPINUDP_NON_IKE = 1;
76
77 /**
Jonathan Basseric61b70d2017-04-21 15:53:51 -070078 * IPsec traffic will be encapsulated within UDP as per
79 * <a href="https://tools.ietf.org/html/rfc3948">RFC 3498</a>.
Nathan Harold8dc1fd02017-04-04 19:37:48 -070080 *
81 * @hide
82 */
83 public static final int ENCAP_ESPINUDP = 2;
Nathan Harold330e1082017-01-12 18:38:57 -080084
85 /** @hide */
Nathan Harold8dc1fd02017-04-04 19:37:48 -070086 @IntDef(value = {ENCAP_NONE, ENCAP_ESPINUDP, ENCAP_ESPINUDP_NON_IKE})
Nathan Harold330e1082017-01-12 18:38:57 -080087 @Retention(RetentionPolicy.SOURCE)
88 public @interface EncapType {}
89
Benedict Wong9dd3a382018-02-06 20:43:21 -080090 /** @hide */
91 @VisibleForTesting
92 public IpSecTransform(Context context, IpSecConfig config) {
Nathan Harold330e1082017-01-12 18:38:57 -080093 mContext = context;
Benedict Wong9dd3a382018-02-06 20:43:21 -080094 mConfig = new IpSecConfig(config);
Nathan Harold93962f32017-03-07 13:23:36 -080095 mResourceId = INVALID_RESOURCE_ID;
96 }
97
98 private IIpSecService getIpSecService() {
99 IBinder b = ServiceManager.getService(android.content.Context.IPSEC_SERVICE);
100 if (b == null) {
101 throw new RemoteException("Failed to connect to IpSecService")
102 .rethrowAsRuntimeException();
103 }
104
105 return IIpSecService.Stub.asInterface(b);
106 }
107
Nathan Harolda10003d2017-08-23 13:46:33 -0700108 /**
Jonathan Basseri5fb92902017-11-16 10:58:01 -0800109 * Checks the result status and throws an appropriate exception if the status is not Status.OK.
Nathan Harolda10003d2017-08-23 13:46:33 -0700110 */
111 private void checkResultStatus(int status)
Nathan Harold93962f32017-03-07 13:23:36 -0800112 throws IOException, IpSecManager.ResourceUnavailableException,
113 IpSecManager.SpiUnavailableException {
114 switch (status) {
115 case IpSecManager.Status.OK:
116 return;
117 // TODO: Pass Error string back from bundle so that errors can be more specific
118 case IpSecManager.Status.RESOURCE_UNAVAILABLE:
119 throw new IpSecManager.ResourceUnavailableException(
120 "Failed to allocate a new IpSecTransform");
121 case IpSecManager.Status.SPI_UNAVAILABLE:
122 Log.wtf(TAG, "Attempting to use an SPI that was somehow not reserved");
123 // Fall through
124 default:
125 throw new IllegalStateException(
126 "Failed to Create a Transform with status code " + status);
127 }
Nathan Harold330e1082017-01-12 18:38:57 -0800128 }
129
130 private IpSecTransform activate()
131 throws IOException, IpSecManager.ResourceUnavailableException,
132 IpSecManager.SpiUnavailableException {
Nathan Harold330e1082017-01-12 18:38:57 -0800133 synchronized (this) {
Nathan Harold93962f32017-03-07 13:23:36 -0800134 try {
135 IIpSecService svc = getIpSecService();
Nathan Harold592dadb2018-03-15 18:06:06 -0700136 IpSecTransformResponse result = svc.createTransform(
137 mConfig, new Binder(), mContext.getOpPackageName());
Nathan Harold8dc1fd02017-04-04 19:37:48 -0700138 int status = result.status;
Nathan Harolda10003d2017-08-23 13:46:33 -0700139 checkResultStatus(status);
Nathan Harold8dc1fd02017-04-04 19:37:48 -0700140 mResourceId = result.resourceId;
Nathan Harold93962f32017-03-07 13:23:36 -0800141 Log.d(TAG, "Added Transform with Id " + mResourceId);
142 mCloseGuard.open("build");
Nathan Haroldddeb90a2018-04-03 16:13:19 -0700143 } catch (ServiceSpecificException e) {
144 throw IpSecManager.rethrowUncheckedExceptionFromServiceSpecificException(e);
Nathan Harold93962f32017-03-07 13:23:36 -0800145 } catch (RemoteException e) {
146 throw e.rethrowAsRuntimeException();
Nathan Harold330e1082017-01-12 18:38:57 -0800147 }
Nathan Harold330e1082017-01-12 18:38:57 -0800148 }
Nathan Harold330e1082017-01-12 18:38:57 -0800149
150 return this;
151 }
152
153 /**
Chalard Jean9c0ff1b2019-05-30 17:11:14 +0900154 * Standard equals.
Benedict Wong9dd3a382018-02-06 20:43:21 -0800155 */
Chalard Jean9c0ff1b2019-05-30 17:11:14 +0900156 public boolean equals(Object other) {
157 if (this == other) return true;
158 if (!(other instanceof IpSecTransform)) return false;
159 final IpSecTransform rhs = (IpSecTransform) other;
160 return getConfig().equals(rhs.getConfig()) && mResourceId == rhs.mResourceId;
Benedict Wong9dd3a382018-02-06 20:43:21 -0800161 }
162
163 /**
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700164 * Deactivate this {@code IpSecTransform} and free allocated resources.
Nathan Harold330e1082017-01-12 18:38:57 -0800165 *
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700166 * <p>Deactivating a transform while it is still applied to a socket will result in errors on
167 * that socket. Make sure to remove transforms by calling {@link
Nathan Harolda2523312018-01-05 19:25:13 -0800168 * IpSecManager#removeTransportModeTransforms}. Note, removing an {@code IpSecTransform} from a
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700169 * socket will not deactivate it (because one transform may be applied to multiple sockets).
170 *
171 * <p>It is safe to call this method on a transform that has already been deactivated.
Nathan Harold330e1082017-01-12 18:38:57 -0800172 */
173 public void close() {
Nathan Harold93962f32017-03-07 13:23:36 -0800174 Log.d(TAG, "Removing Transform with Id " + mResourceId);
Nathan Harold330e1082017-01-12 18:38:57 -0800175
176 // Always safe to attempt cleanup
Nathan Harold93962f32017-03-07 13:23:36 -0800177 if (mResourceId == INVALID_RESOURCE_ID) {
178 mCloseGuard.close();
Nathan Harold330e1082017-01-12 18:38:57 -0800179 return;
180 }
Nathan Harold93962f32017-03-07 13:23:36 -0800181 try {
Nathan Harold93962f32017-03-07 13:23:36 -0800182 IIpSecService svc = getIpSecService();
Benedict Wongf33f03132018-01-18 14:38:16 -0800183 svc.deleteTransform(mResourceId);
Nathan Haroldc43e89f2017-12-06 19:12:28 -0800184 stopNattKeepalive();
Nathan Harold93962f32017-03-07 13:23:36 -0800185 } catch (RemoteException e) {
186 throw e.rethrowAsRuntimeException();
Nathan Haroldddeb90a2018-04-03 16:13:19 -0700187 } catch (Exception e) {
188 // On close we swallow all random exceptions since failure to close is not
189 // actionable by the user.
190 Log.e(TAG, "Failed to close " + this + ", Exception=" + e);
Nathan Harold93962f32017-03-07 13:23:36 -0800191 } finally {
192 mResourceId = INVALID_RESOURCE_ID;
193 mCloseGuard.close();
194 }
Nathan Harold330e1082017-01-12 18:38:57 -0800195 }
196
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700197 /** Check that the transform was closed properly. */
Nathan Harold330e1082017-01-12 18:38:57 -0800198 @Override
199 protected void finalize() throws Throwable {
200 if (mCloseGuard != null) {
201 mCloseGuard.warnIfOpen();
202 }
203 close();
204 }
205
206 /* Package */
207 IpSecConfig getConfig() {
208 return mConfig;
209 }
210
211 private final IpSecConfig mConfig;
Nathan Harold93962f32017-03-07 13:23:36 -0800212 private int mResourceId;
Nathan Harold330e1082017-01-12 18:38:57 -0800213 private final Context mContext;
214 private final CloseGuard mCloseGuard = CloseGuard.get();
215 private ConnectivityManager.PacketKeepalive mKeepalive;
Nathan Haroldc43e89f2017-12-06 19:12:28 -0800216 private Handler mCallbackHandler;
217 private final ConnectivityManager.PacketKeepaliveCallback mKeepaliveCallback =
Nathan Harold330e1082017-01-12 18:38:57 -0800218 new ConnectivityManager.PacketKeepaliveCallback() {
219
220 @Override
221 public void onStarted() {
Nathan Haroldc43e89f2017-12-06 19:12:28 -0800222 synchronized (this) {
223 mCallbackHandler.post(() -> mUserKeepaliveCallback.onStarted());
Nathan Harold330e1082017-01-12 18:38:57 -0800224 }
225 }
226
227 @Override
228 public void onStopped() {
Nathan Haroldc43e89f2017-12-06 19:12:28 -0800229 synchronized (this) {
230 mKeepalive = null;
231 mCallbackHandler.post(() -> mUserKeepaliveCallback.onStopped());
Nathan Harold330e1082017-01-12 18:38:57 -0800232 }
233 }
234
235 @Override
236 public void onError(int error) {
Nathan Haroldc43e89f2017-12-06 19:12:28 -0800237 synchronized (this) {
238 mKeepalive = null;
239 mCallbackHandler.post(() -> mUserKeepaliveCallback.onError(error));
Nathan Harold330e1082017-01-12 18:38:57 -0800240 }
241 }
242 };
243
Nathan Haroldc43e89f2017-12-06 19:12:28 -0800244 private NattKeepaliveCallback mUserKeepaliveCallback;
Nathan Harold330e1082017-01-12 18:38:57 -0800245
Nathan Harolda10003d2017-08-23 13:46:33 -0700246 /** @hide */
247 @VisibleForTesting
248 public int getResourceId() {
Nathan Harold93962f32017-03-07 13:23:36 -0800249 return mResourceId;
250 }
251
Nathan Haroldc43e89f2017-12-06 19:12:28 -0800252 /**
253 * A callback class to provide status information regarding a NAT-T keepalive session
254 *
255 * <p>Use this callback to receive status information regarding a NAT-T keepalive session
256 * by registering it when calling {@link #startNattKeepalive}.
257 *
258 * @hide
259 */
Nathan Haroldc43e89f2017-12-06 19:12:28 -0800260 public static class NattKeepaliveCallback {
261 /** The specified {@code Network} is not connected. */
262 public static final int ERROR_INVALID_NETWORK = 1;
263 /** The hardware does not support this request. */
264 public static final int ERROR_HARDWARE_UNSUPPORTED = 2;
265 /** The hardware returned an error. */
266 public static final int ERROR_HARDWARE_ERROR = 3;
267
268 /** The requested keepalive was successfully started. */
269 public void onStarted() {}
270 /** The keepalive was successfully stopped. */
271 public void onStopped() {}
272 /** An error occurred. */
273 public void onError(int error) {}
274 }
275
276 /**
277 * Start a NAT-T keepalive session for the current transform.
278 *
279 * For a transform that is using UDP encapsulated IPv4, NAT-T offloading provides
280 * a power efficient mechanism of sending NAT-T packets at a specified interval.
281 *
282 * @param userCallback a {@link #NattKeepaliveCallback} to receive asynchronous status
283 * information about the requested NAT-T keepalive session.
284 * @param intervalSeconds the interval between NAT-T keepalives being sent. The
285 * the allowed range is between 20 and 3600 seconds.
286 * @param handler a handler on which to post callbacks when received.
287 *
288 * @hide
289 */
Nathan Harold5a920ca2018-02-02 18:34:25 -0800290 @RequiresPermission(anyOf = {
Nathan Harold15978842018-03-21 15:32:42 -0700291 android.Manifest.permission.MANAGE_IPSEC_TUNNELS,
Nathan Harold5a920ca2018-02-02 18:34:25 -0800292 android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD
293 })
Nathan Haroldc43e89f2017-12-06 19:12:28 -0800294 public void startNattKeepalive(@NonNull NattKeepaliveCallback userCallback,
295 int intervalSeconds, @NonNull Handler handler) throws IOException {
296 checkNotNull(userCallback);
297 if (intervalSeconds < 20 || intervalSeconds > 3600) {
298 throw new IllegalArgumentException("Invalid NAT-T keepalive interval");
299 }
300 checkNotNull(handler);
301 if (mResourceId == INVALID_RESOURCE_ID) {
302 throw new IllegalStateException(
303 "Packet keepalive cannot be started for an inactive transform");
304 }
305
306 synchronized (mKeepaliveCallback) {
307 if (mKeepaliveCallback != null) {
308 throw new IllegalStateException("Keepalive already active");
309 }
310
311 mUserKeepaliveCallback = userCallback;
312 ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(
313 Context.CONNECTIVITY_SERVICE);
314 mKeepalive = cm.startNattKeepalive(
315 mConfig.getNetwork(), intervalSeconds, mKeepaliveCallback,
316 NetworkUtils.numericToInetAddress(mConfig.getSourceAddress()),
317 4500, // FIXME urgently, we need to get the port number from the Encap socket
318 NetworkUtils.numericToInetAddress(mConfig.getDestinationAddress()));
319 mCallbackHandler = handler;
320 }
321 }
322
323 /**
324 * Stop an ongoing NAT-T keepalive session.
325 *
326 * Calling this API will request that an ongoing NAT-T keepalive session be terminated.
327 * If this API is not called when a Transform is closed, the underlying NAT-T session will
328 * be terminated automatically.
329 *
330 * @hide
331 */
Nathan Harold5a920ca2018-02-02 18:34:25 -0800332 @RequiresPermission(anyOf = {
Nathan Harold15978842018-03-21 15:32:42 -0700333 android.Manifest.permission.MANAGE_IPSEC_TUNNELS,
Nathan Harold5a920ca2018-02-02 18:34:25 -0800334 android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD
335 })
Nathan Haroldc43e89f2017-12-06 19:12:28 -0800336 public void stopNattKeepalive() {
337 synchronized (mKeepaliveCallback) {
338 if (mKeepalive == null) {
339 Log.e(TAG, "No active keepalive to stop");
340 return;
341 }
342 mKeepalive.stop();
343 }
Nathan Harold330e1082017-01-12 18:38:57 -0800344 }
345
Jonathan Basseri5fb92902017-11-16 10:58:01 -0800346 /** This class is used to build {@link IpSecTransform} objects. */
Nathan Harold330e1082017-01-12 18:38:57 -0800347 public static class Builder {
348 private Context mContext;
349 private IpSecConfig mConfig;
350
351 /**
Nathan Harolda2523312018-01-05 19:25:13 -0800352 * Set the encryption algorithm.
Nathan Harold330e1082017-01-12 18:38:57 -0800353 *
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700354 * <p>Encryption is mutually exclusive with authenticated encryption.
Benedict Wong0febe5e2017-08-22 21:42:33 -0700355 *
Nathan Harold330e1082017-01-12 18:38:57 -0800356 * @param algo {@link IpSecAlgorithm} specifying the encryption to be applied.
357 */
Nathan Harold5cd64cc2018-03-16 17:27:30 -0700358 @NonNull
Nathan Harolda2523312018-01-05 19:25:13 -0800359 public IpSecTransform.Builder setEncryption(@NonNull IpSecAlgorithm algo) {
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700360 // TODO: throw IllegalArgumentException if algo is not an encryption algorithm.
Nathan Harolda2523312018-01-05 19:25:13 -0800361 Preconditions.checkNotNull(algo);
362 mConfig.setEncryption(algo);
Nathan Harold330e1082017-01-12 18:38:57 -0800363 return this;
364 }
365
366 /**
Nathan Harolda2523312018-01-05 19:25:13 -0800367 * Set the authentication (integrity) algorithm.
Nathan Harold330e1082017-01-12 18:38:57 -0800368 *
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700369 * <p>Authentication is mutually exclusive with authenticated encryption.
Benedict Wong0febe5e2017-08-22 21:42:33 -0700370 *
Nathan Harold330e1082017-01-12 18:38:57 -0800371 * @param algo {@link IpSecAlgorithm} specifying the authentication to be applied.
372 */
Nathan Harold5cd64cc2018-03-16 17:27:30 -0700373 @NonNull
Nathan Harolda2523312018-01-05 19:25:13 -0800374 public IpSecTransform.Builder setAuthentication(@NonNull IpSecAlgorithm algo) {
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700375 // TODO: throw IllegalArgumentException if algo is not an authentication algorithm.
Nathan Harolda2523312018-01-05 19:25:13 -0800376 Preconditions.checkNotNull(algo);
377 mConfig.setAuthentication(algo);
Nathan Harold330e1082017-01-12 18:38:57 -0800378 return this;
379 }
380
381 /**
Nathan Harolda2523312018-01-05 19:25:13 -0800382 * Set the authenticated encryption algorithm.
Benedict Wong0febe5e2017-08-22 21:42:33 -0700383 *
Nathan Harolda2523312018-01-05 19:25:13 -0800384 * <p>The Authenticated Encryption (AE) class of algorithms are also known as
385 * Authenticated Encryption with Associated Data (AEAD) algorithms, or Combined mode
386 * algorithms (as referred to in
387 * <a href="https://tools.ietf.org/html/rfc4301">RFC 4301</a>).
Benedict Wong0febe5e2017-08-22 21:42:33 -0700388 *
389 * <p>Authenticated encryption is mutually exclusive with encryption and authentication.
390 *
Benedict Wong0febe5e2017-08-22 21:42:33 -0700391 * @param algo {@link IpSecAlgorithm} specifying the authenticated encryption algorithm to
392 * be applied.
393 */
Nathan Harold5cd64cc2018-03-16 17:27:30 -0700394 @NonNull
Nathan Harolda2523312018-01-05 19:25:13 -0800395 public IpSecTransform.Builder setAuthenticatedEncryption(@NonNull IpSecAlgorithm algo) {
396 Preconditions.checkNotNull(algo);
397 mConfig.setAuthenticatedEncryption(algo);
Nathan Harold330e1082017-01-12 18:38:57 -0800398 return this;
399 }
400
401 /**
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700402 * Add UDP encapsulation to an IPv4 transform.
Nathan Harold330e1082017-01-12 18:38:57 -0800403 *
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700404 * <p>This allows IPsec traffic to pass through a NAT.
Nathan Harold330e1082017-01-12 18:38:57 -0800405 *
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700406 * @see <a href="https://tools.ietf.org/html/rfc3948">RFC 3948, UDP Encapsulation of IPsec
Jonathan Basseri5fb92902017-11-16 10:58:01 -0800407 * ESP Packets</a>
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700408 * @see <a href="https://tools.ietf.org/html/rfc7296#section-2.23">RFC 7296 section 2.23,
Jonathan Basseri5fb92902017-11-16 10:58:01 -0800409 * NAT Traversal of IKEv2</a>
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700410 * @param localSocket a socket for sending and receiving encapsulated traffic
411 * @param remotePort the UDP port number of the remote host that will send and receive
412 * encapsulated traffic. In the case of IKEv2, this should be port 4500.
Nathan Harold330e1082017-01-12 18:38:57 -0800413 */
Nathan Harold5cd64cc2018-03-16 17:27:30 -0700414 @NonNull
Nathan Harold330e1082017-01-12 18:38:57 -0800415 public IpSecTransform.Builder setIpv4Encapsulation(
Nathan Harolda2523312018-01-05 19:25:13 -0800416 @NonNull IpSecManager.UdpEncapsulationSocket localSocket, int remotePort) {
417 Preconditions.checkNotNull(localSocket);
Nathan Harolda10003d2017-08-23 13:46:33 -0700418 mConfig.setEncapType(ENCAP_ESPINUDP);
Nathan Harold6119d8d2017-12-13 18:51:35 -0800419 if (localSocket.getResourceId() == INVALID_RESOURCE_ID) {
420 throw new IllegalArgumentException("Invalid UdpEncapsulationSocket");
421 }
Nathan Harolda10003d2017-08-23 13:46:33 -0700422 mConfig.setEncapSocketResourceId(localSocket.getResourceId());
423 mConfig.setEncapRemotePort(remotePort);
Nathan Harold330e1082017-01-12 18:38:57 -0800424 return this;
425 }
426
Nathan Harold330e1082017-01-12 18:38:57 -0800427 /**
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700428 * Build a transport mode {@link IpSecTransform}.
Nathan Harold330e1082017-01-12 18:38:57 -0800429 *
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700430 * <p>This builds and activates a transport mode transform. Note that an active transform
431 * will not affect any network traffic until it has been applied to one or more sockets.
Nathan Harold330e1082017-01-12 18:38:57 -0800432 *
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700433 * @see IpSecManager#applyTransportModeTransform
Nathan Harolda2523312018-01-05 19:25:13 -0800434 * @param sourceAddress the source {@code InetAddress} of traffic on sockets that will use
435 * this transform; this address must belong to the Network used by all sockets that
436 * utilize this transform; if provided, then only traffic originating from the
437 * specified source address will be processed.
438 * @param spi a unique {@link IpSecManager.SecurityParameterIndex} to identify transformed
439 * traffic
Nathan Harold330e1082017-01-12 18:38:57 -0800440 * @throws IllegalArgumentException indicating that a particular combination of transform
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700441 * properties is invalid
Nathan Harolda2523312018-01-05 19:25:13 -0800442 * @throws IpSecManager.ResourceUnavailableException indicating that too many transforms
443 * are active
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700444 * @throws IpSecManager.SpiUnavailableException indicating the rare case where an SPI
445 * collides with an existing transform
446 * @throws IOException indicating other errors
Nathan Harold330e1082017-01-12 18:38:57 -0800447 */
Nathan Harold5cd64cc2018-03-16 17:27:30 -0700448 @NonNull
Nathan Harolda2523312018-01-05 19:25:13 -0800449 public IpSecTransform buildTransportModeTransform(
450 @NonNull InetAddress sourceAddress,
451 @NonNull IpSecManager.SecurityParameterIndex spi)
Nathan Harold330e1082017-01-12 18:38:57 -0800452 throws IpSecManager.ResourceUnavailableException,
453 IpSecManager.SpiUnavailableException, IOException {
Nathan Harolda2523312018-01-05 19:25:13 -0800454 Preconditions.checkNotNull(sourceAddress);
455 Preconditions.checkNotNull(spi);
456 if (spi.getResourceId() == INVALID_RESOURCE_ID) {
457 throw new IllegalArgumentException("Invalid SecurityParameterIndex");
Nathan Harold6119d8d2017-12-13 18:51:35 -0800458 }
Nathan Harolda10003d2017-08-23 13:46:33 -0700459 mConfig.setMode(MODE_TRANSPORT);
Nathan Harolda2523312018-01-05 19:25:13 -0800460 mConfig.setSourceAddress(sourceAddress.getHostAddress());
461 mConfig.setSpiResourceId(spi.getResourceId());
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700462 // FIXME: modifying a builder after calling build can change the built transform.
Nathan Harold330e1082017-01-12 18:38:57 -0800463 return new IpSecTransform(mContext, mConfig).activate();
464 }
465
466 /**
467 * Build and return an {@link IpSecTransform} object as a Tunnel Mode Transform. Some
468 * parameters have interdependencies that are checked at build time.
469 *
Nathan Harolda2523312018-01-05 19:25:13 -0800470 * @param sourceAddress the {@link InetAddress} that provides the source address for this
Nathan Harold330e1082017-01-12 18:38:57 -0800471 * IPsec tunnel. This is almost certainly an address belonging to the {@link Network}
472 * that will originate the traffic, which is set as the {@link #setUnderlyingNetwork}.
Nathan Harolda2523312018-01-05 19:25:13 -0800473 * @param spi a unique {@link IpSecManager.SecurityParameterIndex} to identify transformed
474 * traffic
Nathan Harold330e1082017-01-12 18:38:57 -0800475 * @throws IllegalArgumentException indicating that a particular combination of transform
476 * properties is invalid.
Nathan Harolda2523312018-01-05 19:25:13 -0800477 * @throws IpSecManager.ResourceUnavailableException indicating that too many transforms
478 * are active
479 * @throws IpSecManager.SpiUnavailableException indicating the rare case where an SPI
480 * collides with an existing transform
481 * @throws IOException indicating other errors
Nathan Harold330e1082017-01-12 18:38:57 -0800482 * @hide
483 */
Nathan Haroldc47eacc2018-01-17 16:09:24 -0800484 @SystemApi
Nathan Harold5cd64cc2018-03-16 17:27:30 -0700485 @NonNull
Benedict Wonge265d5f2018-11-08 19:45:34 -0800486 @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
Nathan Harold15978842018-03-21 15:32:42 -0700487 @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
Nathan Harold330e1082017-01-12 18:38:57 -0800488 public IpSecTransform buildTunnelModeTransform(
Nathan Harolda2523312018-01-05 19:25:13 -0800489 @NonNull InetAddress sourceAddress,
490 @NonNull IpSecManager.SecurityParameterIndex spi)
491 throws IpSecManager.ResourceUnavailableException,
492 IpSecManager.SpiUnavailableException, IOException {
493 Preconditions.checkNotNull(sourceAddress);
494 Preconditions.checkNotNull(spi);
495 if (spi.getResourceId() == INVALID_RESOURCE_ID) {
496 throw new IllegalArgumentException("Invalid SecurityParameterIndex");
Nathan Harold6119d8d2017-12-13 18:51:35 -0800497 }
Nathan Harolda10003d2017-08-23 13:46:33 -0700498 mConfig.setMode(MODE_TUNNEL);
Nathan Harolda2523312018-01-05 19:25:13 -0800499 mConfig.setSourceAddress(sourceAddress.getHostAddress());
500 mConfig.setSpiResourceId(spi.getResourceId());
Benedict Wongb8ef5412018-01-24 15:31:39 -0800501 return new IpSecTransform(mContext, mConfig).activate();
Nathan Harold330e1082017-01-12 18:38:57 -0800502 }
503
504 /**
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700505 * Create a new IpSecTransform.Builder.
Nathan Harold330e1082017-01-12 18:38:57 -0800506 *
Jonathan Basseric61b70d2017-04-21 15:53:51 -0700507 * @param context current context
Nathan Harold330e1082017-01-12 18:38:57 -0800508 */
Nathan Harold93962f32017-03-07 13:23:36 -0800509 public Builder(@NonNull Context context) {
510 Preconditions.checkNotNull(context);
Nathan Harold330e1082017-01-12 18:38:57 -0800511 mContext = context;
512 mConfig = new IpSecConfig();
513 }
Nathan Harold330e1082017-01-12 18:38:57 -0800514 }
Nathan Haroldddeb90a2018-04-03 16:13:19 -0700515
516 @Override
517 public String toString() {
518 return new StringBuilder()
519 .append("IpSecTransform{resourceId=")
520 .append(mResourceId)
521 .append("}")
522 .toString();
523 }
Nathan Harold330e1082017-01-12 18:38:57 -0800524}