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