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.ipsec.ike.IkeManager.getIkeLog; 20 import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_FORCE_PORT_4500; 21 import static android.net.ipsec.ike.exceptions.IkeException.wrapAsIkeException; 22 23 import static com.android.internal.net.ipsec.ike.utils.IkeAlarm.IkeAlarmConfig; 24 25 import android.annotation.IntDef; 26 import android.content.Context; 27 import android.net.ConnectivityManager; 28 import android.net.IpSecManager; 29 import android.net.IpSecManager.ResourceUnavailableException; 30 import android.net.IpSecManager.UdpEncapsulationSocket; 31 import android.net.LinkProperties; 32 import android.net.Network; 33 import android.net.NetworkRequest; 34 import android.net.ipsec.ike.IkeSessionConnectionInfo; 35 import android.net.ipsec.ike.IkeSessionParams; 36 import android.net.ipsec.ike.exceptions.IkeException; 37 import android.os.Handler; 38 import android.system.ErrnoException; 39 40 import com.android.internal.annotations.VisibleForTesting; 41 import com.android.internal.net.ipsec.ike.IkeContext; 42 import com.android.internal.net.ipsec.ike.IkeSocket; 43 import com.android.internal.net.ipsec.ike.IkeSocketConfig; 44 import com.android.internal.net.ipsec.ike.IkeUdp4Socket; 45 import com.android.internal.net.ipsec.ike.IkeUdp6Socket; 46 import com.android.internal.net.ipsec.ike.IkeUdp6WithEncapPortSocket; 47 import com.android.internal.net.ipsec.ike.IkeUdpEncapSocket; 48 import com.android.internal.net.ipsec.ike.SaRecord.IkeSaRecord; 49 import com.android.internal.net.ipsec.ike.keepalive.IkeNattKeepalive; 50 import com.android.internal.net.ipsec.ike.message.IkeHeader; 51 import com.android.internal.net.ipsec.ike.shim.ShimUtils; 52 53 import java.io.IOException; 54 import java.lang.annotation.Retention; 55 import java.lang.annotation.RetentionPolicy; 56 import java.net.Inet4Address; 57 import java.net.Inet6Address; 58 import java.net.InetAddress; 59 import java.net.UnknownHostException; 60 import java.util.ArrayList; 61 import java.util.Arrays; 62 import java.util.Collections; 63 import java.util.HashSet; 64 import java.util.List; 65 import java.util.Set; 66 import java.util.concurrent.TimeUnit; 67 68 /** 69 * IkeConnectionController manages all connectivity events for an IKE Session 70 * 71 * <p>IkeConnectionController's responsibilities include: 72 * 73 * <ul> 74 * <li>Manage IkeSocket for sending and receiving IKE packets 75 * <li>Monitor and handle network and addresses changes 76 * <li>Schedule NAT-T keepalive 77 * </ul> 78 * 79 * An IkeConnectionController should be set up when IKE Session is being established and should be 80 * torn down when the IKE Session is terminated. 81 */ 82 public class IkeConnectionController implements IkeNetworkUpdater, IkeSocket.Callback { 83 private static final String TAG = IkeConnectionController.class.getSimpleName(); 84 85 // The maximum number of attempts allowed for a single DNS resolution. 86 private static final int MAX_DNS_RESOLUTION_ATTEMPTS = 3; 87 88 @Retention(RetentionPolicy.SOURCE) 89 @IntDef({ 90 NAT_TRAVERSAL_SUPPORT_NOT_CHECKED, 91 NAT_TRAVERSAL_UNSUPPORTED, 92 NAT_NOT_DETECTED, 93 NAT_DETECTED 94 }) 95 public @interface NatStatus {} 96 97 /** The IKE client has not checked whether the server supports NAT-T */ 98 public static final int NAT_TRAVERSAL_SUPPORT_NOT_CHECKED = 0; 99 /** The IKE server does not support NAT-T */ 100 public static final int NAT_TRAVERSAL_UNSUPPORTED = 1; 101 /** There is no NAT between the IKE client and the server */ 102 public static final int NAT_NOT_DETECTED = 2; 103 /** There is at least a NAT between the IKE client and the server */ 104 public static final int NAT_DETECTED = 3; 105 106 private final IkeContext mIkeContext; 107 private final ConnectivityManager mConnectivityManager; 108 private final IpSecManager mIpSecManager; 109 private final Dependencies mDependencies; 110 private final IkeLocalAddressGenerator mIkeLocalAddressGenerator; 111 private final Callback mCallback; 112 113 private final boolean mForcePort4500; 114 private final boolean mUseCallerConfiguredNetwork; 115 private final String mRemoteHostname; 116 private final int mDscp = 0; 117 private final IkeAlarmConfig mKeepaliveAlarmConfig; 118 119 private IkeSocket mIkeSocket; 120 121 /** Underlying network for this IKE Session. May change if mobility handling is enabled. */ 122 private Network mNetwork; 123 /** 124 * Network callback used to keep IkeConnectionController aware of network changes when mobility 125 * handling is enabled. 126 */ 127 private IkeNetworkCallbackBase mNetworkCallback; 128 129 private boolean mMobilityEnabled = false; 130 131 /** Local address assigned on device. */ 132 private InetAddress mLocalAddress; 133 /** Remote address resolved from caller configured hostname. */ 134 private InetAddress mRemoteAddress; 135 /** Available remote addresses that are v4. */ 136 private final List<Inet4Address> mRemoteAddressesV4 = new ArrayList<>(); 137 /** Available remote addresses that are v6. */ 138 private final List<Inet6Address> mRemoteAddressesV6 = new ArrayList<>(); 139 140 private final Set<IkeSaRecord> mIkeSaRecords = new HashSet<>(); 141 142 @NatStatus private int mNatStatus; 143 144 private IkeNattKeepalive mIkeNattKeepalive; 145 146 /** Constructor of IkeConnectionController */ 147 @VisibleForTesting IkeConnectionController( IkeContext ikeContext, Config config, Dependencies dependencies)148 public IkeConnectionController( 149 IkeContext ikeContext, Config config, Dependencies dependencies) { 150 mIkeContext = ikeContext; 151 mConnectivityManager = mIkeContext.getContext().getSystemService(ConnectivityManager.class); 152 mIpSecManager = mIkeContext.getContext().getSystemService(IpSecManager.class); 153 mDependencies = dependencies; 154 mIkeLocalAddressGenerator = dependencies.newIkeLocalAddressGenerator(); 155 mCallback = config.callback; 156 157 mForcePort4500 = config.ikeParams.hasIkeOption(IKE_OPTION_FORCE_PORT_4500); 158 mRemoteHostname = config.ikeParams.getServerHostname(); 159 mUseCallerConfiguredNetwork = config.ikeParams.getConfiguredNetwork() != null; 160 mKeepaliveAlarmConfig = config.keepaliveAlarmConfig; 161 162 if (mUseCallerConfiguredNetwork) { 163 mNetwork = config.ikeParams.getConfiguredNetwork(); 164 } else { 165 mNetwork = mConnectivityManager.getActiveNetwork(); 166 if (mNetwork == null) { 167 throw new IllegalStateException("No active default network found"); 168 } 169 } 170 171 getIkeLog().d(TAG, "Set up on Network " + mNetwork); 172 173 mNatStatus = NAT_TRAVERSAL_SUPPORT_NOT_CHECKED; 174 } 175 176 /** Constructor of IkeConnectionController */ IkeConnectionController(IkeContext ikeContext, Config config)177 public IkeConnectionController(IkeContext ikeContext, Config config) { 178 this(ikeContext, config, new Dependencies()); 179 } 180 181 /** Config includes all configurations to build an IkeConnectionController */ 182 public static class Config { 183 public final IkeSessionParams ikeParams; 184 public final IkeAlarmConfig keepaliveAlarmConfig; 185 public final Callback callback; 186 187 /** Constructor for IkeConnectionController.Config */ Config( IkeSessionParams ikeParams, IkeAlarmConfig keepaliveAlarmConfig, Callback callback)188 public Config( 189 IkeSessionParams ikeParams, 190 IkeAlarmConfig keepaliveAlarmConfig, 191 Callback callback) { 192 this.ikeParams = ikeParams; 193 this.keepaliveAlarmConfig = keepaliveAlarmConfig; 194 this.callback = callback; 195 } 196 } 197 198 /** Callback to notify status changes of the connection */ 199 public interface Callback { 200 /** Notify the IkeConnectionController caller the underlying network has changed */ onUnderlyingNetworkUpdated()201 void onUnderlyingNetworkUpdated(); 202 203 /** Notify the IkeConnectionController caller that the underlying network died */ onUnderlyingNetworkDied(Network network)204 void onUnderlyingNetworkDied(Network network); 205 206 /** Notify the IkeConnectionController caller of the incoming IKE packet */ onIkePacketReceived(IkeHeader ikeHeader, byte[] ikePackets)207 void onIkePacketReceived(IkeHeader ikeHeader, byte[] ikePackets); 208 209 /** Notify the IkeConnectionController caller of the IKE error */ onError(IkeException exception)210 void onError(IkeException exception); 211 } 212 213 /** External dependencies, for injection in tests */ 214 @VisibleForTesting 215 public static class Dependencies { 216 /** Gets an IkeLocalAddressGenerator */ newIkeLocalAddressGenerator()217 public IkeLocalAddressGenerator newIkeLocalAddressGenerator() { 218 return new IkeLocalAddressGenerator(); 219 } 220 221 /** Builds and starts NATT keepalive */ newIkeNattKeepalive( Context context, InetAddress localAddress, InetAddress remoteAddress, UdpEncapsulationSocket udpEncapSocket, Network network, IkeAlarmConfig alarmConfig)222 public IkeNattKeepalive newIkeNattKeepalive( 223 Context context, 224 InetAddress localAddress, 225 InetAddress remoteAddress, 226 UdpEncapsulationSocket udpEncapSocket, 227 Network network, 228 IkeAlarmConfig alarmConfig) 229 throws IOException { 230 IkeNattKeepalive keepalive = 231 new IkeNattKeepalive( 232 context, 233 context.getSystemService(ConnectivityManager.class), 234 (int) TimeUnit.MILLISECONDS.toSeconds(alarmConfig.delayMs), 235 (Inet4Address) localAddress, 236 (Inet4Address) remoteAddress, 237 udpEncapSocket, 238 network, 239 alarmConfig); 240 keepalive.start(); 241 return keepalive; 242 } 243 244 /** Builds and returns a new IkeUdp4Socket */ newIkeUdp4Socket( IkeSocketConfig sockConfig, IkeSocket.Callback callback, Handler handler)245 public IkeUdp4Socket newIkeUdp4Socket( 246 IkeSocketConfig sockConfig, IkeSocket.Callback callback, Handler handler) 247 throws ErrnoException, IOException { 248 return IkeUdp4Socket.getInstance(sockConfig, callback, handler); 249 } 250 251 /** Builds and returns a new IkeUdp6Socket */ newIkeUdp6Socket( IkeSocketConfig sockConfig, IkeSocket.Callback callback, Handler handler)252 public IkeUdp6Socket newIkeUdp6Socket( 253 IkeSocketConfig sockConfig, IkeSocket.Callback callback, Handler handler) 254 throws ErrnoException, IOException { 255 return IkeUdp6Socket.getInstance(sockConfig, callback, handler); 256 } 257 258 /** Builds and returns a new IkeUdp6WithEncapPortSocket */ newIkeUdp6WithEncapPortSocket( IkeSocketConfig sockConfig, IkeSocket.Callback callback, Handler handler)259 public IkeUdp6WithEncapPortSocket newIkeUdp6WithEncapPortSocket( 260 IkeSocketConfig sockConfig, IkeSocket.Callback callback, Handler handler) 261 throws ErrnoException, IOException { 262 return IkeUdp6WithEncapPortSocket.getIkeUdpEncapSocket(sockConfig, callback, handler); 263 } 264 265 /** Builds and returns a new IkeUdpEncapSocket */ newIkeUdpEncapSocket( IkeSocketConfig sockConfig, IpSecManager ipSecManager, IkeSocket.Callback callback, Handler handler)266 public IkeUdpEncapSocket newIkeUdpEncapSocket( 267 IkeSocketConfig sockConfig, 268 IpSecManager ipSecManager, 269 IkeSocket.Callback callback, 270 Handler handler) 271 throws ErrnoException, IOException, ResourceUnavailableException { 272 return IkeUdpEncapSocket.getIkeUdpEncapSocket( 273 sockConfig, ipSecManager, callback, handler.getLooper()); 274 } 275 } 276 277 /** Starts NAT-T keepalive for current IkeUdpEncapSocket */ buildAndStartNattKeepalive()278 private IkeNattKeepalive buildAndStartNattKeepalive() throws IOException { 279 IkeNattKeepalive keepalive = 280 mDependencies.newIkeNattKeepalive( 281 mIkeContext.getContext(), 282 mLocalAddress, 283 mRemoteAddress, 284 ((IkeUdpEncapSocket) mIkeSocket).getUdpEncapsulationSocket(), 285 mNetwork, 286 mKeepaliveAlarmConfig); 287 288 return keepalive; 289 } 290 getIkeSocket(boolean isIpv4, boolean useEncapPort)291 private IkeSocket getIkeSocket(boolean isIpv4, boolean useEncapPort) throws IkeException { 292 IkeSocketConfig sockConfig = new IkeSocketConfig(mNetwork, mDscp); 293 294 try { 295 if (useEncapPort) { 296 if (isIpv4) { 297 return mDependencies.newIkeUdpEncapSocket( 298 sockConfig, mIpSecManager, this, new Handler(mIkeContext.getLooper())); 299 } else { 300 return mDependencies.newIkeUdp6WithEncapPortSocket( 301 sockConfig, this, new Handler(mIkeContext.getLooper())); 302 } 303 } else { 304 if (isIpv4) { 305 return mDependencies.newIkeUdp4Socket( 306 sockConfig, this, new Handler(mIkeContext.getLooper())); 307 } else { 308 return mDependencies.newIkeUdp6Socket( 309 sockConfig, this, new Handler(mIkeContext.getLooper())); 310 } 311 } 312 } catch (ErrnoException | IOException | ResourceUnavailableException e) { 313 throw wrapAsIkeException(e); 314 } 315 } 316 migrateSpiToIkeSocket(long localSpi, IkeSocket oldSocket, IkeSocket newSocket)317 private void migrateSpiToIkeSocket(long localSpi, IkeSocket oldSocket, IkeSocket newSocket) { 318 newSocket.registerIke(localSpi, this); 319 oldSocket.unregisterIke(localSpi); 320 } 321 getAndSwitchToIkeSocket(boolean isIpv4, boolean useEncapPort)322 private void getAndSwitchToIkeSocket(boolean isIpv4, boolean useEncapPort) throws IkeException { 323 IkeSocket newSocket = getIkeSocket(isIpv4, useEncapPort); 324 if (newSocket == mIkeSocket) { 325 // Attempting to switch to current socket - ignore. 326 return; 327 } 328 329 if (mIkeNattKeepalive != null) { 330 mIkeNattKeepalive.stop(); 331 mIkeNattKeepalive = null; 332 } 333 334 for (IkeSaRecord saRecord : mIkeSaRecords) { 335 migrateSpiToIkeSocket(saRecord.getLocalSpi(), mIkeSocket, newSocket); 336 } 337 mIkeSocket.releaseReference(this); 338 mIkeSocket = newSocket; 339 340 try { 341 if (mIkeSocket instanceof IkeUdpEncapSocket) { 342 mIkeNattKeepalive = buildAndStartNattKeepalive(); 343 } 344 } catch (IOException e) { 345 throw wrapAsIkeException(e); 346 } 347 } 348 /** Sets up the IkeConnectionController */ setUp()349 public void setUp() throws IkeException { 350 // Make sure all the resources, especially the NetworkCallback, is released before creating 351 // new one. 352 unregisterResources(); 353 354 try { 355 resolveAndSetAvailableRemoteAddresses(); 356 setRemoteAddress(); 357 358 int remotePort = 359 mForcePort4500 360 ? IkeSocket.SERVER_PORT_UDP_ENCAPSULATED 361 : IkeSocket.SERVER_PORT_NON_UDP_ENCAPSULATED; 362 boolean isIpv4 = mRemoteAddress instanceof Inet4Address; 363 mLocalAddress = 364 mIkeLocalAddressGenerator.generateLocalAddress( 365 mNetwork, isIpv4, mRemoteAddress, remotePort); 366 mIkeSocket = getIkeSocket(isIpv4, mForcePort4500); 367 368 if (mIkeSocket instanceof IkeUdpEncapSocket) { 369 mIkeNattKeepalive = buildAndStartNattKeepalive(); 370 } 371 } catch (IOException | ErrnoException e) { 372 throw wrapAsIkeException(e); 373 } 374 375 try { 376 if (mUseCallerConfiguredNetwork) { 377 // Caller configured a specific Network - track it 378 // ConnectivityManager does not provide a callback for tracking a specific 379 // Network. In order to do so, create a NetworkRequest without any 380 // capabilities so it will match all Networks. The NetworkCallback will then 381 // filter for the correct (caller-specified) Network. 382 NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build(); 383 mNetworkCallback = new IkeSpecificNetworkCallback(this, mNetwork, mLocalAddress); 384 mConnectivityManager.registerNetworkCallback( 385 request, mNetworkCallback, new Handler(mIkeContext.getLooper())); 386 } else { 387 // Caller did not configure a specific Network - track the default 388 mNetworkCallback = new IkeDefaultNetworkCallback(this, mNetwork, mLocalAddress); 389 mConnectivityManager.registerDefaultNetworkCallback( 390 mNetworkCallback, new Handler(mIkeContext.getLooper())); 391 } 392 } catch (RuntimeException e) { 393 mNetworkCallback = null; 394 throw wrapAsIkeException(e); 395 } 396 } 397 unregisterResources()398 private void unregisterResources() { 399 if (mIkeNattKeepalive != null) { 400 mIkeNattKeepalive.stop(); 401 mIkeNattKeepalive = null; 402 } 403 404 if (mNetworkCallback != null) { 405 mConnectivityManager.unregisterNetworkCallback(mNetworkCallback); 406 mNetworkCallback = null; 407 } 408 409 if (mIkeSocket != null) { 410 for (IkeSaRecord saRecord : mIkeSaRecords) { 411 mIkeSocket.unregisterIke(saRecord.getLocalSpi()); 412 } 413 414 mIkeSocket.releaseReference(this); 415 mIkeSocket = null; 416 } 417 418 mIkeSaRecords.clear(); 419 } 420 421 /** Tears down the IkeConnectionController */ tearDown()422 public void tearDown() { 423 unregisterResources(); 424 } 425 426 /** Returns the IkeSocket */ getIkeSocket()427 public IkeSocket getIkeSocket() { 428 return mIkeSocket; 429 } 430 431 /** Returns if the IkeSocket is a UDP encapsulation socket */ useUdpEncapSocket()432 public boolean useUdpEncapSocket() { 433 return mIkeSocket instanceof IkeUdpEncapSocket; 434 } 435 436 /** Sends out an IKE packet */ sendIkePacket(byte[] ikePacket)437 public void sendIkePacket(byte[] ikePacket) { 438 mIkeSocket.sendIkePacket(ikePacket, mRemoteAddress); 439 } 440 441 /** Registers the local SPI for an IKE SA waiting for the IKE INIT response */ registerIkeSpi(long ikeSpi)442 public void registerIkeSpi(long ikeSpi) { 443 mIkeSocket.registerIke(ikeSpi, this); 444 } 445 446 /** Unregisters the local SPI for an IKE SA that failed IKE INIT exchange */ unregisterIkeSpi(long ikeSpi)447 public void unregisterIkeSpi(long ikeSpi) { 448 mIkeSocket.unregisterIke(ikeSpi); 449 } 450 451 /** Registers a newly created IKE SA */ registerIkeSaRecord(IkeSaRecord saRecord)452 public void registerIkeSaRecord(IkeSaRecord saRecord) { 453 mIkeSaRecords.add(saRecord); 454 mIkeSocket.registerIke(saRecord.getLocalSpi(), this); 455 } 456 457 /** Unregisters a deleted IKE SA */ unregisterIkeSaRecord(IkeSaRecord saRecord)458 public void unregisterIkeSaRecord(IkeSaRecord saRecord) { 459 mIkeSaRecords.remove(saRecord); 460 mIkeSocket.unregisterIke(saRecord.getLocalSpi()); 461 } 462 463 /** Returns all registered IKE SAs */ 464 @VisibleForTesting getIkeSaRecords()465 public Set<IkeSaRecord> getIkeSaRecords() { 466 return Collections.unmodifiableSet(mIkeSaRecords); 467 } 468 469 /** Updates the underlying network */ setNetwork(Network network)470 public void setNetwork(Network network) { 471 if (!mMobilityEnabled) { 472 // Program error. IkeSessionStateMachine should never call this method before enabling 473 // mobility. 474 getIkeLog().wtf(TAG, "Attempt to update network when mobility is disabled"); 475 return; 476 } 477 478 onUnderlyingNetworkUpdated(network); 479 } 480 481 /** Gets the underlying network */ getNetwork()482 public Network getNetwork() { 483 return mNetwork; 484 } 485 486 /** Check if mobility is enabled */ isMobilityEnabled()487 public boolean isMobilityEnabled() { 488 return mMobilityEnabled; 489 } 490 491 /** 492 * Sets the local address. 493 * 494 * <p>This MUST only be called in a test. 495 */ 496 @VisibleForTesting setLocalAddress(InetAddress address)497 public void setLocalAddress(InetAddress address) { 498 mLocalAddress = address; 499 } 500 501 /** Gets the local address */ getLocalAddress()502 public InetAddress getLocalAddress() { 503 return mLocalAddress; 504 } 505 506 /** 507 * Sets the remote address. 508 * 509 * <p>This MUST only be called in a test. 510 */ 511 @VisibleForTesting setRemoteAddress(InetAddress address)512 public void setRemoteAddress(InetAddress address) { 513 mRemoteAddress = address; 514 addRemoteAddress(address); 515 } 516 517 /** 518 * Adds a remote address. 519 * 520 * <p>This MUST only be called in a test. 521 */ 522 @VisibleForTesting addRemoteAddress(InetAddress address)523 public void addRemoteAddress(InetAddress address) { 524 if (address instanceof Inet4Address) { 525 mRemoteAddressesV4.add((Inet4Address) address); 526 } else { 527 mRemoteAddressesV6.add((Inet6Address) address); 528 } 529 } 530 531 /** Gets the remote addresses */ getRemoteAddress()532 public InetAddress getRemoteAddress() { 533 return mRemoteAddress; 534 } 535 536 /** Gets all the IPv4 remote addresses */ getAllRemoteIpv4Addresses()537 public List<Inet4Address> getAllRemoteIpv4Addresses() { 538 return new ArrayList<>(mRemoteAddressesV4); 539 } 540 541 /** Gets all the IPv6 remote addresses */ getAllRemoteIpv6Addresses()542 public List<Inet6Address> getAllRemoteIpv6Addresses() { 543 return new ArrayList<>(mRemoteAddressesV6); 544 } 545 546 /** Gets the local port */ getLocalPort()547 public int getLocalPort() { 548 try { 549 return mIkeSocket.getLocalPort(); 550 } catch (ErrnoException e) { 551 throw new IllegalStateException("Fail to get local port", e); 552 } 553 } 554 555 /** Gets the remote port */ getRemotePort()556 public int getRemotePort() { 557 return mIkeSocket.getIkeServerPort(); 558 } 559 560 /** Handles NAT detection result in IKE INIT */ handleNatDetectionResultInIkeInit(boolean isNatDetected, long localSpi)561 public void handleNatDetectionResultInIkeInit(boolean isNatDetected, long localSpi) 562 throws IkeException { 563 if (!isNatDetected) { 564 mNatStatus = NAT_NOT_DETECTED; 565 return; 566 } 567 568 mNatStatus = NAT_DETECTED; 569 if (mRemoteAddress instanceof Inet6Address) { 570 throw wrapAsIkeException(new UnsupportedOperationException("IPv6 NAT-T not supported")); 571 } 572 573 getIkeLog().d(TAG, "Switching to send to remote port 4500 if it's not already"); 574 575 IkeSocket newSocket = getIkeSocket(true /* isIpv4 */, true /* useEncapPort */); 576 if (newSocket == mIkeSocket) { 577 // Attempting to switch to current socket - ignore. 578 return; 579 } 580 581 if (mIkeNattKeepalive != null) { 582 mIkeNattKeepalive.stop(); 583 mIkeNattKeepalive = null; 584 } 585 586 migrateSpiToIkeSocket(localSpi, mIkeSocket, newSocket); 587 mIkeSocket.releaseReference(this); 588 mIkeSocket = newSocket; 589 590 try { 591 if (mIkeSocket instanceof IkeUdpEncapSocket) { 592 mIkeNattKeepalive = buildAndStartNattKeepalive(); 593 } 594 } catch (IOException e) { 595 throw wrapAsIkeException(e); 596 } 597 } 598 599 /** Handles NAT detection result in the MOBIKE INFORMATIONAL exchange */ handleNatDetectionResultInMobike(boolean isNatDetected)600 public void handleNatDetectionResultInMobike(boolean isNatDetected) throws IkeException { 601 if (!isNatDetected) { 602 mNatStatus = NAT_NOT_DETECTED; 603 return; 604 } 605 606 mNatStatus = NAT_DETECTED; 607 if (mRemoteAddress instanceof Inet6Address) { 608 throw wrapAsIkeException(new UnsupportedOperationException("IPv6 NAT-T not supported")); 609 } 610 611 getIkeLog().d(TAG, "Switching to send to remote port 4500 if it's not already"); 612 getAndSwitchToIkeSocket(true /* isIpv4 */, true /* useEncapPort */); 613 } 614 615 /** 616 * Marks that the server does not support NAT-T 617 * 618 * <p>This is method should only be called at the first time IKE client sends NAT_DETECTION (in 619 * other words the first time IKE client is using IPv4 address since IKE does not support IPv6 620 * NAT-T) 621 */ markSeverNattUnsupported()622 public void markSeverNattUnsupported() { 623 mNatStatus = NAT_TRAVERSAL_UNSUPPORTED; 624 } 625 626 /** 627 * Clears the knowledge of sever's NAT-T support 628 * 629 * <p>This MUST only be called in a test. 630 */ 631 @VisibleForTesting resetSeverNattSupport()632 public void resetSeverNattSupport() { 633 mNatStatus = NAT_TRAVERSAL_SUPPORT_NOT_CHECKED; 634 } 635 636 /** This MUST only be called in a test. */ 637 @VisibleForTesting setNatDetected(boolean isNatDetected)638 public void setNatDetected(boolean isNatDetected) { 639 if (!isNatDetected) { 640 mNatStatus = NAT_NOT_DETECTED; 641 return; 642 } 643 644 mNatStatus = NAT_DETECTED; 645 } 646 647 /** Returns the NAT status */ 648 @NatStatus getNatStatus()649 public int getNatStatus() { 650 return mNatStatus; 651 } 652 653 /** Returns the IkeNattKeepalive */ getIkeNattKeepalive()654 public IkeNattKeepalive getIkeNattKeepalive() { 655 return mIkeNattKeepalive; 656 } 657 658 /** Fire software keepalive */ fireKeepAlive()659 public void fireKeepAlive() { 660 // Software keepalive alarm is fired. Ignore the alarm whe NAT-T keepalive is no 661 // longer needed (e.g. migrating from IPv4 to IPv6) 662 if (mIkeNattKeepalive != null) { 663 mIkeNattKeepalive.onAlarmFired(); 664 } 665 } 666 resolveAndSetAvailableRemoteAddresses()667 private void resolveAndSetAvailableRemoteAddresses() throws IOException { 668 // TODO(b/149954916): Do DNS resolution asynchronously 669 InetAddress[] allRemoteAddresses = null; 670 671 for (int attempts = 0; 672 attempts < MAX_DNS_RESOLUTION_ATTEMPTS 673 && (allRemoteAddresses == null || allRemoteAddresses.length == 0); 674 attempts++) { 675 try { 676 allRemoteAddresses = mNetwork.getAllByName(mRemoteHostname); 677 } catch (UnknownHostException e) { 678 final boolean willRetry = attempts + 1 < MAX_DNS_RESOLUTION_ATTEMPTS; 679 getIkeLog() 680 .d( 681 TAG, 682 "Failed to look up host for attempt " 683 + (attempts + 1) 684 + ": " 685 + mRemoteHostname 686 + " retrying? " 687 + willRetry, 688 e); 689 } 690 } 691 if (allRemoteAddresses == null || allRemoteAddresses.length == 0) { 692 final String errMsg = 693 "DNS resolution for " 694 + mRemoteHostname 695 + " failed after " 696 + MAX_DNS_RESOLUTION_ATTEMPTS 697 + " attempts"; 698 699 throw ShimUtils.getInstance().getDnsFailedException(errMsg); 700 } 701 702 getIkeLog() 703 .d( 704 TAG, 705 "Resolved addresses for peer: " 706 + Arrays.toString(allRemoteAddresses) 707 + " to replace old addresses: v4=" 708 + mRemoteAddressesV4 709 + " v6=" 710 + mRemoteAddressesV6); 711 712 mRemoteAddressesV4.clear(); 713 mRemoteAddressesV6.clear(); 714 for (InetAddress remoteAddress : allRemoteAddresses) { 715 if (remoteAddress instanceof Inet4Address) { 716 mRemoteAddressesV4.add((Inet4Address) remoteAddress); 717 } else { 718 mRemoteAddressesV6.add((Inet6Address) remoteAddress); 719 } 720 } 721 } 722 723 /** 724 * Set the remote address for the peer. 725 * 726 * <p>Prefers IPv6 addresses if: 727 * 728 * <ul> 729 * <li>an IPv6 address is known for the peer, and 730 * <li>the current underlying Network has a global (non-link local) IPv6 address available 731 * </ul> 732 * 733 * Otherwise, an IPv4 address will be used. 734 */ setRemoteAddress()735 private void setRemoteAddress() { 736 LinkProperties linkProperties = mConnectivityManager.getLinkProperties(mNetwork); 737 if (!mRemoteAddressesV6.isEmpty() && linkProperties.hasGlobalIpv6Address()) { 738 // TODO(b/175348096): randomly choose from available addresses 739 mRemoteAddress = mRemoteAddressesV6.get(0); 740 } else { 741 if (mRemoteAddressesV4.isEmpty()) { 742 throw new IllegalArgumentException("No valid IPv4 or IPv6 addresses for peer"); 743 } 744 745 // TODO(b/175348096): randomly choose from available addresses 746 mRemoteAddress = mRemoteAddressesV4.get(0); 747 } 748 } 749 750 /** 751 * Enables IkeConnectionController to handle mobility events 752 * 753 * <p>This method will enable IkeConnectionController to monitor and handle changes of the 754 * underlying network and addresses. 755 */ enableMobility()756 public void enableMobility() throws IkeException { 757 mMobilityEnabled = true; 758 759 if (mNatStatus != NAT_TRAVERSAL_UNSUPPORTED 760 && mIkeSocket.getIkeServerPort() != IkeSocket.SERVER_PORT_UDP_ENCAPSULATED) { 761 getAndSwitchToIkeSocket( 762 mRemoteAddress instanceof Inet4Address, true /* useEncapPort */); 763 } 764 } 765 766 /** Creates a IkeSessionConnectionInfo */ buildIkeSessionConnectionInfo()767 public IkeSessionConnectionInfo buildIkeSessionConnectionInfo() { 768 return new IkeSessionConnectionInfo(mLocalAddress, mRemoteAddress, mNetwork); 769 } 770 771 @Override onUnderlyingNetworkUpdated(Network network)772 public void onUnderlyingNetworkUpdated(Network network) { 773 if (!mMobilityEnabled) { 774 getIkeLog().d(TAG, "onUnderlyingNetworkUpdated: Unable to handle network update"); 775 mCallback.onUnderlyingNetworkDied(mNetwork); 776 777 return; 778 } 779 780 Network oldNetwork = mNetwork; 781 InetAddress oldLocalAddress = mLocalAddress; 782 InetAddress oldRemoteAddress = mRemoteAddress; 783 784 mNetwork = network; 785 786 // If the network changes, perform a new DNS lookup to ensure that the correct remote 787 // address is used. This ensures that DNS returns addresses for the correct address families 788 // (important if using a v4/v6-only network). This also ensures that DNS64 is handled 789 // correctly when switching between networks that may have different IPv6 prefixes. 790 if (!mNetwork.equals(oldNetwork)) { 791 try { 792 resolveAndSetAvailableRemoteAddresses(); 793 } catch (IOException e) { 794 mCallback.onError(wrapAsIkeException(e)); 795 return; 796 } 797 } 798 799 setRemoteAddress(); 800 801 boolean isIpv4 = mRemoteAddress instanceof Inet4Address; 802 803 // If it is known that the server supports NAT-T, use port 4500. Otherwise, use port 500. 804 boolean nattSupported = mNatStatus != NAT_TRAVERSAL_UNSUPPORTED; 805 int serverPort = 806 nattSupported 807 ? IkeSocket.SERVER_PORT_UDP_ENCAPSULATED 808 : IkeSocket.SERVER_PORT_NON_UDP_ENCAPSULATED; 809 810 try { 811 mLocalAddress = 812 mIkeLocalAddressGenerator.generateLocalAddress( 813 mNetwork, isIpv4, mRemoteAddress, serverPort); 814 815 if (mNetwork.equals(oldNetwork) 816 && mLocalAddress.equals(oldLocalAddress) 817 && mRemoteAddress.equals(oldRemoteAddress)) { 818 getIkeLog() 819 .d( 820 TAG, 821 "onUnderlyingNetworkUpdated: None of network, local or remote" 822 + " address has changed. No action needed here."); 823 return; 824 } 825 826 if (!mNetwork.equals(oldNetwork)) { 827 boolean useEncapPort = mForcePort4500 || nattSupported; 828 getAndSwitchToIkeSocket(mLocalAddress instanceof Inet4Address, useEncapPort); 829 } 830 831 for (IkeSaRecord record : mIkeSaRecords) { 832 record.migrate(mLocalAddress, mRemoteAddress); 833 } 834 } catch (IkeException | ErrnoException | IOException e) { 835 mCallback.onError(wrapAsIkeException(e)); 836 return; 837 } 838 839 mNetworkCallback.setNetwork(mNetwork); 840 mNetworkCallback.setAddress(mLocalAddress); 841 842 // TODO: Update IkeSocket and NATT keepalive 843 844 mCallback.onUnderlyingNetworkUpdated(); 845 } 846 847 @Override onUnderlyingNetworkDied()848 public void onUnderlyingNetworkDied() { 849 mCallback.onUnderlyingNetworkDied(mNetwork); 850 } 851 852 @Override onIkePacketReceived(IkeHeader ikeHeader, byte[] ikePackets)853 public void onIkePacketReceived(IkeHeader ikeHeader, byte[] ikePackets) { 854 mCallback.onIkePacketReceived(ikeHeader, ikePackets); 855 } 856 } 857