diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/services/core/java/com/android/server/connectivity/DnsManager.java index 7aaac06024..d51a196b76 100644 --- a/services/core/java/com/android/server/connectivity/DnsManager.java +++ b/services/core/java/com/android/server/connectivity/DnsManager.java @@ -49,6 +49,7 @@ import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -211,6 +212,8 @@ public class DnsManager { } // Validation statuses of pairs for a single netId + // Caution : not thread-safe. As mentioned in the top file comment, all + // methods of this class must only be called on ConnectivityService's thread. private Map, ValidationStatus> mValidationMap; private PrivateDnsValidationStatuses() { @@ -262,6 +265,16 @@ public class DnsManager { mValidationMap.put(p, ValidationStatus.FAILED); } } + + private LinkProperties fillInValidatedPrivateDns(LinkProperties lp) { + lp.setValidatedPrivateDnsServers(Collections.EMPTY_LIST); + mValidationMap.forEach((key, value) -> { + if (value == ValidationStatus.SUCCEEDED) { + lp.addValidatedPrivateDnsServer(key.second); + } + }); + return lp; + } } private final Context mContext; @@ -315,23 +328,19 @@ public class DnsManager { PRIVATE_DNS_OFF); final boolean useTls = privateDnsCfg.useTls; + final PrivateDnsValidationStatuses statuses = + useTls ? mPrivateDnsValidationMap.get(netId) : null; + final boolean validated = (null != statuses) && statuses.hasValidatedServer(); final boolean strictMode = privateDnsCfg.inStrictMode(); - final String tlsHostname = strictMode ? privateDnsCfg.hostname : ""; + final String tlsHostname = strictMode ? privateDnsCfg.hostname : null; + final boolean usingPrivateDns = strictMode || validated; - if (strictMode) { - lp.setUsePrivateDns(true); - lp.setPrivateDnsServerName(tlsHostname); - } else if (useTls) { - // We are in opportunistic mode. Private DNS should be used if there - // is a known DNS-over-TLS validated server. - boolean validated = mPrivateDnsValidationMap.containsKey(netId) && - mPrivateDnsValidationMap.get(netId).hasValidatedServer(); - lp.setUsePrivateDns(validated); - lp.setPrivateDnsServerName(null); + lp.setUsePrivateDns(usingPrivateDns); + lp.setPrivateDnsServerName(tlsHostname); + if (usingPrivateDns && null != statuses) { + statuses.fillInValidatedPrivateDns(lp); } else { - // Private DNS is disabled. - lp.setUsePrivateDns(false); - lp.setPrivateDnsServerName(null); + lp.setValidatedPrivateDnsServers(Collections.EMPTY_LIST); } } diff --git a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java index bcd8bf3df7..1ec4eec1bc 100644 --- a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java +++ b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java @@ -28,8 +28,11 @@ import static org.mockito.Mockito.when; import android.content.ContentResolver; import android.content.Context; +import android.net.IpPrefix; +import android.net.LinkAddress; import android.net.LinkProperties; import android.net.Network; +import android.net.RouteInfo; import android.os.INetworkManagementService; import android.provider.Settings; import android.support.test.filters.SmallTest; @@ -40,6 +43,7 @@ import com.android.internal.util.test.FakeSettingsProvider; import com.android.server.connectivity.MockableSystemProperties; import java.net.InetAddress; +import java.util.Arrays; import org.junit.runner.RunWith; import org.junit.Before; @@ -56,6 +60,7 @@ import org.mockito.MockitoAnnotations; @RunWith(AndroidJUnit4.class) @SmallTest public class DnsManagerTest { + static final String TEST_IFACENAME = "test_wlan0"; static final int TEST_NETID = 100; static final int TEST_NETID_ALTERNATE = 101; static final int TEST_NETID_UNTRACKED = 102; @@ -92,6 +97,7 @@ public class DnsManagerTest { mDnsManager.updatePrivateDns(new Network(TEST_NETID_ALTERNATE), mDnsManager.getPrivateDnsConfig()); LinkProperties lp = new LinkProperties(); + lp.setInterfaceName(TEST_IFACENAME); lp.addDnsServer(InetAddress.getByName("3.3.3.3")); lp.addDnsServer(InetAddress.getByName("4.4.4.4")); @@ -109,21 +115,51 @@ public class DnsManagerTest { mDnsManager.updatePrivateDnsStatus(TEST_NETID_ALTERNATE, fixedLp); assertTrue(fixedLp.isPrivateDnsActive()); assertNull(fixedLp.getPrivateDnsServerName()); + assertEquals(Arrays.asList(InetAddress.getByName("4.4.4.4")), + fixedLp.getValidatedPrivateDnsServers()); + + // Set up addresses for strict mode and switch to it. + lp.addLinkAddress(new LinkAddress("192.0.2.4/24")); + lp.addRoute(new RouteInfo((IpPrefix) null, InetAddress.getByName("192.0.2.4"), + TEST_IFACENAME)); + lp.addLinkAddress(new LinkAddress("2001:db8:1::1/64")); + lp.addRoute(new RouteInfo((IpPrefix) null, InetAddress.getByName("2001:db8:1::1"), + TEST_IFACENAME)); - // Switch to strict mode Settings.Global.putString(mContentResolver, - Settings.Global.PRIVATE_DNS_MODE, - PRIVATE_DNS_MODE_PROVIDER_HOSTNAME); + Settings.Global.PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_PROVIDER_HOSTNAME); Settings.Global.putString(mContentResolver, Settings.Global.PRIVATE_DNS_SPECIFIER, "strictmode.com"); mDnsManager.updatePrivateDns(new Network(TEST_NETID), - mDnsManager.getPrivateDnsConfig()); + new DnsManager.PrivateDnsConfig("strictmode.com", new InetAddress[] { + InetAddress.parseNumericAddress("6.6.6.6"), + InetAddress.parseNumericAddress("2001:db8:66:66::1") + })); mDnsManager.setDnsConfigurationForNetwork(TEST_NETID, lp, IS_DEFAULT); fixedLp = new LinkProperties(lp); mDnsManager.updatePrivateDnsStatus(TEST_NETID, fixedLp); assertTrue(fixedLp.isPrivateDnsActive()); assertEquals("strictmode.com", fixedLp.getPrivateDnsServerName()); + // No validation events yet. + assertEquals(Arrays.asList(new InetAddress[0]), fixedLp.getValidatedPrivateDnsServers()); + // Validate one. + mDnsManager.updatePrivateDnsValidation( + new DnsManager.PrivateDnsValidationUpdate(TEST_NETID, + InetAddress.parseNumericAddress("6.6.6.6"), "strictmode.com", true)); fixedLp = new LinkProperties(lp); + mDnsManager.updatePrivateDnsStatus(TEST_NETID, fixedLp); + assertEquals(Arrays.asList(InetAddress.parseNumericAddress("6.6.6.6")), + fixedLp.getValidatedPrivateDnsServers()); + // Validate the 2nd one. + mDnsManager.updatePrivateDnsValidation( + new DnsManager.PrivateDnsValidationUpdate(TEST_NETID, + InetAddress.parseNumericAddress("2001:db8:66:66::1"), "strictmode.com", true)); + fixedLp = new LinkProperties(lp); + mDnsManager.updatePrivateDnsStatus(TEST_NETID, fixedLp); + assertEquals(Arrays.asList( + InetAddress.parseNumericAddress("2001:db8:66:66::1"), + InetAddress.parseNumericAddress("6.6.6.6")), + fixedLp.getValidatedPrivateDnsServers()); } @Test