123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225 |
- // Copyright 2021 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 "net/dns/dns_config_service_android.h"
- #include <sys/system_properties.h>
- #include <memory>
- #include <string>
- #include <utility>
- #include "base/android/build_info.h"
- #include "base/bind.h"
- #include "base/files/file_path.h"
- #include "base/logging.h"
- #include "base/memory/raw_ptr.h"
- #include "base/sequence_checker.h"
- #include "base/time/time.h"
- #include "net/android/network_library.h"
- #include "net/base/address_tracker_linux.h"
- #include "net/base/ip_address.h"
- #include "net/base/ip_endpoint.h"
- #include "net/base/network_change_notifier.h"
- #include "net/base/network_interfaces.h"
- #include "net/dns/dns_config.h"
- #include "net/dns/dns_config_service.h"
- #include "net/dns/public/dns_protocol.h"
- #include "net/dns/serial_worker.h"
- #include "third_party/abseil-cpp/absl/types/optional.h"
- namespace net {
- namespace internal {
- namespace {
- constexpr base::FilePath::CharType kFilePathHosts[] =
- FILE_PATH_LITERAL("/system/etc/hosts");
- bool IsVpnPresent() {
- NetworkInterfaceList networks;
- if (!GetNetworkList(&networks, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES))
- return false;
- for (NetworkInterface network : networks) {
- if (AddressTrackerLinux::IsTunnelInterfaceName(network.name.c_str()))
- return true;
- }
- return false;
- }
- } // namespace
- // static
- constexpr base::TimeDelta DnsConfigServiceAndroid::kConfigChangeDelay;
- class DnsConfigServiceAndroid::Watcher
- : public DnsConfigService::Watcher,
- public NetworkChangeNotifier::NetworkChangeObserver {
- public:
- explicit Watcher(DnsConfigServiceAndroid& service)
- : DnsConfigService::Watcher(service) {}
- ~Watcher() override {
- NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
- }
- Watcher(const Watcher&) = delete;
- Watcher& operator=(const Watcher&) = delete;
- // DnsConfigService::Watcher:
- bool Watch() override {
- CheckOnCorrectSequence();
- // On Android, assume DNS config may have changed on every network change.
- NetworkChangeNotifier::AddNetworkChangeObserver(this);
- // Hosts file should never change on Android (and watching it is
- // problematic; see http://crbug.com/600442), so don't watch it.
- return true;
- }
- // NetworkChangeNotifier::NetworkChangeObserver:
- void OnNetworkChanged(NetworkChangeNotifier::ConnectionType type) override {
- if (type != NetworkChangeNotifier::CONNECTION_NONE)
- OnConfigChanged(true);
- }
- };
- class DnsConfigServiceAndroid::ConfigReader : public SerialWorker {
- public:
- explicit ConfigReader(DnsConfigServiceAndroid& service,
- android::DnsServerGetter dns_server_getter)
- : dns_server_getter_(std::move(dns_server_getter)), service_(&service) {}
- ~ConfigReader() override = default;
- ConfigReader(const ConfigReader&) = delete;
- ConfigReader& operator=(const ConfigReader&) = delete;
- std::unique_ptr<SerialWorker::WorkItem> CreateWorkItem() override {
- return std::make_unique<WorkItem>(dns_server_getter_);
- }
- bool OnWorkFinished(std::unique_ptr<SerialWorker::WorkItem>
- serial_worker_work_item) override {
- DCHECK(serial_worker_work_item);
- DCHECK(!IsCancelled());
- WorkItem* work_item = static_cast<WorkItem*>(serial_worker_work_item.get());
- if (work_item->dns_config_.has_value()) {
- service_->OnConfigRead(std::move(work_item->dns_config_).value());
- return true;
- } else {
- LOG(WARNING) << "Failed to read DnsConfig.";
- return false;
- }
- }
- private:
- class WorkItem : public SerialWorker::WorkItem {
- public:
- explicit WorkItem(android::DnsServerGetter dns_server_getter)
- : dns_server_getter_(std::move(dns_server_getter)) {}
- void DoWork() override {
- dns_config_.emplace();
- dns_config_->unhandled_options = false;
- if (base::android::BuildInfo::GetInstance()->sdk_int() >=
- base::android::SDK_VERSION_MARSHMALLOW) {
- if (!dns_server_getter_.Run(
- &dns_config_->nameservers, &dns_config_->dns_over_tls_active,
- &dns_config_->dns_over_tls_hostname, &dns_config_->search)) {
- dns_config_.reset();
- }
- return;
- }
- if (IsVpnPresent()) {
- dns_config_->unhandled_options = true;
- }
- // NOTE(pauljensen): __system_property_get and the net.dns1/2 properties
- // are not supported APIs, but they're only read on pre-Marshmallow
- // Android which was released years ago and isn't changing.
- char property_value[PROP_VALUE_MAX];
- __system_property_get("net.dns1", property_value);
- std::string dns1_string = property_value;
- __system_property_get("net.dns2", property_value);
- std::string dns2_string = property_value;
- if (dns1_string.empty() && dns2_string.empty()) {
- dns_config_.reset();
- return;
- }
- IPAddress dns1_address;
- IPAddress dns2_address;
- bool parsed1 = dns1_address.AssignFromIPLiteral(dns1_string);
- bool parsed2 = dns2_address.AssignFromIPLiteral(dns2_string);
- if (!parsed1 && !parsed2) {
- dns_config_.reset();
- return;
- }
- if (parsed1) {
- IPEndPoint dns1(dns1_address, dns_protocol::kDefaultPort);
- dns_config_->nameservers.push_back(dns1);
- }
- if (parsed2) {
- IPEndPoint dns2(dns2_address, dns_protocol::kDefaultPort);
- dns_config_->nameservers.push_back(dns2);
- }
- }
- private:
- friend class ConfigReader;
- android::DnsServerGetter dns_server_getter_;
- absl::optional<DnsConfig> dns_config_;
- };
- android::DnsServerGetter dns_server_getter_;
- // Raw pointer to owning DnsConfigService.
- const raw_ptr<DnsConfigServiceAndroid> service_;
- };
- DnsConfigServiceAndroid::DnsConfigServiceAndroid()
- : DnsConfigService(kFilePathHosts, kConfigChangeDelay) {
- // Allow constructing on one thread and living on another.
- DETACH_FROM_SEQUENCE(sequence_checker_);
- dns_server_getter_ = base::BindRepeating(&android::GetCurrentDnsServers);
- }
- DnsConfigServiceAndroid::~DnsConfigServiceAndroid() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (config_reader_)
- config_reader_->Cancel();
- }
- void DnsConfigServiceAndroid::ReadConfigNow() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (!config_reader_) {
- DCHECK(dns_server_getter_);
- config_reader_ =
- std::make_unique<ConfigReader>(*this, std::move(dns_server_getter_));
- }
- config_reader_->WorkNow();
- }
- bool DnsConfigServiceAndroid::StartWatching() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- // TODO(crbug.com/116139): re-start watcher if that makes sense.
- watcher_ = std::make_unique<Watcher>(*this);
- return watcher_->Watch();
- }
- } // namespace internal
- // static
- std::unique_ptr<DnsConfigService> DnsConfigService::CreateSystemService() {
- return std::make_unique<internal::DnsConfigServiceAndroid>();
- }
- } // namespace net
|