Move the logic of (re)evaluation of Private DNS
Moves this out of ConnectivityService and into each NetworkMonitor
(where it's more self-contained).
Test: as follows
- builds, flashes, boots
- runtest frameworks-net passes
- manual testing with working and non-working hostnames behaves
somewhat (but not entirely) as expected, and not always quickly
Bug: 64133961
Bug: 72345192
Bug: 73872000
Bug: 77140445
Merged-In: I5dc90ecfe6f6f10967b7501645ad8e030cb38982
Merged-In: Ida4967d22f0781524f0f269e30e653b8ec867258
Change-Id: Ic4322af3cb49149f2d975cb31f54b2ac7927f907
(cherry picked from commit 736353a584aa89a29e737e21e29c49fad0d38a63)
This commit is contained in:
@@ -943,6 +943,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
mHandler.sendEmptyMessage(EVENT_CONFIGURE_MOBILE_DATA_ALWAYS_ON);
|
mHandler.sendEmptyMessage(EVENT_CONFIGURE_MOBILE_DATA_ALWAYS_ON);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// See FakeSettingsProvider comment above.
|
||||||
|
@VisibleForTesting
|
||||||
|
void updatePrivateDnsSettings() {
|
||||||
|
mHandler.sendEmptyMessage(EVENT_PRIVATE_DNS_SETTINGS_CHANGED);
|
||||||
|
}
|
||||||
|
|
||||||
private void handleMobileDataAlwaysOn() {
|
private void handleMobileDataAlwaysOn() {
|
||||||
final boolean enable = toBool(Settings.Global.getInt(
|
final boolean enable = toBool(Settings.Global.getInt(
|
||||||
mContext.getContentResolver(), Settings.Global.MOBILE_DATA_ALWAYS_ON, 1));
|
mContext.getContentResolver(), Settings.Global.MOBILE_DATA_ALWAYS_ON, 1));
|
||||||
@@ -972,8 +978,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void registerPrivateDnsSettingsCallbacks() {
|
private void registerPrivateDnsSettingsCallbacks() {
|
||||||
for (Uri u : DnsManager.getPrivateDnsSettingsUris()) {
|
for (Uri uri : DnsManager.getPrivateDnsSettingsUris()) {
|
||||||
mSettingsObserver.observe(u, EVENT_PRIVATE_DNS_SETTINGS_CHANGED);
|
mSettingsObserver.observe(uri, EVENT_PRIVATE_DNS_SETTINGS_CHANGED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1026,8 +1032,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
if (network == null) {
|
if (network == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
return getNetworkAgentInfoForNetId(network.netId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private NetworkAgentInfo getNetworkAgentInfoForNetId(int netId) {
|
||||||
synchronized (mNetworkForNetId) {
|
synchronized (mNetworkForNetId) {
|
||||||
return mNetworkForNetId.get(network.netId);
|
return mNetworkForNetId.get(netId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1167,9 +1177,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
}
|
}
|
||||||
NetworkAgentInfo nai;
|
NetworkAgentInfo nai;
|
||||||
if (vpnNetId != NETID_UNSET) {
|
if (vpnNetId != NETID_UNSET) {
|
||||||
synchronized (mNetworkForNetId) {
|
nai = getNetworkAgentInfoForNetId(vpnNetId);
|
||||||
nai = mNetworkForNetId.get(vpnNetId);
|
|
||||||
}
|
|
||||||
if (nai != null) return nai.network;
|
if (nai != null) return nai.network;
|
||||||
}
|
}
|
||||||
nai = getDefaultNetwork();
|
nai = getDefaultNetwork();
|
||||||
@@ -2155,41 +2163,21 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
case NetworkMonitor.EVENT_NETWORK_TESTED: {
|
case NetworkMonitor.EVENT_NETWORK_TESTED: {
|
||||||
final NetworkAgentInfo nai;
|
final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(msg.arg2);
|
||||||
synchronized (mNetworkForNetId) {
|
|
||||||
nai = mNetworkForNetId.get(msg.arg2);
|
|
||||||
}
|
|
||||||
if (nai == null) break;
|
if (nai == null) break;
|
||||||
|
|
||||||
final boolean valid = (msg.arg1 == NetworkMonitor.NETWORK_TEST_RESULT_VALID);
|
final boolean valid = (msg.arg1 == NetworkMonitor.NETWORK_TEST_RESULT_VALID);
|
||||||
final boolean wasValidated = nai.lastValidated;
|
final boolean wasValidated = nai.lastValidated;
|
||||||
final boolean wasDefault = isDefaultNetwork(nai);
|
final boolean wasDefault = isDefaultNetwork(nai);
|
||||||
|
|
||||||
final PrivateDnsConfig privateDnsCfg = (msg.obj instanceof PrivateDnsConfig)
|
|
||||||
? (PrivateDnsConfig) msg.obj : null;
|
|
||||||
final String redirectUrl = (msg.obj instanceof String) ? (String) msg.obj : "";
|
final String redirectUrl = (msg.obj instanceof String) ? (String) msg.obj : "";
|
||||||
|
|
||||||
final boolean reevaluationRequired;
|
|
||||||
final String logMsg;
|
|
||||||
if (valid) {
|
|
||||||
reevaluationRequired = updatePrivateDns(nai, privateDnsCfg);
|
|
||||||
logMsg = (DBG && (privateDnsCfg != null))
|
|
||||||
? " with " + privateDnsCfg.toString() : "";
|
|
||||||
} else {
|
|
||||||
reevaluationRequired = false;
|
|
||||||
logMsg = (DBG && !TextUtils.isEmpty(redirectUrl))
|
|
||||||
? " with redirect to " + redirectUrl : "";
|
|
||||||
}
|
|
||||||
if (DBG) {
|
if (DBG) {
|
||||||
|
final String logMsg = !TextUtils.isEmpty(redirectUrl)
|
||||||
|
? " with redirect to " + redirectUrl
|
||||||
|
: "";
|
||||||
log(nai.name() + " validation " + (valid ? "passed" : "failed") + logMsg);
|
log(nai.name() + " validation " + (valid ? "passed" : "failed") + logMsg);
|
||||||
}
|
}
|
||||||
// If there is a change in Private DNS configuration,
|
|
||||||
// trigger reevaluation of the network to test it.
|
|
||||||
if (reevaluationRequired) {
|
|
||||||
nai.networkMonitor.sendMessage(
|
|
||||||
NetworkMonitor.CMD_FORCE_REEVALUATION, Process.SYSTEM_UID);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (valid != nai.lastValidated) {
|
if (valid != nai.lastValidated) {
|
||||||
if (wasDefault) {
|
if (wasDefault) {
|
||||||
metricsLogger().defaultNetworkMetrics().logDefaultNetworkValidity(
|
metricsLogger().defaultNetworkMetrics().logDefaultNetworkValidity(
|
||||||
@@ -2218,10 +2206,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
case NetworkMonitor.EVENT_PROVISIONING_NOTIFICATION: {
|
case NetworkMonitor.EVENT_PROVISIONING_NOTIFICATION: {
|
||||||
final int netId = msg.arg2;
|
final int netId = msg.arg2;
|
||||||
final boolean visible = toBool(msg.arg1);
|
final boolean visible = toBool(msg.arg1);
|
||||||
final NetworkAgentInfo nai;
|
final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(netId);
|
||||||
synchronized (mNetworkForNetId) {
|
|
||||||
nai = mNetworkForNetId.get(netId);
|
|
||||||
}
|
|
||||||
// If captive portal status has changed, update capabilities or disconnect.
|
// If captive portal status has changed, update capabilities or disconnect.
|
||||||
if (nai != null && (visible != nai.lastCaptivePortalDetected)) {
|
if (nai != null && (visible != nai.lastCaptivePortalDetected)) {
|
||||||
final int oldScore = nai.getCurrentScore();
|
final int oldScore = nai.getCurrentScore();
|
||||||
@@ -2252,18 +2237,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case NetworkMonitor.EVENT_PRIVATE_DNS_CONFIG_RESOLVED: {
|
case NetworkMonitor.EVENT_PRIVATE_DNS_CONFIG_RESOLVED: {
|
||||||
final NetworkAgentInfo nai;
|
final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(msg.arg2);
|
||||||
synchronized (mNetworkForNetId) {
|
|
||||||
nai = mNetworkForNetId.get(msg.arg2);
|
|
||||||
}
|
|
||||||
if (nai == null) break;
|
if (nai == null) break;
|
||||||
|
|
||||||
final PrivateDnsConfig cfg = (PrivateDnsConfig) msg.obj;
|
updatePrivateDns(nai, (PrivateDnsConfig) msg.obj);
|
||||||
final boolean reevaluationRequired = updatePrivateDns(nai, cfg);
|
|
||||||
if (nai.lastValidated && reevaluationRequired) {
|
|
||||||
nai.networkMonitor.sendMessage(
|
|
||||||
NetworkMonitor.CMD_FORCE_REEVALUATION, Process.SYSTEM_UID);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2301,61 +2278,38 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean networkRequiresValidation(NetworkAgentInfo nai) {
|
||||||
|
return NetworkMonitor.isValidationRequired(
|
||||||
|
mDefaultRequest.networkCapabilities, nai.networkCapabilities);
|
||||||
|
}
|
||||||
|
|
||||||
private void handlePrivateDnsSettingsChanged() {
|
private void handlePrivateDnsSettingsChanged() {
|
||||||
final PrivateDnsConfig cfg = mDnsManager.getPrivateDnsConfig();
|
final PrivateDnsConfig cfg = mDnsManager.getPrivateDnsConfig();
|
||||||
|
|
||||||
for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
|
for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
|
||||||
|
handlePerNetworkPrivateDnsConfig(nai, cfg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handlePerNetworkPrivateDnsConfig(NetworkAgentInfo nai, PrivateDnsConfig cfg) {
|
||||||
// Private DNS only ever applies to networks that might provide
|
// Private DNS only ever applies to networks that might provide
|
||||||
// Internet access and therefore also require validation.
|
// Internet access and therefore also require validation.
|
||||||
if (!NetworkMonitor.isValidationRequired(
|
if (!networkRequiresValidation(nai)) return;
|
||||||
mDefaultRequest.networkCapabilities, nai.networkCapabilities)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Notify the NetworkMonitor thread in case it needs to cancel or
|
// Notify the NetworkMonitor thread in case it needs to cancel or
|
||||||
// schedule DNS resolutions. If a DNS resolution is required the
|
// schedule DNS resolutions. If a DNS resolution is required the
|
||||||
// result will be sent back to us.
|
// result will be sent back to us.
|
||||||
nai.networkMonitor.notifyPrivateDnsSettingsChanged(cfg);
|
nai.networkMonitor.notifyPrivateDnsSettingsChanged(cfg);
|
||||||
|
|
||||||
if (!cfg.inStrictMode()) {
|
// With Private DNS bypass support, we can proceed to update the
|
||||||
// No strict mode hostname DNS resolution needed, so just update
|
// Private DNS config immediately, even if we're in strict mode
|
||||||
// DNS settings directly. In opportunistic and "off" modes this
|
// and have not yet resolved the provider name into a set of IPs.
|
||||||
// just reprograms netd with the network-supplied DNS servers
|
|
||||||
// (and of course the boolean of whether or not to attempt TLS).
|
|
||||||
//
|
|
||||||
// TODO: Consider code flow parity with strict mode, i.e. having
|
|
||||||
// NetworkMonitor relay the PrivateDnsConfig back to us and then
|
|
||||||
// performing this call at that time.
|
|
||||||
updatePrivateDns(nai, cfg);
|
updatePrivateDns(nai, cfg);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean updatePrivateDns(NetworkAgentInfo nai, PrivateDnsConfig newCfg) {
|
private void updatePrivateDns(NetworkAgentInfo nai, PrivateDnsConfig newCfg) {
|
||||||
final boolean reevaluationRequired = true;
|
mDnsManager.updatePrivateDns(nai.network, newCfg);
|
||||||
final boolean dontReevaluate = false;
|
|
||||||
|
|
||||||
final PrivateDnsConfig oldCfg = mDnsManager.updatePrivateDns(nai.network, newCfg);
|
|
||||||
updateDnses(nai.linkProperties, null, nai.network.netId);
|
updateDnses(nai.linkProperties, null, nai.network.netId);
|
||||||
|
|
||||||
if (newCfg == null) {
|
|
||||||
if (oldCfg == null) return dontReevaluate;
|
|
||||||
return oldCfg.useTls ? reevaluationRequired : dontReevaluate;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (oldCfg == null) {
|
|
||||||
return newCfg.useTls ? reevaluationRequired : dontReevaluate;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (oldCfg.useTls != newCfg.useTls) {
|
|
||||||
return reevaluationRequired;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newCfg.inStrictMode() && !Objects.equals(oldCfg.hostname, newCfg.hostname)) {
|
|
||||||
return reevaluationRequired;
|
|
||||||
}
|
|
||||||
|
|
||||||
return dontReevaluate;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateLingerState(NetworkAgentInfo nai, long now) {
|
private void updateLingerState(NetworkAgentInfo nai, long now) {
|
||||||
@@ -3300,7 +3254,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
if (isNetworkWithLinkPropertiesBlocked(lp, uid, false)) {
|
if (isNetworkWithLinkPropertiesBlocked(lp, uid, false)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
nai.networkMonitor.sendMessage(NetworkMonitor.CMD_FORCE_REEVALUATION, uid);
|
nai.networkMonitor.forceReevaluation(uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ProxyInfo getDefaultProxy() {
|
private ProxyInfo getDefaultProxy() {
|
||||||
@@ -4919,7 +4873,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void handleUpdateLinkProperties(NetworkAgentInfo nai, LinkProperties newLp) {
|
public void handleUpdateLinkProperties(NetworkAgentInfo nai, LinkProperties newLp) {
|
||||||
if (mNetworkForNetId.get(nai.network.netId) != nai) {
|
if (getNetworkAgentInfoForNetId(nai.network.netId) != nai) {
|
||||||
// Ignore updates for disconnected networks
|
// Ignore updates for disconnected networks
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -5495,6 +5449,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
if (!networkAgent.everConnected && state == NetworkInfo.State.CONNECTED) {
|
if (!networkAgent.everConnected && state == NetworkInfo.State.CONNECTED) {
|
||||||
networkAgent.everConnected = true;
|
networkAgent.everConnected = true;
|
||||||
|
|
||||||
|
handlePerNetworkPrivateDnsConfig(networkAgent, mDnsManager.getPrivateDnsConfig());
|
||||||
updateLinkProperties(networkAgent, null);
|
updateLinkProperties(networkAgent, null);
|
||||||
notifyIfacesChangedForNetworkStats();
|
notifyIfacesChangedForNetworkStats();
|
||||||
|
|
||||||
|
|||||||
@@ -61,6 +61,51 @@ import java.util.StringJoiner;
|
|||||||
* This class it NOT designed for concurrent access. Furthermore, all non-static
|
* This class it NOT designed for concurrent access. Furthermore, all non-static
|
||||||
* methods MUST be called from ConnectivityService's thread.
|
* methods MUST be called from ConnectivityService's thread.
|
||||||
*
|
*
|
||||||
|
* [ Private DNS ]
|
||||||
|
* The code handling Private DNS is spread across several components, but this
|
||||||
|
* seems like the least bad place to collect all the observations.
|
||||||
|
*
|
||||||
|
* Private DNS handling and updating occurs in response to several different
|
||||||
|
* events. Each is described here with its corresponding intended handling.
|
||||||
|
*
|
||||||
|
* [A] Event: A new network comes up.
|
||||||
|
* Mechanics:
|
||||||
|
* [1] ConnectivityService gets notifications from NetworkAgents.
|
||||||
|
* [2] in updateNetworkInfo(), the first time the NetworkAgent goes into
|
||||||
|
* into CONNECTED state, the Private DNS configuration is retrieved,
|
||||||
|
* programmed, and strict mode hostname resolution (if applicable) is
|
||||||
|
* enqueued in NetworkAgent's NetworkMonitor, via a call to
|
||||||
|
* handlePerNetworkPrivateDnsConfig().
|
||||||
|
* [3] Re-resolution of strict mode hostnames that fail to return any
|
||||||
|
* IP addresses happens inside NetworkMonitor; it sends itself a
|
||||||
|
* delayed CMD_EVALUATE_PRIVATE_DNS message in a simple backoff
|
||||||
|
* schedule.
|
||||||
|
* [4] Successfully resolved hostnames are sent to ConnectivityService
|
||||||
|
* inside an EVENT_PRIVATE_DNS_CONFIG_RESOLVED message. The resolved
|
||||||
|
* IP addresses are programmed into netd via:
|
||||||
|
*
|
||||||
|
* updatePrivateDns() -> updateDnses()
|
||||||
|
*
|
||||||
|
* both of which make calls into DnsManager.
|
||||||
|
* [5] Upon a successful hostname resolution NetworkMonitor initiates a
|
||||||
|
* validation attempt in the form of a lookup for a one-time hostname
|
||||||
|
* that uses Private DNS.
|
||||||
|
*
|
||||||
|
* [B] Event: Private DNS settings are changed.
|
||||||
|
* Mechanics:
|
||||||
|
* [1] ConnectivityService gets notifications from its SettingsObserver.
|
||||||
|
* [2] handlePrivateDnsSettingsChanged() is called, which calls
|
||||||
|
* handlePerNetworkPrivateDnsConfig() and the process proceeds
|
||||||
|
* as if from A.3 above.
|
||||||
|
*
|
||||||
|
* [C] Event: An application calls ConnectivityManager#reportBadNetwork().
|
||||||
|
* Mechanics:
|
||||||
|
* [1] NetworkMonitor is notified and initiates a reevaluation, which
|
||||||
|
* always bypasses Private DNS.
|
||||||
|
* [2] Once completed, NetworkMonitor checks if strict mode is in operation
|
||||||
|
* and if so enqueues another evaluation of Private DNS, as if from
|
||||||
|
* step A.5 above.
|
||||||
|
*
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
public class DnsManager {
|
public class DnsManager {
|
||||||
|
|||||||
@@ -17,6 +17,9 @@
|
|||||||
package com.android.server;
|
package com.android.server;
|
||||||
|
|
||||||
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
|
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
|
||||||
|
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF;
|
||||||
|
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
|
||||||
|
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
|
||||||
import static android.net.ConnectivityManager.TYPE_ETHERNET;
|
import static android.net.ConnectivityManager.TYPE_ETHERNET;
|
||||||
import static android.net.ConnectivityManager.TYPE_MOBILE;
|
import static android.net.ConnectivityManager.TYPE_MOBILE;
|
||||||
import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA;
|
import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA;
|
||||||
@@ -70,6 +73,7 @@ import static org.mockito.Mockito.reset;
|
|||||||
import static org.mockito.Mockito.spy;
|
import static org.mockito.Mockito.spy;
|
||||||
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.times;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
|
||||||
@@ -181,6 +185,9 @@ public class ConnectivityServiceTest {
|
|||||||
private static final int TIMEOUT_MS = 500;
|
private static final int TIMEOUT_MS = 500;
|
||||||
private static final int TEST_LINGER_DELAY_MS = 120;
|
private static final int TEST_LINGER_DELAY_MS = 120;
|
||||||
|
|
||||||
|
private static final String MOBILE_IFNAME = "test_rmnet_data0";
|
||||||
|
private static final String WIFI_IFNAME = "test_wlan0";
|
||||||
|
|
||||||
private MockContext mServiceContext;
|
private MockContext mServiceContext;
|
||||||
private WrappedConnectivityService mService;
|
private WrappedConnectivityService mService;
|
||||||
private WrappedConnectivityManager mCm;
|
private WrappedConnectivityManager mCm;
|
||||||
@@ -751,7 +758,7 @@ public class ConnectivityServiceTest {
|
|||||||
|
|
||||||
// NetworkMonitor implementation allowing overriding of Internet connectivity probe result.
|
// NetworkMonitor implementation allowing overriding of Internet connectivity probe result.
|
||||||
private class WrappedNetworkMonitor extends NetworkMonitor {
|
private class WrappedNetworkMonitor extends NetworkMonitor {
|
||||||
public Handler connectivityHandler;
|
public final Handler connectivityHandler;
|
||||||
// HTTP response code fed back to NetworkMonitor for Internet connectivity probe.
|
// HTTP response code fed back to NetworkMonitor for Internet connectivity probe.
|
||||||
public int gen204ProbeResult = 500;
|
public int gen204ProbeResult = 500;
|
||||||
public String gen204ProbeRedirectUrl = null;
|
public String gen204ProbeRedirectUrl = null;
|
||||||
@@ -928,6 +935,7 @@ public class ConnectivityServiceTest {
|
|||||||
// Ensure that the default setting for Captive Portals is used for most tests
|
// Ensure that the default setting for Captive Portals is used for most tests
|
||||||
setCaptivePortalMode(Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT);
|
setCaptivePortalMode(Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT);
|
||||||
setMobileDataAlwaysOn(false);
|
setMobileDataAlwaysOn(false);
|
||||||
|
setPrivateDnsSettings(PRIVATE_DNS_MODE_OFF, "ignored.example.com");
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
@@ -2582,6 +2590,14 @@ public class ConnectivityServiceTest {
|
|||||||
waitForIdle();
|
waitForIdle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setPrivateDnsSettings(String mode, String specifier) {
|
||||||
|
final ContentResolver cr = mServiceContext.getContentResolver();
|
||||||
|
Settings.Global.putString(cr, Settings.Global.PRIVATE_DNS_MODE, mode);
|
||||||
|
Settings.Global.putString(cr, Settings.Global.PRIVATE_DNS_SPECIFIER, specifier);
|
||||||
|
mService.updatePrivateDnsSettings();
|
||||||
|
waitForIdle();
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isForegroundNetwork(MockNetworkAgent network) {
|
private boolean isForegroundNetwork(MockNetworkAgent network) {
|
||||||
NetworkCapabilities nc = mCm.getNetworkCapabilities(network.getNetwork());
|
NetworkCapabilities nc = mCm.getNetworkCapabilities(network.getNetwork());
|
||||||
assertNotNull(nc);
|
assertNotNull(nc);
|
||||||
@@ -3583,7 +3599,7 @@ public class ConnectivityServiceTest {
|
|||||||
mCm.registerNetworkCallback(networkRequest, networkCallback);
|
mCm.registerNetworkCallback(networkRequest, networkCallback);
|
||||||
|
|
||||||
LinkProperties lp = new LinkProperties();
|
LinkProperties lp = new LinkProperties();
|
||||||
lp.setInterfaceName("wlan0");
|
lp.setInterfaceName(WIFI_IFNAME);
|
||||||
LinkAddress myIpv4Address = new LinkAddress("192.168.12.3/24");
|
LinkAddress myIpv4Address = new LinkAddress("192.168.12.3/24");
|
||||||
RouteInfo myIpv4DefaultRoute = new RouteInfo((IpPrefix) null,
|
RouteInfo myIpv4DefaultRoute = new RouteInfo((IpPrefix) null,
|
||||||
NetworkUtils.numericToInetAddress("192.168.12.1"), lp.getInterfaceName());
|
NetworkUtils.numericToInetAddress("192.168.12.1"), lp.getInterfaceName());
|
||||||
@@ -3672,52 +3688,63 @@ public class ConnectivityServiceTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBasicDnsConfigurationPushed() throws Exception {
|
public void testBasicDnsConfigurationPushed() throws Exception {
|
||||||
final String IFNAME = "test_rmnet_data0";
|
setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com");
|
||||||
final String[] EMPTY_TLS_SERVERS = new String[0];
|
ArgumentCaptor<String[]> tlsServers = ArgumentCaptor.forClass(String[].class);
|
||||||
|
|
||||||
|
// Clear any interactions that occur as a result of CS starting up.
|
||||||
|
reset(mNetworkManagementService);
|
||||||
|
|
||||||
|
final String[] EMPTY_STRING_ARRAY = new String[0];
|
||||||
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
|
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
|
||||||
waitForIdle();
|
waitForIdle();
|
||||||
verify(mNetworkManagementService, never()).setDnsConfigurationForNetwork(
|
verify(mNetworkManagementService, never()).setDnsConfigurationForNetwork(
|
||||||
anyInt(), any(), any(), any(), anyString(), eq(EMPTY_TLS_SERVERS));
|
anyInt(), eq(EMPTY_STRING_ARRAY), any(), any(), eq(""), eq(EMPTY_STRING_ARRAY));
|
||||||
|
verifyNoMoreInteractions(mNetworkManagementService);
|
||||||
|
|
||||||
final LinkProperties cellLp = new LinkProperties();
|
final LinkProperties cellLp = new LinkProperties();
|
||||||
cellLp.setInterfaceName(IFNAME);
|
cellLp.setInterfaceName(MOBILE_IFNAME);
|
||||||
// Add IPv4 and IPv6 default routes, because DNS-over-TLS code does
|
// Add IPv4 and IPv6 default routes, because DNS-over-TLS code does
|
||||||
// "is-reachable" testing in order to not program netd with unreachable
|
// "is-reachable" testing in order to not program netd with unreachable
|
||||||
// nameservers that it might try repeated to validate.
|
// nameservers that it might try repeated to validate.
|
||||||
cellLp.addLinkAddress(new LinkAddress("192.0.2.4/24"));
|
cellLp.addLinkAddress(new LinkAddress("192.0.2.4/24"));
|
||||||
cellLp.addRoute(new RouteInfo((IpPrefix) null, InetAddress.getByName("192.0.2.4"), IFNAME));
|
cellLp.addRoute(new RouteInfo((IpPrefix) null, InetAddress.getByName("192.0.2.4"),
|
||||||
|
MOBILE_IFNAME));
|
||||||
cellLp.addLinkAddress(new LinkAddress("2001:db8:1::1/64"));
|
cellLp.addLinkAddress(new LinkAddress("2001:db8:1::1/64"));
|
||||||
cellLp.addRoute(
|
cellLp.addRoute(new RouteInfo((IpPrefix) null, InetAddress.getByName("2001:db8:1::1"),
|
||||||
new RouteInfo((IpPrefix) null, InetAddress.getByName("2001:db8:1::1"), IFNAME));
|
MOBILE_IFNAME));
|
||||||
mCellNetworkAgent.sendLinkProperties(cellLp);
|
mCellNetworkAgent.sendLinkProperties(cellLp);
|
||||||
mCellNetworkAgent.connect(false);
|
mCellNetworkAgent.connect(false);
|
||||||
waitForIdle();
|
waitForIdle();
|
||||||
verify(mNetworkManagementService, times(1)).setDnsConfigurationForNetwork(
|
|
||||||
anyInt(), mStringArrayCaptor.capture(), any(), any(),
|
|
||||||
anyString(), eq(EMPTY_TLS_SERVERS));
|
|
||||||
// CS tells netd about the empty DNS config for this network.
|
// CS tells netd about the empty DNS config for this network.
|
||||||
assertEmpty(mStringArrayCaptor.getValue());
|
verify(mNetworkManagementService, atLeastOnce()).setDnsConfigurationForNetwork(
|
||||||
|
anyInt(), eq(EMPTY_STRING_ARRAY), any(), any(), eq(""), eq(EMPTY_STRING_ARRAY));
|
||||||
reset(mNetworkManagementService);
|
reset(mNetworkManagementService);
|
||||||
|
|
||||||
cellLp.addDnsServer(InetAddress.getByName("2001:db8::1"));
|
cellLp.addDnsServer(InetAddress.getByName("2001:db8::1"));
|
||||||
mCellNetworkAgent.sendLinkProperties(cellLp);
|
mCellNetworkAgent.sendLinkProperties(cellLp);
|
||||||
waitForIdle();
|
waitForIdle();
|
||||||
verify(mNetworkManagementService, times(1)).setDnsConfigurationForNetwork(
|
verify(mNetworkManagementService, atLeastOnce()).setDnsConfigurationForNetwork(
|
||||||
anyInt(), mStringArrayCaptor.capture(), any(), any(),
|
anyInt(), mStringArrayCaptor.capture(), any(), any(),
|
||||||
anyString(), eq(EMPTY_TLS_SERVERS));
|
eq(""), tlsServers.capture());
|
||||||
assertEquals(1, mStringArrayCaptor.getValue().length);
|
assertEquals(1, mStringArrayCaptor.getValue().length);
|
||||||
assertTrue(ArrayUtils.contains(mStringArrayCaptor.getValue(), "2001:db8::1"));
|
assertTrue(ArrayUtils.contains(mStringArrayCaptor.getValue(), "2001:db8::1"));
|
||||||
|
// Opportunistic mode.
|
||||||
|
assertTrue(ArrayUtils.contains(tlsServers.getValue(), "2001:db8::1"));
|
||||||
reset(mNetworkManagementService);
|
reset(mNetworkManagementService);
|
||||||
|
|
||||||
cellLp.addDnsServer(InetAddress.getByName("192.0.2.1"));
|
cellLp.addDnsServer(InetAddress.getByName("192.0.2.1"));
|
||||||
mCellNetworkAgent.sendLinkProperties(cellLp);
|
mCellNetworkAgent.sendLinkProperties(cellLp);
|
||||||
waitForIdle();
|
waitForIdle();
|
||||||
verify(mNetworkManagementService, times(1)).setDnsConfigurationForNetwork(
|
verify(mNetworkManagementService, atLeastOnce()).setDnsConfigurationForNetwork(
|
||||||
anyInt(), mStringArrayCaptor.capture(), any(), any(),
|
anyInt(), mStringArrayCaptor.capture(), any(), any(),
|
||||||
anyString(), eq(EMPTY_TLS_SERVERS));
|
eq(""), tlsServers.capture());
|
||||||
assertEquals(2, mStringArrayCaptor.getValue().length);
|
assertEquals(2, mStringArrayCaptor.getValue().length);
|
||||||
assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(),
|
assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(),
|
||||||
new String[]{"2001:db8::1", "192.0.2.1"}));
|
new String[]{"2001:db8::1", "192.0.2.1"}));
|
||||||
|
// Opportunistic mode.
|
||||||
|
assertEquals(2, tlsServers.getValue().length);
|
||||||
|
assertTrue(ArrayUtils.containsAll(tlsServers.getValue(),
|
||||||
|
new String[]{"2001:db8::1", "192.0.2.1"}));
|
||||||
reset(mNetworkManagementService);
|
reset(mNetworkManagementService);
|
||||||
|
|
||||||
final String TLS_SPECIFIER = "tls.example.com";
|
final String TLS_SPECIFIER = "tls.example.com";
|
||||||
@@ -3730,7 +3757,7 @@ public class ConnectivityServiceTest {
|
|||||||
mCellNetworkAgent.getNetwork().netId,
|
mCellNetworkAgent.getNetwork().netId,
|
||||||
new DnsManager.PrivateDnsConfig(TLS_SPECIFIER, TLS_IPS)));
|
new DnsManager.PrivateDnsConfig(TLS_SPECIFIER, TLS_IPS)));
|
||||||
waitForIdle();
|
waitForIdle();
|
||||||
verify(mNetworkManagementService, times(1)).setDnsConfigurationForNetwork(
|
verify(mNetworkManagementService, atLeastOnce()).setDnsConfigurationForNetwork(
|
||||||
anyInt(), mStringArrayCaptor.capture(), any(), any(),
|
anyInt(), mStringArrayCaptor.capture(), any(), any(),
|
||||||
eq(TLS_SPECIFIER), eq(TLS_SERVERS));
|
eq(TLS_SPECIFIER), eq(TLS_SERVERS));
|
||||||
assertEquals(2, mStringArrayCaptor.getValue().length);
|
assertEquals(2, mStringArrayCaptor.getValue().length);
|
||||||
@@ -3739,6 +3766,77 @@ public class ConnectivityServiceTest {
|
|||||||
reset(mNetworkManagementService);
|
reset(mNetworkManagementService);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPrivateDnsSettingsChange() throws Exception {
|
||||||
|
final String[] EMPTY_STRING_ARRAY = new String[0];
|
||||||
|
ArgumentCaptor<String[]> tlsServers = ArgumentCaptor.forClass(String[].class);
|
||||||
|
|
||||||
|
// Clear any interactions that occur as a result of CS starting up.
|
||||||
|
reset(mNetworkManagementService);
|
||||||
|
|
||||||
|
// The default on Android is opportunistic mode ("Automatic").
|
||||||
|
setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com");
|
||||||
|
|
||||||
|
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
|
||||||
|
waitForIdle();
|
||||||
|
// CS tells netd about the empty DNS config for this network.
|
||||||
|
verify(mNetworkManagementService, never()).setDnsConfigurationForNetwork(
|
||||||
|
anyInt(), eq(EMPTY_STRING_ARRAY), any(), any(), eq(""), eq(EMPTY_STRING_ARRAY));
|
||||||
|
verifyNoMoreInteractions(mNetworkManagementService);
|
||||||
|
|
||||||
|
final LinkProperties cellLp = new LinkProperties();
|
||||||
|
cellLp.setInterfaceName(MOBILE_IFNAME);
|
||||||
|
// Add IPv4 and IPv6 default routes, because DNS-over-TLS code does
|
||||||
|
// "is-reachable" testing in order to not program netd with unreachable
|
||||||
|
// nameservers that it might try repeated to validate.
|
||||||
|
cellLp.addLinkAddress(new LinkAddress("192.0.2.4/24"));
|
||||||
|
cellLp.addRoute(new RouteInfo((IpPrefix) null, InetAddress.getByName("192.0.2.4"),
|
||||||
|
MOBILE_IFNAME));
|
||||||
|
cellLp.addLinkAddress(new LinkAddress("2001:db8:1::1/64"));
|
||||||
|
cellLp.addRoute(new RouteInfo((IpPrefix) null, InetAddress.getByName("2001:db8:1::1"),
|
||||||
|
MOBILE_IFNAME));
|
||||||
|
cellLp.addDnsServer(InetAddress.getByName("2001:db8::1"));
|
||||||
|
cellLp.addDnsServer(InetAddress.getByName("192.0.2.1"));
|
||||||
|
|
||||||
|
mCellNetworkAgent.sendLinkProperties(cellLp);
|
||||||
|
mCellNetworkAgent.connect(false);
|
||||||
|
waitForIdle();
|
||||||
|
verify(mNetworkManagementService, atLeastOnce()).setDnsConfigurationForNetwork(
|
||||||
|
anyInt(), mStringArrayCaptor.capture(), any(), any(),
|
||||||
|
eq(""), tlsServers.capture());
|
||||||
|
assertEquals(2, mStringArrayCaptor.getValue().length);
|
||||||
|
assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(),
|
||||||
|
new String[]{"2001:db8::1", "192.0.2.1"}));
|
||||||
|
// Opportunistic mode.
|
||||||
|
assertEquals(2, tlsServers.getValue().length);
|
||||||
|
assertTrue(ArrayUtils.containsAll(tlsServers.getValue(),
|
||||||
|
new String[]{"2001:db8::1", "192.0.2.1"}));
|
||||||
|
reset(mNetworkManagementService);
|
||||||
|
|
||||||
|
setPrivateDnsSettings(PRIVATE_DNS_MODE_OFF, "ignored.example.com");
|
||||||
|
verify(mNetworkManagementService, times(1)).setDnsConfigurationForNetwork(
|
||||||
|
anyInt(), mStringArrayCaptor.capture(), any(), any(),
|
||||||
|
eq(""), eq(EMPTY_STRING_ARRAY));
|
||||||
|
assertEquals(2, mStringArrayCaptor.getValue().length);
|
||||||
|
assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(),
|
||||||
|
new String[]{"2001:db8::1", "192.0.2.1"}));
|
||||||
|
reset(mNetworkManagementService);
|
||||||
|
|
||||||
|
setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com");
|
||||||
|
verify(mNetworkManagementService, atLeastOnce()).setDnsConfigurationForNetwork(
|
||||||
|
anyInt(), mStringArrayCaptor.capture(), any(), any(),
|
||||||
|
eq(""), tlsServers.capture());
|
||||||
|
assertEquals(2, mStringArrayCaptor.getValue().length);
|
||||||
|
assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(),
|
||||||
|
new String[]{"2001:db8::1", "192.0.2.1"}));
|
||||||
|
assertEquals(2, tlsServers.getValue().length);
|
||||||
|
assertTrue(ArrayUtils.containsAll(tlsServers.getValue(),
|
||||||
|
new String[]{"2001:db8::1", "192.0.2.1"}));
|
||||||
|
reset(mNetworkManagementService);
|
||||||
|
|
||||||
|
// Can't test strict mode without properly mocking out the DNS lookups.
|
||||||
|
}
|
||||||
|
|
||||||
private void checkDirectlyConnectedRoutes(Object callbackObj,
|
private void checkDirectlyConnectedRoutes(Object callbackObj,
|
||||||
Collection<LinkAddress> linkAddresses, Collection<RouteInfo> otherRoutes) {
|
Collection<LinkAddress> linkAddresses, Collection<RouteInfo> otherRoutes) {
|
||||||
assertTrue(callbackObj instanceof LinkProperties);
|
assertTrue(callbackObj instanceof LinkProperties);
|
||||||
|
|||||||
Reference in New Issue
Block a user