Snap for 10597884 from 8d972b1737da5ff7ccc46d18aa33681537f3fd1a to mainline-networking-release
Change-Id: Ib0782edb77ecd7a3b3960786c68f66a3dc40bd44
diff --git a/OWNERS b/OWNERS
index 14d68d7..8d6e439 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,8 +1,13 @@
-# Bug component: 827526
-benedictwong@google.com
+# Bug component: 1364804
+
+amruthr@google.com #{LAST_RESORT_SUGGESTION}
+jackyu@google.com
+nagendranb@google.com
+rgreenwalt@google.com #{LAST_RESORT_SUGGESTION}
+sangyun@google.com
+
+benedictwong@google.com #{LAST_RESORT_SUGGESTION}
evitayan@google.com
-jchalard@google.com
-lorenzo@google.com
-nharold@google.com
+nharold@google.com #{LAST_RESORT_SUGGESTION}
include platform/packages/modules/common:/MODULES_OWNERS
diff --git a/src/java/com/android/internal/net/ipsec/ike/net/IkeConnectionController.java b/src/java/com/android/internal/net/ipsec/ike/net/IkeConnectionController.java
index 71c14be..2bdec16 100644
--- a/src/java/com/android/internal/net/ipsec/ike/net/IkeConnectionController.java
+++ b/src/java/com/android/internal/net/ipsec/ike/net/IkeConnectionController.java
@@ -38,6 +38,7 @@
import android.annotation.IntDef;
import android.app.PendingIntent;
import android.net.ConnectivityManager;
+import android.net.IpPrefix;
import android.net.IpSecManager;
import android.net.IpSecManager.ResourceUnavailableException;
import android.net.LinkAddress;
@@ -79,6 +80,7 @@
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
+import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@@ -162,7 +164,7 @@
/** Available remote addresses that are v4. */
private final List<Inet4Address> mRemoteAddressesV4 = new ArrayList<>();
/** Available remote addresses that are v6. */
- private final List<Inet6Address> mRemoteAddressesV6 = new ArrayList<>();
+ private final List<Ipv6AddrInfo> mRemoteAddressesV6 = new ArrayList<>();
private final Set<IkeSaRecord> mIkeSaRecords = new HashSet<>();
@@ -217,6 +219,25 @@
this(ikeContext, config, new Dependencies());
}
+ private static class Ipv6AddrInfo {
+ public final Inet6Address address;
+ public final boolean isNat64Addr;
+
+ Ipv6AddrInfo(Inet6Address address, boolean isNat64Addr) {
+ this.address = address;
+ this.isNat64Addr = isNat64Addr;
+ }
+
+ @Override
+ public String toString() {
+ String result = address.toString();
+ if (isNat64Addr) {
+ return result + "(Nat64)";
+ }
+ return result;
+ }
+ }
+
/** Config includes all configurations to build an IkeConnectionController */
public static class Config {
public final IkeSessionParams ikeParams;
@@ -481,7 +502,7 @@
+ mNetwork
+ " with null LinkProperties or null NetworkCapabilities"));
}
- resolveAndSetAvailableRemoteAddresses();
+ resolveAndSetAvailableRemoteAddresses(linkProperties);
selectAndSetRemoteAddress(linkProperties);
int remotePort =
@@ -616,6 +637,18 @@
return;
}
+ getIkeLog()
+ .d(
+ TAG,
+ "onNetworkSetByUser: network "
+ + network
+ + " ipVersion "
+ + ipVersion
+ + " encapType "
+ + encapType
+ + " keepaliveDelaySeconds "
+ + keepaliveDelaySeconds);
+
// This is call is directly from the IkeSessionStateMachine, and thus cannot be
// accidentally called in a NetworkCallback. See
// ConnectivityManager.NetworkCallback#onLinkPropertiesChanged() and
@@ -727,10 +760,32 @@
if (address instanceof Inet4Address) {
mRemoteAddressesV4.add((Inet4Address) address);
} else {
- mRemoteAddressesV6.add((Inet6Address) address);
+ mRemoteAddressesV6.add(
+ new Ipv6AddrInfo((Inet6Address) address, false /* isNat64Addr */));
}
}
+ /**
+ * Adds a remote IPv6 address.
+ *
+ * <p>This MUST only be called in a test.
+ */
+ @VisibleForTesting
+ public void addRemoteAddressV6(Inet6Address address, boolean isNat64Addr) {
+ mRemoteAddressesV6.add(new Ipv6AddrInfo((Inet6Address) address, isNat64Addr));
+ }
+
+ /**
+ * Clear all remote address cache.
+ *
+ * <p>This MUST only be called in a test.
+ */
+ @VisibleForTesting
+ public void clearRemoteAddress() {
+ mRemoteAddressesV4.clear();
+ mRemoteAddressesV6.clear();
+ }
+
/** Gets the remote addresses */
public InetAddress getRemoteAddress() {
return mRemoteAddress;
@@ -743,7 +798,11 @@
/** Gets all the IPv6 remote addresses */
public List<Inet6Address> getAllRemoteIpv6Addresses() {
- return new ArrayList<>(mRemoteAddressesV6);
+ final List<Inet6Address> addresses = new ArrayList<>();
+ for (Ipv6AddrInfo info : mRemoteAddressesV6) {
+ addresses.add(info.address);
+ }
+ return addresses;
}
/** Gets the local port */
@@ -858,7 +917,8 @@
}
}
- private void resolveAndSetAvailableRemoteAddresses() throws IOException {
+ private void resolveAndSetAvailableRemoteAddresses(LinkProperties linkProperties)
+ throws IOException {
// TODO(b/149954916): Do DNS resolution asynchronously
InetAddress[] allRemoteAddresses = null;
@@ -909,7 +969,10 @@
if (remoteAddress instanceof Inet4Address) {
mRemoteAddressesV4.add((Inet4Address) remoteAddress);
} else {
- mRemoteAddressesV6.add((Inet6Address) remoteAddress);
+ Inet6Address address = (Inet6Address) remoteAddress;
+ IpPrefix ipPrefix = linkProperties.getNat64Prefix();
+ mRemoteAddressesV6.add(
+ new Ipv6AddrInfo(address, ipPrefix != null && ipPrefix.contains(address)));
}
}
}
@@ -958,11 +1021,11 @@
throw ShimUtils.getInstance().getDnsFailedException(
"IPv6 required but no global IPv6 address available");
}
- mRemoteAddress = mRemoteAddressesV6.get(0);
+ mRemoteAddress = mRemoteAddressesV6.get(0).address;
} else if (isIpV4Preferred(mIkeParams, mNc) && canConnectWithIpv4) {
mRemoteAddress = mRemoteAddressesV4.get(0);
} else if (canConnectWithIpv6) {
- mRemoteAddress = mRemoteAddressesV6.get(0);
+ mRemoteAddress = mRemoteAddressesV6.get(0).address;
} else if (canConnectWithIpv4) {
mRemoteAddress = mRemoteAddressesV4.get(0);
} else {
@@ -1037,6 +1100,61 @@
ShimUtils.getInstance().executeOrSendFatalError(r, mCallback);
}
+ private static Set<Integer> getSupportedVersions(boolean isV4Supported, boolean isV6Supported) {
+ final Set<Integer> versions = new HashSet<>();
+
+ if (isV4Supported) {
+ versions.add(ESP_IP_VERSION_IPV4);
+ }
+ if (isV6Supported) {
+ versions.add(ESP_IP_VERSION_IPV6);
+ }
+
+ return versions;
+ }
+
+ /**
+ * Return whether DNS lookup is required during mobility update
+ *
+ * <p>Require DNS lookup when one of the following condition is true:
+ *
+ * <ul>
+ * <li>The network has changed
+ * <li>The locally supported versions misaligned with the cached remotely supported versions
+ * <li>Neither of the two versions are supported locally or remotely
+ * </ul>
+ */
+ @VisibleForTesting
+ public boolean isDnsLookupRequiredWithGlobalRemoteAddress(
+ Network oldNetwork, Network network, LinkProperties linkProperties) {
+ // If the network changes, perform a new DNS lookup to ensure that the correct remote
+ // address is used. This ensures that DNS returns addresses for the correct address families
+ // (important if using a v4/v6-only network). This also ensures that DNS64 is handled
+ // correctly when switching between networks that may have different IPv6 prefixes.
+ if (!network.equals(oldNetwork)) {
+ return true;
+ }
+
+ final Set<Integer> localIpVersions =
+ getSupportedVersions(
+ hasLocalIpV4Address(linkProperties), linkProperties.hasGlobalIpv6Address());
+ final Set<Integer> remoteIpVersionsCached =
+ getSupportedVersions(!mRemoteAddressesV4.isEmpty(), !mRemoteAddressesV6.isEmpty());
+
+ getIkeLog()
+ .d(
+ TAG,
+ "isDnsLookupRequiredWithGlobalRemoteAddress localIpVersions "
+ + localIpVersions
+ + " remoteIpVersionsCached "
+ + remoteIpVersionsCached);
+
+ if (Objects.equals(localIpVersions, remoteIpVersionsCached) && !localIpVersions.isEmpty()) {
+ return false;
+ }
+ return true;
+ }
+
// This method is never expected be called due to the capabilities change of the existing
// underlying network. Only explicit user requests, network changes, addresses changes or
// configuration changes (such as the protocol preference) will call into this method.
@@ -1059,13 +1177,16 @@
mNetwork = network;
mNc = networkCapabilities;
- // If the network changes, perform a new DNS lookup to ensure that the correct remote
- // address is used. This ensures that DNS returns addresses for the correct address families
- // (important if using a v4/v6-only network). This also ensures that DNS64 is handled
- // correctly when switching between networks that may have different IPv6 prefixes.
- if (!mNetwork.equals(oldNetwork)) {
+ // Remove all NAT64 addresses since they might be out-of-date
+ for (Ipv6AddrInfo info : mRemoteAddressesV6) {
+ if (info.isNat64Addr) {
+ mRemoteAddressesV6.remove(info);
+ }
+ }
+
+ if (isDnsLookupRequiredWithGlobalRemoteAddress(oldNetwork, mNetwork, linkProperties)) {
try {
- resolveAndSetAvailableRemoteAddresses();
+ resolveAndSetAvailableRemoteAddresses(linkProperties);
} catch (IOException e) {
mCallback.onError(wrapAsIkeException(e));
return;
diff --git a/tests/cts/OWNERS b/tests/cts/OWNERS
index 212b907..2003198 100644
--- a/tests/cts/OWNERS
+++ b/tests/cts/OWNERS
@@ -1,6 +1,8 @@
-# Bug component: 827526
+# Bug component: 1364804
set noparent
-lorenzo@google.com
-nharold@google.com
-satk@google.com
+amruthr@google.com
+jackyu@google.com
+rgreenwalt@google.com #{LAST_RESORT_SUGGESTION}
+
+nharold@google.com #{LAST_RESORT_SUGGESTION}
diff --git a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/net/IkeConnectionControllerTest.java b/tests/iketests/src/java/com/android/internal/net/ipsec/ike/net/IkeConnectionControllerTest.java
index 346c423..a60e081 100644
--- a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/net/IkeConnectionControllerTest.java
+++ b/tests/iketests/src/java/com/android/internal/net/ipsec/ike/net/IkeConnectionControllerTest.java
@@ -1445,4 +1445,193 @@
verifyKeepalive(true /* hasOldKeepalive */, true /* isKeepaliveExpected */);
assertEquals(underpinnedNetwork, mIkeConnectionCtrl.getUnderpinnedNetwork());
}
+
+ private void verifyIsDnsLookupRequired(
+ boolean isNetworkChanged,
+ boolean hasLocalV4,
+ boolean hasLocalV6,
+ boolean hasRemoteV4Cached,
+ boolean hasRemoteV6Cached,
+ boolean dnsExpected)
+ throws Exception {
+ final Network newNetwork = isNetworkChanged ? mock(Network.class) : mMockDefaultNetwork;
+
+ final Inet4Address localV4 = hasLocalV4 ? LOCAL_ADDRESS : null;
+ final Inet6Address localV6 = hasLocalV6 ? LOCAL_ADDRESS_V6 : null;
+ setupLocalAddressForNetwork(newNetwork, localV4, localV6);
+
+ mIkeConnectionCtrl.clearRemoteAddress();
+ if (hasRemoteV4Cached) {
+ mIkeConnectionCtrl.addRemoteAddress(REMOTE_ADDRESS);
+ }
+ if (hasRemoteV6Cached) {
+ mIkeConnectionCtrl.addRemoteAddress(REMOTE_ADDRESS_V6);
+ }
+
+ assertEquals(
+ dnsExpected,
+ mIkeConnectionCtrl.isDnsLookupRequiredWithGlobalRemoteAddress(
+ mMockDefaultNetwork,
+ newNetwork,
+ mMockConnectManager.getLinkProperties(newNetwork)));
+ }
+
+ private void verifyIsDnsLookupRequired(
+ boolean hasLocalV4,
+ boolean hasLocalV6,
+ boolean hasRemoteV4Cached,
+ boolean hasRemoteV6Cached,
+ boolean dnsExpected)
+ throws Exception {
+ verifyIsDnsLookupRequired(
+ false /* isNetworkChanged */,
+ hasLocalV4,
+ hasLocalV6,
+ hasRemoteV4Cached,
+ hasRemoteV6Cached,
+ dnsExpected);
+ }
+
+ @Test
+ public void testIsDnsLookupRequired_NetworkChange() throws Exception {
+ verifyIsDnsLookupRequired(
+ true /* isNetworkChanged */,
+ true /* hasLocalV4 */,
+ true /* hasLocalV6 */,
+ true /* hasRemoteV4Cached */,
+ true /* hasRemoteV6Cached */,
+ true /* dnsExpected */);
+ }
+
+ @Test
+ public void testIsDnsLookupRequired_LocalV4V6_RemoteV4() throws Exception {
+ verifyIsDnsLookupRequired(
+ true /* hasLocalV4 */,
+ true /* hasLocalV6 */,
+ true /* hasRemoteV4Cached */,
+ false /* hasRemoteV6Cached */,
+ true /* dnsExpected */);
+ }
+
+ @Test
+ public void testIsDnsLookupRequired_LocalV4V6_RemoteV6() throws Exception {
+ verifyIsDnsLookupRequired(
+ true /* hasLocalV4 */,
+ true /* hasLocalV6 */,
+ false /* hasRemoteV4Cached */,
+ true /* hasRemoteV6Cached */,
+ true /* dnsExpected */);
+ }
+
+ @Test
+ public void testIsDnsLookupRequired_LocalV4_RemoteV6() throws Exception {
+ verifyIsDnsLookupRequired(
+ true /* hasLocalV4 */,
+ false /* hasLocalV6 */,
+ false /* hasRemoteV4Cached */,
+ true /* hasRemoteV6Cached */,
+ true /* dnsExpected */);
+ }
+
+ @Test
+ public void testIsDnsLookupRequired_LocalV6_RemoteV4() throws Exception {
+ verifyIsDnsLookupRequired(
+ false /* hasLocalV4 */,
+ true /* hasLocalV6 */,
+ true /* hasRemoteV4Cached */,
+ false /* hasRemoteV6Cached */,
+ true /* dnsExpected */);
+ }
+
+ @Test
+ public void testIsDnsLookupRequired_LocalNone_RemoteV4() throws Exception {
+ verifyIsDnsLookupRequired(
+ false /* hasLocalV4 */,
+ false /* hasLocalV6 */,
+ true /* hasRemoteV4Cached */,
+ false /* hasRemoteV6Cached */,
+ true /* dnsExpected */);
+ }
+
+ @Test
+ public void testIsDnsLookupRequired_LocalV6_RemoteNone() throws Exception {
+ verifyIsDnsLookupRequired(
+ false /* hasLocalV4 */,
+ true /* hasLocalV6 */,
+ false /* hasRemoteV4Cached */,
+ false /* hasRemoteV6Cached */,
+ true /* dnsExpected */);
+ }
+
+ @Test
+ public void testIsDnsLookupRequired_LocalNone_RemoteNone() throws Exception {
+ verifyIsDnsLookupRequired(
+ false /* hasLocalV4 */,
+ false /* hasLocalV6 */,
+ false /* hasRemoteV4Cached */,
+ false /* hasRemoteV6Cached */,
+ true /* dnsExpected */);
+ }
+
+ @Test
+ public void testIsDnsLookupRequired_LocalV4_RemoteV4() throws Exception {
+ verifyIsDnsLookupRequired(
+ true /* hasLocalV4 */,
+ false /* hasLocalV6 */,
+ true /* hasRemoteV4Cached */,
+ false /* hasRemoteV6Cached */,
+ false /* dnsExpected */);
+ }
+
+ @Test
+ public void testIsDnsLookupRequired_LocalV6_RemoteV6() throws Exception {
+ verifyIsDnsLookupRequired(
+ false /* hasLocalV4 */,
+ true /* hasLocalV6 */,
+ false /* hasRemoteV4Cached */,
+ true /* hasRemoteV6Cached */,
+ false /* dnsExpected */);
+ }
+
+ @Test
+ public void testIsDnsLookupRequired_LocalV4V6_RemoteV4V6() throws Exception {
+ verifyIsDnsLookupRequired(
+ true /* hasLocalV4 */,
+ true /* hasLocalV6 */,
+ true /* hasRemoteV4Cached */,
+ true /* hasRemoteV6Cached */,
+ false /* dnsExpected */);
+ }
+
+ private void verifyDnsLookupWithCachedIpv6Address(boolean isNat64, boolean dnsExpected)
+ throws Exception {
+ reset(mMockDefaultNetwork);
+ setupLocalAddressForNetwork(mMockDefaultNetwork, LOCAL_ADDRESS_V6);
+ setupRemoteAddressForNetwork(mMockDefaultNetwork, REMOTE_ADDRESS_V6);
+
+ mIkeConnectionCtrl.clearRemoteAddress();
+ mIkeConnectionCtrl.addRemoteAddressV6(REMOTE_ADDRESS_V6, isNat64);
+
+ IkeNetworkCallbackBase callback = enableMobilityAndReturnCb(true /* isDefaultNetwork */);
+ mIkeConnectionCtrl.onUnderlyingNetworkUpdated(
+ mMockDefaultNetwork,
+ mMockConnectManager.getLinkProperties(mMockDefaultNetwork),
+ mMockNetworkCapabilities);
+
+ if (dnsExpected) {
+ verify(mMockDefaultNetwork).getAllByName(anyString());
+ } else {
+ verify(mMockDefaultNetwork, never()).getAllByName(anyString());
+ }
+ }
+
+ @Test
+ public void testOnUnderlyingNetworkUpdatedWithGlobalV6Address() throws Exception {
+ verifyDnsLookupWithCachedIpv6Address(false /* isNat64 */, false /* dnsExpected */);
+ }
+
+ @Test
+ public void testOnUnderlyingNetworkUpdatedWithNat64V6Address() throws Exception {
+ verifyDnsLookupWithCachedIpv6Address(true /* isNat64 */, true /* dnsExpected */);
+ }
}