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