1 /* 2 * Copyright (C) 2021 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 */ 16 17 package com.android.internal.net.ipsec.ike.net; 18 19 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; 20 import static android.net.NetworkCapabilities.TRANSPORT_WIFI; 21 import static android.net.ipsec.ike.IkeManager.getIkeLog; 22 import static android.net.ipsec.ike.IkeSessionParams.ESP_ENCAP_TYPE_NONE; 23 import static android.net.ipsec.ike.IkeSessionParams.ESP_ENCAP_TYPE_UDP; 24 import static android.net.ipsec.ike.IkeSessionParams.ESP_IP_VERSION_AUTO; 25 import static android.net.ipsec.ike.IkeSessionParams.ESP_IP_VERSION_IPV4; 26 import static android.net.ipsec.ike.IkeSessionParams.ESP_IP_VERSION_IPV6; 27 import static android.net.ipsec.ike.IkeSessionParams.IKE_NATT_KEEPALIVE_DELAY_SEC_MAX; 28 import static android.net.ipsec.ike.IkeSessionParams.IKE_NATT_KEEPALIVE_DELAY_SEC_MIN; 29 import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_AUTOMATIC_ADDRESS_FAMILY_SELECTION; 30 import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_AUTOMATIC_NATT_KEEPALIVES; 31 import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_FORCE_DNS_RESOLUTION; 32 import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_FORCE_PORT_4500; 33 import static android.net.ipsec.ike.exceptions.IkeException.wrapAsIkeException; 34 35 import static com.android.internal.net.ipsec.ike.IkeContext.CONFIG_AUTO_NATT_KEEPALIVES_CELLULAR_TIMEOUT_OVERRIDE_SECONDS; 36 import static com.android.internal.net.ipsec.ike.IkeContext.CONFIG_USE_CACHED_ADDRS; 37 import static com.android.internal.net.ipsec.ike.utils.IkeAlarm.IkeAlarmConfig; 38 import static com.android.internal.net.ipsec.ike.utils.IkeAlarmReceiver.ACTION_KEEPALIVE; 39 40 import android.annotation.IntDef; 41 import android.app.PendingIntent; 42 import android.net.ConnectivityManager; 43 import android.net.IpPrefix; 44 import android.net.IpSecManager; 45 import android.net.IpSecManager.ResourceUnavailableException; 46 import android.net.LinkAddress; 47 import android.net.LinkProperties; 48 import android.net.Network; 49 import android.net.NetworkCapabilities; 50 import android.net.NetworkRequest; 51 import android.net.ipsec.ike.IkeSessionConnectionInfo; 52 import android.net.ipsec.ike.IkeSessionParams; 53 import android.net.ipsec.ike.exceptions.IkeException; 54 import android.os.Handler; 55 import android.os.Message; 56 import android.system.ErrnoException; 57 import android.util.SparseArray; 58 59 import com.android.internal.annotations.VisibleForTesting; 60 import com.android.internal.net.ipsec.ike.IkeContext; 61 import com.android.internal.net.ipsec.ike.IkeSocket; 62 import com.android.internal.net.ipsec.ike.IkeSocketConfig; 63 import com.android.internal.net.ipsec.ike.IkeUdp4Socket; 64 import com.android.internal.net.ipsec.ike.IkeUdp6Socket; 65 import com.android.internal.net.ipsec.ike.IkeUdp6WithEncapPortSocket; 66 import com.android.internal.net.ipsec.ike.IkeUdpEncapSocket; 67 import com.android.internal.net.ipsec.ike.SaRecord.IkeSaRecord; 68 import com.android.internal.net.ipsec.ike.keepalive.IkeNattKeepalive; 69 import com.android.internal.net.ipsec.ike.keepalive.IkeNattKeepalive.KeepaliveConfig; 70 import com.android.internal.net.ipsec.ike.message.IkeHeader; 71 import com.android.internal.net.ipsec.ike.shim.ShimUtils; 72 import com.android.internal.net.ipsec.ike.utils.IkeAlarm; 73 import com.android.internal.net.ipsec.ike.utils.IkeMetrics; 74 75 import java.io.IOException; 76 import java.io.PrintWriter; 77 import java.lang.annotation.Retention; 78 import java.lang.annotation.RetentionPolicy; 79 import java.net.Inet4Address; 80 import java.net.Inet6Address; 81 import java.net.InetAddress; 82 import java.net.UnknownHostException; 83 import java.util.ArrayList; 84 import java.util.Arrays; 85 import java.util.Collections; 86 import java.util.HashSet; 87 import java.util.List; 88 import java.util.Objects; 89 import java.util.Set; 90 import java.util.concurrent.TimeUnit; 91 92 /** 93 * IkeConnectionController manages all connectivity events for an IKE Session 94 * 95 * <p>IkeConnectionController's responsibilities include: 96 * 97 * <ul> 98 * <li>Manage IkeSocket for sending and receiving IKE packets 99 * <li>Monitor and handle network and addresses changes 100 * <li>Schedule NAT-T keepalive 101 * </ul> 102 * 103 * An IkeConnectionController should be set up when IKE Session is being established and should be 104 * torn down when the IKE Session is terminated. 105 */ 106 public class IkeConnectionController implements IkeNetworkUpdater, IkeSocket.Callback { 107 private static final String TAG = IkeConnectionController.class.getSimpleName(); 108 109 // The maximum number of attempts allowed for a single DNS resolution. 110 private static final int MAX_DNS_RESOLUTION_ATTEMPTS = 3; 111 112 @VisibleForTesting public static final int AUTO_KEEPALIVE_DELAY_SEC_WIFI = 15; 113 @VisibleForTesting public static final int AUTO_KEEPALIVE_DELAY_SEC_CELL = 150; 114 115 @Retention(RetentionPolicy.SOURCE) 116 @IntDef({ 117 NAT_TRAVERSAL_SUPPORT_NOT_CHECKED, 118 NAT_TRAVERSAL_UNSUPPORTED, 119 NAT_NOT_DETECTED, 120 NAT_DETECTED 121 }) 122 public @interface NatStatus {} 123 124 /** The IKE client has not checked whether the server supports NAT-T */ 125 public static final int NAT_TRAVERSAL_SUPPORT_NOT_CHECKED = 0; 126 /** The IKE server does not support NAT-T */ 127 public static final int NAT_TRAVERSAL_UNSUPPORTED = 1; 128 /** There is no NAT between the IKE client and the server */ 129 public static final int NAT_NOT_DETECTED = 2; 130 /** There is at least a NAT between the IKE client and the server */ 131 public static final int NAT_DETECTED = 3; 132 133 private final IkeContext mIkeContext; 134 private final Config mConfig; 135 private final ConnectivityManager mConnectivityManager; 136 private final IpSecManager mIpSecManager; 137 private final Dependencies mDependencies; 138 private final IkeLocalAddressGenerator mIkeLocalAddressGenerator; 139 private final Callback mCallback; 140 141 private final boolean mForcePort4500; 142 private final boolean mUseCallerConfiguredNetwork; 143 private final String mRemoteHostname; 144 private final int mDscp; 145 private final IkeSessionParams mIkeParams; 146 // Must only be touched on the IkeSessionStateMachine thread. 147 private IkeAlarmConfig mKeepaliveAlarmConfig; 148 149 private IkeSocket mIkeSocket; 150 151 /** Underlying network for this IKE Session. May change if mobility handling is enabled. */ 152 private Network mNetwork; 153 154 /** NetworkCapabilities of the underlying network */ 155 private NetworkCapabilities mNc; 156 157 /** 158 * Network callback used to keep IkeConnectionController aware of network changes when mobility 159 * handling is enabled. 160 */ 161 private IkeNetworkCallbackBase mNetworkCallback; 162 163 private boolean mMobilityEnabled = false; 164 165 /** Local address assigned on device. */ 166 private InetAddress mLocalAddress; 167 /** Remote address resolved from caller configured hostname. */ 168 private InetAddress mRemoteAddress; 169 /** Available remote addresses that are v4. */ 170 private final List<Inet4Address> mRemoteAddressesV4 = new ArrayList<>(); 171 /** Available remote addresses that are v6. */ 172 private final List<Ipv6AddrInfo> mRemoteAddressesV6 = new ArrayList<>(); 173 174 private final Set<IkeSaRecord> mIkeSaRecords = new HashSet<>(); 175 176 @NatStatus private int mNatStatus; 177 178 // Must only be touched on the IkeSessionStateMachine thread. 179 @IkeSessionParams.EspIpVersion private int mIpVersion; 180 @IkeSessionParams.EspEncapType private int mEncapType; 181 182 //Must only be touched on the IkeSessionStateMachine thread. 183 private Network mUnderpinnedNetwork; 184 185 private int mKeepaliveDelaySeconds; 186 private IkeNattKeepalive mIkeNattKeepalive; 187 188 private static final SparseArray<String> NAT_STATUS_TO_STR; 189 190 static { 191 NAT_STATUS_TO_STR = new SparseArray<>(); NAT_STATUS_TO_STR.put( NAT_TRAVERSAL_SUPPORT_NOT_CHECKED, "NAT_TRAVERSAL_SUPPORT_NOT_CHECKED")192 NAT_STATUS_TO_STR.put( 193 NAT_TRAVERSAL_SUPPORT_NOT_CHECKED, "NAT_TRAVERSAL_SUPPORT_NOT_CHECKED"); NAT_STATUS_TO_STR.put(NAT_TRAVERSAL_UNSUPPORTED, "NAT_TRAVERSAL_UNSUPPORTED")194 NAT_STATUS_TO_STR.put(NAT_TRAVERSAL_UNSUPPORTED, "NAT_TRAVERSAL_UNSUPPORTED"); NAT_STATUS_TO_STR.put(NAT_NOT_DETECTED, "NAT_NOT_DETECTED")195 NAT_STATUS_TO_STR.put(NAT_NOT_DETECTED, "NAT_NOT_DETECTED"); NAT_STATUS_TO_STR.put(NAT_DETECTED, "NAT_DETECTED")196 NAT_STATUS_TO_STR.put(NAT_DETECTED, "NAT_DETECTED"); 197 } 198 199 /** Constructor of IkeConnectionController */ 200 @VisibleForTesting IkeConnectionController( IkeContext ikeContext, Config config, Dependencies dependencies)201 public IkeConnectionController( 202 IkeContext ikeContext, Config config, Dependencies dependencies) { 203 mIkeContext = ikeContext; 204 mConfig = config; 205 mConnectivityManager = mIkeContext.getContext().getSystemService(ConnectivityManager.class); 206 mIpSecManager = mIkeContext.getContext().getSystemService(IpSecManager.class); 207 mDependencies = dependencies; 208 mIkeLocalAddressGenerator = dependencies.newIkeLocalAddressGenerator(); 209 mCallback = config.callback; 210 211 mIkeParams = config.ikeParams; 212 mForcePort4500 = config.ikeParams.hasIkeOption(IKE_OPTION_FORCE_PORT_4500); 213 mRemoteHostname = config.ikeParams.getServerHostname(); 214 mUseCallerConfiguredNetwork = config.ikeParams.getConfiguredNetwork() != null; 215 mIpVersion = config.ikeParams.getIpVersion(); 216 mEncapType = config.ikeParams.getEncapType(); 217 mKeepaliveDelaySeconds = config.ikeParams.getNattKeepAliveDelaySeconds(); 218 mDscp = config.ikeParams.getDscp(); 219 mUnderpinnedNetwork = null; 220 221 if (mUseCallerConfiguredNetwork) { 222 mNetwork = config.ikeParams.getConfiguredNetwork(); 223 } else { 224 mNetwork = mConnectivityManager.getActiveNetwork(); 225 if (mNetwork == null) { 226 throw new IllegalStateException("No active default network found"); 227 } 228 } 229 230 getIkeLog().d(TAG, "Set up on Network " + mNetwork); 231 232 mNatStatus = NAT_TRAVERSAL_SUPPORT_NOT_CHECKED; 233 } 234 235 /** Constructor of IkeConnectionController */ IkeConnectionController(IkeContext ikeContext, Config config)236 public IkeConnectionController(IkeContext ikeContext, Config config) { 237 this(ikeContext, config, new Dependencies()); 238 } 239 240 private static class Ipv6AddrInfo { 241 public final Inet6Address address; 242 public final boolean isNat64Addr; 243 Ipv6AddrInfo(Inet6Address address, boolean isNat64Addr)244 Ipv6AddrInfo(Inet6Address address, boolean isNat64Addr) { 245 this.address = address; 246 this.isNat64Addr = isNat64Addr; 247 } 248 249 @Override toString()250 public String toString() { 251 String result = address.toString(); 252 if (isNat64Addr) { 253 return result + "(Nat64)"; 254 } 255 return result; 256 } 257 } 258 259 /** Config includes all configurations to build an IkeConnectionController */ 260 public static class Config { 261 public final Handler ikeHandler; 262 public final IkeSessionParams ikeParams; 263 public final int ikeSessionId; 264 public final int alarmCmd; 265 public final int sendKeepaliveCmd; 266 public final Callback callback; 267 268 /** Constructor for IkeConnectionController.Config */ Config( Handler ikeHandler, IkeSessionParams ikeParams, int ikeSessionId, int alarmCmd, int sendKeepaliveCmd, Callback callback)269 public Config( 270 Handler ikeHandler, 271 IkeSessionParams ikeParams, 272 int ikeSessionId, 273 int alarmCmd, 274 int sendKeepaliveCmd, 275 Callback callback) { 276 this.ikeHandler = ikeHandler; 277 this.ikeParams = ikeParams; 278 this.ikeSessionId = ikeSessionId; 279 this.alarmCmd = alarmCmd; 280 this.sendKeepaliveCmd = sendKeepaliveCmd; 281 this.callback = callback; 282 } 283 } 284 285 /** Callback to notify status changes of the connection */ 286 public interface Callback { 287 /** Notify the IkeConnectionController caller the underlying network has changed */ onUnderlyingNetworkUpdated()288 void onUnderlyingNetworkUpdated(); 289 290 /** Notify the IkeConnectionController caller that the underlying network died */ onUnderlyingNetworkDied(Network network)291 void onUnderlyingNetworkDied(Network network); 292 293 /** Notify the IkeConnectionController caller of the incoming IKE packet */ onIkePacketReceived(IkeHeader ikeHeader, byte[] ikePackets)294 void onIkePacketReceived(IkeHeader ikeHeader, byte[] ikePackets); 295 296 /** Notify the IkeConnectionController caller of the IKE fatal error */ onError(IkeException exception)297 void onError(IkeException exception); 298 } 299 300 /** External dependencies, for injection in tests */ 301 @VisibleForTesting 302 public static class Dependencies { 303 /** Gets an IkeLocalAddressGenerator */ newIkeLocalAddressGenerator()304 public IkeLocalAddressGenerator newIkeLocalAddressGenerator() { 305 return new IkeLocalAddressGenerator(); 306 } 307 308 /** Builds and starts NATT keepalive */ newIkeNattKeepalive( IkeContext ikeContext, KeepaliveConfig keepaliveConfig)309 public IkeNattKeepalive newIkeNattKeepalive( 310 IkeContext ikeContext, KeepaliveConfig keepaliveConfig) throws IOException { 311 IkeNattKeepalive keepalive = 312 new IkeNattKeepalive( 313 ikeContext, 314 ikeContext.getContext().getSystemService(ConnectivityManager.class), 315 keepaliveConfig); 316 keepalive.start(); 317 return keepalive; 318 } 319 320 /** Builds and returns a new IkeUdp4Socket */ newIkeUdp4Socket( IkeSocketConfig sockConfig, IkeSocket.Callback callback, Handler handler)321 public IkeUdp4Socket newIkeUdp4Socket( 322 IkeSocketConfig sockConfig, IkeSocket.Callback callback, Handler handler) 323 throws ErrnoException, IOException { 324 return IkeUdp4Socket.getInstance(sockConfig, callback, handler); 325 } 326 327 /** Builds and returns a new IkeUdp6Socket */ newIkeUdp6Socket( IkeSocketConfig sockConfig, IkeSocket.Callback callback, Handler handler)328 public IkeUdp6Socket newIkeUdp6Socket( 329 IkeSocketConfig sockConfig, IkeSocket.Callback callback, Handler handler) 330 throws ErrnoException, IOException { 331 return IkeUdp6Socket.getInstance(sockConfig, callback, handler); 332 } 333 334 /** Builds and returns a new IkeUdp6WithEncapPortSocket */ newIkeUdp6WithEncapPortSocket( IkeSocketConfig sockConfig, IkeSocket.Callback callback, Handler handler)335 public IkeUdp6WithEncapPortSocket newIkeUdp6WithEncapPortSocket( 336 IkeSocketConfig sockConfig, IkeSocket.Callback callback, Handler handler) 337 throws ErrnoException, IOException { 338 return IkeUdp6WithEncapPortSocket.getIkeUdpEncapSocket(sockConfig, callback, handler); 339 } 340 341 /** Builds and returns a new IkeUdpEncapSocket */ newIkeUdpEncapSocket( IkeSocketConfig sockConfig, IpSecManager ipSecManager, IkeSocket.Callback callback, Handler handler)342 public IkeUdpEncapSocket newIkeUdpEncapSocket( 343 IkeSocketConfig sockConfig, 344 IpSecManager ipSecManager, 345 IkeSocket.Callback callback, 346 Handler handler) 347 throws ErrnoException, IOException, ResourceUnavailableException { 348 return IkeUdpEncapSocket.getIkeUdpEncapSocket( 349 sockConfig, ipSecManager, callback, handler.getLooper()); 350 } 351 } 352 353 /** 354 * Get the keepalive delay from params, transports and device config. 355 * 356 * If the AUTOMATIC_NATT_KEEPALIVES option is set, look up the transport in the network 357 * capabilities ; if Wi-Fi use the fixed delay, if cell use the device property int 358 * (or a fixed delay in the absence of the permission to read device properties). 359 * For other transports, or if the AUTOMATIC_NATT_KEEPALIVES option is not set, use the 360 * delay from the session params. 361 * 362 * @param ikeContext Context to read the device config, if necessary. 363 * @param ikeParams the session params 364 * @param nc the capabilities of the underlying network 365 * @return the keepalive delay to use, in seconds. 366 */ 367 @VisibleForTesting getKeepaliveDelaySec( IkeContext ikeContext, IkeSessionParams ikeParams, NetworkCapabilities nc)368 public static int getKeepaliveDelaySec( 369 IkeContext ikeContext, IkeSessionParams ikeParams, NetworkCapabilities nc) { 370 int keepaliveDelaySeconds = ikeParams.getNattKeepAliveDelaySeconds(); 371 372 if (ikeParams.hasIkeOption(IKE_OPTION_AUTOMATIC_NATT_KEEPALIVES)) { 373 if (nc.hasTransport(TRANSPORT_WIFI)) { 374 // Most of the time, IKE Session will use shorter keepalive timer on WiFi. Thus 375 // choose the Wifi timer as a more conservative value when the NetworkCapabilities 376 // have both TRANSPORT_WIFI and TRANSPORT_CELLULAR 377 final int autoDelaySeconds = AUTO_KEEPALIVE_DELAY_SEC_WIFI; 378 keepaliveDelaySeconds = Math.min(keepaliveDelaySeconds, autoDelaySeconds); 379 } else if (nc.hasTransport(TRANSPORT_CELLULAR)) { 380 final int autoDelaySeconds = 381 ikeContext.getDeviceConfigPropertyInt( 382 CONFIG_AUTO_NATT_KEEPALIVES_CELLULAR_TIMEOUT_OVERRIDE_SECONDS, 383 IKE_NATT_KEEPALIVE_DELAY_SEC_MIN, 384 IKE_NATT_KEEPALIVE_DELAY_SEC_MAX, 385 AUTO_KEEPALIVE_DELAY_SEC_CELL); 386 keepaliveDelaySeconds = Math.min(keepaliveDelaySeconds, autoDelaySeconds); 387 } 388 } 389 390 return keepaliveDelaySeconds; 391 } 392 buildInitialKeepaliveAlarmConfig( IkeContext ikeContext, Config config, IkeSessionParams ikeParams, NetworkCapabilities nc)393 private static IkeAlarmConfig buildInitialKeepaliveAlarmConfig( 394 IkeContext ikeContext, 395 Config config, 396 IkeSessionParams ikeParams, 397 NetworkCapabilities nc) { 398 final Message keepaliveMsg = 399 config.ikeHandler.obtainMessage( 400 config.alarmCmd /* what */, 401 config.ikeSessionId /* arg1 */, 402 config.sendKeepaliveCmd /* arg2 */); 403 final PendingIntent keepaliveIntent = IkeAlarm.buildIkeAlarmIntent(ikeContext.getContext(), 404 ACTION_KEEPALIVE, getIntentIdentifier(config.ikeSessionId), keepaliveMsg); 405 406 return new IkeAlarmConfig( 407 ikeContext.getContext(), 408 ACTION_KEEPALIVE, 409 TimeUnit.SECONDS.toMillis(getKeepaliveDelaySec(ikeContext, ikeParams, nc)), 410 keepaliveIntent, 411 keepaliveMsg); 412 } 413 getIntentIdentifier(int ikeSessionId)414 private static String getIntentIdentifier(int ikeSessionId) { 415 return TAG + "_" + ikeSessionId; 416 } 417 418 /** Update the IKE NATT keepalive */ setupOrUpdateNattKeeaplive(IkeSocket ikeSocket)419 private void setupOrUpdateNattKeeaplive(IkeSocket ikeSocket) throws IOException { 420 if (!(ikeSocket instanceof IkeUdpEncapSocket)) { 421 if (mIkeNattKeepalive != null) { 422 mIkeNattKeepalive.stop(); 423 mIkeNattKeepalive = null; 424 } 425 return; 426 } 427 428 final KeepaliveConfig keepaliveConfig = 429 new KeepaliveConfig( 430 (Inet4Address) mLocalAddress, 431 (Inet4Address) mRemoteAddress, 432 ((IkeUdpEncapSocket) ikeSocket).getUdpEncapsulationSocket(), 433 mNetwork, 434 mUnderpinnedNetwork, 435 mKeepaliveAlarmConfig, 436 mIkeParams); 437 438 if (mIkeNattKeepalive != null) { 439 mIkeNattKeepalive.restart(keepaliveConfig); 440 } else { 441 mIkeNattKeepalive = mDependencies.newIkeNattKeepalive(mIkeContext, keepaliveConfig); 442 } 443 } 444 getIkeSocket(boolean isIpv4, boolean useEncapPort)445 private IkeSocket getIkeSocket(boolean isIpv4, boolean useEncapPort) throws IkeException { 446 IkeSocketConfig sockConfig = new IkeSocketConfig(this, mDscp); 447 IkeSocket result = null; 448 449 try { 450 if (useEncapPort) { 451 if (isIpv4) { 452 result = mDependencies.newIkeUdpEncapSocket( 453 sockConfig, mIpSecManager, this, new Handler(mIkeContext.getLooper())); 454 } else { 455 result = mDependencies.newIkeUdp6WithEncapPortSocket( 456 sockConfig, this, new Handler(mIkeContext.getLooper())); 457 } 458 } else { 459 if (isIpv4) { 460 result = mDependencies.newIkeUdp4Socket( 461 sockConfig, this, new Handler(mIkeContext.getLooper())); 462 } else { 463 result = mDependencies.newIkeUdp6Socket( 464 sockConfig, this, new Handler(mIkeContext.getLooper())); 465 } 466 } 467 468 if (result == null) { 469 throw new IOException("No socket created"); 470 } 471 472 result.bindToNetwork(mNetwork); 473 return result; 474 } catch (ErrnoException | IOException | ResourceUnavailableException e) { 475 throw wrapAsIkeException(e); 476 } 477 } 478 migrateSpiToIkeSocket(long localSpi, IkeSocket oldSocket, IkeSocket newSocket)479 private void migrateSpiToIkeSocket(long localSpi, IkeSocket oldSocket, IkeSocket newSocket) { 480 newSocket.registerIke(localSpi, this); 481 oldSocket.unregisterIke(localSpi); 482 } 483 getAndSwitchToIkeSocket(boolean isIpv4, boolean useEncapPort)484 private void getAndSwitchToIkeSocket(boolean isIpv4, boolean useEncapPort) throws IkeException { 485 IkeSocket newSocket = getIkeSocket(isIpv4, useEncapPort); 486 487 try { 488 setupOrUpdateNattKeeaplive(newSocket); 489 } catch (IOException e) { 490 throw wrapAsIkeException(e); 491 } 492 493 if (newSocket != mIkeSocket) { 494 for (IkeSaRecord saRecord : mIkeSaRecords) { 495 migrateSpiToIkeSocket(saRecord.getLocalSpi(), mIkeSocket, newSocket); 496 } 497 mIkeSocket.releaseReference(this); 498 mIkeSocket = newSocket; 499 } 500 } 501 502 /** Sets up the IkeConnectionController */ setUp()503 public void setUp() throws IkeException { 504 // Make sure all the resources, especially the NetworkCallback, is released before creating 505 // new one. 506 unregisterResources(); 507 508 // This is call is directly from the IkeSessionStateMachine, and thus cannot be 509 // accidentally called in a NetworkCallback. See 510 // ConnectivityManager.NetworkCallback#onLinkPropertiesChanged() and 511 // ConnectivityManager.NetworkCallback#onCapabilitiesChanged() for discussion of 512 // mixing callbacks and synchronous polling methods. 513 LinkProperties linkProperties = mConnectivityManager.getLinkProperties(mNetwork); 514 mNc = mConnectivityManager.getNetworkCapabilities(mNetwork); 515 mKeepaliveAlarmConfig = 516 buildInitialKeepaliveAlarmConfig(mIkeContext, mConfig, mIkeParams, mNc); 517 try { 518 if (linkProperties == null || mNc == null) { 519 // Throw NPE to preserve the existing behaviour for backward compatibility 520 throw wrapAsIkeException( 521 new NullPointerException( 522 "Attempt setup on network " 523 + mNetwork 524 + " with null LinkProperties or null NetworkCapabilities")); 525 } 526 resolveAndSetAvailableRemoteAddresses(linkProperties); 527 selectAndSetRemoteAddress(linkProperties); 528 529 int remotePort = 530 mForcePort4500 531 ? IkeSocket.SERVER_PORT_UDP_ENCAPSULATED 532 : IkeSocket.SERVER_PORT_NON_UDP_ENCAPSULATED; 533 boolean isIpv4 = mRemoteAddress instanceof Inet4Address; 534 mLocalAddress = 535 mIkeLocalAddressGenerator.generateLocalAddress( 536 mNetwork, isIpv4, mRemoteAddress, remotePort); 537 mIkeSocket = getIkeSocket(isIpv4, mForcePort4500); 538 539 setupOrUpdateNattKeeaplive(mIkeSocket); 540 } catch (IOException | ErrnoException e) { 541 throw wrapAsIkeException(e); 542 } 543 544 try { 545 if (mUseCallerConfiguredNetwork) { 546 // Caller configured a specific Network - track it 547 // ConnectivityManager does not provide a callback for tracking a specific 548 // Network. In order to do so, create a NetworkRequest without any 549 // capabilities so it will match all Networks. The NetworkCallback will then 550 // filter for the correct (caller-specified) Network. 551 NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build(); 552 mNetworkCallback = 553 new IkeSpecificNetworkCallback( 554 this, mNetwork, mLocalAddress, linkProperties, mNc); 555 mConnectivityManager.registerNetworkCallback( 556 request, mNetworkCallback, new Handler(mIkeContext.getLooper())); 557 } else { 558 // Caller did not configure a specific Network - track the default 559 mNetworkCallback = 560 new IkeDefaultNetworkCallback( 561 this, mNetwork, mLocalAddress, linkProperties, mNc); 562 mConnectivityManager.registerDefaultNetworkCallback( 563 mNetworkCallback, new Handler(mIkeContext.getLooper())); 564 } 565 } catch (RuntimeException e) { 566 mNetworkCallback = null; 567 throw wrapAsIkeException(e); 568 } 569 } 570 unregisterResources()571 private void unregisterResources() { 572 if (mIkeNattKeepalive != null) { 573 mIkeNattKeepalive.stop(); 574 mIkeNattKeepalive = null; 575 } 576 577 if (mNetworkCallback != null) { 578 mConnectivityManager.unregisterNetworkCallback(mNetworkCallback); 579 mNetworkCallback = null; 580 } 581 582 if (mIkeSocket != null) { 583 for (IkeSaRecord saRecord : mIkeSaRecords) { 584 mIkeSocket.unregisterIke(saRecord.getLocalSpi()); 585 } 586 587 mIkeSocket.releaseReference(this); 588 mIkeSocket = null; 589 } 590 591 mIkeSaRecords.clear(); 592 } 593 594 /** Tears down the IkeConnectionController */ tearDown()595 public void tearDown() { 596 unregisterResources(); 597 } 598 599 /** Returns the IkeSocket */ getIkeSocket()600 public IkeSocket getIkeSocket() { 601 return mIkeSocket; 602 } 603 604 /** Returns if the IkeSocket is a UDP encapsulation socket */ useUdpEncapSocket()605 public boolean useUdpEncapSocket() { 606 return mIkeSocket instanceof IkeUdpEncapSocket; 607 } 608 609 /** Sends out an IKE packet */ sendIkePacket(byte[] ikePacket)610 public void sendIkePacket(byte[] ikePacket) { 611 mIkeSocket.sendIkePacket(ikePacket, mRemoteAddress); 612 } 613 614 /** Registers the local SPI for an IKE SA waiting for the IKE INIT response */ registerIkeSpi(long ikeSpi)615 public void registerIkeSpi(long ikeSpi) { 616 mIkeSocket.registerIke(ikeSpi, this); 617 } 618 619 /** Unregisters the local SPI for an IKE SA that failed IKE INIT exchange */ unregisterIkeSpi(long ikeSpi)620 public void unregisterIkeSpi(long ikeSpi) { 621 mIkeSocket.unregisterIke(ikeSpi); 622 } 623 624 /** Registers a newly created IKE SA */ registerIkeSaRecord(IkeSaRecord saRecord)625 public void registerIkeSaRecord(IkeSaRecord saRecord) { 626 mIkeSaRecords.add(saRecord); 627 mIkeSocket.registerIke(saRecord.getLocalSpi(), this); 628 } 629 630 /** Unregisters a deleted IKE SA */ unregisterIkeSaRecord(IkeSaRecord saRecord)631 public void unregisterIkeSaRecord(IkeSaRecord saRecord) { 632 mIkeSaRecords.remove(saRecord); 633 mIkeSocket.unregisterIke(saRecord.getLocalSpi()); 634 } 635 636 /** Returns all registered IKE SAs */ 637 @VisibleForTesting getIkeSaRecords()638 public Set<IkeSaRecord> getIkeSaRecords() { 639 return Collections.unmodifiableSet(mIkeSaRecords); 640 } 641 642 /** Returns the keepalive config */ 643 @VisibleForTesting getKeepaliveAlarmConfig()644 public IkeAlarmConfig getKeepaliveAlarmConfig() { 645 return mKeepaliveAlarmConfig; 646 } 647 648 /** 649 * Updates the underlying network 650 * 651 * <p>This call is always from IkeSessionStateMachine for migrating IKE to a caller configured 652 * network, or to update the protocol preference or keepalive delay. 653 */ onNetworkSetByUser( Network network, int ipVersion, int encapType, int keepaliveDelaySeconds)654 public void onNetworkSetByUser( 655 Network network, 656 int ipVersion, 657 int encapType, 658 int keepaliveDelaySeconds) 659 throws IkeException { 660 if (!mMobilityEnabled) { 661 // Program error. IkeSessionStateMachine should never call this method before enabling 662 // mobility. 663 getIkeLog().wtf(TAG, "Attempt to update network when mobility is disabled"); 664 return; 665 } 666 667 getIkeLog() 668 .d( 669 TAG, 670 "onNetworkSetByUser: network " 671 + network 672 + " ipVersion " 673 + ipVersion 674 + " encapType " 675 + encapType 676 + " keepaliveDelaySeconds " 677 + keepaliveDelaySeconds); 678 679 // This is call is directly from the IkeSessionStateMachine, and thus cannot be 680 // accidentally called in a NetworkCallback. See 681 // ConnectivityManager.NetworkCallback#onLinkPropertiesChanged() and 682 // ConnectivityManager.NetworkCallback#onCapabilitiesChanged() for discussion of 683 // mixing callbacks and synchronous polling methods. 684 final LinkProperties linkProperties = mConnectivityManager.getLinkProperties(network); 685 final NetworkCapabilities networkCapabilities = 686 mConnectivityManager.getNetworkCapabilities(network); 687 688 if (linkProperties == null || networkCapabilities == null) { 689 // Throw NPE to preserve the existing behaviour for backward compatibility 690 throw wrapAsIkeException( 691 new NullPointerException( 692 "Attempt migrating to network " 693 + network 694 + " with null LinkProperties or null NetworkCapabilities")); 695 696 // TODO(b/224686889): Notify caller of failed mobility attempt and keep this IKE Session 697 // alive 698 } 699 700 mIpVersion = ipVersion; 701 mEncapType = encapType; 702 mKeepaliveDelaySeconds = keepaliveDelaySeconds; 703 704 // Switch to monitor a new network. This call is never expected to trigger a callback 705 mNetworkCallback.setNetwork(network, linkProperties, networkCapabilities); 706 handleUnderlyingNetworkUpdated( 707 network, linkProperties, networkCapabilities, false /* skipIfSameNetwork */); 708 } 709 710 /** Called when the underpinned network is set by the user */ onUnderpinnedNetworkSetByUser(final Network underpinnedNetwork)711 public void onUnderpinnedNetworkSetByUser(final Network underpinnedNetwork) 712 throws IkeException { 713 mUnderpinnedNetwork = underpinnedNetwork; 714 restartKeepaliveIfRunning(); 715 } 716 restartKeepaliveIfRunning()717 private void restartKeepaliveIfRunning() throws IkeException { 718 try { 719 setupOrUpdateNattKeeaplive(mIkeSocket); 720 } catch (IOException e) { 721 throw wrapAsIkeException(e); 722 } 723 } 724 725 /** Gets the underlying network */ getNetwork()726 public Network getNetwork() { 727 return mNetwork; 728 } 729 730 /** Gets the underlying network type for Metrics */ getMetricsNetworkType()731 public @IkeMetrics.IkeUnderlyingNetworkType int getMetricsNetworkType() { 732 if (mNc.hasTransport(TRANSPORT_WIFI)) { 733 return IkeMetrics.IKE_UNDERLYING_NETWORK_TYPE_WIFI; 734 } else if (mNc.hasTransport(TRANSPORT_CELLULAR)) { 735 return IkeMetrics.IKE_UNDERLYING_NETWORK_TYPE_CELLULAR; 736 } 737 738 // for other types. 739 return IkeMetrics.IKE_UNDERLYING_NETWORK_TYPE_UNSPECIFIED; 740 } 741 742 /** Gets the underpinned network */ getUnderpinnedNetwork()743 public Network getUnderpinnedNetwork() { 744 return mUnderpinnedNetwork; 745 } 746 747 /** Check if mobility is enabled */ isMobilityEnabled()748 public boolean isMobilityEnabled() { 749 return mMobilityEnabled; 750 } 751 752 /** Differentiated Services Code Point information used at socket configuration */ 753 @VisibleForTesting getDscp()754 public int getDscp() { 755 return mDscp; 756 } 757 758 /** 759 * Sets the local address. 760 * 761 * <p>This MUST only be called in a test. 762 */ 763 @VisibleForTesting setLocalAddress(InetAddress address)764 public void setLocalAddress(InetAddress address) { 765 mLocalAddress = address; 766 } 767 768 /** Gets the local address */ getLocalAddress()769 public InetAddress getLocalAddress() { 770 return mLocalAddress; 771 } 772 773 /** 774 * Sets the remote address. 775 * 776 * <p>This MUST only be called in a test. 777 */ 778 @VisibleForTesting setRemoteAddress(InetAddress address)779 public void setRemoteAddress(InetAddress address) { 780 mRemoteAddress = address; 781 addRemoteAddress(address); 782 } 783 784 /** 785 * Adds a remote address. 786 * 787 * <p>This MUST only be called in a test. 788 */ 789 @VisibleForTesting addRemoteAddress(InetAddress address)790 public void addRemoteAddress(InetAddress address) { 791 if (address instanceof Inet4Address) { 792 mRemoteAddressesV4.add((Inet4Address) address); 793 } else { 794 mRemoteAddressesV6.add( 795 new Ipv6AddrInfo((Inet6Address) address, false /* isNat64Addr */)); 796 } 797 } 798 799 /** 800 * Adds a remote IPv6 address. 801 * 802 * <p>This MUST only be called in a test. 803 */ 804 @VisibleForTesting addRemoteAddressV6(Inet6Address address, boolean isNat64Addr)805 public void addRemoteAddressV6(Inet6Address address, boolean isNat64Addr) { 806 mRemoteAddressesV6.add(new Ipv6AddrInfo((Inet6Address) address, isNat64Addr)); 807 } 808 809 /** 810 * Clear all remote address cache. 811 * 812 * <p>This MUST only be called in a test. 813 */ 814 @VisibleForTesting clearRemoteAddress()815 public void clearRemoteAddress() { 816 mRemoteAddressesV4.clear(); 817 mRemoteAddressesV6.clear(); 818 } 819 820 /** Gets the remote addresses */ getRemoteAddress()821 public InetAddress getRemoteAddress() { 822 return mRemoteAddress; 823 } 824 825 /** Gets all the IPv4 remote addresses */ getAllRemoteIpv4Addresses()826 public List<Inet4Address> getAllRemoteIpv4Addresses() { 827 return new ArrayList<>(mRemoteAddressesV4); 828 } 829 830 /** Gets all the IPv6 remote addresses */ getAllRemoteIpv6Addresses()831 public List<Inet6Address> getAllRemoteIpv6Addresses() { 832 final List<Inet6Address> addresses = new ArrayList<>(); 833 for (Ipv6AddrInfo info : mRemoteAddressesV6) { 834 addresses.add(info.address); 835 } 836 return addresses; 837 } 838 839 /** Gets the local port */ getLocalPort()840 public int getLocalPort() { 841 try { 842 return mIkeSocket.getLocalPort(); 843 } catch (ErrnoException e) { 844 throw new IllegalStateException("Fail to get local port", e); 845 } 846 } 847 848 /** Gets the remote port */ getRemotePort()849 public int getRemotePort() { 850 return mIkeSocket.getIkeServerPort(); 851 } 852 853 /** Handles NAT detection result in IKE INIT */ handleNatDetectionResultInIkeInit(boolean isNatDetected, long localSpi)854 public void handleNatDetectionResultInIkeInit(boolean isNatDetected, long localSpi) 855 throws IkeException { 856 if (!isNatDetected) { 857 mNatStatus = NAT_NOT_DETECTED; 858 return; 859 } 860 861 mNatStatus = NAT_DETECTED; 862 if (mRemoteAddress instanceof Inet6Address) { 863 throw wrapAsIkeException(new UnsupportedOperationException("IPv6 NAT-T not supported")); 864 } 865 866 getIkeLog().d(TAG, "Switching to send to remote port 4500 if it's not already"); 867 868 IkeSocket newSocket = getIkeSocket(true /* isIpv4 */, true /* useEncapPort */); 869 870 try { 871 setupOrUpdateNattKeeaplive(newSocket); 872 } catch (IOException e) { 873 throw wrapAsIkeException(e); 874 } 875 876 if (newSocket != mIkeSocket) { 877 migrateSpiToIkeSocket(localSpi, mIkeSocket, newSocket); 878 mIkeSocket.releaseReference(this); 879 mIkeSocket = newSocket; 880 } 881 } 882 883 /** Handles NAT detection result in the MOBIKE INFORMATIONAL exchange */ handleNatDetectionResultInMobike(boolean isNatDetected)884 public void handleNatDetectionResultInMobike(boolean isNatDetected) throws IkeException { 885 if (!isNatDetected) { 886 mNatStatus = NAT_NOT_DETECTED; 887 return; 888 } 889 890 mNatStatus = NAT_DETECTED; 891 if (mRemoteAddress instanceof Inet6Address) { 892 throw wrapAsIkeException(new UnsupportedOperationException("IPv6 NAT-T not supported")); 893 } 894 895 getIkeLog().d(TAG, "Switching to send to remote port 4500 if it's not already"); 896 getAndSwitchToIkeSocket(true /* isIpv4 */, true /* useEncapPort */); 897 } 898 899 /** 900 * Marks that the server does not support NAT-T 901 * 902 * <p>This is method should only be called at the first time IKE client sends NAT_DETECTION (in 903 * other words the first time IKE client is using IPv4 address since IKE does not support IPv6 904 * NAT-T) 905 */ markSeverNattUnsupported()906 public void markSeverNattUnsupported() { 907 mNatStatus = NAT_TRAVERSAL_UNSUPPORTED; 908 } 909 910 /** 911 * Clears the knowledge of sever's NAT-T support 912 * 913 * <p>This MUST only be called in a test. 914 */ 915 @VisibleForTesting resetSeverNattSupport()916 public void resetSeverNattSupport() { 917 mNatStatus = NAT_TRAVERSAL_SUPPORT_NOT_CHECKED; 918 } 919 920 /** This MUST only be called in a test. */ 921 @VisibleForTesting setNatDetected(boolean isNatDetected)922 public void setNatDetected(boolean isNatDetected) { 923 if (!isNatDetected) { 924 mNatStatus = NAT_NOT_DETECTED; 925 return; 926 } 927 928 mNatStatus = NAT_DETECTED; 929 } 930 931 /** Returns the NAT status */ 932 @NatStatus getNatStatus()933 public int getNatStatus() { 934 return mNatStatus; 935 } 936 937 /** Returns the IkeNattKeepalive */ getIkeNattKeepalive()938 public IkeNattKeepalive getIkeNattKeepalive() { 939 return mIkeNattKeepalive; 940 } 941 942 /** Fire software keepalive */ fireKeepAlive()943 public void fireKeepAlive() { 944 // Software keepalive alarm is fired. Ignore the alarm whe NAT-T keepalive is no 945 // longer needed (e.g. migrating from IPv4 to IPv6) 946 if (mIkeNattKeepalive != null) { 947 mIkeNattKeepalive.onAlarmFired(); 948 } 949 } 950 resolveAndSetAvailableRemoteAddresses(LinkProperties linkProperties)951 private void resolveAndSetAvailableRemoteAddresses(LinkProperties linkProperties) 952 throws IOException { 953 // TODO(b/149954916): Do DNS resolution asynchronously 954 InetAddress[] allRemoteAddresses = null; 955 956 for (int attempts = 0; 957 attempts < MAX_DNS_RESOLUTION_ATTEMPTS 958 && (allRemoteAddresses == null || allRemoteAddresses.length == 0); 959 attempts++) { 960 try { 961 allRemoteAddresses = mNetwork.getAllByName(mRemoteHostname); 962 } catch (UnknownHostException e) { 963 final boolean willRetry = attempts + 1 < MAX_DNS_RESOLUTION_ATTEMPTS; 964 getIkeLog() 965 .d( 966 TAG, 967 "Failed to look up host for attempt " 968 + (attempts + 1) 969 + ": " 970 + mRemoteHostname 971 + " retrying? " 972 + willRetry, 973 e); 974 } 975 } 976 if (allRemoteAddresses == null || allRemoteAddresses.length == 0) { 977 final String errMsg = 978 "DNS resolution for " 979 + mRemoteHostname 980 + " failed after " 981 + MAX_DNS_RESOLUTION_ATTEMPTS 982 + " attempts"; 983 984 throw ShimUtils.getInstance().getDnsFailedException(errMsg); 985 } 986 987 getIkeLog() 988 .d( 989 TAG, 990 "Resolved addresses for peer: " 991 + Arrays.toString(allRemoteAddresses) 992 + " to replace old addresses: v4=" 993 + mRemoteAddressesV4 994 + " v6=" 995 + mRemoteAddressesV6); 996 997 mRemoteAddressesV4.clear(); 998 mRemoteAddressesV6.clear(); 999 for (InetAddress remoteAddress : allRemoteAddresses) { 1000 if (remoteAddress instanceof Inet4Address) { 1001 mRemoteAddressesV4.add((Inet4Address) remoteAddress); 1002 } else { 1003 Inet6Address address = (Inet6Address) remoteAddress; 1004 IpPrefix ipPrefix = linkProperties.getNat64Prefix(); 1005 mRemoteAddressesV6.add( 1006 new Ipv6AddrInfo(address, ipPrefix != null && ipPrefix.contains(address))); 1007 } 1008 } 1009 } 1010 hasLocalIpV4Address(LinkProperties linkProperties)1011 private static boolean hasLocalIpV4Address(LinkProperties linkProperties) { 1012 for (LinkAddress linkAddress : linkProperties.getAllLinkAddresses()) { 1013 if (linkAddress.getAddress() instanceof Inet4Address) { 1014 return true; 1015 } 1016 } 1017 1018 return false; 1019 } 1020 isNattSupported()1021 private boolean isNattSupported() { 1022 return mNatStatus != NAT_TRAVERSAL_UNSUPPORTED 1023 && mNatStatus != NAT_TRAVERSAL_SUPPORT_NOT_CHECKED; 1024 } 1025 1026 /** 1027 * Set the remote address for the peer. 1028 * 1029 * <p>The selection of IP address is as follows: 1030 * 1031 * <ul> 1032 * <li>If the caller passed in an IP address family, use that address family. 1033 * <li>Otherwise, always prefer IPv6 over IPv4. 1034 * </ul> 1035 * 1036 * Otherwise, an IPv4 address will be used. 1037 */ 1038 @VisibleForTesting selectAndSetRemoteAddress(LinkProperties linkProperties)1039 public void selectAndSetRemoteAddress(LinkProperties linkProperties) throws IOException { 1040 // TODO(b/175348096): Randomly choose from available addresses when the IP family is 1041 // decided. 1042 final boolean canConnectWithIpv4 = 1043 !mRemoteAddressesV4.isEmpty() && hasLocalIpV4Address(linkProperties); 1044 final boolean canConnectWithIpv6 = 1045 !mRemoteAddressesV6.isEmpty() && linkProperties.hasGlobalIpv6Address(); 1046 1047 adjustIpVersionPreference(); 1048 1049 if (isIpVersionRequired(ESP_IP_VERSION_IPV4)) { 1050 if (!canConnectWithIpv4) { 1051 throw ShimUtils.getInstance().getDnsFailedException( 1052 "IPv4 required but no IPv4 address available"); 1053 } 1054 mRemoteAddress = mRemoteAddressesV4.get(0); 1055 } else if (isIpVersionRequired(ESP_IP_VERSION_IPV6)) { 1056 if (!canConnectWithIpv6) { 1057 throw ShimUtils.getInstance().getDnsFailedException( 1058 "IPv6 required but no global IPv6 address available"); 1059 } 1060 mRemoteAddress = mRemoteAddressesV6.get(0).address; 1061 } else if (isIpV4Preferred(mIkeParams, mNc) && canConnectWithIpv4) { 1062 mRemoteAddress = mRemoteAddressesV4.get(0); 1063 } else if (canConnectWithIpv6) { 1064 mRemoteAddress = mRemoteAddressesV6.get(0).address; 1065 } else if (canConnectWithIpv4) { 1066 mRemoteAddress = mRemoteAddressesV4.get(0); 1067 } else { 1068 // For backwards compatibility, synchronously throw IAE instead of triggering callback. 1069 throw new IllegalArgumentException("No valid IPv4 or IPv6 addresses for peer"); 1070 } 1071 } 1072 adjustIpVersionPreference()1073 private void adjustIpVersionPreference() { 1074 // As ESP isn't supported on v4 and UDP isn't supported on v6, a request for ENCAP_UDP 1075 // should force v4 and a request for ENCAP_NONE should force v6 when the family is set 1076 // to auto. 1077 // TODO : instead of fudging the arguments here, this should actually be taken into 1078 // account when figuring out whether to send the NAT detection packet. 1079 int adjustedIpVersion = mIpVersion; 1080 if (mIpVersion == ESP_IP_VERSION_AUTO) { 1081 if (mEncapType == ESP_ENCAP_TYPE_NONE) { 1082 adjustedIpVersion = ESP_IP_VERSION_IPV6; 1083 } else if (mEncapType == ESP_ENCAP_TYPE_UDP) { 1084 adjustedIpVersion = ESP_IP_VERSION_IPV4; 1085 } 1086 1087 if (adjustedIpVersion != mIpVersion) { 1088 getIkeLog().i(TAG, "IP version preference is overridden from " 1089 + mIpVersion + " to " + adjustedIpVersion); 1090 mIpVersion = adjustedIpVersion; 1091 } 1092 } 1093 } 1094 isIpVersionRequired(final int ipVersion)1095 private boolean isIpVersionRequired(final int ipVersion) { 1096 return ipVersion == mIpVersion; 1097 } 1098 1099 @VisibleForTesting isIpV4Preferred(IkeSessionParams ikeParams, NetworkCapabilities nc)1100 public boolean isIpV4Preferred(IkeSessionParams ikeParams, NetworkCapabilities nc) { 1101 // Note that in production code mIpVersion can't be == ESP_IP_VERSION_IPV4 because the 1102 // only caller, selectAndSetRemoteAddress, would never call this method because 1103 // isIpVersionRequired(ESP_IP_VERSION_IPV4) would return true. Still, it makes sense in 1104 // this method to accept ESP_IP_VERSION_IPV4. 1105 return (mIpVersion == ESP_IP_VERSION_AUTO || mIpVersion == ESP_IP_VERSION_IPV4) 1106 && ikeParams.hasIkeOption(IKE_OPTION_AUTOMATIC_ADDRESS_FAMILY_SELECTION) 1107 && nc.hasTransport(TRANSPORT_WIFI); 1108 } 1109 1110 /** 1111 * Enables IkeConnectionController to handle mobility events 1112 * 1113 * <p>This method will enable IkeConnectionController to monitor and handle changes of the 1114 * underlying network and addresses. 1115 */ enableMobility()1116 public void enableMobility() throws IkeException { 1117 mMobilityEnabled = true; 1118 1119 if (isNattSupported() 1120 && mIkeSocket.getIkeServerPort() != IkeSocket.SERVER_PORT_UDP_ENCAPSULATED) { 1121 getAndSwitchToIkeSocket( 1122 mRemoteAddress instanceof Inet4Address, true /* useEncapPort */); 1123 } 1124 } 1125 1126 /** Creates a IkeSessionConnectionInfo */ buildIkeSessionConnectionInfo()1127 public IkeSessionConnectionInfo buildIkeSessionConnectionInfo() { 1128 return new IkeSessionConnectionInfo(mLocalAddress, mRemoteAddress, mNetwork); 1129 } 1130 1131 /** 1132 * All the calls that are not initiated from the IkeSessionStateMachine MUST be run in this 1133 * method unless there are mechanisms to guarantee these calls will never crash the process. 1134 */ executeOrSendFatalError(Runnable r)1135 private void executeOrSendFatalError(Runnable r) { 1136 ShimUtils.getInstance().executeOrSendFatalError(r, mCallback); 1137 } 1138 getSupportedVersions(boolean isV4Supported, boolean isV6Supported)1139 private static Set<Integer> getSupportedVersions(boolean isV4Supported, boolean isV6Supported) { 1140 final Set<Integer> versions = new HashSet<>(); 1141 1142 if (isV4Supported) { 1143 versions.add(ESP_IP_VERSION_IPV4); 1144 } 1145 if (isV6Supported) { 1146 versions.add(ESP_IP_VERSION_IPV6); 1147 } 1148 1149 return versions; 1150 } 1151 1152 /** 1153 * Return whether DNS lookup is required during mobility update 1154 * 1155 * <p>DNS lookup will be skipped when IKE_OPTION_FORCE_DNS_RESOLUTION is disabled and one of the 1156 * following condition is true: 1157 * 1158 * <ul> 1159 * <li>The cached remote addresses include both IPv4 and IPv6 addresses 1160 * <li>The locally supported IP families and cached remote addresses match. In other words, if 1161 * local addresses include both IP versions and the cached remote addresses only have one 1162 * IP family, DNS lookup is required. This might happen when it takes longer for the 1163 * device to provide 464xlat IPv4 and thus the cached addresses do not have it. However, 1164 * if the local addresses only support IPv4, but the cached remote addresses have global 1165 * IPv4 and IPv6 addresses, DNS lookup can be skipped. 1166 * </ul> 1167 */ 1168 @VisibleForTesting isDnsLookupRequiredWithGlobalRemoteAddress( Network oldNetwork, Network network, LinkProperties linkProperties)1169 public boolean isDnsLookupRequiredWithGlobalRemoteAddress( 1170 Network oldNetwork, Network network, LinkProperties linkProperties) { 1171 final Set<Integer> localIpVersions = 1172 getSupportedVersions( 1173 hasLocalIpV4Address(linkProperties), linkProperties.hasGlobalIpv6Address()); 1174 final Set<Integer> remoteIpVersionsCached = 1175 getSupportedVersions( 1176 !mRemoteAddressesV4.isEmpty(), 1177 !mRemoteAddressesV6.isEmpty() /* NAT64 not included */); 1178 1179 getIkeLog() 1180 .d( 1181 TAG, 1182 "isDnsLookupRequiredWithGlobalRemoteAddress localIpVersions " 1183 + localIpVersions 1184 + " remoteIpVersionsCached " 1185 + remoteIpVersionsCached); 1186 1187 // Programming error 1188 if (localIpVersions.isEmpty()) { 1189 getIkeLog() 1190 .wtf( 1191 TAG, 1192 "isDnsLookupRequiredWithGlobalRemoteAddress no local address on the" 1193 + " Network"); 1194 return true; 1195 } 1196 1197 if (mIkeParams.hasIkeOption(IKE_OPTION_FORCE_DNS_RESOLUTION)) { 1198 return true; 1199 } 1200 1201 if (network.equals(oldNetwork) && Objects.equals(localIpVersions, remoteIpVersionsCached)) { 1202 return false; 1203 } 1204 1205 if (mIkeContext.getDeviceConfigPropertyBoolean( 1206 CONFIG_USE_CACHED_ADDRS, false /* defaultValue */) 1207 && remoteIpVersionsCached.containsAll(localIpVersions)) { 1208 return false; 1209 } 1210 1211 return true; 1212 } 1213 1214 // This method is never expected be called due to the capabilities change of the existing 1215 // underlying network. Only explicit user requests, network changes, addresses changes or 1216 // configuration changes (such as the protocol preference) will call into this method. handleUnderlyingNetworkUpdated( Network network, LinkProperties linkProperties, NetworkCapabilities networkCapabilities, boolean skipIfSameNetwork)1217 private void handleUnderlyingNetworkUpdated( 1218 Network network, 1219 LinkProperties linkProperties, 1220 NetworkCapabilities networkCapabilities, 1221 boolean skipIfSameNetwork) { 1222 if (!mMobilityEnabled) { 1223 getIkeLog().d(TAG, "onUnderlyingNetworkUpdated: Unable to handle network update"); 1224 mCallback.onUnderlyingNetworkDied(mNetwork); 1225 1226 return; 1227 } 1228 1229 Network oldNetwork = mNetwork; 1230 InetAddress oldLocalAddress = mLocalAddress; 1231 InetAddress oldRemoteAddress = mRemoteAddress; 1232 1233 mNetwork = network; 1234 mNc = networkCapabilities; 1235 1236 try { 1237 if (mKeepaliveDelaySeconds == IkeSessionParams.NATT_KEEPALIVE_INTERVAL_AUTO) { 1238 mKeepaliveDelaySeconds = getKeepaliveDelaySec(mIkeContext, mIkeParams, mNc); 1239 } 1240 1241 final long keepaliveDelayMs = TimeUnit.SECONDS.toMillis(mKeepaliveDelaySeconds); 1242 1243 if (keepaliveDelayMs != mKeepaliveAlarmConfig.delayMs) { 1244 mKeepaliveAlarmConfig = 1245 mKeepaliveAlarmConfig.buildCopyWithDelayMs(keepaliveDelayMs); 1246 restartKeepaliveIfRunning(); 1247 } 1248 } catch (IkeException e) { 1249 mCallback.onError(wrapAsIkeException(e)); 1250 return; 1251 } 1252 1253 // If there is no local address on the Network, report a fatal error and return 1254 if (!hasLocalIpV4Address(linkProperties) && !linkProperties.hasGlobalIpv6Address()) { 1255 mCallback.onError( 1256 wrapAsIkeException( 1257 ShimUtils.getInstance() 1258 .getDnsFailedException( 1259 "No local address on the Network " + mNetwork))); 1260 return; 1261 } 1262 1263 // Remove all NAT64 addresses since they might be out-of-date 1264 for (Ipv6AddrInfo info : mRemoteAddressesV6) { 1265 if (info.isNat64Addr) { 1266 mRemoteAddressesV6.remove(info); 1267 } 1268 } 1269 1270 if (isDnsLookupRequiredWithGlobalRemoteAddress(oldNetwork, mNetwork, linkProperties)) { 1271 try { 1272 resolveAndSetAvailableRemoteAddresses(linkProperties); 1273 } catch (IOException e) { 1274 mCallback.onError(wrapAsIkeException(e)); 1275 return; 1276 } 1277 } 1278 1279 try { 1280 selectAndSetRemoteAddress(linkProperties); 1281 } catch (IOException e) { 1282 mCallback.onError(wrapAsIkeException(e)); 1283 return; 1284 } 1285 1286 boolean isIpv4 = mRemoteAddress instanceof Inet4Address; 1287 1288 // If it is known that the server supports NAT-T, use port 4500. Otherwise, use port 500. 1289 int serverPort = 1290 isNattSupported() 1291 ? IkeSocket.SERVER_PORT_UDP_ENCAPSULATED 1292 : IkeSocket.SERVER_PORT_NON_UDP_ENCAPSULATED; 1293 1294 try { 1295 mLocalAddress = 1296 mIkeLocalAddressGenerator.generateLocalAddress( 1297 mNetwork, isIpv4, mRemoteAddress, serverPort); 1298 1299 if (ShimUtils.getInstance().shouldSkipIfSameNetwork(skipIfSameNetwork) 1300 && mNetwork.equals(oldNetwork) 1301 && mLocalAddress.equals(oldLocalAddress) 1302 && mRemoteAddress.equals(oldRemoteAddress)) { 1303 getIkeLog() 1304 .d( 1305 TAG, 1306 "onUnderlyingNetworkUpdated: None of network, local or remote" 1307 + " address has changed, and the update is skippable. No action" 1308 + " needed here."); 1309 return; 1310 } 1311 1312 if (!mNetwork.equals(oldNetwork)) { 1313 boolean useEncapPort = mForcePort4500 || isNattSupported(); 1314 getAndSwitchToIkeSocket(mLocalAddress instanceof Inet4Address, useEncapPort); 1315 } 1316 1317 for (IkeSaRecord record : mIkeSaRecords) { 1318 record.migrate(mLocalAddress, mRemoteAddress); 1319 } 1320 } catch (IkeException | ErrnoException | IOException e) { 1321 mCallback.onError(wrapAsIkeException(e)); 1322 return; 1323 } 1324 1325 mNetworkCallback.setAddress(mLocalAddress); 1326 1327 mCallback.onUnderlyingNetworkUpdated(); 1328 } 1329 1330 /** 1331 * Dumps the state of {@link IkeConnectionController} 1332 * 1333 * @param pw {@link PrintWriter} to write the state of the object. 1334 * @param prefix prefix for indentation 1335 */ dump(PrintWriter pw, String prefix)1336 public void dump(PrintWriter pw, String prefix) { 1337 // Please make sure that the dump is thread-safe 1338 // so the client won't get a crash or exception when adding codes to the dump. 1339 1340 pw.println("------------------------------"); 1341 pw.println("IkeConnectionController:"); 1342 pw.println(prefix + "Network: " + mNetwork); 1343 pw.println(prefix + "Nat status: " + NAT_STATUS_TO_STR.get(mNatStatus)); 1344 pw.println(prefix + "Local address: " + mLocalAddress); 1345 pw.println(prefix + "Remote(Server) address: " + mRemoteAddress); 1346 pw.println(prefix + "Mobility status: " + mMobilityEnabled); 1347 printPortInfo(pw, prefix); 1348 pw.println( 1349 prefix + "Esp ip version: " + IkeSessionParams.IP_VERSION_TO_STR.get(mIpVersion)); 1350 pw.println( 1351 prefix + "Esp encap type: " + IkeSessionParams.ENCAP_TYPE_TO_STR.get(mEncapType)); 1352 pw.println("------------------------------"); 1353 pw.println(); 1354 } 1355 1356 /** 1357 * Port information may sometimes cause exceptions such as NPE or RTE, Dumps ports including the 1358 * exception. 1359 * 1360 * @param pw {@link PrintWriter} to write the state of the object. 1361 * @param prefix prefix for indentation 1362 */ printPortInfo(PrintWriter pw, String prefix)1363 private void printPortInfo(PrintWriter pw, String prefix) { 1364 // Make it thread-safe. Since this method may be accessed simultaneously from 1365 // multiple threads, The socket is assigned locally and then printed. 1366 IkeSocket socket = mIkeSocket; 1367 if (socket == null) { 1368 pw.println(prefix + "Local port: null socket"); 1369 pw.println(prefix + "Remote(server) port: null socket"); 1370 } else { 1371 try { 1372 pw.println(prefix + "Local port: " + socket.getLocalPort()); 1373 } catch (ErrnoException e) { 1374 pw.println(prefix + "Local port: failed to get port"); 1375 } 1376 pw.println(prefix + "Remote(server) port: " + socket.getIkeServerPort()); 1377 } 1378 } 1379 1380 @Override onUnderlyingNetworkUpdated( Network network, LinkProperties linkProperties, NetworkCapabilities networkCapabilities)1381 public void onUnderlyingNetworkUpdated( 1382 Network network, 1383 LinkProperties linkProperties, 1384 NetworkCapabilities networkCapabilities) { 1385 executeOrSendFatalError( 1386 () -> { 1387 handleUnderlyingNetworkUpdated( 1388 network, 1389 linkProperties, 1390 networkCapabilities, 1391 true /* skipIfSameNetwork */); 1392 }); 1393 } 1394 1395 @Override onCapabilitiesUpdated(NetworkCapabilities networkCapabilities)1396 public void onCapabilitiesUpdated(NetworkCapabilities networkCapabilities) { 1397 executeOrSendFatalError( 1398 () -> { 1399 mNc = networkCapabilities; 1400 1401 // No action. There is no known use case to perform mobility or update keepalive 1402 // timer when NetworkCapabilities changes. 1403 }); 1404 } 1405 1406 @Override onUnderlyingNetworkDied()1407 public void onUnderlyingNetworkDied() { 1408 executeOrSendFatalError( 1409 () -> { 1410 mCallback.onUnderlyingNetworkDied(mNetwork); 1411 }); 1412 } 1413 1414 @Override onIkePacketReceived(IkeHeader ikeHeader, byte[] ikePackets)1415 public void onIkePacketReceived(IkeHeader ikeHeader, byte[] ikePackets) { 1416 executeOrSendFatalError( 1417 () -> { 1418 mCallback.onIkePacketReceived(ikeHeader, ikePackets); 1419 }); 1420 } 1421 } 1422