• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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