Commit 2367ac92 authored by Kartik Hegde's avatar Kartik Hegde Committed by Commit Bot

network_diagnostics: Add ResolverPresentRoutine

Add a routine to determine whether the current network has nameservers
available for DNS resolution.

BUG=chromium:956783
TEST=unit_tests --gtest_filter=ResolverPresentRoutineTest.*

Change-Id: Ic9055f2bdce2df0e5bd8c3e147a635cd0e6a31c8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2151676Reviewed-by: default avatarSteven Bennetts <stevenjb@chromium.org>
Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Commit-Queue: Kartik Hegde <khegde@chromium.org>
Cr-Commit-Position: refs/heads/master@{#770840}
parent ba82f691
......@@ -1745,6 +1745,8 @@ source_set("chromeos") {
"net/delay_network_call.h",
"net/dhcp_wpad_url_client.cc",
"net/dhcp_wpad_url_client.h",
"net/network_diagnostics/dns_resolver_present_routine.cc",
"net/network_diagnostics/dns_resolver_present_routine.h",
"net/network_diagnostics/gateway_can_be_pinged_routine.cc",
"net/network_diagnostics/gateway_can_be_pinged_routine.h",
"net/network_diagnostics/has_secure_wifi_connection_routine.cc",
......@@ -3079,6 +3081,7 @@ source_set("unit_tests") {
"login/version_updater/version_updater_unittest.cc",
"mobile/mobile_activator_unittest.cc",
"net/client_cert_store_chromeos_unittest.cc",
"net/network_diagnostics/dns_resolver_present_routine_unittest.cc",
"net/network_diagnostics/gateway_can_be_pinged_routine_unittest.cc",
"net/network_diagnostics/has_secure_wifi_connection_routine_unittest.cc",
"net/network_diagnostics/lan_connectivity_routine_unittest.cc",
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/chromeos/net/network_diagnostics/dns_resolver_present_routine.h"
#include <string>
#include <utility>
#include <vector>
#include "base/bind.h"
#include "base/optional.h"
#include "chromeos/services/network_config/in_process_instance.h"
#include "chromeos/services/network_config/public/cpp/cros_network_config_util.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
namespace chromeos {
namespace network_diagnostics {
namespace {
bool NameServersAreWellFormed(const std::vector<std::string>& name_servers) {
for (const auto& name_server : name_servers) {
if (name_server == "0.0.0.0" || name_server == "::/0") {
return false;
}
}
return true;
}
bool NameServersAreNonEmpty(const std::vector<std::string>& name_servers) {
for (const auto& name_server : name_servers) {
if (name_server.empty()) {
return false;
}
}
return true;
}
} // namespace
DnsResolverPresentRoutine::DnsResolverPresentRoutine() {
set_verdict(mojom::RoutineVerdict::kNotRun);
network_config::BindToInProcessInstance(
remote_cros_network_config_.BindNewPipeAndPassReceiver());
}
DnsResolverPresentRoutine::~DnsResolverPresentRoutine() = default;
bool DnsResolverPresentRoutine::CanRun() {
DCHECK(remote_cros_network_config_);
return true;
}
void DnsResolverPresentRoutine::RunTest(
mojom::NetworkDiagnosticsRoutines::DnsResolverPresentCallback callback) {
if (!CanRun()) {
std::move(callback).Run(verdict(), std::move(problems_));
return;
}
routine_completed_callback_ = std::move(callback);
FetchActiveNetworks();
}
void DnsResolverPresentRoutine::AnalyzeResultsAndExecuteCallback() {
if (!name_servers_found_) {
set_verdict(mojom::RoutineVerdict::kProblem);
problems_.emplace_back(
mojom::DnsResolverPresentProblem::kNoNameServersFound);
} else if (!non_empty_name_servers_) {
set_verdict(mojom::RoutineVerdict::kProblem);
problems_.emplace_back(mojom::DnsResolverPresentProblem::kEmptyNameServers);
} else if (!well_formed_name_servers_) {
set_verdict(mojom::RoutineVerdict::kProblem);
problems_.emplace_back(
mojom::DnsResolverPresentProblem::kMalformedNameServers);
} else {
// The availability of non-empty, well-formed nameservers ensures that DNS
// resolution should be possible.
set_verdict(mojom::RoutineVerdict::kNoProblem);
}
std::move(routine_completed_callback_).Run(verdict(), std::move(problems_));
}
void DnsResolverPresentRoutine::FetchActiveNetworks() {
DCHECK(remote_cros_network_config_);
remote_cros_network_config_->GetNetworkStateList(
network_config::mojom::NetworkFilter::New(
network_config::mojom::FilterType::kActive,
network_config::mojom::NetworkType::kAll,
network_config::mojom::kNoLimit),
base::BindOnce(&DnsResolverPresentRoutine::OnNetworkStateListReceived,
base::Unretained(this)));
}
void DnsResolverPresentRoutine::FetchManagedProperties(
const std::string& guid) {
remote_cros_network_config_->GetManagedProperties(
guid,
base::BindOnce(&DnsResolverPresentRoutine::OnManagedPropertiesReceived,
base::Unretained(this)));
}
void DnsResolverPresentRoutine::OnManagedPropertiesReceived(
network_config::mojom::ManagedPropertiesPtr managed_properties) {
if (!managed_properties || !managed_properties->ip_configs.has_value()) {
AnalyzeResultsAndExecuteCallback();
return;
}
for (const auto& ip_config : managed_properties->ip_configs.value()) {
if (ip_config->name_servers.has_value() &&
ip_config->name_servers->size() != 0) {
name_servers_found_ = true;
if (NameServersAreNonEmpty(ip_config->name_servers.value())) {
non_empty_name_servers_ = true;
}
if (NameServersAreWellFormed(ip_config->name_servers.value())) {
well_formed_name_servers_ = true;
break;
}
}
}
AnalyzeResultsAndExecuteCallback();
}
// Process the network interface information.
void DnsResolverPresentRoutine::OnNetworkStateListReceived(
std::vector<network_config::mojom::NetworkStatePropertiesPtr> networks) {
std::string default_guid;
for (const auto& network : networks) {
if (network_config::StateIsConnected(network->connection_state)) {
default_guid = network->guid;
break;
}
}
// Since we are not connected, proceed to analyzing the results and executing
// the completion callback.
if (default_guid.empty()) {
AnalyzeResultsAndExecuteCallback();
} else {
FetchManagedProperties(default_guid);
}
}
} // namespace network_diagnostics
} // namespace chromeos
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_CHROMEOS_NET_NETWORK_DIAGNOSTICS_DNS_RESOLVER_PRESENT_ROUTINE_H_
#define CHROME_BROWSER_CHROMEOS_NET_NETWORK_DIAGNOSTICS_DNS_RESOLVER_PRESENT_ROUTINE_H_
#include <vector>
#include "base/callback.h"
#include "chrome/browser/chromeos/net/network_diagnostics/network_diagnostics_routine.h"
#include "chromeos/services/network_config/public/mojom/cros_network_config.mojom.h"
#include "mojo/public/cpp/bindings/remote.h"
namespace chromeos {
namespace network_diagnostics {
// Tests whether the current network is set up correctly for performing DNS
// resolution.
class DnsResolverPresentRoutine : public NetworkDiagnosticsRoutine {
public:
DnsResolverPresentRoutine();
~DnsResolverPresentRoutine() override;
// NetworkDiagnosticsRoutine:
bool CanRun() override;
void AnalyzeResultsAndExecuteCallback() override;
// Run the core logic of this routine. Set |callback| to
// |routine_completed_callback_|, which is to be executed in
// AnalyzeResultsAndExecuteCallback().
void RunTest(
mojom::NetworkDiagnosticsRoutines::DnsResolverPresentCallback callback);
private:
void FetchActiveNetworks();
void FetchManagedProperties(const std::string& guid);
void OnManagedPropertiesReceived(
chromeos::network_config::mojom::ManagedPropertiesPtr managed_properties);
void OnNetworkStateListReceived(
std::vector<chromeos::network_config::mojom::NetworkStatePropertiesPtr>
networks);
bool name_servers_found_ = false;
bool non_empty_name_servers_ = false;
bool well_formed_name_servers_ = false;
std::vector<mojom::DnsResolverPresentProblem> problems_;
mojo::Remote<chromeos::network_config::mojom::CrosNetworkConfig>
remote_cros_network_config_;
mojom::NetworkDiagnosticsRoutines::DnsResolverPresentCallback
routine_completed_callback_;
DISALLOW_COPY_AND_ASSIGN(DnsResolverPresentRoutine);
};
} // namespace network_diagnostics
} // namespace chromeos
#endif // CHROME_BROWSER_CHROMEOS_NET_NETWORK_DIAGNOSTICS_DNS_RESOLVER_PRESENT_ROUTINE_H_
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/chromeos/net/network_diagnostics/dns_resolver_present_routine.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/debug_daemon/fake_debug_daemon_client.h"
#include "chromeos/login/login_state/login_state.h"
#include "chromeos/network/managed_network_configuration_handler.h"
#include "chromeos/network/network_cert_loader.h"
#include "chromeos/network/network_configuration_handler.h"
#include "chromeos/network/network_handler.h"
#include "chromeos/network/network_metadata_store.h"
#include "chromeos/network/network_profile_handler.h"
#include "chromeos/network/onc/onc_utils.h"
#include "chromeos/network/proxy/ui_proxy_config_service.h"
#include "chromeos/services/network_config/public/cpp/cros_network_config_test_helper.h"
#include "components/onc/onc_constants.h"
#include "components/onc/onc_pref_names.h"
#include "components/prefs/testing_pref_service.h"
#include "components/proxy_config/pref_proxy_config_tracker_impl.h"
#include "components/proxy_config/proxy_config_pref_names.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "content/public/test/browser_task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/cros_system_api/dbus/shill/dbus-constants.h"
namespace chromeos {
namespace network_diagnostics {
namespace {
// The IP v4 config path specified here must match the IP v4 config path
// specified in NetworkStateTestHelper::ResetDevicesAndServices(), which itself
// is based on the IP v4 config path used to set up IP v4 configs in
// FakeShillManagerClient::SetupDefaultEnvironment().
const char kIPv4ConfigPath[] = "ipconfig_v4_path";
const std::vector<std::string> kWellFormedDnsServers = {
"192.168.1.100", "192.168.1.101", "192.168.1.102"};
const std::vector<std::string> kMalformedDnsServers = {"0.0.0.0",
"192.168.1.100", "::/0"};
const std::vector<std::string> kEmptyDnsServers = {"192.168.1.100", ""};
} // namespace
class DnsResolverPresentRoutineTest : public ::testing::Test {
public:
DnsResolverPresentRoutineTest() {
LoginState::Initialize();
NetworkCertLoader::Initialize();
InitializeManagedNetworkConfigurationHandler();
// Note that |cros_network_config_test_helper_| must be initialized before
// |dns_resolver_present_routine_| is initialized. This is because
// |g_network_config_override| in OverrideInProcessInstanceForTesting() must
// be called before BindToInProcessInstance() is called. See
// chromeos/services/network_config/in_process_instance.cc for further
// details.
cros_network_config_test_helper().Initialize(
managed_network_configuration_handler_.get());
dns_resolver_present_routine_ =
std::make_unique<DnsResolverPresentRoutine>();
// Wait until |cros_network_config_test_helper_| has initialized.
base::RunLoop().RunUntilIdle();
}
~DnsResolverPresentRoutineTest() override {
NetworkCertLoader::Shutdown();
LoginState::Shutdown();
managed_network_configuration_handler_.reset();
ui_proxy_config_service_.reset();
network_configuration_handler_.reset();
network_profile_handler_.reset();
}
void CompareVerdict(
mojom::RoutineVerdict expected_verdict,
const std::vector<mojom::DnsResolverPresentProblem>& expected_problems,
mojom::RoutineVerdict actual_verdict,
const std::vector<mojom::DnsResolverPresentProblem>& actual_problems) {
EXPECT_EQ(expected_verdict, actual_verdict);
EXPECT_EQ(expected_problems, actual_problems);
run_loop_.Quit();
}
void SetUpWiFi(const char* state) {
DCHECK(wifi_path_.empty());
// By default, NetworkStateTestHelper already adds a WiFi device, so, we
// do not need to add one here. All that remains to be done is configuring
// the WiFi service.
wifi_path_ = ConfigureService(
R"({"GUID": "wifi_guid", "Type": "wifi", "State": "idle"})");
SetServiceProperty(wifi_path_, shill::kStateProperty, base::Value(state));
// Wait until the |wifi_path_| is set up.
base::RunLoop().RunUntilIdle();
}
// Set up the name servers and change the IPConfigs for the WiFi device and
// service by overwriting the initial IPConfigs that are set up in
// FakeShillManagerClient::SetupDefaultEnvironment(). Attach name
// servers to the IP config.
void SetUpNameServers(const std::vector<std::string>& name_servers) {
DCHECK(!wifi_path_.empty());
// Set up the name servers
base::ListValue dns_servers;
for (const std::string& name_server : name_servers) {
dns_servers.AppendString(name_server);
}
// Set up the IP v4 config
base::DictionaryValue ip_config_v4_properties;
ip_config_v4_properties.SetKey(shill::kNameServersProperty,
base::Value(dns_servers.Clone()));
network_state_helper().ip_config_test()->AddIPConfig(
kIPv4ConfigPath, ip_config_v4_properties);
std::string wifi_device_path =
network_state_helper().device_test()->GetDevicePathForType(
shill::kTypeWifi);
network_state_helper().device_test()->SetDeviceProperty(
wifi_device_path, shill::kIPConfigsProperty, ip_config_v4_properties,
/*notify_changed=*/true);
SetServiceProperty(wifi_path_, shill::kIPConfigProperty,
base::Value(kIPv4ConfigPath));
// Wait until the changed name servers have been notified (notification
// triggered by call to SetDeviceProperty() above) and that the |wifi_path_|
// has been set up.
base::RunLoop().RunUntilIdle();
}
void InitializeManagedNetworkConfigurationHandler() {
network_profile_handler_ = NetworkProfileHandler::InitializeForTesting();
network_configuration_handler_ =
base::WrapUnique<NetworkConfigurationHandler>(
NetworkConfigurationHandler::InitializeForTest(
network_state_helper().network_state_handler(),
cros_network_config_test_helper().network_device_handler()));
PrefProxyConfigTrackerImpl::RegisterProfilePrefs(user_prefs_.registry());
PrefProxyConfigTrackerImpl::RegisterPrefs(local_state_.registry());
::onc::RegisterProfilePrefs(user_prefs_.registry());
::onc::RegisterPrefs(local_state_.registry());
ui_proxy_config_service_ = std::make_unique<chromeos::UIProxyConfigService>(
&user_prefs_, &local_state_,
network_state_helper().network_state_handler(),
network_profile_handler_.get());
managed_network_configuration_handler_ =
ManagedNetworkConfigurationHandler::InitializeForTesting(
network_state_helper().network_state_handler(),
network_profile_handler_.get(),
cros_network_config_test_helper().network_device_handler(),
network_configuration_handler_.get(),
ui_proxy_config_service_.get());
managed_network_configuration_handler_->SetPolicy(
::onc::ONC_SOURCE_DEVICE_POLICY,
/*userhash=*/std::string(),
/*network_configs_onc=*/base::ListValue(),
/*global_network_config=*/base::DictionaryValue());
// Wait until the |managed_network_configuration_handler_| is initialized
// and set up.
base::RunLoop().RunUntilIdle();
}
void RunTest(
mojom::RoutineVerdict routine_verdict,
const std::vector<mojom::DnsResolverPresentProblem>& expected_problems) {
dns_resolver_present_routine_->RunTest(
base::BindOnce(&DnsResolverPresentRoutineTest::CompareVerdict,
weak_ptr(), routine_verdict, expected_problems));
run_loop().Run();
}
network_config::CrosNetworkConfigTestHelper&
cros_network_config_test_helper() {
return cros_network_config_test_helper_;
}
chromeos::NetworkStateTestHelper& network_state_helper() {
return cros_network_config_test_helper_.network_state_helper();
}
DnsResolverPresentRoutine* dns_resolver_present_routine() {
return dns_resolver_present_routine_.get();
}
base::RunLoop& run_loop() { return run_loop_; }
protected:
base::WeakPtr<DnsResolverPresentRoutineTest> weak_ptr() {
return weak_factory_.GetWeakPtr();
}
private:
std::string ConfigureService(const std::string& shill_json_string) {
return network_state_helper().ConfigureService(shill_json_string);
}
void SetServiceProperty(const std::string& service_path,
const std::string& key,
const base::Value& value) {
network_state_helper().SetServiceProperty(service_path, key, value);
}
const std::string& wifi_path() const { return wifi_path_; }
content::BrowserTaskEnvironment task_environment_;
base::RunLoop run_loop_;
network_config::CrosNetworkConfigTestHelper cros_network_config_test_helper_{
false};
std::unique_ptr<DnsResolverPresentRoutine> dns_resolver_present_routine_;
std::unique_ptr<FakeDebugDaemonClient> debug_daemon_client_;
std::string wifi_path_;
std::unique_ptr<NetworkProfileHandler> network_profile_handler_;
std::unique_ptr<NetworkConfigurationHandler> network_configuration_handler_;
std::unique_ptr<ManagedNetworkConfigurationHandler>
managed_network_configuration_handler_;
std::unique_ptr<UIProxyConfigService> ui_proxy_config_service_;
sync_preferences::TestingPrefServiceSyncable user_prefs_;
TestingPrefServiceSimple local_state_;
base::WeakPtrFactory<DnsResolverPresentRoutineTest> weak_factory_{this};
DISALLOW_COPY_AND_ASSIGN(DnsResolverPresentRoutineTest);
};
TEST_F(DnsResolverPresentRoutineTest, TestResolverPresent) {
SetUpWiFi(shill::kStateOnline);
SetUpNameServers(kWellFormedDnsServers);
RunTest(mojom::RoutineVerdict::kNoProblem, {});
}
TEST_F(DnsResolverPresentRoutineTest, TestNoResolverPresent) {
SetUpWiFi(shill::kStateOnline);
RunTest(mojom::RoutineVerdict::kProblem,
{mojom::DnsResolverPresentProblem::kNoNameServersFound});
}
TEST_F(DnsResolverPresentRoutineTest, TestMalformedNameServers) {
SetUpWiFi(shill::kStateOnline);
SetUpNameServers(kMalformedDnsServers);
RunTest(mojom::RoutineVerdict::kProblem,
{mojom::DnsResolverPresentProblem::kMalformedNameServers});
}
TEST_F(DnsResolverPresentRoutineTest, TestEmptyNameServers) {
SetUpWiFi(shill::kStateOnline);
SetUpNameServers(kEmptyDnsServers);
RunTest(mojom::RoutineVerdict::kProblem,
{mojom::DnsResolverPresentProblem::kEmptyNameServers});
}
} // namespace network_diagnostics
} // namespace chromeos
......@@ -46,6 +46,14 @@ enum HasSecureWiFiConnectionProblem {
kUnknownSecurityType,
};
// Messages related to the DnsResolverPresent routine.
[Extensible]
enum DnsResolverPresentProblem {
kNoNameServersFound,
kMalformedNameServers,
kEmptyNameServers,
};
// This interface is to be used by any clients that need to run specific
// network-related diagnostics. Expected clients of this interface are
// NetworkHealth, cros_healthd, and a connectivity diagnostics Web UI (to name
......@@ -69,4 +77,8 @@ interface NetworkDiagnosticsRoutines {
// connected, the routine will result in a |kNotRun| verdict.
HasSecureWiFiConnection() => (RoutineVerdict verdict,
array<HasSecureWiFiConnectionProblem> problems);
// Tests whether a DNS resolver is available to the browser.
DnsResolverPresent() => (RoutineVerdict verdict,
array<DnsResolverPresentProblem> problems);
};
......@@ -6,6 +6,7 @@
#include <memory>
#include "chrome/browser/chromeos/net/network_diagnostics/dns_resolver_present_routine.h"
#include "chrome/browser/chromeos/net/network_diagnostics/gateway_can_be_pinged_routine.h"
#include "chrome/browser/chromeos/net/network_diagnostics/has_secure_wifi_connection_routine.h"
#include "chrome/browser/chromeos/net/network_diagnostics/lan_connectivity_routine.h"
......@@ -51,5 +52,11 @@ void NetworkDiagnosticsImpl::HasSecureWiFiConnection(
has_secure_wifi_connection_routine.RunTest(std::move(callback));
}
void NetworkDiagnosticsImpl::DnsResolverPresent(
DnsResolverPresentCallback callback) {
DnsResolverPresentRoutine dns_resolver_present_routine;
dns_resolver_present_routine.RunTest(std::move(callback));
}
} // namespace network_diagnostics
} // namespace chromeos
......@@ -30,6 +30,7 @@ class NetworkDiagnosticsImpl : public mojom::NetworkDiagnosticsRoutines {
void GatewayCanBePinged(GatewayCanBePingedCallback callback) override;
void HasSecureWiFiConnection(
HasSecureWiFiConnectionCallback callback) override;
void DnsResolverPresent(DnsResolverPresentCallback callback) override;
private:
mojo::ReceiverSet<mojom::NetworkDiagnosticsRoutines> receivers_;
......
......@@ -39,6 +39,7 @@ NetworkStateTestHelper::NetworkStateTestHelper(
profile_test_ = ShillProfileClient::Get()->GetTestInterface();
device_test_ = ShillDeviceClient::Get()->GetTestInterface();
service_test_ = ShillServiceClient::Get()->GetTestInterface();
ip_config_test_ = ShillIPConfigClient::Get()->GetTestInterface();
profile_test_->AddProfile(NetworkProfileHandler::GetSharedProfilePath(),
std::string() /* shared profile */);
......
......@@ -10,6 +10,7 @@
#include "base/memory/weak_ptr.h"
#include "chromeos/dbus/shill/shill_device_client.h"
#include "chromeos/dbus/shill/shill_ipconfig_client.h"
#include "chromeos/dbus/shill/shill_manager_client.h"
#include "chromeos/dbus/shill/shill_profile_client.h"
#include "chromeos/dbus/shill/shill_service_client.h"
......@@ -87,6 +88,9 @@ class NetworkStateTestHelper {
ShillProfileClient::TestInterface* profile_test() { return profile_test_; }
ShillDeviceClient::TestInterface* device_test() { return device_test_; }
ShillServiceClient::TestInterface* service_test() { return service_test_; }
ShillIPConfigClient::TestInterface* ip_config_test() {
return ip_config_test_;
}
private:
void ConfigureCallback(const dbus::ObjectPath& result);
......@@ -98,6 +102,7 @@ class NetworkStateTestHelper {
ShillProfileClient::TestInterface* profile_test_;
ShillDeviceClient::TestInterface* device_test_;
ShillServiceClient::TestInterface* service_test_;
ShillIPConfigClient::TestInterface* ip_config_test_;
std::unique_ptr<NetworkStateHandler> network_state_handler_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment