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