xref: /aosp_15_r20/external/cronet/net/dns/dns_config_service_android.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2021 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "net/dns/dns_config_service_android.h"
6 
7 #include <sys/system_properties.h>
8 
9 #include <memory>
10 #include <optional>
11 #include <string>
12 #include <utility>
13 
14 #include "base/android/build_info.h"
15 #include "base/files/file_path.h"
16 #include "base/functional/bind.h"
17 #include "base/logging.h"
18 #include "base/memory/raw_ptr.h"
19 #include "base/sequence_checker.h"
20 #include "base/time/time.h"
21 #include "net/android/network_library.h"
22 #include "net/base/address_tracker_linux.h"
23 #include "net/base/ip_address.h"
24 #include "net/base/ip_endpoint.h"
25 #include "net/base/network_interfaces.h"
26 #include "net/dns/dns_config.h"
27 #include "net/dns/dns_config_service.h"
28 #include "net/dns/public/dns_protocol.h"
29 #include "net/dns/serial_worker.h"
30 
31 namespace net {
32 namespace internal {
33 
34 namespace {
35 
36 constexpr base::FilePath::CharType kFilePathHosts[] =
37     FILE_PATH_LITERAL("/system/etc/hosts");
38 
IsVpnPresent()39 bool IsVpnPresent() {
40   NetworkInterfaceList networks;
41   if (!GetNetworkList(&networks, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES))
42     return false;
43 
44   for (NetworkInterface network : networks) {
45     if (AddressTrackerLinux::IsTunnelInterfaceName(network.name.c_str()))
46       return true;
47   }
48   return false;
49 }
50 
51 }  // namespace
52 
53 // static
54 constexpr base::TimeDelta DnsConfigServiceAndroid::kConfigChangeDelay;
55 
56 class DnsConfigServiceAndroid::ConfigReader : public SerialWorker {
57  public:
ConfigReader(DnsConfigServiceAndroid & service,android::DnsServerGetter dns_server_getter)58   explicit ConfigReader(DnsConfigServiceAndroid& service,
59                         android::DnsServerGetter dns_server_getter)
60       : dns_server_getter_(std::move(dns_server_getter)), service_(&service) {}
61 
62   ~ConfigReader() override = default;
63 
64   ConfigReader(const ConfigReader&) = delete;
65   ConfigReader& operator=(const ConfigReader&) = delete;
66 
CreateWorkItem()67   std::unique_ptr<SerialWorker::WorkItem> CreateWorkItem() override {
68     return std::make_unique<WorkItem>(dns_server_getter_);
69   }
70 
OnWorkFinished(std::unique_ptr<SerialWorker::WorkItem> serial_worker_work_item)71   bool OnWorkFinished(std::unique_ptr<SerialWorker::WorkItem>
72                           serial_worker_work_item) override {
73     DCHECK(serial_worker_work_item);
74     DCHECK(!IsCancelled());
75 
76     WorkItem* work_item = static_cast<WorkItem*>(serial_worker_work_item.get());
77     if (work_item->dns_config_.has_value()) {
78       service_->OnConfigRead(std::move(work_item->dns_config_).value());
79       return true;
80     } else {
81       LOG(WARNING) << "Failed to read DnsConfig.";
82       return false;
83     }
84   }
85 
86  private:
87   class WorkItem : public SerialWorker::WorkItem {
88    public:
WorkItem(android::DnsServerGetter dns_server_getter)89     explicit WorkItem(android::DnsServerGetter dns_server_getter)
90         : dns_server_getter_(std::move(dns_server_getter)) {}
91 
DoWork()92     void DoWork() override {
93       dns_config_.emplace();
94       dns_config_->unhandled_options = false;
95 
96       if (base::android::BuildInfo::GetInstance()->sdk_int() >=
97           base::android::SDK_VERSION_MARSHMALLOW) {
98         if (!dns_server_getter_.Run(
99                 &dns_config_->nameservers, &dns_config_->dns_over_tls_active,
100                 &dns_config_->dns_over_tls_hostname, &dns_config_->search)) {
101           dns_config_.reset();
102         }
103         return;
104       }
105 
106       if (IsVpnPresent()) {
107         dns_config_->unhandled_options = true;
108       }
109 
110       // NOTE(pauljensen): __system_property_get and the net.dns1/2 properties
111       // are not supported APIs, but they're only read on pre-Marshmallow
112       // Android which was released years ago and isn't changing.
113       char property_value[PROP_VALUE_MAX];
114       __system_property_get("net.dns1", property_value);
115       std::string dns1_string = property_value;
116       __system_property_get("net.dns2", property_value);
117       std::string dns2_string = property_value;
118       if (dns1_string.empty() && dns2_string.empty()) {
119         dns_config_.reset();
120         return;
121       }
122 
123       IPAddress dns1_address;
124       IPAddress dns2_address;
125       bool parsed1 = dns1_address.AssignFromIPLiteral(dns1_string);
126       bool parsed2 = dns2_address.AssignFromIPLiteral(dns2_string);
127       if (!parsed1 && !parsed2) {
128         dns_config_.reset();
129         return;
130       }
131 
132       if (parsed1) {
133         IPEndPoint dns1(dns1_address, dns_protocol::kDefaultPort);
134         dns_config_->nameservers.push_back(dns1);
135       }
136       if (parsed2) {
137         IPEndPoint dns2(dns2_address, dns_protocol::kDefaultPort);
138         dns_config_->nameservers.push_back(dns2);
139       }
140     }
141 
142    private:
143     friend class ConfigReader;
144     android::DnsServerGetter dns_server_getter_;
145     std::optional<DnsConfig> dns_config_;
146   };
147 
148   android::DnsServerGetter dns_server_getter_;
149 
150   // Raw pointer to owning DnsConfigService.
151   const raw_ptr<DnsConfigServiceAndroid> service_;
152 };
153 
DnsConfigServiceAndroid()154 DnsConfigServiceAndroid::DnsConfigServiceAndroid()
155     : DnsConfigService(kFilePathHosts, kConfigChangeDelay) {
156   // Allow constructing on one thread and living on another.
157   DETACH_FROM_SEQUENCE(sequence_checker_);
158   dns_server_getter_ = base::BindRepeating(&android::GetCurrentDnsServers);
159 }
160 
~DnsConfigServiceAndroid()161 DnsConfigServiceAndroid::~DnsConfigServiceAndroid() {
162   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
163   if (is_watching_network_change_) {
164     NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
165   }
166   if (config_reader_)
167     config_reader_->Cancel();
168 }
169 
ReadConfigNow()170 void DnsConfigServiceAndroid::ReadConfigNow() {
171   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
172   if (!config_reader_) {
173     DCHECK(dns_server_getter_);
174     config_reader_ =
175         std::make_unique<ConfigReader>(*this, std::move(dns_server_getter_));
176   }
177   config_reader_->WorkNow();
178 }
179 
StartWatching()180 bool DnsConfigServiceAndroid::StartWatching() {
181   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
182   CHECK(!is_watching_network_change_);
183   is_watching_network_change_ = true;
184 
185   // On Android, assume DNS config may have changed on every network change.
186   NetworkChangeNotifier::AddNetworkChangeObserver(this);
187 
188   // Hosts file should never change on Android (and watching it is
189   // problematic; see http://crbug.com/600442), so don't watch it.
190 
191   return true;
192 }
193 
OnNetworkChanged(NetworkChangeNotifier::ConnectionType type)194 void DnsConfigServiceAndroid::OnNetworkChanged(
195     NetworkChangeNotifier::ConnectionType type) {
196   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
197   if (type != NetworkChangeNotifier::CONNECTION_NONE) {
198     OnConfigChanged(/*succeeded=*/true);
199   }
200 }
201 }  // namespace internal
202 
203 // static
CreateSystemService()204 std::unique_ptr<DnsConfigService> DnsConfigService::CreateSystemService() {
205   return std::make_unique<internal::DnsConfigServiceAndroid>();
206 }
207 
208 }  // namespace net
209